feat: multi-device support via ESPHome packages#22
Open
flowcool wants to merge 10 commits into
Open
Conversation
This is a discussion proposal — not a merge request for the current
single-device configuration.yaml.
## Context
I'm running 8 Smart Plant boards at home. With the current flat
configuration.yaml, maintaining 8 copies means:
- every bug fix or improvement must be applied 8 times
- calibration values are scattered across 8 files
- inconsistencies creep in over time
## Proposed structure
examples/multi-device/
├── packages/
│ └── smart_plant_base.yaml # all shared config (~250 lines)
└── my-lemon-tree.yaml # per-plant overrides (~20 lines)
The base package contains everything that is currently in
configuration.yaml. Each device file only defines its substitutions
(name, timezone, label image, soil calibration, gauge ranges) and
includes the package with a single !include.
Benefits:
- A bug fix in smart_plant_base.yaml propagates to all devices on the
next OTA — no copy-paste
- Soil calibration is clearly visible per device, not buried in a
shared file
- New plant = 15-line file, not a 400-line copy
Also included in the base:
- All fixes from PRs JGAguado#18 (SNTP), JGAguado#19 (power_save_mode / timezone)
- draw_gauge refactored as a C++ lambda to eliminate the 4×50-line
repeated block
- device_class: battery on the battery_level sensor
## Questions for @JGAguado
1. Would you consider adding this as an `examples/` directory rather
than replacing configuration.yaml? The single-file config would
remain the default for users with one plant; this would be an
opt-in for multi-plant setups.
2. The draw_gauge lambda refactor inside the display lambda — is that
acceptable in terms of ESPHome compatibility across versions?
3. Are there plans to migrate the project to esp-idf framework? That
would affect some of the deep sleep optimisations.
Note: I've been working on this refactoring with AI assistance
(Claude Code) for my personal multi-plant setup. The PRs in this
series are the result of a careful diff between the upstream config
and my production setup. Happy to iterate on any of this.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace api: with mqtt: (MQTT required for deep-sleep compatibility) - Add substitutions: device_comment, mqtt_topic_prefix, ota_password, ap_ssid — all previously hardcoded per-device - Improve on_boot: Wire.begin() + wait for mqtt.connected + wait for valid SNTP time (replaces fixed 20s delay, fixes 1970 display bug) - Update my-lemon-tree.yaml to show static IP override pattern and github:// package URL for zero-local-copy deployment Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… init Wire is not in scope in ESPHome lambdas without explicit include; the i2c: component already initializes the bus before on_boot runs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bypasses mDNS resolution (which fails with name_add_mac_suffix: true). Device files set use_address to their static IP; default falls back to device_name for setups without static IP. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes the 30s blocking wait for SNTP in on_boot — display already handles the missing-time case gracefully with dashes. Adds on_time_sync callback instead: display refreshes immediately the moment SNTP syncs, regardless of network latency. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pool.ntp.org alone can be slow on some networks (ESP32 UDP stack init latency + retry cycles). Adding cloudflare and google as fallbacks increases the chance of a fast first sync without any local IP dependency. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
DNS resolution can fail on ESP32 depending on router/DHCP config. Using Cloudflare (162.159.200.1) and Google (216.239.35.0) stable anycast IPs as primary servers with pool.ntp.org as hostname fallback. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ESP32-S2 default changed to 240MHz in ESPHome 2026.4 — cap at 160MHz to avoid ~3 mAh/day extra drain during wake windows on battery devices. Add power_save_mode: LIGHT during wake for additional WiFi savings. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both api: and mqtt: can coexist — MQTT keeps deep-sleep retained values, api: adds mDNS advertisement (_esphomelib._tcp.local.) so the ESPHome dashboard discovers devices via mDNS instead of ping only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the multi-device architecture proposed in #21, now validated in production on 8 devices.
examples/multi-device/packages/smart_plant_base.yaml— shared base package (~320 lines): all firmware in one place, every OTA push propagates to all devices automaticallyexamples/multi-device/my-lemon-tree.yaml— minimal per-device file (~20 lines): plant-specific substitutions onlyIncludes all fixes accumulated since the RFC:
on_time_sync: display refreshes as soon as time is available, nowait_untiluse_addresssubstitution: reliable OTA/log connections with static IP overridecpu_frequency: 160MHz: prevents ~3 mAh/day extra drain from ESPHome 2026.4 new 240MHz defaultpower_save_mode: LIGHT: WiFi savings during wake windowtopic_prefixsubstitution,log_topicdisabled (bandwidth), birth/will disabled (no "unavailable" flash on wake)No changes to existing
docs/source/files/configuration.yaml— fully additive.Validation
Running on 8 ESP32-S2 Saola boards in production for 2+ days:
Closes #21