Reverse engineering ACCESSORY port – Rain Bird ESP-RZX

Hello everyone,

I’m currently trying to find a way to communicate with a Rain Bird ESP-RZX controller using Home Assistant via ESPHome.

I’m sharing here the progress of my investigation on the ACCESSORY port (5 pins) of the Rain Bird ESP-RZX, which is used in particular by the WiFi LNK module.


:electric_plug: Measured pinout (from left to right)

Pin Function Measured Voltage
1 +12V OK
2 GND OK
3 +5V OK
4 Logic signal ~3.3V
5 Logic signal ~3.3V

:zap: Electrical measurements

  • Pin 4 → GND: 180 kΩ
  • Pin 5 → GND: 100 kΩ
  • Pin 4 → +5V: ∞ (no continuity)
  • Pin 5 → +5V:
  • Pin 4 ↔ Pin 5: 4.7 kΩ

:point_right: The two logic lines (pins 4 and 5) are weakly pulled to ground and coupled together via an internal resistance of about 4.7 kΩ.


:zzz: Behavior with no module connected

  • Pins 4 and 5 are synchronous
  • Square wave signal at approximately 50 Hz
  • No communication frames observed

:zap: Module presence detection

By injecting a signal on pin 5 that is synchronized but inverted relative to pin 4 (using an ESP32), the controller:

  • exits idle mode
  • appears to start transmitting digital frames

:point_right: The presence of a module seems to be detected through activity on the DATA line (pin 5).


:satellite: Observed communication

Once activated:

  • Pin 4: regular signal (clock)
  • Pin 5: synchronized signal with variable content

:point_right: The communication appears to be synchronous.


:x: Protocol tests

  • UART decoding: invalid
  • Signal is not compatible with UART

:white_check_mark: Captured frames (SPI decoding)

Examples of captured data:

20 43 80 04 08 10 A1 00 02 02 ...

or

02 07 16 80 02 00 43 80 04 ...

:point_right: The data is structured and repetitive, confirming a digital protocol.


:warning: Important behavior

  • If activity on pin 5 stops:
    → immediate return to the 50 Hz signal

:point_right: The controller requires continuous activity to keep the communication active.


:wrench: Tests performed

Active injection (ESP32)

Code used:

int inPin = 22; // pin 4
int outPin = 23; // pin 5

void setup() {
  pinMode(inPin, INPUT_PULLUP);
  pinMode(outPin, OUTPUT);
}

void loop() {
  int state = digitalRead(inPin);
  digitalWrite(outPin, !state);
}

Result:

  • bus activation
  • frames appear
  • but data is corrupted

Weak injection (short pulses)

  • microsecond pulses synchronized with the clock
  • clean frames observed
  • but no functional response

:jigsaw: Conclusion (established facts)

  • The ACCESSORY port uses a synchronous communication
  • Pin 4 acts as a clock
  • Pin 5 carries the data
  • The two lines are coupled via ~4.7 kΩ
  • The controller remains in idle mode without activity on DATA
  • Activity on the DATA line is required to activate communication
  • Communication stops immediately if this activity ceases
  • The protocol is not UART

:dart: Current status

  • Bus activation: :heavy_check_mark:
  • Frame capture: :heavy_check_mark:
  • Partial understanding of physical layer: :heavy_check_mark:
  • Full protocol decoding: in progress

If anyone has already worked on this port or the WiFi LNK module, I’d be happy to exchange ideas :+1:

1 Like

Is your household power 50Hz or 60Hz? You may be picking up background hum.

Good question :+1:

My mains frequency is 50 Hz (France), so that was one of my first thoughts as well.

However, this signal is not background noise:

  • It is very stable and clean
  • It appears only on pins 4 and 5, perfectly synchronized
  • It disappears immediately when activity is injected on the DATA line
  • It is replaced by structured digital communication when the bus is activated

So this 50 Hz signal is actually generated by the controller itself and corresponds to its idle state when no module is detected, not external interference.

1 Like

OK, so keep alive to keep the transmission bus primed for traffic.