Jacuzzi J345 (ProLink)¶
This guide sets up the MQTT bridge for a Jacuzzi J345: a J-300 series tub with an
unencrypted control board, reached through the original Jacuzzi ProLink Wi-Fi module.
Older threads and file names call this tub a "J335". The definition ID is jacuzzi_j345.
Nobody on the project has this tub
The definition was decoded from five logs that the tub's owner shared, and checked against pyjacuzzi. The project has not run it against the tub. Start receive-only, compare every value with the topside, and report what you see.
What is supported¶
Each row has the evidence status from the definition. Confirmed means a capture shows a command and the tub's reaction, or the same change from the topside in several captures. Inferred means the captures agree with pyjacuzzi but nobody compared the value with the tub. Hypothesis means a pattern in the data only. The plain protocol reference has the bytes.
Read¶
| Entity | Status | Notes |
|---|---|---|
| Current Water Temperature | Inferred | Whole °F. Never compared with the topside display |
| Target Water Temperature | Confirmed | Whole °F |
| Pump 1, Pump 2 | Confirmed | On or off. A low speed, if a pump has one, would read as off |
| Circulation Pump | Inferred | |
| Heater Active | Hypothesis | Follows the thermostat in the captures. No reference names the bit |
| Light Mode | Confirmed | off, a colour name, blend or blend paused |
| Light Brightness | Confirmed | Percent |
| Secondary Temperature, Flow Switch, CLEARRAY Days Remaining | Inferred | Diagnostics |
| Set Mode Active, Reminder Active, Celsius Mode, Display State, State Raw, Error Code, Light Red, Light Green, Light Blue | Mixed | Diagnostics, disabled by default |
Control¶
All controls are unavailable until you enable transmit.
| Entity | Status | What it sends |
|---|---|---|
| Temperature Set Control | Confirmed for 90, 100 and 101 °F | One set-temperature frame. Range 80 to 104 °F, step 1 |
| Pump 1 Button, Pump 2 Button | Confirmed | One button frame. Each press toggles the pump |
| Pump 1, Pump 2 (switches) | Confirmed | The same button frame, sent only when the pump is not already in the state you chose. One frame, no retry |
| Light White … Light Aqua (nine buttons) | Confirmed | One light frame that selects the colour |
| Light Brightness | Confirmed for 0, 20, 40, 60, 80, 100, with a colour already on | One light frame. 0 turns the lights off. Select a colour first: see Known limits |
Not supported¶
- The ESPHome component. This tub is bridge-only.
- Temperature up and down buttons, the topside light and colour buttons, UV and the menu. Their codes come from a different tub.
- Clock setting, locks, filter cycles and heat mode.
- Pump 3 and the blower.
- Light blend mode as a control. pyjacuzzi notes that the board refuses it as a direct
command. Raising the brightness from
0may start it: see Known limits. - Celsius. The definition is Fahrenheit only, and the bridge refuses to send a setpoint while the tub reports Celsius mode.
Hardware path¶
There is nothing to wire. The bridge connects to the ProLink module over your network.
| Item | Value |
|---|---|
| Address | The ProLink module's LAN address. Find it in your router's client list and give it a fixed lease |
| TCP port | 4257 |
| Adapter | None. Do not use the EW11A settings (port 8899) |
| Bus address the bridge sends from | 0x0A, the ProLink's own address. Set by the definition |
The ProLink is assumed to serve one client at a time. Stop pyjacuzzi, the v1 bridge and any other tool before you start spa2mqtt. Whether the official app can run at the same time is unknown.
Install with Docker Compose¶
Follow Install with Docker Compose with these values in
.env:
SPA_IP=192.168.1.50
SPA_PORT=4257
SPA_DEFINITION=jacuzzi_j345
SPA_TRANSMIT=false
MQTT_BROKER=192.168.1.7
MQTT_PORT=1883
MQTT_USERNAME=
MQTT_PASSWORD=
Install with Portainer on Home Assistant OS¶
Portainer under Home Assistant OS cannot mount files, so every setting is an environment
variable. Follow Install with Portainer, method A. Use the same
stack file,
deploy/portainer-stack.yml,
and set these variables:
| Variable | Value |
|---|---|
SPA_IP |
ProLink address, for example 192.168.1.50 |
SPA_PORT |
4257 |
SPA_DEFINITION |
jacuzzi_j345 |
SPA_TRANSMIT |
false |
MQTT_BROKER |
Broker address. For the Mosquitto add-on, use the Home Assistant host's LAN address: core-mosquitto does not resolve from a Portainer stack |
MQTT_PORT |
1883 |
MQTT_USERNAME, MQTT_PASSWORD |
Broker login, if the broker needs one |
LOG_LEVEL |
INFO |
SPA_PORT and SPA_DEFINITION matter most: the defaults are for the J235 behind an
EW11A. SPA_IP and MQTT_BROKER are required, and the stack refuses to deploy without
them.
Coming from the v1 debug image
The old name jacuzzi_j335_unencrypted_farenheit still selects this definition, and
VARIANT_DEFINITION is still read. The stack file passes only the variables in the
table, so set SPA_DEFINITION there.
The image must include this definition. If the log says
unknown tub definition 'jacuzzi_j345', the image is older than this guide: update it
(Update).
Verify, receive-only first¶
With SPA_TRANSMIT=false the bridge cannot change the tub. Nothing is written to the
ProLink.
- In Home Assistant, open Settings > Devices & services > MQTT. A device named Jacuzzi J345 appears within a few seconds. The controls show as unavailable. That is expected.
-
Stand at the tub, or ask someone to, and compare with the topside:
Check How Current Water Temperature Same number as the topside display Target Water Temperature Change the setpoint at the topside by 1 °F and back Pump 1, Pump 2 Press each jets button on and off Circulation Pump Is the circulation pump running? Heater Active Does it match the heater indicator on the topside? Light Brightness Switch the light on at the topside and step its brightness -
Report what matched and what did not in discussion 13. A value that matches moves from inferred to confirmed. A value that does not match is just as useful.
The log names the fields that are still hypotheses at start-up. Any time the bridge decodes is the tub's own clock. In the captures that clock runs about 51 minutes slow.
Enable transmit¶
Read Safety first.
First commands on a tub the project has never driven
The frames the bridge sends are the frames pyjacuzzi sent to this tub in a captured session, byte for byte, and the test suite checks that. That shows the bytes are right. It does not show that the bridge's timing suits the ProLink. Have someone at the tub for the first commands.
What the bridge sends:
- At start-up, nothing.
- On the first command after each connection, one connection check frame
(
7e 07 0a bf 19 01 00 95 7e). pyjacuzzi sends this first, and the tub answers it. Whether commands need it is unknown. - Then one frame per command, at least four status frames (about 1.2 seconds) apart. There is no retry. The next status frame shows whether the tub obeyed.
Set SPA_TRANSMIT=true and update the stack. The log shows TRANSMIT ENABLED. Then test
in this order, one command at a time, and watch the topside after each:
- A light colour, for example Light Blue. Then Light Brightness to
0to turn the lights off. - Pump 2 Button, twice: on, then off.
- Pump 1 Button, twice.
- Temperature Set Control, 1 °F up, then back.
Turn the lights off with brightness 0
A colour button writes all four light records in the tub. The topside changes only the
first one. Set Light Brightness to 0 to clear all four.
To stop, set SPA_TRANSMIT=false and update the stack. If the topside shows an error,
isolate the spa at the breaker and wait before you switch it on again.
Send captures back¶
A capture with the times of your actions settles the open questions below. The monitor is read-only and can print the capture into the container log, so it works without a mounted file.
- Stop the
spa2mqttcontainer. - In Portainer, select Containers > Add container. Set Name to
spa2mqtt-monitorand Image toghcr.io/srleach/spa2mqtt:2. -
Under Advanced container settings > Command & logging, set Command to:
Set Console to Interactive & TTY. Under Restart policy, select Never.
-
Deploy the container and open its Logs. Turn Display timestamps off. Raise Lines from the default
100to5000or more: the capture adds about four lines per second. - Do one thing at a time at the topside, about ten seconds apart, and write down the time of each: the displayed water temperature, each pump on and off, the light, the setpoint up and down.
- Copy the whole log and post it in
discussion 13 with your notes.
The log shows the ProLink's LAN address in the line that starts
spa2mqtt monitor:and in every line that containsconnected to. Remove the address from those lines, or delete them, before you post. Only theRXlines are needed. - Stop and remove
spa2mqtt-monitor, then startspa2mqttagain.
The lines that matter look like 1748000000.123 RX 7e25ffaf16…. The report lines between
them are ignored when the log is replayed.
Known limits¶
- Fahrenheit only. Celsius mode on this board was never captured. Keep the topside in °F. If the Celsius Mode bit is set, the bridge refuses Temperature Set Control and logs a warning: pyjacuzzi sends half degrees Celsius in the same byte in that mode, so "80" would ask for 40 °C. The bridge also refuses the setpoint until it has decoded one status frame. The temperature readings would still be published with the °F unit and would be wrong.
- The setpoint range is 80 to 104 °F. These are the lowest and highest setpoints in any capture. Only 90, 100 and 101 were sent remotely. The bridge ignores a value outside the range and logs a warning. It does not clamp it.
- Select a colour before you raise Light Brightness. In the capture, every non-zero
brightness command was sent while a colour was on. pyjacuzzi's source says that raising
the brightness from 0 is how the lights enter blend mode (
src/jacuzziui.pyL487–499). So a non-zero brightness sent while the lights are off is expected to start the colour cycle, not a steady light. Nobody has seen this on this tub. - Light Brightness steps by 20. Those are the values the capture shows accepted. The topside's own steps (100, 66, 33) still display correctly.
Open questions that a capture or a test at the tub would answer:
- Is the connection check needed before commands work?
- Does the ProLink accept a second TCP client, or the official app at the same time?
- Does the water temperature match the topside? What does the second sensor measure?
- Is Heater Active the heater? It rests on one bit that no reference names.
- Does either pump have a low speed? Is there a pump 3, a blower or a UV button?
- What does the tub do with a setpoint outside 80 to 104 °F? The bridge never sends one.
- Does a non-zero brightness sent while the lights are off start blend mode, as pyjacuzzi's source says?
- Why did the CLEARRAY counter fall from 364 to 0 in six days?
The plain protocol reference lists the unknown bytes.