Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
platform_climate_controls.h
Go to the documentation of this file.
1#pragma once
2
3/// @file platform_climate_controls.h
4/// @brief Generated per-heater auxiliary entities: the window binary sensor, the open-window
5/// detection switch and the night light.
6/// @ingroup hioc_platforms
7///
8/// All are device-bound companions (DeviceBoundCompanion) that climate.py generates alongside a
9/// `climate:` entity: the window pair when the device kind has WINDOW_COMPANIONS, the night light when
10/// the YAML asks for it on a kind with NIGHT_LIGHT. They show readings the hub's poll already stores in
11/// IoDevice::heating and add no radio traffic of their own, except their writes and the read-backs that
12/// confirm them.
13///
14/// @todo Experimental: the meaning of registers 0x010E (window sensor) and 0x0106 (open-window
15/// detection) is unconfirmed on hardware. An AGILIA IO radiator answers both reads (window 0,
16/// detection 1, tests/corpus/captures/exchange/atlantic_agilia_exchange_status_read.yaml), but no
17/// report has opened a window or switched detection off yet
18/// ([issue #165](https://github.com/laberning/home_io_control/issues/165)).
19
20#include "esphome/components/binary_sensor/binary_sensor.h"
21#include "esphome/components/light/light_output.h"
22#include "esphome/components/switch/switch.h"
23#include "esphome/core/component.h"
24#include "hub_core.h"
26#include "platform_light.h"
27#include "proto_device_model.h"
28
29namespace esphome {
30namespace home_io_control {
31
32/// @brief Binary sensor (`device_class: window`) that is ON while the heater's window sensor reports open.
33/// @ingroup hioc_platforms
34///
35/// Reads IoDevice::heating.window_open. No state until the first poll has read register 0x010E, so
36/// "closed" always means the heater said so.
37class IOHomeWindowBinarySensor : public binary_sensor::BinarySensor, public Component, public DeviceBoundCompanion {
38 public:
39 /// @brief Subscribe to the device's updates and publish what is already known.
40 void setup() override;
41
42 /// @brief Dump sensor configuration to the log.
43 void dump_config() override;
44
45 /// @brief Get setup priority so the parent hub is available first.
46 /// @return setup_priority::DATA.
47 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
48};
49
50/// @brief Switch that turns the heater's open-window detection on and off.
51/// @ingroup hioc_platforms
52///
53/// A write sends register 0x0106 and reads it back; the switch shows what the heater answered, so it
54/// has no state until the first read (the boot poll) and never shows a command the heater did not
55/// confirm. Disabled by default and in the config entity category.
56class IOHomeOpenWindowDetectionSwitch : public switch_::Switch, public Component, public DeviceBoundCompanion {
57 public:
58 /// @brief Subscribe to the device's updates and publish what is already known.
59 void setup() override;
60
61 /// @brief Dump switch configuration to the log.
62 void dump_config() override;
63
64 /// @brief Get setup priority so the parent hub is available first.
65 /// @return setup_priority::DATA.
66 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
67
68 protected:
69 /// @brief Write the detection setting and read it back.
70 /// @param state True to switch detection on.
71 void write_state(bool state) override;
72};
73
74/// @brief Dimmable light for a heater's night light (`night_light:` on a heater with io_model
75/// `heater_with_light`).
76/// @ingroup hioc_platforms
77///
78/// On/off is register 0x0144 and the brightness register 0x0142, a percentage that maps 1:1 onto Home
79/// Assistant's brightness (100 % = full). The light shows what the heater reports: no state until the
80/// first poll has read 0x0144, every acknowledged write is read back, and a write the heater does not
81/// acknowledge leaves the light showing the heater's last reading.
82///
83/// Switching on writes the brightness only when it differs from what the heater holds, then the on/off
84/// register; so on/off at an unchanged brightness never depends on the brightness write.
85///
86/// \todo Experimental: confirm on a real heater that writing 0x0144 switches the light (the heater's
87/// own controller writes it, issue #222) and that writing 0x0142 dims it.
88class IOHomeHeaterNightLight : public light::LightOutput, public Component, public DeviceBoundCompanion {
89 public:
90 /// @brief Subscribe to the device's updates and publish what is already known.
91 void setup() override;
92
93 /// @brief Dump light configuration to the log.
94 void dump_config() override;
95
96 /// @brief Get setup priority so the parent hub is available first.
97 /// @return setup_priority::DATA.
98 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
99
100 /// @brief Brightness is the light's only colour mode.
101 /// @return Traits with ColorMode::BRIGHTNESS.
102 light::LightTraits get_traits() override;
103
104 /// @brief Store the LightState and swallow the write its restore_mode makes at boot.
105 ///
106 /// LightState::setup() applies its restore_mode through a real write_state() right after this call;
107 /// on a radio-controlled light that would switch the heater's light at every reboot. The poll is the
108 /// source of truth, so that one write is suppressed.
109 /// @param state The LightState this output belongs to.
110 void setup_state(light::LightState *state) override {
111 this->state_ = state;
112 this->suppress_write_ = true;
113 }
114
115 /// @brief Send the requested state to the heater and read it back.
116 /// @param state The LightState holding the requested values.
117 void write_state(light::LightState *state) override;
118
119 protected:
120 /// @brief Publish the heater's light state, without echoing it back as a write.
121 /// @param dev The device record.
122 void on_device_update_(const IoDevice &dev);
123
124 /// @brief Write one light register.
125 /// @param fn NIGHT_LIGHT or NIGHT_LIGHT_BRIGHTNESS.
126 /// @param value Value to write.
127 /// @return true when the heater acknowledged it.
128 bool write_register_(HeatingFunction fn, float value);
129
130 light::LightState *state_{nullptr};
131 /// Swallows the write_state() that LightState::make_call().perform() causes for a state this entity
132 /// publishes itself (and the boot-time restore, see setup_state()).
133 bool suppress_write_{false};
134 /// True while write_state() runs its writes and read-backs: the device updates they cause are not
135 /// published one by one (a half-updated reading would flash a stale brightness), but once at the end.
136 bool writing_{false};
137};
138
139} // namespace home_io_control
140} // namespace esphome
Mixin holding the parent + device-id binding shared by per-device entities that are not full entity p...
Dimmable light for a heater's night light (night_light: on a heater with io_model heater_with_light).
void on_device_update_(const IoDevice &dev)
Publish the heater's light state, without echoing it back as a write.
light::LightTraits get_traits() override
Brightness is the light's only colour mode.
void write_state(light::LightState *state) override
Send the requested state to the heater and read it back.
void setup_state(light::LightState *state) override
Store the LightState and swallow the write its restore_mode makes at boot.
float get_setup_priority() const override
Get setup priority so the parent hub is available first.
void dump_config() override
Dump light configuration to the log.
bool writing_
True while write_state() runs its writes and read-backs: the device updates they cause are not publis...
void setup() override
Subscribe to the device's updates and publish what is already known.
bool write_register_(HeatingFunction fn, float value)
Write one light register.
bool suppress_write_
Swallows the write_state() that LightState::make_call().perform() causes for a state this entity publ...
Switch that turns the heater's open-window detection on and off.
void dump_config() override
Dump switch configuration to the log.
void write_state(bool state) override
Write the detection setting and read it back.
void setup() override
Subscribe to the device's updates and publish what is already known.
float get_setup_priority() const override
Get setup priority so the parent hub is available first.
Binary sensor (device_class: window) that is ON while the heater's window sensor reports open.
void dump_config() override
Dump sensor configuration to the log.
float get_setup_priority() const override
Get setup priority so the parent hub is available first.
void setup() override
Subscribe to the device's updates and publish what is already known.
IO-Homecontrol ESPHome component — protocol controller.
HeatingFunction
Registers and functions of a 2W heater, one row of the descriptor table each.
Shared device-binding mixins for IO-Homecontrol entity platforms.
Binary or dimmable light entity for IO‑Homecontrol devices.
IO-Homecontrol device-type model, capabilities and runtime device state.
Runtime state of a paired IO‑Homecontrol device.