can you add the layout of the pins as well ? My spa is still in installation phase (hasn’t even been unpacked yet) but I can start designing the pcb already.
I was thinking to make it possible to connect it in read mode and man-in-the-middle mode. We just need to know the number of pins that carry data of interest and if they would be RO or RW
JST-XH 6P
1 2 3 4 5 6
GND VCC RO1 RO2 RO3 RO4
but add more TXS0108E depending on the number of ports that would need RW and RO and offcourse replace the esp8266 with an esp32. That way we have more IO ports, so we could read the ports and eventually also write data back to the bus in passtrough mode if the device is inserted in between.
KEY = JST-XH 8P (pin 1)
1=VCC, 2=VSS, 3=K0, 4=K1, 5=K2, 6=P6, 7=P7, 8=P8.
VCC/VSS: Do not power the module from this connector. Any current draw on these pins will freeze the keypad/panel. Use only for high-impedance measurement (sniffing), without a load.
P7/P8: Unconfirmed, retained as an option for sniffing.
LCD = JST-XH 6P (pin 2)
1=F-OP, 2=VDD, 3=VSS, 4=DIO, 5=WR, 6=CS.
F-OP not used. Sniff reading only: DIO + WR (and CS recommended for framing). No writing to this bus.
Modes:
Read: LCD (DIO/WR/CS), KEY (K0/K1/K2/P6 + P7/P8 option).
Injection: K0 and K1 only via 74HC4066 (temporary grounding, passthrough maintained).
Levels:
SPA bus = 5V, ESP32 = 3.3V.
DIO/WR/CS and P7/P8 via dividers to 3.3V.
K0/K1/K2/P6 via 74HC125 at 3.3V + 1k series resistors.
TXS0108E not selected: unnecessary for reading (dividers + buffers are more stable), and not suitable for injection (the bus is not driven, it is temporarily forced to 0 via the 4066).
Appendix: V2 vs V1 corrections (4066 pinout validation + GPIO12 pull-down). Please route strictly according to these pins; this is the point that already caused an error in V1.
I was referring to input impedance (not “altitude voltage”).
On the VCC/VSS of the KEY connector: target = 0 mA (I don’t even connect the +5V KEY to the module anymore, otherwise the keyboard freezes).
On the signal lines: only high-impedance inputs (order of magnitude ≥ 1 MΩ, ideally 10 MΩ, leakage currents in µA).
With CMOS buffers (74HC125 powered by 3.3V) + dividers, it remains transparent and the panel no longer freezes.
There was some confusion: we’re using 1× 4066 + 2× 74HC125.
Power supply levels:
The 74HC125s are powered by 5V (5V on the SPA side).
The Y outputs of the 74HC125s to the ESP32 must be stepped down to 3.3V using a 10k/20k voltage divider (Y = 10k = node = GPIO; node = 20k = GND).
A inputs of the 74HC125s: direct from the SPA lines (no divider).
Injection (keypress):
Ideal: 74HCT4066 at 5V (TTL threshold OK with 3.3V GPIO).
I only have an HCF4066BE (CMOS), so I’m going to add a translation to the E inputs:
NPN + 10k pull-up resistor to 5V: collector to E, emitter to GND, base via 10k from GPIO.
For your information, I’m developing my own single-sided circuit in parallel, while you’re working on a double-sided version.
I’m using an HCF4066BE (VCC=5V). Since its thresholds aren’t TTL, I added a switch to the E inputs: 2× 2N2222 (NPN) + 10k pull-up resistor to 5V (controlled from GPIO18/GPIO19). Inverted logic (GPIO=0 → switch ON).
I removed the AMS1117: the ESP32 DevKit is powered by 5V from VIN (3.3V regulator already integrated).
The 74HC125s are powered by 5V. The outputs to the ESP32 are stepped down via 10k/20k dividers to obtain ~3.3V on the GPIO pins.
My single-sided PCB has several shunts (routing constraints). Your double-sided version will be much cleaner (ground planes, fewer jumpers).
Latest modification: adding pins to the LCD and KEY to allow insertion of a logic analyzer, and adding 330-ohm resistors to G21, G4, and G5.
Also added: removable jumpers to G19 and G18 for testing without injection (sniff mode).
edit : I just corrected an error: the 74HC125 was powered by 5V, so I switched to 3.3V from the ESP32.
I’ve had time to make some progress on the project, even though it’s not finished. I’ll share where I’m at.
I managed to decode the communication bus between the KL8300 panel and the spa board.
Architecture
Simplified 3-wire SPI serial bus:
DIO = data
WR = clock
CS = strobe (frame delimiter)
Operation:
LSB first transmission
Valid data on the rising edge of WR
CS goes low during each frame
Data Structure
Two frame types:
Short frames → screen refresh (of little use)
Long frame (~64 bytes) → complete spa state
The long frame contains fixed blocks that encode:
Panel state
Pump 1 / Pump 2
Heating
Blower
LED
Temperature
Key Decoding Points
The critical signal is CS (not F-0P)
Without CS → frames cannot be reconstructed
WR must be clean (otherwise no decoding)
Essential logic levels (5V → 3.3V via divider)
Problems Encountered
Bad Sync Signal Initially (F-0P instead of CS)
Incorrect logic analyzer settings → inconsistent data
Misinterpreted divider → unstable threshold
Rogue resistance on WR → clock stuck (CLK always HIGH)
Once these issues are corrected → stable decoding.
Integration
ESP32 used in read-only mode:
GPIO4 = DIO
GPIO5 = WR
GPIO21 = CS
Real-time decoding + reporting to Home Assistant via ESPHome.
Result
Reliable reading of:
pumps
heater
blower
LED
panel status
temperature
Without altering the spa’s operation (passive sniffing).
Conclusion:
The KL8300 uses a simple protocol, but requires:
a good sync signal (CS)
a clean clock (WR)
correct logic levels
Once these requirements are met, decoding is straightforward and usable.
Here is the final PCB (I think), I will modify it if there are any problems with the control but it is functional for reading.
Wow!
Amazing project!
I have the same Hot Tub, and I always wanted to do the same.
So, I will be following your awesome work.
My knowledge is more limited than yours, as I can see; but if I can help you in something, just let me know.
I continued to make progress, modifying the setup again to send commands from the CD4066BE. I also added a second one, my goal being to be able to control:
Pump 1
Pump 2
Blower
Heater
Set temperature
Lighting
Filtration
On/Off panel
The matrix is of the type k0-p6, k1-p6, k2-p6, k0-p7, k1-p7...
So the initial results are:
k0-p6 = Pump 1
k0-p8 = Lighting
k1-p6 = Pump 2
k1-p8 = Filtration (ozonator)
The others, which I won't implement but found in case anyone is interested:
k0-p7 = Time setting
k1-p7 = CD player
k2-p6 = Radio
Control of the 4 found elements works perfectly from Home Assistant.
As a reminder, this is the connector The 8-pin connector is the key connector, with the following pins in order: VDD, VSS, K0, K1, K2, P6, P7, P8.
After numerous tests on the KL8300's keyboard bus, I finally understood that the numeric keypad doesn't use simple push-buttons. It's a true matrix keyboard scanned by the Holtek microcontroller.
Important: the connector is actually k0-k1-k2-k3-k4-p6-p7-p8. VDD and VSS do not use this connector.
The previous assumption was incorrect:
Grounding a key row does NOT reproduce the actual behavior of the button.
The correct behavior is as follows:
A physical button connects a "K" row to a "P" scan row.
Example:
Pump 1 is not “K0 -> GND”.
It is actually:
K0 ↔ P6
This explains why some earlier tests triggered unexpected functions like “CD”.
I manually mapped the matrix by briefly shorting Kx/Px combinations while the spa was powered ON.
I've updated the GitHub repository with all the necessary elements to reproduce the assembly: Gerber files, netlist, BOM, Fritzing project, keypad mappings, etc.
The current PCB is intentionally single-sided, as I'm not yet proficient enough in double-sided design. The routing is therefore quite large and not very compact, but fully functional.
There isn't yet a professional-grade schematic; that's not my area of expertise either.
If anyone would like to take over the project to create a clean schematic or a more compact double-sided version, all the necessary information is now available on GitHub.
I have a KL8-3H-BAA6 board on my Jazzi Spa (2009). I'd be interested in trying to integrate it's functionalities with Home Assistant, but your great findings and instructions are still beyond my knowledge to actually try the integration myself.
Any suggestion on how to start?
I'm attaching a couple of pics of my board if that can help anyone else.
This looks very nice indeed. I have the same version in name, but apparently my display controller is not using a din25 connecter, but just a round din 8 pin connector to connect to the controller board. I no longer have the keyboard matrix exposed. My plan is to also read the data on the bus and see if there is 2-way communication.
There are actually only 5 pins in use in my display connection.
I guess they are Clock, Strobe, DATA, VCC and GND, only issue I'm not sure about is how 2way communication is achieved. I'll have to use copilot or something to help me figure this out.
On my version, I haven't found true bidirectional communication on the LCD connector. The LCD receives information such as segments, LEDs, icons, the displayed temperature, pump status, heating, filtration, panel status, etc.
The keypad control section doesn't use this LCD connector on my version. It uses the 8-pin KEY connector. The keypad isn't a simple contact to GND; it's a true matrix scanned by the Holtek microcontroller.
Note: the exact values may vary depending on the panel or controller version. The safest approach is to capture data with several known states: panel ON/OFF, pump 1 ON/OFF, pump 2 ON/OFF, heating ON/OFF, LED ON/OFF, then compare the changing bytes.
To verify if there is truly bidirectional communication on your version, you need to check if the DIO line is sometimes released by the controller board and controlled by the display. If there is only one DATA line and no separate MISO, bidirectional communication is only possible if DIO goes into high impedance during certain phases. In my capture, I did not observe this phase on the LCD bus: only writing to the display.
Hi Francki85,
I found your KL8300 ESPHome project and I would like to use it on my Dimhora Beata spa.
My hardware is:
Control board: KL8-3H-CB16
Topside panel: KL8-3H-FACE3
Would your latest PCB be compatible with this combination?
Also, do you happen to have a spare assembled PCB (or even a bare PCB) that you could sell and ship to Italy? I would of course cover the board and shipping costs.
I can send you photos of my control board and panel if useful.
Thanks for sharing your work!