8import esphome.codegen
as cg
9import esphome.config_validation
as cv
10from esphome
import pins
11from esphome.components
import spi
12from esphome.const
import CONF_ID
14DEPENDENCIES = [
"api",
"spi"]
15AUTO_LOAD = [
"button",
"cover",
"light",
"lock",
"switch",
"text_sensor"]
18CONF_HOME_IO_CONTROL_ID =
"home_io_control_id"
19CONF_RST_PIN =
"rst_pin"
20CONF_DIO0_PIN =
"dio0_pin"
21CONF_DIO4_PIN =
"dio4_pin"
22CONF_DIO1_PIN =
"dio1_pin"
23CONF_BUSY_PIN =
"busy_pin"
24CONF_NODE_ID =
"node_id"
25CONF_SYSTEM_KEY =
"system_key"
26CONF_TX_POWER =
"tx_power"
28CONF_RADIO_TYPE =
"radio_type"
29CONF_FEM_EN_PIN =
"fem_en_pin"
30CONF_VFEM_PIN =
"vfem_pin"
31CONF_FEM_PA_PIN =
"fem_pa_pin"
32CONF_TCXO_VOLTAGE =
"tcxo_voltage"
33MIN_STATUS_POLL_INTERVAL_MS = 500
35home_io_control_ns = cg.esphome_ns.namespace(
"home_io_control")
36IOHomeControlComponent = home_io_control_ns.class_(
37 "IOHomeControlComponent", cg.Component, spi.SPIDevice
50TCXO_VOLTAGE_OPTIONS = {
61DEVICE_TYPE_OPTIONS = {
63 "venetian_blind": 0x01,
64 "roller_shutter": 0x02,
66 "window_opener": 0x04,
67 "garage_opener": 0x05,
70 "rolling_door_opener": 0x08,
75 "heating_temperature_interface": 0x0E,
76 "on_off_switch": 0x0F,
77 "horizontal_awning": 0x10,
78 "external_venetian_blind": 0x11,
80 "curtain_track": 0x13,
81 "intrusion_alarm": 0x17,
82 "swinging_shutter": 0x18,
87 """Validate io_device_type as a named string or integer 0-255."""
88 if isinstance(value, int):
89 return cv.int_range(min=0, max=0xFF)(value)
91 if isinstance(value, str):
92 normalized = cv.string_strict(value).strip().lower()
93 if normalized
in DEVICE_TYPE_OPTIONS:
94 return DEVICE_TYPE_OPTIONS[normalized]
96 return cv.int_range(min=0, max=0xFF)(int(normalized, 0))
97 except ValueError
as err:
99 "Device type must be a known name or an integer in the range 0..255 (for example 0x11)"
103 "Device type must be a known name or an integer in the range 0..255"
108 """Generate a C++ static_cast expression for a validated device type."""
109 return cg.RawExpression(
110 f
"static_cast<esphome::home_io_control::DeviceType>(0x{value:02X})"
115 """Validate node_id as exactly 6 hex characters (3 bytes)."""
116 value = cv.string_strict(value).upper()
118 raise cv.Invalid(
"Node ID must be exactly 6 hex characters (3 bytes)")
122 raise cv.Invalid(
"Node ID must be valid hexadecimal")
127 """Validate system_key as exactly 32 hex characters (16 bytes)."""
128 value = cv.string_strict(value).upper()
130 raise cv.Invalid(
"System key must be exactly 32 hex characters (16 bytes)")
134 raise cv.Invalid(
"System key must be valid hexadecimal")
139 """Validate io_device_id as exactly 6 hex characters (3 bytes)."""
140 value = cv.string_strict(value).upper()
142 raise cv.Invalid(
"Device ID must be exactly 6 hex characters (3 bytes)")
146 raise cv.Invalid(
"Device ID must be valid hexadecimal")
151 """Validate status_poll_interval is at least MIN_STATUS_POLL_INTERVAL_MS."""
152 value = cv.positive_time_period_milliseconds(value)
153 if value.total_milliseconds < MIN_STATUS_POLL_INTERVAL_MS:
155 f
"status_poll_interval must be at least {MIN_STATUS_POLL_INTERVAL_MS}ms"
163 cv.GenerateID(): cv.declare_id(IOHomeControlComponent),
164 cv.Required(CONF_RST_PIN): pins.internal_gpio_output_pin_schema,
165 cv.Optional(CONF_DIO0_PIN): pins.internal_gpio_input_pin_schema,
166 cv.Optional(CONF_DIO4_PIN): pins.internal_gpio_input_pin_schema,
167 cv.Optional(CONF_DIO1_PIN): pins.internal_gpio_input_pin_schema,
168 cv.Optional(CONF_BUSY_PIN): pins.internal_gpio_input_pin_schema,
169 cv.Required(CONF_NODE_ID): validate_node_id,
170 cv.Required(CONF_SYSTEM_KEY): validate_system_key,
171 cv.Optional(CONF_TX_POWER, default=17): cv.int_range(min=0, max=22),
172 cv.Optional(CONF_PA_PIN, default=
"BOOST"): cv.enum(
173 PA_PIN_OPTIONS, upper=
True
175 cv.Optional(CONF_RADIO_TYPE): cv.enum(RADIO_TYPE_OPTIONS, lower=
True),
176 cv.Optional(CONF_FEM_EN_PIN): pins.internal_gpio_output_pin_schema,
177 cv.Optional(CONF_VFEM_PIN): pins.internal_gpio_output_pin_schema,
178 cv.Optional(CONF_FEM_PA_PIN): pins.internal_gpio_output_pin_schema,
179 cv.Optional(CONF_TCXO_VOLTAGE, default=
"1_8V"): cv.enum(
180 TCXO_VOLTAGE_OPTIONS, upper=
True
184 .extend(cv.COMPONENT_SCHEMA)
185 .extend(spi.spi_device_schema(
True, 8e6,
"mode0"))
195 cg.add_define(
"USE_API_USER_DEFINED_ACTIONS")
196 cg.add_define(
"USE_API_CUSTOM_SERVICES")
197 cg.add_define(
"USE_API_HOMEASSISTANT_SERVICES")
199 var = cg.new_Pvariable(config[CONF_ID])
200 await cg.register_component(var, config)
201 await spi.register_spi_device(var, config)
203 rst_pin = await cg.gpio_pin_expression(config[CONF_RST_PIN])
204 cg.add(var.set_rst_pin(rst_pin))
206 if CONF_DIO0_PIN
in config:
207 dio0_pin = await cg.gpio_pin_expression(config[CONF_DIO0_PIN])
208 cg.add(var.set_dio0_pin(dio0_pin))
210 if CONF_DIO4_PIN
in config:
211 dio4_pin = await cg.gpio_pin_expression(config[CONF_DIO4_PIN])
212 cg.add(var.set_dio4_pin(dio4_pin))
214 if CONF_DIO1_PIN
in config:
215 dio1_pin = await cg.gpio_pin_expression(config[CONF_DIO1_PIN])
216 cg.add(var.set_dio1_pin(dio1_pin))
218 if CONF_BUSY_PIN
in config:
219 busy_pin = await cg.gpio_pin_expression(config[CONF_BUSY_PIN])
220 cg.add(var.set_busy_pin(busy_pin))
222 if CONF_FEM_EN_PIN
in config:
223 fem_en_pin = await cg.gpio_pin_expression(config[CONF_FEM_EN_PIN])
224 cg.add(var.set_fem_en_pin(fem_en_pin))
226 if CONF_VFEM_PIN
in config:
227 vfem_pin = await cg.gpio_pin_expression(config[CONF_VFEM_PIN])
228 cg.add(var.set_vfem_pin(vfem_pin))
230 if CONF_FEM_PA_PIN
in config:
231 fem_pa_pin = await cg.gpio_pin_expression(config[CONF_FEM_PA_PIN])
232 cg.add(var.set_fem_pa_pin(fem_pa_pin))
234 cg.add(var.set_node_id(config[CONF_NODE_ID]))
235 cg.add(var.set_system_key(config[CONF_SYSTEM_KEY]))
236 cg.add(var.set_tx_power(config[CONF_TX_POWER]))
237 cg.add(var.set_pa_pin(config[CONF_PA_PIN]))
239 if CONF_RADIO_TYPE
in config:
240 cg.add(var.set_radio_type(config[CONF_RADIO_TYPE]))
242 cg.add(var.set_tcxo_voltage(config[CONF_TCXO_VOLTAGE]))
device_type_expression(value)
validate_device_type(value)
validate_status_poll_interval(value)
validate_device_id(value)
validate_system_key(value)