21constexpr size_t DEVICE_TYPE_HEX_STRING_BUFFER_SIZE = 8;
24std::string format_device_type_hex(
DeviceType type) {
25 char buf[DEVICE_TYPE_HEX_STRING_BUFFER_SIZE];
26 snprintf(buf,
sizeof(buf),
"0x%02X",
static_cast<unsigned>(type));
27 return std::string(buf);
49 return "not_reported";
57 return "not_reported";
76 return "UNKNOWN_COVER_CMD";
81 return static_cast<DeviceType>((type_msb << DEVICE_TYPE_LOW_BITS_SHIFT) |
82 (type_subtype >> DEVICE_TYPE_HIGH_BITS_SHIFT));
90 const auto raw =
static_cast<uint16_t
>(
static_cast<uint16_t
>(type) & DEVICE_TYPE_WIRE_MASK);
91 type_msb =
static_cast<uint8_t
>(raw >> DEVICE_TYPE_LOW_BITS_SHIFT);
92 type_subtype =
static_cast<uint8_t
>((raw << DEVICE_TYPE_HIGH_BITS_SHIFT) | (subtype & DEVICE_SUBTYPE_MASK));
97 bool const target_valid = target_raw <= STATUS_POS_MAX;
98 bool const current_valid = current_raw <= STATUS_POS_MAX;
99 float const decoded_current = current_valid ? current_raw * 100.0F / STATUS_POS_MAX : UNKNOWN_POSITION;
102 target = target_raw * 100.0F / STATUS_POS_MAX;
103 }
else if (is_stopped && current_valid) {
107 target = decoded_current;
109 target = UNKNOWN_POSITION;
113 position = decoded_current;
114 }
else if (is_stopped && target_valid) {
117 position = UNKNOWN_POSITION;
122 if (target == UNKNOWN_POSITION || position == UNKNOWN_POSITION)
124 float const tolerance = STATUS_POS_TOLERANCE_RAW * 100.0F / STATUS_POS_MAX;
125 return std::fabs(target - position) <= tolerance;
129 if (tilt_raw > STATUS_POS_MAX)
130 return UNKNOWN_POSITION;
131 return 100.0F - (tilt_raw * 100.0F / STATUS_POS_MAX);
141 return row !=
nullptr ? row->
name :
"unknown";
146 return row !=
nullptr && (row->
flags & device_type_flags::YAML_SELECTABLE) != 0 ? row->
name :
nullptr;
168 return "heater_level";
255 if (subtype == SUBTYPE_MAIN_PARAMETER_ONLY)
258 return row !=
nullptr && (row->
flags & device_type_flags::MAIN_PARAMETER_ONLY) != 0;
310 return "binary_on_off";
336 std::string raw = format_device_type_hex(type);
337 if (name !=
nullptr && strcmp(name,
"unknown") != 0) {
338 return std::string(name) +
" (" + raw +
")";
345 if (name !=
nullptr) {
346 return std::string(
"\"") + name +
"\"";
348 return format_device_type_hex(type);
352 bool metadata_complete,
bool inverted,
bool low_power,
353 const std::string &system_key_hex) {
357 const std::string low_power_line = low_power ?
" low_power: true\n" :
"";
358 const std::string system_key_line = system_key_hex.empty() ?
"" :
" system_key: \"" + system_key_hex +
"\"\n";
360 if (!metadata_complete) {
361 return " <cover|light|switch|lock>:\n"
362 " - platform: home_io_control\n"
363 " name: \"My Device\"\n"
364 " io_device_id: \"" +
367 " # io_device_type: left unset — this device didn't report its type during\n"
368 " # discovery, so the controller learns it automatically from the next status\n"
369 " # reply. Add it explicitly once you see it logged, to skip re-learning on\n"
370 " # every future boot.\n" +
371 low_power_line + system_key_line;
375 if (platform ==
nullptr)
378 std::string extra_lines;
380 extra_lines +=
" invert_position: true\n";
382 extra_lines +=
" dimmable: true\n";
383 extra_lines += low_power_line;
384 extra_lines += system_key_line;
386 const std::string subtype_line =
" io_subtype: " + std::to_string(subtype) +
"\n";
388 return " " + std::string(platform) +
390 " - platform: home_io_control\n"
391 " name: \"My Device\"\n"
392 " io_device_id: \"" +
const char * device_operation_profile_name(DeviceType type)
Human‑readable operation profile name for a device type.
void encode_packed_device_type(DeviceType type, uint8_t subtype, uint8_t &type_msb, uint8_t &type_subtype)
Encode a DeviceType/subtype pair into the two-byte packed metadata format used by discovery responses...
bool device_takes_main_parameter_only(DeviceType type, uint8_t subtype)
Does this device take movement commands as the main parameter only?
std::string format_device_type_for_yaml(DeviceType type)
Build the YAML value for a device's io_device_type key.
RainSensorState
What the hub's latest minimum-limitation read says about a rain-protection limit.
@ UNKNOWN
No usable reading: never read, or the last reads went unanswered.
@ DRY
The device answered and reports no rain-sized opening limit.
@ RAIN
The device answered and reports an opening limit of rain size.
const char * rain_sensor_state_name(RainSensorState state)
Get a human-readable name for a RainSensorState.
const HeatingProfile * find_heating_profile(DeviceType type, uint8_t subtype)
Look up the heating profile for a (type, subtype).
DeviceCapabilityClass device_capability_class(DeviceType type)
Map a raw IO‑Homecontrol type to the closest ESPHome/Home Assistant entity family.
bool default_inverted_for_type(DeviceType type)
Determine whether a device type has inverted position mapping by default.
CoverCommand
Named device commands for cover-type actuators.
@ FAVORITE
Move to stored favorite/"My" position.
@ STOP
Stop movement immediately.
@ VENT
Move to ventilation position (window-type devices).
@ FORCE_OPEN
Move to fully open at elevated priority; intended to bypass soft locks and environmental limits (conf...
bool device_supports_position_control(DeviceType type)
Does this device type support precise position control (0–100)?
bool device_supports_vent(DeviceType type)
Does this device type support the ventilation position command?
const char * device_type_name(DeviceType type)
Convert a DeviceType to a lowercase string identifier.
DeviceType
IO-Homecontrol node types.
@ LOUVRE_BLIND
Louvre blind.
@ SLIDING_WINDOW
Sliding window.
@ EXTERIOR_VENETIAN_BLIND
Exterior venetian blind.
@ VERTICAL_INTERIOR_BLIND
Vertical interior blind.
@ CENTRAL_HOUSE_CONTROL
Central house control.
@ GATE_OPENER
Gate opener.
@ ELECTRICAL_HEATER
Electrical heater.
@ VERTICAL_EXTERIOR_AWNING
Vertical exterior awning.
@ HEATING_TEMPERATURE_INTERFACE
Heating temperature interface.
@ BEACON
Beacon (unpaired/announcement).
@ SECURE_CONFIGURATION_DEVICE
Secure configuration device (a commissioning tool, not an actuator).
@ INTERIOR_VENETIAN_BLIND
Interior venetian blind.
@ UNKNOWN
Unknown/unspecified device.
@ DOMESTIC_HOT_WATER
Domestic hot water.
@ ZONE_CONTROL
Zone control.
@ INTRUSION_ALARM
Intrusion alarm.
@ WINDOW_OPENER
Window opening actuator.
@ SWINGING_SHUTTER
Swinging shutter.
@ HEAT_RECOVERY_VENTILATION
Heat recovery ventilation.
@ HORIZONTAL_AWNING
Horizontal awning (open/close inverted).
@ ROLLING_DOOR_OPENER
Rolling door opener.
@ ON_OFF_SWITCH
Generic on/off switch.
@ EXTERIOR_HEATING
Exterior heating.
@ TEST_AND_EVALUATION
Test and evaluation equipment.
@ DUAL_ROLLER_SHUTTER
Dual-section roller shutter.
@ VENTILATION_POINT
Ventilation point.
@ ROLLER_SHUTTER
Roller shutter.
@ REMOTE_CONTROLLER
Remote controller (all ten type bits set, packed bytes FF C0).
@ CURTAIN_TRACK
Curtain track.
@ BIOCLIMATIC_PERGOLA
Bioclimatic pergola (louvre opening as the position).
@ GARAGE_OPENER
Garage door opener.
bool device_supports_binary_control(DeviceType type)
Does this device type support binary on/off control?
@ PRIVATE_REGISTERS
CMD_WRITE_PRIVATE register reads and writes (proto_heating.h).
static constexpr uint8_t STATUS_BATTERY_MASK
Byte 1 bits 5-6: the device's coarse battery level (BatteryState).
float decode_tilt_report(uint16_t tilt_raw)
Decode tilt angle from raw 16‑bit value.
bool device_supports_lock_control(DeviceType type)
Does this device type support binary lock/unlock control via execute commands?
const DeviceTypeInfo * find_exact_device_type_info(DeviceType type, uint8_t subtype)
Look up the table row with exactly this (type, subtype), without falling back.
bool device_supports_climate_control(DeviceType type, uint8_t subtype)
Can a climate entity drive this device?
DeviceType decode_packed_device_type(uint8_t type_msb, uint8_t type_subtype)
Decode the 10-bit node type from two packed metadata bytes.
BatteryState
A device's coarse battery level, as it reports it in byte 1 of its status payload.
@ FULL_CHARGE
Battery full.
@ NORMAL_CHARGE
Battery neither low nor full.
@ NOT_REPORTED
The device does not report a battery (mains powered), or no status was read yet.
const char * cover_command_name(CoverCommand cmd)
Get a human-readable name for a CoverCommand.
const char * device_platform_name(DeviceType type, uint8_t subtype)
Name of the ESPHome platform that drives this (type, subtype).
bool device_supports_heat_level_control(DeviceType type)
Does this device take a heat level as its position (exterior heating)?
const char * device_capability_class_name(DeviceType type)
Get a human‑readable name for a capability class.
std::string build_device_yaml_snippet(DeviceType type, uint8_t subtype, const std::string &device_id, bool metadata_complete, bool inverted, bool low_power, const std::string &system_key_hex)
Build the ready-to-paste YAML block describing a device, for both a fully-decoded device and one whos...
const DeviceTypeInfo * find_device_type_info(DeviceType type, uint8_t subtype)
Look up the table row for a (type, subtype) pair.
bool is_known_device_type(uint16_t raw)
True when a raw 10-bit device-type value is a named DeviceType enumerator.
uint8_t decode_packed_device_subtype(uint8_t type_subtype)
Decode a protocol-packed device subtype from the second metadata byte.
bool device_supports_status_requests(DeviceType type)
Does this device type support status request commands (0x03)?
static constexpr uint8_t STATUS_BATTERY_SHIFT
Right shift that brings STATUS_BATTERY_MASK down to 0-3.
bool device_has_no_motion(DeviceType type, uint8_t subtype)
Does this device never move, so a status reply must not start the movement settle loop?
bool has_reached_target_position(float target, float position)
Has the device reached its target within tolerance?
const char * yaml_device_type_name(DeviceType type)
Return the YAML-friendly device-type name for types exposed in the Python schema.
DeviceCapabilityClass
High‑level capability class derived from DeviceType.
@ CLIMATE
Climate device (heating/cooling).
@ SWITCH
Binary on/off switch.
@ UNKNOWN
Unknown capability.
@ HEATER_LEVEL
Heater with a heat level in the position field (exterior heating).
@ COVER
Position‑controlled cover (shutter/blind/awning).
@ LIGHT
Binary on/off light.
BatteryState decode_battery_state(uint8_t status_byte)
Decode the coarse battery level from byte 1 of a status payload (CMD_PRIVATE_RESP to a status poll,...
const char * battery_state_name(BatteryState state)
Get the name a battery level is published under.
std::string format_device_type_diagnostic(DeviceType type)
Human-readable device type string for diagnostics, including the raw numeric value.
void decode_position_report(uint16_t target_raw, uint16_t current_raw, bool is_stopped, float &target, float &position)
Decode target/current position values from a status frame.
bool device_supports_tilt(DeviceType type)
Does this device type support tilt (slat angle) control?
bool device_light_is_brightness_only(DeviceType type, uint8_t subtype)
Is this light limited to brightness (no colour, no colour temperature)?
IO-Homecontrol command IDs, result codes and protocol enumerations.
IO-Homecontrol device-type model, capabilities and runtime device state.
The IO node-type and subtype table: names, entity class, platform and behaviour flags.
Heating profiles: what a climate card offers for each kind of heater, and how.
One row of the node-type / subtype table.
uint8_t flags
device_type_flags bits.
const char * name
Type row: lowercase identifier ("roller_shutter").
HeatingControlPath path
How the heater is commanded and read.