Add new Hotspring Integration - #177992
Conversation
There was a problem hiding this comment.
When adding new integrations, limit included platforms to a single platform. While we appreciate the effort, reviewing larger than necessary PRs slows down the review process. Please reduce this PR to a single platform. See the review process for more details.
There was a problem hiding this comment.
Pull request overview
Adds a local-polling Hot Spring spa integration with configuration, diagnostics, and water-heater control.
Changes:
- Adds config-entry setup, polling, and reconfiguration.
- Exposes spa temperature through a water-heater entity.
- Adds diagnostics, tests, dependency metadata, and generated registration.
Reviewed changes
Copilot reviewed 18 out of 20 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
.strict-typing |
Enables strict typing. |
homeassistant/components/hotspring/__init__.py |
Sets up and unloads the integration. |
homeassistant/components/hotspring/config_flow.py |
Implements setup and reconfiguration flows. |
homeassistant/components/hotspring/const.py |
Defines integration constants. |
homeassistant/components/hotspring/coordinator.py |
Polls the spa API. |
homeassistant/components/hotspring/diagnostics.py |
Exposes diagnostic data. |
homeassistant/components/hotspring/entity.py |
Defines shared entity metadata. |
homeassistant/components/hotspring/icons.json |
Adds icon metadata. |
homeassistant/components/hotspring/manifest.json |
Declares integration metadata and dependency. |
homeassistant/components/hotspring/strings.json |
Adds configuration-flow strings. |
homeassistant/components/hotspring/water_heater.py |
Implements temperature control. |
homeassistant/generated/config_flows.py |
Registers the config flow. |
homeassistant/generated/integrations.json |
Registers generated integration metadata. |
requirements_all.txt |
Adds python-hotspring. |
tests/components/hotspring/__init__.py |
Adds platform setup helper. |
tests/components/hotspring/conftest.py |
Adds fixtures and API mocks. |
tests/components/hotspring/test_config_flow.py |
Tests setup and reconfiguration. |
tests/components/hotspring/test_diagnostics.py |
Tests diagnostics. |
tests/components/hotspring/test_init.py |
Tests entry lifecycle and setup failure. |
tests/components/hotspring/test_water_heater.py |
Tests state and temperature control. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 21 out of 23 changed files in this pull request and generated no new comments.
Suppressed comments (4)
tests/components/hotspring/test_diagnostics.py:21
- Commit the generated Syrupy snapshot for this assertion. There is no
tests/components/hotspring/snapshots/test_diagnostics.ambr, so this test reports a missing snapshot and fails in normal CI runs.
assert (
await get_diagnostics_for_config_entry(hass, hass_client, init_integration)
== snapshot
tests/components/hotspring/test_water_heater.py:34
- Commit the generated Syrupy snapshots for this test. No Hot Spring snapshot files are present, so the state and entity-registry snapshot assertions fail as missing snapshots in normal CI runs.
assert state == snapshot
homeassistant/components/hotspring/config_flow.py:34
- Handle
HotSpringErrorin this validation path as well. The sameupdate()call is treated as raising bothHotSpringConnectionErrorandHotSpringErrorby the coordinator, so a known API/response failure currently escapes the config flow instead of returning a form error.
except HotSpringConnectionError:
errors["base"] = "cannot_connect"
homeassistant/components/hotspring/diagnostics.py:11
- Redact the spa's
ssidfield from diagnostics. The currentSpaInfopayload includes the user's Wi-Fi network name, so diagnostics exports expose network-identifying data; other integrations redact this field (for example,homeassistant/components/aosmith/diagnostics.py:24).
TO_REDACT = {"unique_id", "mac_address"}
- Handle HotSpringError in config flow - Redact hostname and ssid from diagnostics payload - Add exception translations for UpdateFailed and HomeAssistantError - Add approved Syrupy test snapshots
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 23 changed files in this pull request and generated no new comments.
Suppressed comments (3)
homeassistant/components/hotspring/quality_scale.yaml:56
- Mark diagnostics as
todorather thanexempt. Planning diagnostics for a follow-up means the rule applies but is not implemented; established quality-scale metadata represents this astodo(for example,homeassistant/components/energyid/quality_scale.yaml:64-66), while exemptions are reserved for integrations with no diagnosable data.
diagnostics:
status: exempt
comment: Diagnostics will be added in a follow-up PR.
tests/components/hotspring/test_water_heater.py:60
- Use an in-range temperature in this successful service test. The default test unit system is Celsius and this entity advertises a 40 °C maximum, so
103is converted to 217.4 °F—well beyond the device's 104 °F maximum—and the permissive mock masks that this is not a valid successful device call.
ATTR_TEMPERATURE: 103,
homeassistant/components/hotspring/coordinator.py:48
- Add a setup/update test for this
HotSpringErrorbranch. The setup test only injectsHotSpringConnectionError, so theinvalid_responsetranslation path is currently unverified even though it has distinct behavior and dedicated handling.
except HotSpringError as error:
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 22 changed files in this pull request and generated no new comments.
Suppressed comments (2)
homeassistant/components/hotspring/quality_scale.yaml:56
- Mark diagnostics as
todountil the rule is implemented. Deferring diagnostics to a follow-up means the rule is incomplete, not exempt; other integrations represent this state asdiagnostics: todo.
diagnostics:
status: exempt
comment: Diagnostics will be added in a follow-up PR.
tests/components/hotspring/test_water_heater.py:60
- Use a temperature within the entity's advertised range in this success-path test. The test environment uses Celsius, so
103is converted to217.4°F, well above the entity's104°Fmaximum, and therefore verifies an invalid command that a real spa may reject.
mock_hotspring.set_temperature.assert_called_once_with(217.4)
erwindouna
left a comment
There was a problem hiding this comment.
Thanks for adding the new integration, @Moustachauve! Here's an initial review. :)
| raise UpdateFailed( | ||
| translation_domain=DOMAIN, | ||
| translation_key="cannot_connect", | ||
| translation_placeholders={"error": str(error)}, |
There was a problem hiding this comment.
Errors are badly translatable. I advise to omit them. :)
There was a problem hiding this comment.
This is not allowed to be part of the PR.
|
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
|
Side note: do we also need to add branding? |
Yes, it's in home-assistant/brands#10898. Thanks for the review, will work on the comments tonight! |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 22 changed files in this pull request and generated no new comments.
Suppressed comments (1)
homeassistant/components/hotspring/quality_scale.yaml:37
- Mark
action-exceptionsasdoneinstead of exempt. This integration exposeswater_heater.set_temperatureand translates its dependency failures (water_heater.py:63-68), matching the established declaration inhomewizard/quality_scale.yaml:38; the current claim that it has no actions is inaccurate.
action-exceptions:
status: exempt
comment: Integration does not have custom actions.
Proposed change
This PR introduces a new Hotspring integration to control hot tubs that are equipped with the official Connected Spa Kit from Hotspring.
Type of change
Additional information
Checklist
ruff format homeassistant tests)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest.requirements_all.txt.Updated by running
python3 -m script.gen_requirements_all.To help with the load of incoming pull requests: