Rada's £313 box is a microcontroller on a cable. We can be that microcontroller.
Rada's Networking Upgrade Pack plugs into the valve's own control-panel port and translates Modbus into whatever the valve already speaks. The valve, not the box, does the work. Three ways to talk to it ourselves, from £2 to £8, ordered by how little wiring they need.
What the documents established
- The valve is the brain. The wall panel is a dumb infrared sensor plate on a 3 m "data cable" (6 m max, 9 V DC feed to the panel). Every command in Rada's Modbus map (valve on/off/pause, outlet 1 and 2 on/off, setpoint, run time, live temperature, error codes) is something the valve executes when asked over that cable.
- The Networking Pack is a man-in-the-middle. Its ports are labelled ENG (control panel), VLV (valve), NET (RS485 Modbus), RLY, PIR, KS. Panel and valve plug into it; it relays and injects. Valves made after July 2014 need no PCB change, so the cable protocol on your valve already accepts a third party.
- Your valve is the Bluetooth generation. The dual-shower manual for part 1.1653.030 says a Bluetooth LE app is required to configure it, default PIN 2502. Kohler Mira's other BLE shower, the Mira Mode, has a fully reverse-engineered protocol: same company, same years, same "dual outlet" product shape, and its BLE command set includes outlet on/off and temperature.
- The Rada app itself has no start button, only settings, so nobody has bothered to look. The valve firmware may still implement the control command, because the Mira stack does. That is the cheapest thing to test and it is where I would start.
Recommendation
- Tonight: the checks in section 2. They need a phone, a screwdriver and a multimeter, and they tell us which route is open.
- If the valve advertises the Mira BLE service: Route 1. An ESP32 in the airing cupboard, no wiring, done in an evening once the pairing exchange has been captured from the app.
- Otherwise: Route 2. A £5 logic analyser on the panel cable for one evening, then the ESP32 splice board. This is the certain route; Rada's product proves the port accepts commands.
- Route 3 only if you want on/off this weekend without waiting for a capture. It is invisible, reliable, and can be replaced by 1 or 2 later without changing anything in Home Assistant.
Four checks that pick the route
No soldering, nothing disconnected under load. Each check answers one question; send me the results and photos and I will write the firmware against them.
- Bluetooth scan (5 min, phone only).
Install nRF Connect (Nordic, free) on your phone, stand near the valve and scan. Find the device whose name matches the alias in the Rada app (or anything from Kohler / Mira / Rada). Tap it, connect, and screenshot the service list. What we want to see is a service containing
bccb0002-ca66-11e5-88a4-0002a5d5c51b(write) andbccb0003-…(notify). If those are there, it is the Mira Mode stack and Route 1 is on. Also note the MAC address; the ESP config needs it. - Valve label (1 min).
Photo of the label on the mixing valve enclosure: part number, "Wk/Yr" manufacture date, and the PSU part number. It confirms the generation.
- Panel cable at the valve (10 min, power ON, then OFF).
Open the valve's electronics cover (screws, no seal to break; it is 12 V SELV in there). Photograph the connector where the control-panel cable lands, close enough to read any silkscreen, and the PCB around it. Then with the multimeter on DC volts, black probe on the PSU's 0 V, read each pin of the panel connector with the panel idle. Write the numbers down in pin order. The pattern tells us the bus: one pin near 9 V and one at 0 V are power; a pin sitting at about 3.3 V or 5 V is a TTL UART line; a pair sitting at about 2.5 V and 2.5 V with a small difference is RS485; a pin at 9–12 V that dips when you wave at the panel is a single-wire bus.
- Count the cores (2 min, power OFF).
How many wires in the panel cable, and their colours. Three cores is power, ground, one data line. Four is power, ground, two data (either a UART pair TX/RX or an RS485 pair). Five or more usually means separate LED or sensor lines and a simpler panel.
Do not unplug the panel cable with the PSU live; the valve's own protection may latch an error that needs a power cycle to clear, and we lose an hour wondering why. And do not probe the PSU's mains side; everything we need is on the 12 V side of it.
What the answers decide
| Finding | Route | Next step |
|---|---|---|
| Mira service UUIDs present | 1 | Capture the app's pairing exchange (section 3), then flash the BLE ESP32. |
| BLE present but different UUIDs | 1 or 2 | Decompile the Rada app (section 3) to read its command table; if it only carries settings, go to Route 2. |
| Panel cable has a 3.3 V or 5 V data line, or an RS485 pair | 2 | Logic-analyser capture (section 4), then the splice board. |
| Panel cable is 9 V + ground + one odd line | 2 or 3 | Capture it anyway; a single-wire bus is still just serial. Route 3 if it turns out to be analogue. |
Talk to the valve the way its own app does
The Mira Mode protocol is documented in the python-miramode project. It is a tiny framed protocol with a 16-bit CRC, a client id you get by pairing once, and one command that switches both outlets and sets the temperature. If the Sense valve shares the stack, an ESP32-C3 in the cupboard is the whole build.
The protocol, as known from Mira Mode
| Item | Value | Notes |
|---|---|---|
| Write characteristic | bccb0002-ca66-11e5-88a4-0002a5d5c51b | Write without response, 20-byte chunks |
| Notify characteristic | bccb0003-ca66-11e5-88a4-0002a5d5c51b | Responses arrive here, possibly fragmented |
| Frame | payload + CRC16(payload + client_id) | CRC-CCITT, poly 0x1021, init 0xFFFF; client_id is 4 bytes big-endian and is not transmitted, only mixed into the CRC. That is the authentication. |
| Pairing | [0x00, 0xEB, 24, id(4), name(20)] | CRC'd with the magic id 0x54D2EE63. Mira enters pairing by holding the outlet button 5 s; Rada uses PIN 2502 in the app instead, so the Sense pairing frame will differ and must be captured. |
| Client slot | notify[0] − 0x40 | Returned after pairing; first byte of every later command. |
| Control outlets | [slot, 0x87, 0x05, timer, tempHi, tempLo, out1, out2] | timer 1 = running, 3 = paused; temperature ×10 big-endian; outlet 0x64 = on, 0x00 = off |
| Request state | [slot, 0x07, 0x00] | Reply (10 bytes): timer, target °C×10, actual °C×10, outlet1, outlet2, seconds remaining, counter |
Capture the Rada app talking to the valve
Two ways, both using your own phone and the app you already have. The first gets the pairing frames and the client id; the second gets the whole command table.
A · Bluetooth HCI snoop log
- On the phone: Settings → Developer options → enable Bluetooth HCI snoop log. Toggle Bluetooth off and on.
- Open the Rada Sense app, connect to the valve with the PIN, change the flow time by one second and save, read the usage data, disconnect.
- Pull the log with adb from the Pi (the phone is already authorised there) and open it in Wireshark with the filter
btatt. Every write tobccb0002is a frame; the first ones after connecting are the PIN/pairing exchange.
B · Read the app's own code
- Pull the installed APK from the phone:
adb shell pm path com.kohler.radasensethenadb pull <path> rada.apk. - Open it in jadx-gui on the PC. Search for
bccb0002,0x1021or2502. The class that builds frames lists every command byte the app knows, including any it never shows a button for. - If a
0x87-style control command exists there, or the frame builder is byte-for-byte the Mira one, Route 1 is confirmed before we power anything.
The ESP32 build
One ESP32-C3 on a USB adapter within about 8 m of the valve. ESPHome's BLE client connects, writes frames, and listens for the state notification. The CRC and frame builder are in the lambda, so once the capture gives us slot and client id they are two substitutions.
You can skip the ESP entirely for the first test: pip install python-miramode on DECS, run devices-list, then device-state with the slot and client id from the capture. If the valve answers with a sensible temperature, the protocol is confirmed and the ESP build above is a formality.
Sit where Rada's box sits
The panel cable carries power to the panel and serial data both ways. Rada's box proves the valve will take commands from a third device on that port. The job is to read the traffic once, then build a £8 board that relays the panel and injects our own frames.
Step 1 · Identify the bus (from tonight's multimeter readings)
| Idle reading on a data pin | Bus | How to listen |
|---|---|---|
| 3.3 V or 5 V steady, dips during traffic | TTL UART, one line per direction (or one shared line) | Logic analyser straight on the pins, ground to 0 V. ESP32 UART RX pins direct (5 V needs a 10 k / 20 k divider). |
| Two pins both around 2–3 V, differing by 0.2–0.5 V | RS485 pair (A/B) | Logic analyser across the pair via a MAX3485 module; the ESP uses one MAX3485 per side. |
| 9–12 V that dips briefly when the panel is used | Single-wire bus, power and data on one core | Logic analyser via a 10 k / 3.3 k divider to 3.3 V logic; the ESP needs an open-collector driver to inject. |
| Pins that change slowly (0–3 V analogue) when you wave | Not a bus; the panel sends raw sensor levels | Route 3, or Route 1. |
Step 2 · Capture one evening of traffic
- Wire the logic analyser.
A £5 8-channel 24 MHz USB analyser (the Saleae-clone) with PulseView. GND to the PSU 0 V, one channel per data pin. For RS485, the A line alone against ground decodes fine at this speed.
- Record with the panel idle for 60 s.
Most of these buses poll: the valve asks the panel for its sensor state every 50–200 ms and the panel replies. That gives baud rate, framing and the idle poll pattern before you touch anything.
- Record one action each.
Hand at the flow sensor (on), again (off), up once, down once, the magnetic cleaning key on and off. Name each capture.
- Decode.
PulseView's UART decoder with the baud guessed from the shortest pulse (1 / width). 9600, 19200 and 38400 are the likely ones; Rada's Modbus side runs 9600 8N1, and firmware writers rarely use two speeds. Look for a repeating header byte, a length, and two trailing bytes that change with every frame (a CRC; try 0x1021 init 0xFFFF first, it is the one Kohler Mira used on Bluetooth).
- Find the command.
Compare the frames sent panel→valve during "hand at flow sensor" with the idle ones. Either the panel sends an event frame ("flow touched") or the valve polls and the panel's reply has a bit set. Either way, replaying that frame from the ESP is our on switch. Temperature up/down the same way.
Step 3 · The splice board
Firmware · sniffer first, relay second
The same sketch does both jobs. On its own it logs both directions with timestamps over USB so you can confirm the decode from PulseView against live traffic. With RELAY on, it passes bytes through and accepts inject <hex> on the USB console or from Home Assistant. Once the frames are known this becomes a proper ESPHome component; the sketch is for the discovery week.
At 9600 baud a byte lasts about 1 ms and the ESP adds roughly 0.1 ms of delay in each direction, well inside any serial timeout. If the bus turns out to be a single shared line rather than two directions, the sketch changes to one UART with the TX driven open-collector, and the injection is a matter of waiting for a quiet gap. Both cases are a few lines once the capture exists.
A hand the panel cannot tell from yours, hidden inside it
The panel's three controls are infrared proximity sensors: an emitter flashes, a detector looks for the reflection off your hand. A phototransistor watching the emitter and an IR LED aimed at the detector, switched on together by the ESP, is a reflection with the panel's own timing. It needs no protocol and no capture.
Fitting it
- Take the panel off the wall (two screws behind the cover; silicone bead on the back). Photograph the PCB. Each sensor position has an emitter and a detector, usually a black-domed pair or a single reflective module.
- Q1 goes beside the emitter with a dab of hot glue, D1 beside the detector pointing at it, both inside the front shell so nothing shows.
- Tune with the multimeter on the panel's detector output if it is accessible, otherwise empirically: start with R2 at 220 Ω (dim) and reduce until the panel reacts every time and never reacts with the enable off.
- Wires out through the existing cable hole to the ESP. The ESP can share the panel's 9 V feed through a tiny buck, or take its own USB adapter in the ceiling void.
On/off, warmer, cooler: the same three things a person can do at the panel. No temperature readback, no error codes, no "is it running" beyond the state Home Assistant assumes. That is why it is the fallback and not the plan.
“Hey Google, turn on the shower”
Whichever route wins, Home Assistant sees the same three entities: two outlet switches and a temperature number. The voice layer, the safety timers and the presence tie-in are written once, here.
Voice phrases that will work
| Say | Happens | Via |
|---|---|---|
| "Hey Google, turn on the shower" | Overhead outlet on at the stored temperature; auto-off timer starts | switch.shower → Google Assistant |
| "Hey Google, turn off the shower" | Both outlets off | same |
| "Hey Google, shower in five minutes" | A Google routine that waits then turns the switch on | Google routine |
| "Hey Google, make the shower warmer" | Number entity up 1 °C, still capped at the valve's 41 °C | Google routine → HA script |
| Local, no cloud | Same phrases through Assist once the Speech-to-Phrase satellite exists | HA Assist |
Everything, for all three routes
Order the discovery kit now; it covers whichever route the checks pick and still comes to less than a tenth of Rada's box.
| Item | For | £ | Note |
|---|---|---|---|
| ESP32-C3 Super Mini × 2 | All routes (one spare) | 4.00 | Same board as the presence nodes; same secrets, same dashboard on the Pi. |
| USB logic analyser, 8 ch 24 MHz | Route 2 capture | 5.00 | "24MHz 8CH USB logic analyzer"; PulseView is free. |
| MAX3485 RS485 modules × 2 | Route 2 if the bus is RS485 | 2.00 | 3.3 V modules, not MAX485 (5 V). |
| MP1584 buck module | Route 2 / 3 power from the 9 V feed | 0.80 | Set to 5.0 V before connecting. |
| IR LED 940 nm × 3, phototransistor × 3, BC337 × 3, resistors | Route 3 | 1.50 | Any "IR emitter + receiver pair" listing. |
| Dupont leads, perfboard, heat-shrink | All | 2.00 | |
| nRF Connect (phone app), Wireshark, jadx, PulseView | Discovery | 0 | All free. |
| Total | ≈ 15 | versus £313 + £8 for the Rada route |
What we are not going to touch
- The thermostatic limit stays the valve's. Every route asks the valve for a temperature; the valve's own maximum (41 °C as shipped, TMV3) and its thermistor shutdown still apply. Nothing here can make water hotter than the panel can. The ESP configs clamp at 41 °C as a second fence.
- No mains work. Everything lives on the 12 V / 9 V side. The PSU stays sealed and on its fused spur.
- The panel keeps working. Route 2 relays it; Routes 1 and 3 never interrupt it. If the ESP dies, the shower is exactly as it was.
- Voice cannot leave it running. The auto-off timer is in Home Assistant and the valve's own run time is a third layer; set that to 20 minutes in the app rather than 60.
- Disinfection stays manual. The Modbus map has an arm/trigger sequence for 60–80 °C thermal disinfection. We never send it and the HA package has no path to it.
- Warranty and WRAS. Splicing the panel cable is reversible with two connectors and does not change the water side; the valve remains a WRAS-approved TMV3. If Rada ever service it, unplug our board and the cable is as delivered.
The nRF Connect screenshot, the valve label photo, the connector photo with your pin voltages, and the core count. With those I write the exact firmware for the route that opened, the same day.