Hi everyone,
I've been following this thread for a while and finally have something to contribute. I'm building a Home Assistant integration for the P25B85 controller and wanted to share progress.
Disclaimer: I'm obviously using AI (mainly Claude Opus and GPT Codex) for the analysis and the implementation. This is what has been done so far:
My setup:
- Home Deluxe White Marble outdoor whirlpool
- Controller: Joyonway P25B85 (PCB P2325B0003 R05)
- Touchpad: PB554 colour screen
- Bridge: Elfin EW11 (RS-485 → WiFi, TCP server on port 8899)
- One dual-speed pump (low = filtration, high = jets), blower, RGB LED, 2 kW heater
The integration is based on the excellent work by @KDy (pseudo-escape discovery, byte map, Python reading script) and @christopheknap (HACS integration structure, community captures, frame analyzer tool). Huge thanks to both of you — without your posts in this thread I wouldn't have gotten anywhere.
Repo (work in progress): GitHub - alexbde/ha-joyonway-p25b85: Home Assistant custom integration for Joyonway P25B85 spa via RS485 · GitHub
Everything is still under development and hasn't been released yet. Live testing at the spa is the next step.
What's working so far
Reading: temperature, setpoint, pump state, heater state (off/circulation/heating/disinfection), blower state, light state, spa clock — all parsed from the broadcast frames.
Writing: I've captured command frames for all available actions on the P25B85:
- Light toggle
- Pump OFF → Low → High → OFF (cycle)
- Heater ON / OFF
- Blower ON / OFF
- Temperature setpoint changes (full range 10–40°C)
- DateTime set
- Filter schedule
- Heat schedule
All captured frames are documented with full hex in the protocol reference (see below, I can only add 2 links as new member of this forum).
CRC-32 checksum cracked
The big news: I believe I managed to fully crack the CRC algorithm used on the P25B85 command frames. This means I can now generate valid frames dynamically for any command. No more "capture one frame per degree" limitation.
The algorithm turned out to be:
- Standard CRC-32 (polynomial
0x04C11DB7 — same as Ethernet/zlib)
- Non-reflected (MSB-first)
- Init:
0x00000000, XorOut: 0x552D22C8
- Trick: each 32-bit word of the 16-byte payload is byte-reversed before feeding into the CRC
That last point — the word byte-swap — is why standard CRC tools couldn't find it. It's characteristic of an ARM Cortex-M MCU feeding a hardware CRC peripheral in little-endian word order. The PB554 touchpad likely uses such an MCU.
Verified against 21 unique command frames captured in a single session (all command types). 24/24 frames rebuild byte-identical to the original wire captures including escape sequences.
The full analysis and algorithm details are in docs/protocol.md.
What this enables
With the CRC cracked my future goals are:
- Set any temperature dynamically (no lookup table needed)
- Sync the spa clock from HA
- Program heating and filtration schedules from HA
- Generate valid frames for any future command we understand
This effectively should remove the "replay-only" safety constraint. We now compute correct CRC values, so the risk KDy reported (invalid CRC unexpectedly turning on the heater) will be eliminated hopefully.
For other Joyonway models
Yannickt26, your P20B29 frames share the same structure (0x1A framing, same header bytes). The CRC polynomial is likely identical across the Joyonway family since it's a standard algorithm tied to the MCU hardware. I'd be interested to know if this is working for you, too.
christopheknap, same offer for the P23B32. If the CRC checks out on your captured frames, you could generate arbitrary setpoint frames without needing to capture each temperature individually.
Happy to answer questions. More updates once I've done live testing at the spa.