2026-11-05 12:27:54 +01:00
|
|
|
###############################################################################
|
|
|
|
|
# One alarm's controls. Included once per alarm from wake-up-light-ii.yaml.
|
|
|
|
|
# n = alarm number
|
|
|
|
|
# o = offset of this alarm's 12-byte block inside DP127
|
|
|
|
|
# dp = this alarm's on/off datapoint
|
|
|
|
|
# Byte layout is documented next to the DP127 handler in the main file.
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
# Bit 0 = Monday, per Tuya's definition and a ringing test. No days set = one time.
|
|
|
|
|
packages:
|
|
|
|
|
mon: !include { file: alarm_day.yaml, vars: { day: "Mon", bit: "0", w: "11" } }
|
|
|
|
|
tue: !include { file: alarm_day.yaml, vars: { day: "Tue", bit: "1", w: "12" } }
|
|
|
|
|
wed: !include { file: alarm_day.yaml, vars: { day: "Wed", bit: "2", w: "13" } }
|
|
|
|
|
thu: !include { file: alarm_day.yaml, vars: { day: "Thu", bit: "3", w: "14" } }
|
|
|
|
|
fri: !include { file: alarm_day.yaml, vars: { day: "Fri", bit: "4", w: "15" } }
|
|
|
|
|
sat: !include { file: alarm_day.yaml, vars: { day: "Sat", bit: "5", w: "16" } }
|
|
|
|
|
sun: !include { file: alarm_day.yaml, vars: { day: "Sun", bit: "6", w: "17" } }
|
|
|
|
|
|
|
|
|
|
web_server:
|
|
|
|
|
sorting_groups:
|
|
|
|
|
- id: group_alarm_${n}
|
|
|
|
|
name: "Alarm ${n}"
|
|
|
|
|
sorting_weight: 3${n}
|
|
|
|
|
|
|
|
|
|
switch:
|
|
|
|
|
- platform: tuya
|
|
|
|
|
id: alarm_${n}_enable
|
|
|
|
|
name: "Alarm ${n}"
|
|
|
|
|
switch_datapoint: ${dp}
|
|
|
|
|
web_server:
|
|
|
|
|
sorting_group_id: group_alarm_${n}
|
|
|
|
|
sorting_weight: 1
|
|
|
|
|
|
|
|
|
|
# Stored inverted: 0 = snooze allowed, 1 = not allowed.
|
|
|
|
|
- platform: template
|
|
|
|
|
id: alarm_${n}_snooze_allowed
|
|
|
|
|
name: "Alarm ${n} Snooze Allowed"
|
|
|
|
|
web_server:
|
|
|
|
|
sorting_group_id: group_alarm_${n}
|
|
|
|
|
sorting_weight: 10
|
|
|
|
|
lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return {};
|
|
|
|
|
return id(alarm_raw)[${o} + 11] == 0;
|
|
|
|
|
turn_on_action:
|
|
|
|
|
- lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return;
|
|
|
|
|
id(alarm_raw)[${o} + 11] = 0;
|
|
|
|
|
- script.execute: send_alarm_settings
|
|
|
|
|
turn_off_action:
|
|
|
|
|
- lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return;
|
|
|
|
|
id(alarm_raw)[${o} + 11] = 1;
|
|
|
|
|
- script.execute: send_alarm_settings
|
|
|
|
|
|
|
|
|
|
datetime:
|
|
|
|
|
- platform: template
|
|
|
|
|
id: alarm_${n}_time
|
|
|
|
|
name: "Alarm ${n} Time"
|
|
|
|
|
type: time
|
|
|
|
|
update_interval: 2s
|
|
|
|
|
web_server:
|
|
|
|
|
sorting_group_id: group_alarm_${n}
|
|
|
|
|
sorting_weight: 2
|
|
|
|
|
lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return {};
|
|
|
|
|
uint16_t mins = (static_cast<uint16_t>(id(alarm_raw)[${o} + 1]) << 8) | id(alarm_raw)[${o} + 2];
|
|
|
|
|
if (mins >= 1440) return {};
|
|
|
|
|
ESPTime t{};
|
|
|
|
|
t.hour = mins / 60;
|
|
|
|
|
t.minute = mins % 60;
|
|
|
|
|
t.second = 0;
|
|
|
|
|
return t;
|
|
|
|
|
set_action:
|
|
|
|
|
- lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return;
|
|
|
|
|
uint16_t mins = static_cast<uint16_t>(x.hour) * 60 + x.minute;
|
|
|
|
|
id(alarm_raw)[${o} + 1] = (mins >> 8) & 0xFF;
|
|
|
|
|
id(alarm_raw)[${o} + 2] = mins & 0xFF;
|
|
|
|
|
- script.execute: send_alarm_settings
|
|
|
|
|
|
|
|
|
|
select:
|
|
|
|
|
- platform: template
|
|
|
|
|
id: alarm_${n}_mode
|
|
|
|
|
name: "Alarm ${n} Mode"
|
|
|
|
|
options:
|
|
|
|
|
- "Sound"
|
|
|
|
|
- "Sound + Light"
|
|
|
|
|
- "Radio"
|
|
|
|
|
- "Radio + Light"
|
|
|
|
|
update_interval: 2s
|
|
|
|
|
web_server:
|
|
|
|
|
sorting_group_id: group_alarm_${n}
|
|
|
|
|
sorting_weight: 2.5
|
|
|
|
|
lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return {};
|
|
|
|
|
switch (id(alarm_raw)[${o} + 5]) {
|
|
|
|
|
case 0: return std::string("Sound");
|
|
|
|
|
case 1: return std::string("Sound + Light");
|
|
|
|
|
case 2: return std::string("Radio");
|
|
|
|
|
case 3: return std::string("Radio + Light");
|
|
|
|
|
default: return {};
|
|
|
|
|
}
|
|
|
|
|
set_action:
|
|
|
|
|
- lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return;
|
|
|
|
|
uint8_t value = 0;
|
|
|
|
|
if (x == "Sound + Light") value = 1;
|
|
|
|
|
else if (x == "Radio") value = 2;
|
|
|
|
|
else if (x == "Radio + Light") value = 3;
|
|
|
|
|
id(alarm_raw)[${o} + 5] = value;
|
|
|
|
|
// The MCU drops a light mode if brightness is 0, so give it a level.
|
|
|
|
|
if ((value == 1 || value == 3) && id(alarm_raw)[${o} + 10] == 0) id(alarm_raw)[${o} + 10] = 10;
|
|
|
|
|
- script.execute: send_alarm_settings
|
|
|
|
|
|
|
|
|
|
- platform: template
|
|
|
|
|
id: alarm_${n}_sound
|
|
|
|
|
name: "Alarm ${n} Sound"
|
|
|
|
|
options:
|
|
|
|
|
- "Off"
|
2026-11-05 19:19:54 +01:00
|
|
|
- "Birds"
|
|
|
|
|
- "Beach"
|
|
|
|
|
- "Galaxy Twinkles"
|
|
|
|
|
- "Piano and Birds"
|
|
|
|
|
- "Happy Harp"
|
|
|
|
|
- "Mechanical Alarm Clock"
|
|
|
|
|
- "Digital Alarm Clock"
|
2026-11-05 12:27:54 +01:00
|
|
|
update_interval: 2s
|
|
|
|
|
web_server:
|
|
|
|
|
sorting_group_id: group_alarm_${n}
|
|
|
|
|
sorting_weight: 3
|
|
|
|
|
lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return {};
|
|
|
|
|
uint8_t s = id(alarm_raw)[${o} + 6];
|
2026-11-05 19:19:54 +01:00
|
|
|
static const char *const names[8] = {"Off", "Birds", "Beach", "Galaxy Twinkles", "Piano and Birds",
|
|
|
|
|
"Happy Harp", "Mechanical Alarm Clock", "Digital Alarm Clock"};
|
|
|
|
|
if (s > 7) return {};
|
|
|
|
|
return std::string(names[s]);
|
2026-11-05 12:27:54 +01:00
|
|
|
set_action:
|
|
|
|
|
- lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return;
|
|
|
|
|
uint8_t value = 0;
|
2026-11-05 19:19:54 +01:00
|
|
|
if (x == "Birds") value = 1;
|
|
|
|
|
else if (x == "Beach") value = 2;
|
|
|
|
|
else if (x == "Galaxy Twinkles") value = 3;
|
|
|
|
|
else if (x == "Piano and Birds") value = 4;
|
|
|
|
|
else if (x == "Happy Harp") value = 5;
|
|
|
|
|
else if (x == "Mechanical Alarm Clock") value = 6;
|
|
|
|
|
else if (x == "Digital Alarm Clock") value = 7;
|
2026-11-05 12:27:54 +01:00
|
|
|
id(alarm_raw)[${o} + 6] = value;
|
|
|
|
|
- script.execute: send_alarm_settings
|
|
|
|
|
|
|
|
|
|
number:
|
|
|
|
|
- platform: template
|
|
|
|
|
id: alarm_${n}_volume
|
|
|
|
|
name: "Alarm ${n} Volume"
|
|
|
|
|
min_value: 1
|
|
|
|
|
max_value: 16
|
|
|
|
|
step: 1
|
|
|
|
|
update_interval: 2s
|
|
|
|
|
web_server:
|
|
|
|
|
sorting_group_id: group_alarm_${n}
|
|
|
|
|
sorting_weight: 4
|
|
|
|
|
lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return {};
|
|
|
|
|
return static_cast<float>(id(alarm_raw)[${o} + 7]);
|
|
|
|
|
set_action:
|
|
|
|
|
- lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return;
|
|
|
|
|
id(alarm_raw)[${o} + 7] = static_cast<uint8_t>(x);
|
|
|
|
|
- script.execute: send_alarm_settings
|
|
|
|
|
|
|
|
|
|
- platform: template
|
|
|
|
|
id: alarm_${n}_wake_brightness
|
|
|
|
|
name: "Alarm ${n} Wake Light"
|
2026-11-05 17:38:23 +01:00
|
|
|
# Reads 0 in modes without light, where the MCU ignores changes.
|
|
|
|
|
min_value: 0
|
2026-11-05 12:27:54 +01:00
|
|
|
max_value: 20
|
|
|
|
|
step: 1
|
|
|
|
|
update_interval: 2s
|
|
|
|
|
web_server:
|
|
|
|
|
sorting_group_id: group_alarm_${n}
|
|
|
|
|
sorting_weight: 5
|
|
|
|
|
lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return {};
|
|
|
|
|
return static_cast<float>(id(alarm_raw)[${o} + 10]);
|
|
|
|
|
set_action:
|
|
|
|
|
- lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return;
|
|
|
|
|
id(alarm_raw)[${o} + 10] = static_cast<uint8_t>(x);
|
|
|
|
|
- script.execute: send_alarm_settings
|
|
|
|
|
|
|
|
|
|
# Tuya's definition says 10-20, default 15, but this lamp reports 30.
|
|
|
|
|
- platform: template
|
|
|
|
|
id: alarm_${n}_ring_duration
|
|
|
|
|
name: "Alarm ${n} Ring Duration"
|
|
|
|
|
unit_of_measurement: "min"
|
|
|
|
|
min_value: 10
|
|
|
|
|
max_value: 60
|
|
|
|
|
step: 5
|
|
|
|
|
update_interval: 2s
|
|
|
|
|
web_server:
|
|
|
|
|
sorting_group_id: group_alarm_${n}
|
|
|
|
|
sorting_weight: 8
|
|
|
|
|
lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return {};
|
|
|
|
|
return static_cast<float>(id(alarm_raw)[${o} + 4]);
|
|
|
|
|
set_action:
|
|
|
|
|
- lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return;
|
|
|
|
|
id(alarm_raw)[${o} + 4] = static_cast<uint8_t>(x);
|
|
|
|
|
- script.execute: send_alarm_settings
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- platform: template
|
|
|
|
|
id: alarm_${n}_sunrise_duration
|
|
|
|
|
name: "Alarm ${n} Sunrise Duration"
|
|
|
|
|
unit_of_measurement: "min"
|
|
|
|
|
min_value: 10
|
|
|
|
|
max_value: 60
|
|
|
|
|
step: 10
|
|
|
|
|
update_interval: 2s
|
|
|
|
|
web_server:
|
|
|
|
|
sorting_group_id: group_alarm_${n}
|
|
|
|
|
sorting_weight: 6
|
|
|
|
|
lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return {};
|
|
|
|
|
return static_cast<float>(id(alarm_raw)[${o} + 9]);
|
|
|
|
|
set_action:
|
|
|
|
|
- lambda: |-
|
|
|
|
|
if (!id(alarm_raw_valid)) return;
|
|
|
|
|
id(alarm_raw)[${o} + 9] = static_cast<uint8_t>(x);
|
|
|
|
|
- script.execute: send_alarm_settings
|
|
|
|
|
|
|
|
|
|
text_sensor:
|
|
|
|
|
- platform: template
|
|
|
|
|
id: alarm_${n}_summary
|
|
|
|
|
name: "Alarm ${n} Summary"
|
|
|
|
|
update_interval: never
|
|
|
|
|
web_server:
|
|
|
|
|
sorting_group_id: group_alarm_${n}
|
|
|
|
|
sorting_weight: 7
|