Summary
When device-builder ingests ESPHome configs, normalize the legacy flat ethernet clk_mode option into the new nested clk: { mode, pin } form so stored and surfaced configs use the current format. Today we carry clk_mode forward unchanged, which is the reason the ESPHome deprecation removal had to be punted (see esphome/esphome#17114, now targeting 2026.9.0). Auto-mutating on ingest lets ESPHome drop the deprecated option.
Background
ESPHome deprecated the flat clk_mode in favor of:
ethernet:
type: LAN8720
mdc_pin: GPIO23
mdio_pin: GPIO18
clk:
mode: CLK_OUT
pin: 17
phy_addr: 0
The legacy form encodes the clock pin in the mode string. We already parse it in a couple of places, e.g. _CLK_MODE_PIN_RE and _ETHERNET_HW_FIELDS (which lists both clk and clk_mode) in script/sync_esphome_devices.py, and it shows up in tests/test_sync_esphome_devices_ethernet.py, tests/test_sync_components_typed_schema.py, and the fixture tests/fixtures/yaml_search/ethernet_proxy.yaml.
Mapping
Legacy clk_mode |
New clk |
GPIO0_IN |
mode: CLK_EXT_IN, pin: 0 |
GPIO0_OUT |
mode: CLK_OUT, pin: 0 |
GPIO16_OUT |
mode: CLK_OUT, pin: 16 |
GPIO17_OUT |
mode: CLK_OUT, pin: 17 |
The rule generalizes: mode is CLK_EXT_IN for *_IN and CLK_OUT for *_OUT; pin is the integer in GPIO<n>_.
Proposed change
On ingest/sync, rewrite any top-level ethernet: block that contains clk_mode so it instead carries clk: { mode, pin } and drops clk_mode. Apply it before we lock featured-component presets and build the pin occupancy map, so downstream code only ever sees the new shape. Where clk_mode is currently special-cased (occupancy parsing, HW preset field set), prefer the nested clk once normalization is in place.
Acceptance criteria
- Incoming configs using
clk_mode are stored/surfaced as clk: { mode, pin }; no clk_mode remains.
- Pin occupancy and featured-component presets still resolve the CLK pin correctly via the nested form.
- Tests/fixtures that assert
clk_mode behavior are updated to the new shape.
- Verified against a config that uses
clk_mode (e.g. the ethernet_proxy.yaml fixture) producing the nested clk output.
Why now
ESPHome punted the clk_mode removal to 2026.9.0 specifically to give device-builder time to handle this (esphome/esphome#17114). Landing this unblocks removing the deprecated option upstream.
Summary
When device-builder ingests ESPHome configs, normalize the legacy flat
ethernetclk_modeoption into the new nestedclk: { mode, pin }form so stored and surfaced configs use the current format. Today we carryclk_modeforward unchanged, which is the reason the ESPHome deprecation removal had to be punted (see esphome/esphome#17114, now targeting 2026.9.0). Auto-mutating on ingest lets ESPHome drop the deprecated option.Background
ESPHome deprecated the flat
clk_modein favor of:The legacy form encodes the clock pin in the mode string. We already parse it in a couple of places, e.g.
_CLK_MODE_PIN_REand_ETHERNET_HW_FIELDS(which lists bothclkandclk_mode) inscript/sync_esphome_devices.py, and it shows up intests/test_sync_esphome_devices_ethernet.py,tests/test_sync_components_typed_schema.py, and the fixturetests/fixtures/yaml_search/ethernet_proxy.yaml.Mapping
clk_modeclkGPIO0_INmode: CLK_EXT_IN,pin: 0GPIO0_OUTmode: CLK_OUT,pin: 0GPIO16_OUTmode: CLK_OUT,pin: 16GPIO17_OUTmode: CLK_OUT,pin: 17The rule generalizes:
modeisCLK_EXT_INfor*_INandCLK_OUTfor*_OUT;pinis the integer inGPIO<n>_.Proposed change
On ingest/sync, rewrite any top-level
ethernet:block that containsclk_modeso it instead carriesclk: { mode, pin }and dropsclk_mode. Apply it before we lock featured-component presets and build the pin occupancy map, so downstream code only ever sees the new shape. Whereclk_modeis currently special-cased (occupancy parsing, HW preset field set), prefer the nestedclkonce normalization is in place.Acceptance criteria
clk_modeare stored/surfaced asclk: { mode, pin }; noclk_moderemains.clk_modebehavior are updated to the new shape.clk_mode(e.g. theethernet_proxy.yamlfixture) producing the nestedclkoutput.Why now
ESPHome punted the
clk_moderemoval to 2026.9.0 specifically to give device-builder time to handle this (esphome/esphome#17114). Landing this unblocks removing the deprecated option upstream.