2026-09-01 14:22:37 +00:00
|
|
|
|
# Hot Spring Connected Spa — Home Assistant integration
|
|
|
|
|
|
|
|
|
|
|
|
Monitor and control a **Watkins / Hot Spring "Connected Spa"** hot tub from Home
|
|
|
|
|
|
Assistant, without the vendor mobile app.
|
|
|
|
|
|
|
2026-09-01 15:12:24 +00:00
|
|
|
|
- **Climate** — target setpoint + current water temperature (heater).
|
|
|
|
|
|
- **Number** — FreshWater salt output level (0–10), settable.
|
|
|
|
|
|
- **Switches** — spa lights (all zones) and jets.
|
|
|
|
|
|
- **Sensors** — water temperature, salt cartridge state.
|
|
|
|
|
|
- Live telemetry over the vendor's HiveMQ Cloud MQTT broker, or — optionally —
|
|
|
|
|
|
polled from the spa's local `/status` endpoint (see below).
|
|
|
|
|
|
|
|
|
|
|
|
Requests are sent with the same User-Agents and MQTT client-id format the
|
|
|
|
|
|
official app uses, so the traffic is indistinguishable from it.
|
2026-09-01 14:22:37 +00:00
|
|
|
|
|
|
|
|
|
|
This is an **unofficial** integration reverse-engineered from the official app.
|
|
|
|
|
|
It talks to Watkins' cloud; there is **no local control path**. If Watkins
|
|
|
|
|
|
changes their API it may break.
|
|
|
|
|
|
|
|
|
|
|
|
## Security / credentials
|
|
|
|
|
|
|
|
|
|
|
|
This repository contains **no secrets**:
|
|
|
|
|
|
|
|
|
|
|
|
- Your **account e-mail + password** are entered in the config-flow UI when you
|
|
|
|
|
|
add the integration and stored in Home Assistant's encrypted config entry —
|
|
|
|
|
|
never in this repo.
|
|
|
|
|
|
- The vendor **mutual-TLS client certificate** required to fetch broker
|
|
|
|
|
|
credentials is Watkins material (extractable from the app APK). It is **not
|
|
|
|
|
|
redistributed here**. You provide it as three PEM files on the host (below).
|
|
|
|
|
|
|
|
|
|
|
|
## Prerequisites: the client certificate
|
|
|
|
|
|
|
|
|
|
|
|
The integration needs three files in a directory on the Home Assistant host
|
|
|
|
|
|
(default `/config/hotspring/certs/`):
|
|
|
|
|
|
|
|
|
|
|
|
| File | Origin |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| `client1_cert.pem` | client cert from the app APK (`res/raw/client1.p12`) |
|
|
|
|
|
|
| `client1_key.pem` | its private key |
|
|
|
|
|
|
| `ca_cert.pem` | firmware CA (`res/raw/ca_cert.der`) |
|
|
|
|
|
|
|
|
|
|
|
|
To produce them from the APK's `client1.p12` and `ca_cert.der` (the P12 is
|
|
|
|
|
|
protected by a short static password embedded in the app — recover it from the
|
|
|
|
|
|
decompiled APK and pass it to `openssl` below):
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
P12PASS=... # static password embedded in the app APK
|
|
|
|
|
|
openssl pkcs12 -legacy -in client1.p12 -passin pass:"$P12PASS" -clcerts -nokeys -out client1_cert.pem
|
|
|
|
|
|
openssl pkcs12 -legacy -in client1.p12 -passin pass:"$P12PASS" -nocerts -nodes -out client1_key.pem
|
|
|
|
|
|
openssl x509 -inform der -in ca_cert.der -out ca_cert.pem
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Install
|
|
|
|
|
|
|
|
|
|
|
|
1. Copy `custom_components/hotspring/` into your Home Assistant `config/custom_components/`.
|
|
|
|
|
|
2. Place the three PEM files in `/config/hotspring/certs/`.
|
|
|
|
|
|
3. Restart Home Assistant.
|
|
|
|
|
|
4. **Settings → Devices & Services → Add Integration → “Hot Spring Connected
|
|
|
|
|
|
Spa”**, and sign in with your account.
|
|
|
|
|
|
|
|
|
|
|
|
## How it works
|
|
|
|
|
|
|
|
|
|
|
|
1. `POST iotsupportportalapi.watkinsmfg.com/api/v1/login/` → JWT.
|
|
|
|
|
|
2. `GET /user_spa_details/` → the spa's `rootTopic` (MQTT prefix).
|
|
|
|
|
|
3. mTLS `GET iotfirmwareota.watkinsmfg.com:8577/` (client cert) → rotating
|
|
|
|
|
|
HiveMQ broker host/user/pass.
|
|
|
|
|
|
4. Subscribe `<rootTopic>/#` for telemetry; publish
|
|
|
|
|
|
`<rootTopic>/<subsystem>/control` with `{"<subsystem>":{"control":{…}}}`
|
|
|
|
|
|
for commands (temperature is an integer string in the spa's unit).
|
|
|
|
|
|
|
|
|
|
|
|
The reusable protocol client lives under `custom_components/hotspring/api/`
|
2026-09-01 15:12:24 +00:00
|
|
|
|
(`cloud.py`, `spa.py`, `protocol.py`); all constant values are in `constants.py`.
|
|
|
|
|
|
|
|
|
|
|
|
## Optional: local read path
|
|
|
|
|
|
|
|
|
|
|
|
If Home Assistant is on the spa's LAN, set **Local `/status` URL** in the config
|
|
|
|
|
|
flow (e.g. `http://<spa-ip>/status`). Telemetry is then polled from the dongle's
|
|
|
|
|
|
local HTTP endpoint instead of subscribed over the cloud broker, keeping
|
|
|
|
|
|
monitoring on-LAN and off the vendor cloud. Control still uses the cloud MQTT
|
|
|
|
|
|
connection. Leave it blank to use cloud MQTT for reads.
|
2026-09-01 14:22:37 +00:00
|
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
|
|
MIT — see [LICENSE](LICENSE).
|