Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
platform_light.cpp
Go to the documentation of this file.
1/// @file platform_light.cpp
2/// @brief Binary or dimmable light entity for IO-Homecontrol devices.
3/// @ingroup hioc_platforms
4
5#include "platform_light.h"
6#include "entity_helpers.h"
7#include "esphome/core/log.h"
8
9namespace esphome {
10namespace home_io_control {
11
12static const char *const TAG = "home_io_control.light";
13
15 // Lights need the shared device registry so discovery/status handling can find their node
16 // metadata the same way covers do; the delayed initial poll matches the cover path.
17 // `dimmable` is a light-only YAML choice; it travels in the device declaration so the registry can
18 // resolve the light's levels from it.
20 this, DeviceCapabilityClass::LIGHT, std::nullopt,
21 [this](const std::string &id, const IoDevice &dev) { this->on_device_update_(id, dev); }, this->dimmable_);
22}
23
24light::LightTraits IOHomeLight::get_traits() {
25 auto traits = light::LightTraits();
26 traits.set_supported_color_modes({this->dimmable_ ? light::ColorMode::BRIGHTNESS : light::ColorMode::ON_OFF});
27 return traits;
28}
29
30void IOHomeLight::write_state(light::LightState *state) {
31 if (this->suppress_write_) {
32 this->suppress_write_ = false;
33 return;
34 }
35
36 if (this->dimmable_) {
37 float brightness = 0.0F;
38 // Deliberately current_values.as_brightness(), not LightState::current_values_as_brightness()
39 // — the latter applies gamma_correct (default 2.8 for a BRIGHTNESS_ONLY light), which is
40 // meant for perceptually-correcting a PWM/LED output and silently mangles the value here (a
41 // real bug caught on hardware: HA-set 50% arrived on the wire as ~15%, matching 0.5^2.8). We
42 // want the exact linear percentage the user set — the Somfy device has its own dimming
43 // behavior, if any, and gamma-correcting on top of that would be wrong regardless of curve.
44 state->current_values.as_brightness(&brightness);
45 // Convert HA brightness (0.0-1.0) to IO position (0-100) via detail::round_percent()
46 // (entity_helpers.h — rounds rather than truncates, see its doc comment): this device family's
47 // convention is 0=full brightness, 100=off — the same inverted mapping platform_cover.cpp
48 // uses for non-inverted covers (HA 1.0 open -> IO 0), confirmed on real dimmable hardware.
49 auto const io_pos = detail::round_percent(1.0F - brightness);
50 this->parent_->queue_set_light_position(this->device_id_, io_pos);
51 return;
52 }
53
54 bool on = false;
55 state->current_values_as_binary(&on);
57}
58
59void IOHomeLight::on_device_update_(const std::string &id, const IoDevice &dev) {
60 // We only publish a stable HA state once the device reports a settled status (shared filter),
61 // and only once the LightState object is available.
62 if (this->state_ == nullptr || !this->passes_binary_update_filter_(id, dev))
63 return;
64
65 if (this->dimmable_) {
66 // Same inverted 0-100 IO position field as the binary path, just read as a continuous value
67 // instead of collapsed at the <50 threshold.
68 const float brightness = 1.0F - (dev.position / 100.0F);
69 publish_light_reading(this->state_, brightness > 0.0F, brightness, this->suppress_write_);
70 return;
71 }
72
73 // Binary endpoints report on/off via the shared 0-100 position field.
74 // Position < 50 is treated as "on", >= 50 as "off".
76 this->suppress_write_);
77}
78
80 ESP_LOGCONFIG(TAG, "IO-Homecontrol %s Light", this->dimmable_ ? "Dimmable" : "Binary");
81 ESP_LOGCONFIG(TAG, " Device ID: %s", this->device_id_.c_str());
83}
84
85} // namespace home_io_control
86} // namespace esphome
void log_poll_interval_config_(const char *tag) const
Emit the shared two-branch poll-interval line for dump_config().
void register_device_binding_(Component *self, DeviceCapabilityClass entity_class, std::optional< bool > invert_override, std::function< void(const std::string &, const IoDevice &)> on_update, bool dimmable=false)
Perform the shared setup() registration ritual.
bool passes_binary_update_filter_(const std::string &id, const IoDevice &dev) const
Shared inbound-update guard for binary endpoints.
virtual void queue_set_light_position(const std::string &device_id, uint8_t position)
Async form of set_light_position() that keeps radio work serialized on the main loop.
virtual void queue_set_light_state(const std::string &device_id, bool on)
Async form of set_light_state() that keeps radio work serialized on the main loop.
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 on_device_update_(const std::string &id, const IoDevice &dev)
Handle inbound device status updates.
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.
Conversions and renderers shared by the hub and its Home Assistant entities.
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.
constexpr float BINARY_ENTITY_ON_POSITION_THRESHOLD
Shared 0-100 cutoff: values below this mean binary "on".
uint8_t round_percent(float fraction)
Convert a 0.0-1.0 HA fraction (position, tilt, or brightness) to a 0-100 IO percent.
static constexpr const char * TAG
static const char *const TAG
Binary or dimmable light entity for IO‑Homecontrol devices.
Runtime state of a paired IO‑Homecontrol device.
float position
Current position: 0=open, 100=closed, or UNKNOWN_POSITION.