Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
platform_light.h
Go to the documentation of this file.
1#pragma once
2
3/// @file platform_light.h
4/// @brief Binary or dimmable light entity for IO‑Homecontrol devices.
5/// @ingroup hioc_platforms
6///
7/// Defaults to a minimal on/off representation (position < 50 is treated as on), validated on
8/// real hardware (a Somfy Izymo dimmer; see the somfy_izymo_dimmer_* captures). Setting
9/// `dimmable: true` in YAML switches to ColorMode::BRIGHTNESS, mapping HA's 0.0-1.0 brightness
10/// onto the same 0-100 IO position field platform_cover.cpp uses for position — confirmed on the
11/// same hardware to produce real intermediate brightness levels, not just the two binary
12/// extremes.
13///
14/// The protocol gives no machine-readable signal for whether a given LIGHT-type device actually
15/// supports intermediate positions (DISCOVER_RESP's subtype byte is manufacturer-opaque) — so
16/// `dimmable` is an explicit opt-in, not auto-detected. Devices that are genuinely binary-only
17/// should leave it unset/false.
18
19#include "esphome/core/component.h"
20#include "esphome/components/light/light_output.h"
22
23#include <optional>
24
25namespace esphome {
26namespace home_io_control {
27
28/// @brief Show a device's light state on its LightState without sending it back to the device.
29/// @ingroup hioc_platforms
30///
31/// LightState::make_call().perform() makes the output's write_state() run, which on these lights is a
32/// radio command. This publishes `on` (and `brightness`, when given) only when the LightState does not
33/// already show it, and arms `suppress_write` so the output swallows that one write_state(). Shared by
34/// every light output of this component.
35/// @param state The LightState to update.
36/// @param on Whether the device reports the light on.
37/// @param brightness The device's brightness, 0.0-1.0; nullopt for an on/off light.
38/// @param[out] suppress_write The output's echo guard; set when a call is performed.
39inline void publish_light_reading(light::LightState *state, bool on, std::optional<float> brightness,
40 bool &suppress_write) {
41 if (state->current_values.is_on() == on && state->remote_values.is_on() == on &&
42 (!brightness.has_value() ||
43 (state->current_values.get_brightness() == *brightness && state->remote_values.get_brightness() == *brightness)))
44 return;
45 suppress_write = true;
46 auto call = state->make_call();
47 call.set_state(on);
48 if (brightness.has_value())
49 call.set_brightness(*brightness);
50 call.set_save(false);
51 call.perform();
52}
53
54/// @brief Binary or dimmable light entity for IO‑Homecontrol devices.
55/// @ingroup hioc_platforms
56///
57/// The device-binding setters, setup() registration ritual and poll-interval dump line come
58/// from DeviceBoundEntity; only the on/off/brightness command and status decoding live here.
59class IOHomeLight : public light::LightOutput, public Component, public DeviceBoundEntity {
60 public:
61 /// @brief Initialize the light entity.
62 void setup() override;
63 /// @brief Dump configuration to log.
64 void dump_config() override;
65 /// @brief Get setup priority (DATA).
66 /// @return setup_priority::DATA.
67 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
68
69 /// @brief Enable brightness control (from YAML). Default false: binary on/off only.
70 /// @param dimmable True to expose ColorMode::BRIGHTNESS instead of ColorMode::ON_OFF.
71 void set_dimmable(bool dimmable) { this->dimmable_ = dimmable; }
72
73 /// @brief Return traits: ColorMode::BRIGHTNESS if dimmable, else ColorMode::ON_OFF.
74 light::LightTraits get_traits() override;
75 /// @brief Store the HA LightState object for state updates.
76 ///
77 /// LightState::setup() calls this first, then — moments later in that same call, before we get
78 /// a chance to do anything else — applies its own restore_mode (default ALWAYS_OFF) via a real
79 /// write_state() call, exactly as if HA had requested it. That's correct for a local PWM/LED
80 /// output (which needs some defined state immediately), but wrong for a radio-controlled device
81 /// with no local output to initialize: it would silently turn the light off (or on) on every
82 /// reflash regardless of the device's actual state. Arm suppress_write_ here so that one
83 /// boot-time write is swallowed the same way an inbound-update echo already is; the delayed
84 /// initial status poll (register_device_binding_(), same as covers) is the real source of truth.
85 /// @param state Pointer to LightState.
86 void setup_state(light::LightState *state) override {
87 this->state_ = state;
88 this->suppress_write_ = true;
89 }
90 void write_state(light::LightState *state) override;
91
92 protected:
93 /// @brief Handle inbound device status updates.
94 /// @param id Device ID.
95 /// @param dev Updated device state.
96 void on_device_update_(const std::string &id, const IoDevice &dev);
97
98 light::LightState *state_{nullptr};
99 bool dimmable_{false};
100 /// Guard so that an inbound radio status (or LightState's own boot-time restore_mode push —
101 /// see setup_state()) does not echo back as a new outbound command.
102 ///
103 /// This flag is a light-only asymmetry: LightState::make_call().perform() re-enters
104 /// write_state(), so both the inbound-update path and setup_state() must suppress that.
105 /// Switches publish state without re-entering write_state(), so they need no equivalent guard.
106 bool suppress_write_{false};
107};
108
109} // namespace home_io_control
110} // namespace esphome
Mixin holding the hub-device binding shared by all IO-Homecontrol entity platforms.
Binary or dimmable light entity for IO‑Homecontrol devices.
void write_state(light::LightState *state) override
bool suppress_write_
Guard so that an inbound radio status (or LightState's own boot-time restore_mode push — see setup_st...
void setup_state(light::LightState *state) override
Store the HA LightState object for state updates.
void on_device_update_(const std::string &id, const IoDevice &dev)
Handle inbound device status updates.
float get_setup_priority() const override
Get setup priority (DATA).
void dump_config() override
Dump configuration to log.
light::LightTraits get_traits() override
Return traits: ColorMode::BRIGHTNESS if dimmable, else ColorMode::ON_OFF.
void setup() override
Initialize the light entity.
void set_dimmable(bool dimmable)
Enable brightness control (from YAML).
void publish_light_reading(light::LightState *state, bool on, std::optional< float > brightness, bool &suppress_write)
Show a device's light state on its LightState without sending it back to the device.
Shared device-binding mixins for IO-Homecontrol entity platforms.
Runtime state of a paired IO‑Homecontrol device.