Skip to content

Commit e055a6f

Browse files
author
Maksym Shtembuliak
committed
Release 0.1.10: add unified device configuration
1 parent f58521a commit e055a6f

24 files changed

Lines changed: 1729 additions & 82 deletions

‎.github/workflows/ci.yml‎

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,11 @@ jobs:
2020
- name: Host tests
2121
run: make -C host_tests test
2222
- name: Validate YAML and docs links
23-
run: |
24-
python - <<'PY'
25-
from pathlib import Path
26-
import re
27-
import yaml
28-
29-
class Loader(yaml.SafeLoader):
30-
pass
31-
Loader.add_constructor("!secret", lambda loader, node: loader.construct_scalar(node))
32-
for path in sorted(Path("examples").glob("*.yaml")):
33-
if path.name == "secrets.yaml":
34-
raise SystemExit("examples/secrets.yaml must not be committed")
35-
yaml.load(path.read_text(), Loader=Loader)
36-
37-
link_re = re.compile(r"\[[^\]]+\]\(([^)]+)\)")
38-
for path in [Path("README.md"), Path("README.uk.md"), *Path("docs").glob("*.md")]:
39-
for match in link_re.finditer(path.read_text()):
40-
target = match.group(1).split("#", 1)[0]
41-
if not target or "://" in target:
42-
continue
43-
if not (path.parent / target).exists():
44-
raise SystemExit(f"{path}: broken link {target}")
45-
PY
46-
- name: Compile release presets
47-
run: python tools/build_web_release.py --compile --local-source --version ci
23+
run: python tools/validate_repo.py
24+
- name: Compile release presets and YAML-only profiles
25+
run: >-
26+
python tools/build_web_release.py
27+
--compile
28+
--compile-yaml-profiles
29+
--local-source
30+
--version ci

‎.github/workflows/release.yml‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,34 @@ jobs:
2828
run: python -m pip install "esphome==${ESPHOME_VERSION}" pyyaml
2929
- name: Host tests
3030
run: make -C host_tests test
31+
- name: Validate YAML and docs links
32+
run: python tools/validate_repo.py
3133
- name: Build web release
32-
run: python tools/build_web_release.py --compile --local-source --version "${GITHUB_REF_NAME}"
34+
run: >-
35+
python tools/build_web_release.py
36+
--compile
37+
--compile-yaml-profiles
38+
--local-source
39+
--version "${GITHUB_REF_NAME}"
40+
- name: Generate checksums
41+
run: |
42+
cd dist/web-release/web
43+
for file in firmware/*.bin manifest-*.json; do
44+
sha256sum "$file" | sed 's# firmware/# #'
45+
done > ../SHA256SUMS
46+
- name: Render release notes
47+
run: >-
48+
python tools/render_release_notes.py
49+
"${GITHUB_REF_NAME}"
50+
--output dist/web-release/RELEASE_NOTES.md
3351
- name: Upload release artifacts
3452
uses: softprops/action-gh-release@v3
3553
with:
54+
body_path: dist/web-release/RELEASE_NOTES.md
3655
files: |
3756
dist/web-release/web/firmware/*.bin
3857
dist/web-release/web/manifest-*.json
58+
dist/web-release/SHA256SUMS
3959
- name: Upload Pages artifact
4060
uses: actions/upload-pages-artifact@v5
4161
with:

‎CHANGELOG.md‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,54 @@ All notable changes to this project are documented here. The format is based on
44
[Keep a Changelog](https://keepachangelog.com/), and this project adheres to
55
[Semantic Versioning](https://semver.org/).
66

7+
## [0.1.10] - 2026-07-10
8+
9+
### Added
10+
- **Unified local configuration page.** `/` now combines Wi-Fi provisioning,
11+
Home Assistant endpoint settings, complete inverter UART framing and web OTA.
12+
It is available on both the normal LAN address and `192.168.4.1` in setup mode.
13+
- **Complete persisted UART framing.** ESP8266 and ESP32 now persist data bits,
14+
parity and stop bits together with baud rate. Existing baud-only preferences
15+
migrate automatically. On BK72xx, UART settings remain build-time-only and can
16+
be changed only by rebuilding and reflashing the firmware.
17+
- **Hardware identity overview.** The page shows the compiled TX/RX and RS485
18+
direction/status/communication LED pins, collector PN and ESPHome hostname.
19+
Build-time fields remain read-only until a platform-safe boot-time
20+
hardware-profile mechanism is available.
21+
- **Interactive Wi-Fi scan.** Nearby networks retain the stock captive-portal
22+
behavior: SSID, a signal-strength indicator and lock state are displayed, and
23+
selecting a row copies its SSID into the Wi-Fi form. Exact RSSI is available
24+
from the indicator tooltip. The configured network remains visible and is
25+
clearly marked as connected or currently unavailable.
26+
- **Configurable collector PN.** The default PN remains protected by a checked
27+
toggle. Disabling it allows a validated custom PN; re-enabling it restores the
28+
default. Identity changes are persisted and applied after a safe restart.
29+
- **Local page translations.** English, Ukrainian and Russian can be selected on
30+
the device page. The browser remembers the selected language.
31+
- **ESPHome Dashboard adoption.** Ready-made ESP8266, ESP32 and BK72xx builds
32+
publish project metadata and a board-specific `dashboard_import` package over
33+
mDNS. The Dashboard can create a local YAML for a device flashed from a
34+
prebuilt binary; no server-specific ownership key is required.
35+
- **UART / RS485 diagnostics.** The local page shows passive live counters for
36+
transmitted bytes and requests, total physical receive bytes and the age of
37+
the last TX/RX activity. Developer-only response/stale counters remain in the
38+
diagnostics JSON. Counters reset at boot and never influence transport behavior.
39+
- **Dark and light themes.** The local page uses the dark theme by default and
40+
remembers the user's theme toggle alongside the language preference.
41+
42+
### Fixed
43+
- The always-on local web server is initialized only after the network stack is
44+
ready. Starting AsyncTCP from the component's pre-Wi-Fi setup priority caused
45+
an ESP32 boot loop; captive-portal registration remains available before Wi-Fi.
46+
47+
### Changed
48+
- Collector identity, Home Assistant endpoint and UART framing now have separate
49+
save actions. PN changes require explicit browser confirmation and explain the
50+
Home Assistant re-add requirement.
51+
- UART persistence wording now explicitly states that settings are stored in
52+
non-volatile device memory and used after every restart.
53+
- `BRIDGE_VERSION` bumped to `0.1.10`.
54+
755
## [0.1.8] - 2026-07-04
856

957
### Fixed
@@ -114,6 +162,8 @@ Home Assistant integration. Highlights:
114162
- Status LED indication and the `AT+VDTU` virtual-bridge capability probe.
115163
- Web installer (GitHub Pages) for the ESP8266 and ESP32 presets.
116164

165+
[0.1.10]: https://github.com/groove-max/esp-eybond-collector/compare/v0.1.8...v0.1.10
166+
[0.1.8]: https://github.com/groove-max/esp-eybond-collector/compare/v0.1.7...v0.1.8
117167
[0.1.7]: https://github.com/groove-max/esp-eybond-collector/compare/v0.1.6...v0.1.7
118168
[0.1.6]: https://github.com/groove-max/esp-eybond-collector/compare/v0.1.5...v0.1.6
119169
[0.1.5]: https://github.com/groove-max/esp-eybond-collector/compare/v0.1.4...v0.1.5

‎README.md‎

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,47 @@ For the custom ESP bridge, EyeBond Local also exposes **Change inverter UART spe
176176

177177
---
178178

179-
## Wi-Fi changes
179+
## Local settings page
180180

181-
The bridge can use normal ESPHome Wi-Fi setup and captive portal behavior. When it opens the setup portal, its temporary Wi-Fi network is named like its virtual collector PN, for example `V00000...`.
181+
Once the collector is connected to your network, open
182+
`http://<collector-ip>/`. If it cannot join Wi-Fi, connect to its temporary
183+
`V00000...` network and open `http://192.168.4.1/` instead. Both addresses show
184+
the same settings page.
185+
186+
From this page you can:
187+
188+
- choose a Wi-Fi network and enter its password;
189+
- set the Home Assistant server address and port;
190+
- view or change the collector PN;
191+
- check the UART pins and change the inverter UART settings;
192+
- see whether data is moving over UART / RS485;
193+
- install a firmware update over the network.
194+
195+
Each section has its own **Save** button. Before changing the PN, server address
196+
or UART settings, the page explains how that change can affect Home Assistant or
197+
the inverter connection. Nearby Wi-Fi networks show signal strength and security;
198+
the network currently configured on the collector is highlighted.
199+
200+
UART settings can be changed directly on ESP8266 and ESP32. They are stored in
201+
flash and remain in use after a restart. On BK72xx they are shown for reference;
202+
to change them, edit the YAML and flash the board again. The page is available in
203+
English, Ukrainian and Russian, with a light or dark theme.
204+
205+
For a custom YAML, enable the page with `web_configuration: true` under
206+
`eybond_collector:` and include `captive_portal:`.
207+
208+
### Add a prebuilt collector to ESPHome Dashboard
209+
210+
You do not need a pairing key. If ESPHome Device Builder is on the same network
211+
and can receive mDNS traffic, it should show the collector as a discovered
212+
device. Click **Adopt** and ESPHome will create a local YAML using the package for
213+
the matching board. Review the board and pin assignment before installing an
214+
update from that YAML.
182215

183216
EyeBond Local can also change collector Wi-Fi settings for the bridge. If the new credentials are wrong, the bridge should fall back to its setup portal instead of becoming permanently unreachable.
184217

185-
The nearby-network list can show only the current network on the first read. Refresh after a few seconds to see the full scan result.
218+
The first Wi-Fi scan may show only the current network. Refresh the page after a
219+
few seconds if the full list has not appeared yet.
186220

187221
---
188222

‎README.uk.md‎

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,48 @@ select:
176176

177177
---
178178

179-
## Зміна Wi-Fi
179+
## Локальна сторінка налаштувань
180180

181-
Міст підтримує звичайне налаштування Wi-Fi через ESPHome і сторінку налаштування. Коли міст відкриває сторінку налаштування, його тимчасова Wi-Fi-мережа має назву як віртуальний PN колектора, наприклад `V00000...`.
181+
Коли колектор підключиться до вашої мережі, відкрийте
182+
`http://<ip-колектора>/`. Якщо підключитися до Wi-Fi не вдалося, приєднайтеся до
183+
тимчасової мережі з назвою на кшталт `V00000...` і відкрийте
184+
`http://192.168.4.1/`. В обох випадках відкриється та сама сторінка.
185+
186+
На ній можна:
187+
188+
- обрати Wi-Fi-мережу та ввести пароль;
189+
- вказати адресу й порт сервера Home Assistant;
190+
- переглянути або змінити PN колектора;
191+
- перевірити UART-піни та налаштувати зв’язок з інвертором;
192+
- побачити, чи надходять і передаються дані через UART / RS485;
193+
- оновити прошивку через мережу.
194+
195+
Кожен блок має окрему кнопку **Зберегти**. Перед зміною PN, адреси сервера або
196+
UART сторінка попередить, як це може вплинути на зв’язок з Home Assistant чи
197+
інвертором. У списку Wi-Fi видно рівень сигналу та захист мережі, а поточну
198+
мережу колектора виділено окремо.
199+
200+
На ESP8266 та ESP32 параметри UART можна змінити прямо на сторінці. Вони
201+
зберігаються у flash-пам’яті й не втрачаються після перезапуску. На BK72xx ці
202+
параметри можна лише переглянути: для зміни потрібно відредагувати YAML і знову
203+
прошити плату. Доступні українська, англійська та російська мови, а також світла
204+
і темна теми.
205+
206+
У власному YAML сторінка вмикається через `web_configuration: true` у
207+
`eybond_collector:` і потребує секції `captive_portal:`.
208+
209+
### Додавання готового колектора до ESPHome Dashboard
210+
211+
Ключ прив’язки не потрібен. Якщо ESPHome Device Builder працює в тій самій
212+
мережі й отримує mDNS-повідомлення, він покаже колектор серед знайдених
213+
пристроїв. Натисніть **Adopt** — ESPHome створить локальний YAML із пакетом для
214+
відповідної плати. Перед першим оновленням перевірте тип плати та призначення
215+
пінів.
182216

183217
EyeBond Local також може змінювати Wi-Fi-налаштування моста. Якщо нові дані неправильні, міст має перейти на сторінку налаштування, а не зникнути назавжди.
184218

185-
Список мереж може спочатку показати тільки поточну мережу. Оновіть через кілька секунд, щоб побачити повний результат сканування.
219+
Під час першого сканування може відобразитися лише поточна мережа. Якщо повний
220+
список не з’явився, оновіть сторінку за кілька секунд.
186221

187222
---
188223

‎components/eybond_collector/__init__.py‎

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import esphome.final_validate as fv
1414
from esphome import pins
1515
from esphome.components import uart
16-
from esphome.const import CONF_ID
16+
from esphome.const import CONF_ID, CONF_NUMBER, CONF_RX_PIN, CONF_TX_PIN, CONF_UART_ID
1717
from esphome.core import CORE
1818

1919
CODEOWNERS = ["@groove-max"]
@@ -33,6 +33,7 @@
3333
CONF_STATUS_LED_PIN = "status_led_pin"
3434
CONF_COM_LED_PIN = "com_led_pin"
3535
CONF_BLE_PROVISIONING = "ble_provisioning"
36+
CONF_WEB_CONFIGURATION = "web_configuration"
3637

3738
eybond_collector_ns = cg.esphome_ns.namespace("eybond_collector")
3839
EybondCollector = eybond_collector_ns.class_("EybondCollector", cg.Component, uart.UARTDevice)
@@ -68,6 +69,7 @@ def _validate_pn(value):
6869
cv.Optional(CONF_STATUS_LED_PIN): pins.gpio_output_pin_schema,
6970
cv.Optional(CONF_COM_LED_PIN): pins.gpio_output_pin_schema,
7071
cv.Optional(CONF_BLE_PROVISIONING, default=False): cv.boolean,
72+
cv.Optional(CONF_WEB_CONFIGURATION, default=False): cv.boolean,
7173
}
7274
)
7375
.extend(cv.COMPONENT_SCHEMA)
@@ -77,20 +79,24 @@ def _validate_pn(value):
7779

7880

7981
def _final_validate(config):
80-
"""ble_provisioning needs ESP32 BLE and the esp32_ble_server GATT server."""
81-
if not config.get(CONF_BLE_PROVISIONING):
82-
return config
83-
if not CORE.is_esp32:
84-
raise cv.Invalid(
85-
"ble_provisioning is only supported on ESP32 (it needs on-chip BLE); "
86-
"ESP8266 and BK72xx/LibreTiny have no usable BLE server."
87-
)
8882
full_config = fv.full_config.get()
89-
if "esp32_ble_server" not in full_config:
83+
if config.get(CONF_BLE_PROVISIONING):
84+
if not CORE.is_esp32:
85+
raise cv.Invalid(
86+
"ble_provisioning is only supported on ESP32 (it needs on-chip BLE); "
87+
"ESP8266 and BK72xx/LibreTiny have no usable BLE server."
88+
)
89+
if "esp32_ble_server" not in full_config:
90+
raise cv.Invalid(
91+
"ble_provisioning requires an 'esp32_ble_server:' entry in your YAML — "
92+
"it provides the BLE GATT server the bridge attaches to. Add an empty "
93+
"'esp32_ble_server:' block (see examples/esp32-ble.yaml)."
94+
)
95+
if config.get(CONF_WEB_CONFIGURATION) and "captive_portal" not in full_config:
9096
raise cv.Invalid(
91-
"ble_provisioning requires an 'esp32_ble_server:' entry in your YAML — "
92-
"it provides the BLE GATT server the bridge attaches to. Add an empty "
93-
"'esp32_ble_server:' block (see examples/esp32-ble.yaml)."
97+
"web_configuration requires a 'captive_portal:' entry; the settings "
98+
"page reuses its stock Wi-Fi setup handlers on both the normal LAN "
99+
"and the fallback access point"
94100
)
95101
return config
96102

@@ -103,6 +109,21 @@ async def to_code(config):
103109
await cg.register_component(var, config)
104110
await uart.register_uart_device(var, config)
105111

112+
# Keep the generated UART component authoritative. These values are only
113+
# metadata for the local configuration page; arbitrary pin remapping is not
114+
# universally reloadable by ESPHome's platform UART implementations.
115+
uart_tx_pin = -1
116+
uart_rx_pin = -1
117+
for uart_config in CORE.config.get("uart", []):
118+
if uart_config.get(CONF_ID) != config[CONF_UART_ID]:
119+
continue
120+
if CONF_TX_PIN in uart_config:
121+
uart_tx_pin = uart_config[CONF_TX_PIN][CONF_NUMBER]
122+
if CONF_RX_PIN in uart_config:
123+
uart_rx_pin = uart_config[CONF_RX_PIN][CONF_NUMBER]
124+
break
125+
cg.add(var.set_uart_pin_numbers(uart_tx_pin, uart_rx_pin))
126+
106127
if CONF_PN in config:
107128
cg.add(var.set_pn(config[CONF_PN]))
108129
cg.add(var.set_udp_port(config[CONF_UDP_PORT]))
@@ -126,3 +147,6 @@ async def to_code(config):
126147
if config[CONF_BLE_PROVISIONING]:
127148
cg.add_define("USE_EYBOND_BLE")
128149
cg.add(var.set_ble_provisioning(True))
150+
if config[CONF_WEB_CONFIGURATION]:
151+
cg.add_define("USE_EYBOND_WEB_CONFIG")
152+
cg.add(var.set_web_configuration(True))

0 commit comments

Comments
 (0)