Skip to content

feat: add Home Assistant MQTT autodiscovery - #64

Open
clement87 wants to merge 2 commits into
jnsbyr:developfrom
clement87:pr/ha-autodiscovery
Open

clement87 wants to merge 2 commits into
jnsbyr:developfrom
clement87:pr/ha-autodiscovery

Conversation

@clement87

Copy link
Copy Markdown

Hi,
thanks for sharing this project.
To make it easy to integrate into Home Assistant, I added the MQTT Autodiscovery feature.

Entities created:

  • climate (heater thermostat with mode and temperature control)
  • switch (power, filter, bubbles)
  • binary_sensor (heater active)
  • sensor (water temp, target temp, error, WiFi RSSI, WiFi module temp, IP)

Disclaimer: I used Claude AI to help me with this feature.

clement87 and others added 2 commits May 25, 2026 10:59
Publishes MQTT discovery configs to homeassistant/ after the first
MQTT connection so Home Assistant automatically creates entities for
the PureSpa without any manual YAML configuration.

Entities created:
- climate (heater thermostat with mode and temperature control)
- switch (power, filter, bubbles)
- binary_sensor (heater active)
- sensor (water temp, target temp, error, WiFi RSSI, WiFi module temp, IP)

Device name and unique IDs are derived from the model name returned by
PureSpaIO::getModelName(), making the feature model-independent.

Requires ArduinoJson >= 6.21.3 (already a project dependency).
@jnsbyr

jnsbyr commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Many thanks for your contribution. At the moment I need to take care of a few other projects. I hope that I will soon find the time to have a look at your PR.

@jnsbyr jnsbyr added the enhancement New feature or request label Jun 13, 2026
@jnsbyr jnsbyr self-assigned this Jun 13, 2026

@andrea689 andrea689 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @clement87, thanks for this — HA autodiscovery is a great addition to the project. I reviewed the code and test-built it against the project defaults; a few findings, one of them blocking:

1. All discovery publishes fail with the default PubSubClient buffer (blocking)

The project uses PubSubClient 2.8 with its default MQTT_MAX_PACKET_SIZE of 256 bytes — there is no setBufferSize() call anywhere in the codebase. The discovery payloads range from roughly 240 bytes (IP sensor) to ~850 bytes (climate), plus topic and MQTT header, so client.publish() returns false for every config and nothing ever reaches the broker (the serial log prints FAIL for each one). I suspect it worked in your tests because of a locally modified PubSubClient.h?

The least invasive fix needs no buffer increase at all: stream the payload, which PubSubClient supports since 2.7 and is the pattern ArduinoJson recommends for MQTT:

size_t len = measureJson(doc);
bool ok = client.beginPublish(topic, len, true);
if (ok)
{
  serializeJson(doc, client);
  ok = client.endPublish();
}

This also makes the 1 KB heap buffer (new char[1024]) unnecessary. Side note: the if (!buf) null check is dead code either way, since this project builds with PIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS, so new throws instead of returning nullptr.

2. Heater binary_sensor stuck on unknown when the heater is off

pool/heater publishes three payloads: on, standby and off. With pl_on: "on" / pl_off: "standby", the off payload matches neither, so the entity shows unknown whenever the heater is switched off entirely. A value template fixes it:

doc["val_tpl"] = "{{ 'ON' if value == 'on' else 'OFF' }}";

(with the default ON/OFF payloads, so pl_on/pl_off can be dropped)

3. unique_id collision for two spas of the same model

devId is derived from the model name only, so two spas of the same model on one broker produce colliding unique_ids and merge into a single HA device. Appending ESP.getChipId() (hex) to devId fixes this.

Minor points

  • The climate min/max temperatures could use the existing PureSpaIO::WATER_TEMP::SET_MIN/SET_MAX constants instead of hardcoded 20/40.
  • DynamicJsonDocument(1024) is not far from the climate config's actual size; a doc.overflowed() check would prevent silently truncated configs (ArduinoJson drops keys silently when the pool is exhausted).
  • Interaction with mqttRetain: with the project default ("no"), state topics are not retained, so after an HA restart the discovered entities sit at unknown until a state actually changes (the firmware only publishes on change). It would be worth recommending mqttRetain: "yes" in the new README section — or, more robustly, subscribing to homeassistant/status and republishing states on HA's birth message.
  • Users without Home Assistant get 11 retained configs under homeassistant/#; a config.json opt-out in the style of mqttRetain (e.g. "haDiscovery": "no") might be worth considering.
  • The SJB-HS-only entities (jet, disinfection) are not exposed; they could be gated on pureSpaIO.getModel().
  • The other source files in this project carry an Apache-2.0 license header — the two new files should probably follow that convention.

With findings 1–3 fixed I can confirm the branch builds clean for the SB-H20 (RAM 40.1% / Flash 40.8%). I have the fixes as a commit on a local branch — happy to share the diff here or as a PR against your fork's branch if that helps.

(Review and testing done with the help of Claude Code.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants