Add local time source, station buttons and link status

Prefer Home Assistant time with public NTP as fallback. Add next and previous
station, ESPHome and LibreTiny versions, and an MCU link sensor. Update notes
with the raw capture results and tidy the README to-do list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-11-05 17:22:24 +01:00
1 parent ae17892441
commit aa929478f6
4 files changed
+105 -29

No files matched your search

+90 -12
View File
@@ -22,7 +22,7 @@ external_components:
- source:
type: git
url: https://mangavalk.com/mangavalk/esphome-wake-up-light-ii.git
ref: v1.0.0
ref: v1.0.1
components: [uart]
refresh: 1d
@@ -136,6 +136,12 @@ globals:
restore_value: no
initial_value: '0'
# When the MCU last sent its once-a-minute clock report.
- id: last_mcu_report
type: uint32_t
restore_value: no
initial_value: '0'
# Last display state the schedule applied: -1 none, 0 day, 1 night.
- id: display_schedule_last
type: int
@@ -165,14 +171,22 @@ time:
- script.execute: sync_lamp_clock
- script.execute: apply_display_schedule
on_time:
- seconds: 0
minutes: 0
then:
- script.execute: sync_lamp_clock
- seconds: 0
then:
- script.execute: apply_display_schedule
# Home Assistant is preferred when connected, so the clock doesn't need internet.
- platform: homeassistant
id: ha_time
on_time_sync:
then:
- delay: 2s
- script.execute: sync_lamp_clock
- script.execute: apply_display_schedule
interval:
- interval: 1h
then:
- script.execute: sync_lamp_clock
- interval: 60s
then:
- script.execute: apply_display_schedule
###############################################################################
# Tuya MCU
@@ -188,6 +202,7 @@ tuya:
datapoint_type: string
then:
- lambda: |-
id(last_mcu_report) = millis();
if (x.size() != 6) return;
auto d = [](char c) -> int { return (c >= '0' && c <= '9') ? c - '0' : -1; };
int h1=d(x[0]), h2=d(x[1]), m1=d(x[2]), m2=d(x[3]), s1=d(x[4]), s2=d(x[5]);
@@ -329,7 +344,8 @@ script:
then:
- lambda: |-
if (!id(display_schedule_enabled).state) return;
auto now = id(network_time).now();
auto now = id(ha_time).now();
if (!now.is_valid()) now = id(network_time).now();
if (!now.is_valid()) return;
int start = id(display_night_start).hour * 60 + id(display_night_start).minute;
int end = id(display_night_end).hour * 60 + id(display_night_end).minute;
@@ -370,6 +386,21 @@ script:
call.set_transition_length(0);
call.perform();
- id: radio_step
mode: queued
parameters:
step: int
then:
- lambda: |-
if (!id(radio_valid) || id(radio_total) == 0) {
ESP_LOGW("radio", "No stations found yet; run Radio Scan first");
return;
}
int total = id(radio_total);
int next = ((id(radio_current) - 1 + step) % total + total) % total + 1;
std::vector<uint8_t> data = {id(radio_total), static_cast<uint8_t>(next)};
id(tuya_mcu).set_raw_datapoint_value(107, data);
- id: radio_sleep
mode: restart
then:
@@ -426,9 +457,10 @@ script:
mode: restart
then:
- lambda: |-
auto now = id(network_time).now();
auto now = id(ha_time).now();
if (!now.is_valid()) now = id(network_time).now();
if (!now.is_valid()) {
ESP_LOGW("clock", "No valid network time; use the Lamp Clock control in the web UI");
ESP_LOGW("clock", "No valid time source; use the Lamp Clock control in the web UI");
return;
}
char buf[7];
@@ -932,6 +964,20 @@ text_sensor:
sorting_group_id: group_device
sorting_weight: 4
- platform: version
name: "ESPHome Version"
hide_timestamp: true
web_server:
sorting_group_id: group_device
sorting_weight: 6
- platform: libretiny
version:
name: "LibreTiny Version"
web_server:
sorting_group_id: group_device
sorting_weight: 7
###############################################################################
# Device health
###############################################################################
@@ -969,6 +1015,16 @@ sensor:
###############################################################################
binary_sensor:
# The MCU reports its clock every minute, so silence means the link is down.
- platform: template
name: "MCU Link"
device_class: connectivity
web_server:
sorting_group_id: group_device
sorting_weight: 0.5
lambda: |-
return id(last_mcu_report) != 0 && millis() - id(last_mcu_report) < 150000;
- platform: gpio
name: "Knock"
icon: "mdi:gesture-tap"
@@ -1049,6 +1105,28 @@ button:
on_press:
- lambda: id(tuya_mcu).force_set_boolean_datapoint_value(126, false);
- platform: template
name: "Next Station"
icon: "mdi:skip-next"
web_server:
sorting_group_id: group_radio
sorting_weight: 2.7
on_press:
- script.execute:
id: radio_step
step: 1
- platform: template
name: "Previous Station"
icon: "mdi:skip-previous"
web_server:
sorting_group_id: group_radio
sorting_weight: 2.6
on_press:
- script.execute:
id: radio_step
step: -1
- platform: template
name: "Start Radio Sleep Timer"
icon: "mdi:timer-outline"