diff --git a/AGENTS.md b/AGENTS.md index c165ddc350f..ac7975d3b00 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -208,8 +208,14 @@ file does, and it is the authority when they disagree. The most useful starting * **Fixed sets of names** (status words, model names): a `PROGMEM_STRING_TABLE` (`esphome/core/progmem.h`), logged with `get_log_str` and `LOG_STR_ARG`, copied out with `ESPHOME_strncpy_P` before `publish_state`. A `dump_config` helper that picks a name returns `const LogString *` from `LOG_STR(...)`. - * **CRCs and bit tricks** come from `esphome/core/helpers.h` (`crc8`, `crc16`, `reverse_bits`, `encode_uint16`); - pick the helper's polynomial and bit-order arguments instead of writing a CRC loop. + * **CRCs and bit tricks** come from `esphome/core/helpers.h` (`crc8`, `crc16`, `xor_bytes`, `sum16_bytes`, + `reverse_bits`, `encode_uint16`, `encode_value_le`, `sign_extend`, `bcd_to_uint8`); pick the helper's + arguments instead of writing a loop. Epson style 7-byte RTC calendars (one-hot weekday) use + `time::decode_bcd_calendar`. + * **Bus helpers:** UART drains with `read_available(on_byte)` and `discard_available()`, text lines with + `LineReader`; I2C has `update_register`, `write_registers` (PROGMEM `I2CRegValue` table), `check_chip_id` + and `read_bytes_16_le`. `if (!this->status_comm_result(ok)) return;` sets or clears the warning. + A child sensor that skips repeated values is `SUB_SENSOR_WITH_DEDUP(name, type)`. * **An unset float is `NAN`**, not `optional`; the optional costs 4 to 8 bytes of padding per member. * **`PollingComponent` first runs `update()`** after a random share of the interval; call `this->update()` at the end of `setup()` when the entities need a state at boot. @@ -429,6 +435,22 @@ file does, and it is the authority when they disagree. The most useful starting and `await cg.add_variable(var.set_bus, config[CONF_BUS_ID])`; both skip a `None` value, so pass `config.get(KEY)` for an optional key, and return what they created. Use `cg.register_parented` for `set_parent`. + - **Hub forwarding entities need no C++ class:** a button, switch, number or select that only calls its hub + uses `button.ApplyButton` (`switch.ApplySwitch`, `number.ApplyNumber`, `select.ApplySelect`) in its schema + and `apply=` on the `sub_*` call. The body is a call on the hub with `entity` and `state`, `value` or + `index`/`option` in scope; on a switch, number or select `publish="before"` or `"after"` publishes the state. + ```python + switches = switch.sub_switches(config, parent=hub) + await switches(CONF_BLUETOOTH, None, apply="set_bluetooth(state)", publish="after") + ``` + + - **Other codegen helpers:** `uart.new_uart_component(config, *ctor_args)` (and `i2c.new_i2c_component`, + `spi.new_spi_component`, `modbus.new_modbus_client_component`, `ble_client.new_ble_node_component`) + constructs, registers and attaches in one call; `display.add_writer(var, config)` sets the lambda; + `MyEnum.options("on", prefix="MY_ENUM_")` builds an enum dict; `button.restart_button_schema(cls)` (and + `factory_reset_`, `query_`) are button presets; `fv.get_declaring_config(id)` finds a hub's config in + final validation. + * **Automations (Triggers, Actions, Conditions):** Automations have three building blocks: **Triggers** (fire when something happens), **Actions** (do something), and **Conditions** (check if something is true).