Technical notes · build reference

The two hardware mods,
in full.

The detail you'll want in your hand at the bench: a battery-eliminator bypass that keeps the tablet's own management board, and an isolated-relay bridge that lets Home Assistant press the alarm key fob's buttons. Wiring, schematics, annotated photos, the code — and an honest account of the dead-end that got us there.


A · Battery bypass

Run the tablet with no battery — the right way

An eleven-year-old lithium pouch, sealed to a wall, permanently warm, is the one genuine hazard in this whole build. The fix is to remove the cell and feed the tablet directly. The trick that makes it reliable — and the part I got wrong the first time — is to keep the pack's own little circuit board.

That PCB glued to the cell is the pack's BMS — battery management. It carries three things the tablet depends on: a protection circuit (over/under-voltage and over-current MOSFETs in series with the cell), an NTC thermistor for temperature, and usually a small fuel-gauge or ID chip. The one thing it does not contain is the charger itself — that CC/CV charging IC lives on the tablet's mainboard.

So feeding the bare mainboard connector is flaky: the tablet misses its thermistor and gauge and often refuses to boot, which is why the crude version needs a faked 10 kΩ resistor. Keep the BMS in circuit instead and feed your supply into its cell pads, and the tablet sees a completely normal battery — nothing to fake.

01

Keep the management board; lose the pouch

Open the pack and separate the lithium pouch from its BMS PCB, leaving the board and its mainboard connector intact. The pouch is done — discharge and dispose of it safely. Everything the tablet talks to stays on that board.

02

Feed ~4.0 V into the cell pads

Wire a regulated supply to the two pads where the pouch's + and − were soldered — not the mainboard connector. Set it to about 4.0 V: above the 3.8 V nominal, safely below the 4.2 V ceiling. The board passes it through its protection FETs to the tablet exactly as the cell would, and the mainboard charger sees a "nearly full" battery and simply idles.

03

Size the supply for the peaks

Use a buck converter that can source the tablet's >2 A current spikes (screen + CPU), fed from a beefy 5 V / 3 A or a 9–12 V brick — never the tablet's own micro-USB port, which can't run the system directly and browns out.

04

Know what changes

Don't exceed ~4.2 V or the board's own over-voltage protection cuts out (that's a safety feature working). And the fuel gauge now reads a fixed percentage forever — cosmetic, but it means the charge-trend tile and the whole power-management system on the wall panel become optional. With nothing left to drain, the panel just runs bright all day.

Advanced, and at your own risk. This means opening the tablet and soldering to a live lithium battery's board. Confirm polarity with a meter before you connect anything — the two pads reading 3.7–4.2 V are + and −. Disconnect and tape off the old pouch before it goes anywhere near the wall. Done right, there's no battery left to drain or swell — which is exactly why wall-panel builders do it.


B · Alarm remote relay bridge

Letting software press the key fob

The alarm's radio hub is slow to wake, so a voice "disarm" can lag. The fix is to press the buttons on a spare enrolled key fob electronically — an ESP32 drives four isolated relays, each closing across one button, so Home Assistant and Google can Arm, Disarm, Part-arm and Panic. The fob keeps floating on its own power; nothing on its side ever touches the ESP32's ground.

How it works

Each relay is an electronic finger. A GPIO goes high, the relay's coil pulls in, and its contact closes across the two pads of one button — electrically identical to pressing it. The contact is a dry, isolated switch: it shares no copper with the coil or the ESP32, so it bridges the fob's button without dragging the fob's ground onto anything else. That isolation isn't a nicety here — as the note below explains, it's the whole reason this works.

Why a relay — and not an optocoupler or a transistor. This is the lesson that cost the most bench time. The fob floats: its button "common" sits behind a reverse-protection diode, not at true ground. Anything that shares a ground with the ESP32 — a common-ground opto board, or a bare transistor — bonds the fob's common to the system ground the moment it switches, and that jams the remote dead every time. We proved it twice before the penny dropped. A relay's contacts are galvanically isolated from its coil and the ESP32, so they bridge a button's two pads exactly like a fingertip, with nothing shared. Isolation here is the whole trick, not an optional extra.

Wire colour map

Two worlds that never meet. On the control side the colours are triggers and everything shares one ground. On the isolated fob side the same colour is that button's signal and one grey serves the shared common. Red and black are power only.

FromWireToPurpose
Control side — shares the ESP32 / 12 V ground
12 V PSU +redRelay DC+ and buck input +Coil power
12 V PSU −blackRelay DC− and buck input −0 V (= ESP32 GND)
Buck Type-CUSB-CESP32 USB-C port5 V for the ESP32
ESP32 D23yellowRelay IN1Arm trigger
ESP32 D22greenRelay IN2Disarm trigger
ESP32 D21blueRelay IN3Part-arm trigger
ESP32 D19whiteRelay IN4Panic trigger
ESP32 GNDblackRelay DC−Logic ground (shared)
Isolated fob side — floats, touches nothing above
Relay COM1yellowArm button, signal padOne side of the press
Relay COM2greenDisarm button, signal padOne side of the press
Relay COM3bluePart-arm button, signal padOne side of the press
Relay COM4whitePanic button, signal padOne side of the press
Relay NO1–4greyThe fob's shared common "G" padOther side of the press

The one rule that makes or breaks it: the fob's grey "G" wires (relay NO) go only to the fob's own common pad — never to the 12 V −, the ESP32 GND, or the relay's DC−. The instant those grounds meet, the remote jams. Leave the fob on its own cell (or give it a completely separate, isolated 12 V supply) so its ground stays its own.

One channel, end to end

D23 high → IN1 → the coil pulls in → the contact closes COM-to-NO, bridging the Arm button's signal pad to the fob's common pad. That's exactly the short a continuity probe makes across those two points to press the button. The other three channels are identical, each with its own colour.

Where everything plugs in

ESP32 · right-hand header

  • D23 yellow → IN1 · Arm
  • D22 green → IN2 · Disarm
  • D21 blue → IN3 · Part-arm
  • D19 white → IN4 · Panic
  • GND black → relay DC−

Relay module (4-ch, 12 V)

  • DC+red → +12 V (coil power)
  • DC−black → 0 V = ESP32 GND
  • IN1-4colour in from D23/D22/D21/D19
  • COMxthat button's signal pad (colour)
  • NOxgrey → the shared common "G"
  • jumperset High-level trigger (3.3 V high = on)

Remote PCB

  • SW1Arm · top
  • SW2Disarm
  • SW3Part-arm
  • SW4Panic · bottom
  • presssignal pad → COM · shared common → NO
  • powerown cell / isolated 12 V — ground stays apart

Your hardware, annotated

The two ends of the isolated side, drawn onto your own photos. Positions are close, but always confirm against the silkscreen and a continuity check before you commit a joint.

Alarm remote: fob case and opened PCB, coloured markers on the four button solder points
The remote. Each button has a signal pad and a shared common "G"; a continuity probe across those two presses the button — that's the pair each relay closes. Function colour to the signal pad → relay COM; one grey to any common pad → relay NO (all four share it). Top switch is Arm, bottom is Panic. Leave the fob floating on its own power.
ESP32 DevKit with D23, D22, D21, D19 and GND marked on the right-hand header
The ESP32. All five control connections on the right-hand header, USB-C at the bottom. D23 and D22 at the top, skip TX0/RX0, then D21 and D19. GND goes to the relay board's DC− — check the silkscreen so black lands on GND, not 3V3.

The road here

The four-channel PC817 optocoupler board that was tried first and abandoned
The dead end. The first attempt used this 4-channel PC817 optocoupler board. On this unit all eight ground screws proved to be one net — a common-ground board, not truly isolating — so bridging a button dragged the fob's common onto the system ground and jammed the remote. The phototransistor outputs metered open even when driven. The fix was to stop chasing the opto and switch to a genuinely isolated relay contact. Kept here because the "why" matters more than the win.

Build order

01

Set the relay board, then bench-test a click

Set the High/Low jumper to High-level trigger. Power DC+/DC− from 12 V, tie DC− to the ESP32 GND, and touch IN1 to 3V3 — the relay should click and a meter across COM–NO should close. Repeat for all four before anything goes near the fob.

02

Keep the fob floating

Leave the fob on its own cell (or a separate, isolated 12 V supply). Its ground must never bond to the ESP32/PSU ground — that single mistake is what jams it. Nothing you wire on the isolated side touches the control side's 0 V.

03

Find each button's two press points

For each button, identify the signal pad and the shared common "G" — a continuity probe across the two triggers that button. Those two points are the relay's COM and NO. On this remote the common sits behind a reverse-protection diode, which is exactly why it must stay isolated.

04

Wire the isolated side

Per channel: COMx → the signal pad in its function colour; NOx → the shared common with grey (one grey serves all four). Screw terminals, or short solder tails if you tap the pads directly. Keep joints small so the case still closes.

05

Wire the control side

DC+ → 12 V, DC− → 0 V. IN1←D23, IN2←D22, IN3←D21, IN4←D19, one black from ESP32 GND to DC−. Every colour is one clean trigger from a GPIO to an IN.

06

Power up in order

12 V to the relay DC+/DC− and to the buck. Meter the buck's USB-C output — confirm ~5 V — before plugging the ESP32. Then buck USB-C → ESP32.

07

Flash the firmware

Load the ESPHome config below over USB once, then adopt in Home Assistant — four button.alarm_remote_bridge_* entities appear. After that it's fully over-the-air.

08

Test each in a safe state

Press each button in HA where a stray Arm or Panic won't wake the street. You should hear the relay click, see the fob's own LED blink, and watch the alarm respond. Panic clicks about eight times over ~4 s — that's deliberate (see below).

Panic pulses, it doesn't hold. This fob self-terminates: hold a button and its transmit LED drops out on its own part-way through, so a single 3–4 s press wouldn't give the panel a sustained panic. Panic instead pulses the relay ~8 times over ~4 s, restarting the fob's transmission each time. Arm, Disarm and Part-arm are a single clean 600 ms press.

The real thing — ESPHome + Home Assistant

Local, no cloud. Four momentary button entities. Three drive their GPIO high for 600 ms then low; Panic repeats a short pulse ~8 times. They arrive in Home Assistant as button.alarm_remote_bridge_arm and friends, ready to wire to the alarm panel or expose to Google.

alarm-remote-bridge.yamlflash once over USB, then OTA
esphome:
  name: alarm-remote-bridge
  friendly_name: Alarm Remote Bridge
esp32:
  board: esp32dev
  framework: { type: arduino }

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap: {}                 # fallback hotspot for first setup
captive_portal:
logger:
api:                     # Home Assistant adds the encryption key
ota:
  - platform: esphome

# relay inputs, driven HIGH to close (board on High-level trigger).
# LOW at boot, so the ESP can never fire the alarm while it resets.
output:
  - { platform: gpio, id: out_arm,    pin: GPIO23 }
  - { platform: gpio, id: out_disarm, pin: GPIO22 }
  - { platform: gpio, id: out_part,   pin: GPIO21 }
  - { platform: gpio, id: out_panic,  pin: GPIO19 }

button:
  - platform: template
    name: Arm
    on_press: [ output.turn_on: out_arm,    delay: 600ms, output.turn_off: out_arm ]
  - platform: template
    name: Disarm
    on_press: [ output.turn_on: out_disarm, delay: 600ms, output.turn_off: out_disarm ]
  - platform: template
    name: Part-arm
    on_press: [ output.turn_on: out_part,   delay: 600ms, output.turn_off: out_part ]

  # Panic: pulse ~8× over ~4 s so a self-terminating fob keeps transmitting
  - platform: template
    name: Panic
    on_press:
      - repeat:
          count: 8
          then:
            - output.turn_on: out_panic
            - delay: 400ms
            - output.turn_off: out_panic
            - delay: 150ms

Flashing: add it in the ESPHome dashboard (or web.esphome.io for the first USB flash), put your Wi-Fi in secrets.yaml, install over USB once, then adopt it in Home Assistant — the four buttons appear automatically. After that it's fully over-the-air. D23/D22/D21/D19 are chosen deliberately: they sit low at boot, so the ESP32 can never ghost-press a button while it resets.

Think twice about voice disarm. Anyone your speaker can hear — including someone shouting through a letterbox — could say "disarm". Keep Disarm app- and dashboard-only, or require Google's PIN confirmation for it. Arm, Part-arm and Panic carry no such risk.

Sanity checklist before the first live press

  • Fob left floating — its ground touches nothing on the ESP32/PSU side
  • Relay board on High-level trigger; every channel clicks on the bench
  • COM → signal pad, NO → the shared common "G"
  • DC+ = 12 V, DC− = ESP32 GND; buck 5 V metered before the ESP32
  • Each trigger is one colour GPIO → INx; each press is COMx → NOx
  • Alarm in a safe state for the first live press

Bench reference

Two mods that take the last cloud and the last weak link out of the house.

The battery bypass ends the one fire risk of an always-on tablet and lets it run bright forever; the relay bridge gives Home Assistant and Google an instant, isolated finger on the alarm's own key fob. Both are local, both are reversible, and both are written down here — dead ends included — so future-you doesn't have to work it out twice.

battery eliminator · keep the BMS·ESP32 + isolated relays ×4 · ESPHome