-
Notifications
You must be signed in to change notification settings - Fork 72
Expand file tree
/
Copy pathathom-rgbcw-light.yaml
More file actions
964 lines (894 loc) · 31 KB
/
Copy pathathom-rgbcw-light.yaml
File metadata and controls
964 lines (894 loc) · 31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
substitutions:
# Default name
name: "athom-rgbcw-bulb"
# Default friendly name
friendly_name: "Athom RGBCW Bulb"
# Allows ESP device to be automatically linked to an 'Area' in Home Assistant. Typically used for areas such as 'Lounge Room', 'Kitchen' etc
room: ""
# Description as appears in ESPHome & top of webserver page
device_description: "athom esp32c3 12w rgbcw bulb"
# Project Name
project_name: "China Athom Technology.Athom 12W RGBCW Bulb"
# Projection version denotes the release version of the yaml file, allowing checking of deployed vs latest version
project_version: "v3.1.7"
# Restore the light (GPO switch) upon reboot to state:
light_restore_mode: RESTORE_DEFAULT_ON
# Define a domain for this device to use. i.e. iot.home.lan (so device will appear as athom-smart-plug-v2.iot.home.lan in DNS/DHCP logs)
dns_domain: ".local"
# Set timezone of the smart plug. Useful if the plug is in a location different to the HA server. Can be entered in unix Country/Area format (i.e. "Australia/Sydney")
timezone: ""
# Set the duration between the sntp service polling ntp.org servers for an update
sntp_update_interval: 6h
# Network time servers for your region, enter from lowest to highest priority. To use local servers update as per zones or countries at: https://www.ntppool.org/zone/@
sntp_server_1: "0.pool.ntp.org"
sntp_server_2: "1.pool.ntp.org"
sntp_server_3: "2.pool.ntp.org"
# Enables faster network connections, with last connected SSID being connected to and no full scan for SSID being undertaken
wifi_fast_connect: "false"
# Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE
log_level: "DEBUG"
# Enable or disable the use of IPv6 networking on the device
ipv6_enable: "false"
color_interlock: "true"
globals:
- id: fast_boot
type: int
restore_value: yes
initial_value: '0'
- id: restore_mode
type: int
restore_value: yes
initial_value: "1"
- id: remote_mac
type: std::array<uint8_t, 6>
restore_value: yes
initial_value: "std::array<uint8_t, 6>{0, 0, 0, 0, 0, 0}"
- id: remote_paired
type: bool
restore_value: yes
initial_value: "false"
- id: remote_last_seq
type: uint32_t
restore_value: no
initial_value: "0xFFFFFFFF"
- id: remote_button
type: uint8_t
restore_value: no
initial_value: "0"
- id: remote_pairing
type: bool
restore_value: no
initial_value: "false"
- id: remote_pair_deadline
type: uint32_t
restore_value: no
initial_value: "0"
- id: bluetooth_proxy_enabled
type: bool
restore_value: yes
initial_value: "false"
- id: espnow_enabled
type: bool
restore_value: yes
initial_value: "true"
select:
- platform: template
name: "Power On State"
id: "power_mode"
optimistic: true
options:
- Always Off
- Always On
- Restore Power Off State
on_value:
then:
- lambda: |-
id(restore_mode)=i+1;
esphome:
name: "${name}"
friendly_name: "${friendly_name}"
comment: "${device_description}"
area: "${room}"
name_add_mac_suffix: true
min_version: 2026.6.0
project:
name: "${project_name}"
version: "${project_version}"
platformio_options:
board_build.flash_mode: dio
on_boot:
- priority: 600
then:
- script.execute: fast_boot_script
- select.set_index:
id: power_mode
index: !lambda |-
return id(restore_mode)-1;
- lambda: |-
switch(id(restore_mode))
{
case 1:{
auto call = id(rgbww_light).turn_off();
call.perform();
break;
}
case 2:{
auto call = id(rgbww_light).turn_on();
call.set_color_mode(ColorMode::WHITE);
call.set_brightness(1.0);
call.perform();
break;
}
default:{
break;
}
}
- priority: -100
then:
- if:
condition:
lambda: 'return id(espnow_enabled);'
then:
# ESP-NOW is configured with enable_on_boot: false so that the saved
# switch state decides whether the stack comes up at all. enable()
# must run before any peer.add - add_peer() returns ESP_ERR_ESPNOW_NOT_INIT
# while the component is disabled.
- lambda: 'id(espnow_component)->enable();'
- if:
condition:
lambda: 'return id(remote_paired);'
then:
- espnow.peer.add:
id: espnow_component
address: !lambda |-
return id(remote_mac);
- lambda: |-
char mac[18];
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
id(remote_mac)[0], id(remote_mac)[1],
id(remote_mac)[2], id(remote_mac)[3],
id(remote_mac)[4], id(remote_mac)[5]);
id(remote_paired_text).publish_state(mac);
id(remote_pairing_status).publish_state("Paired");
else:
- lambda: |-
id(remote_paired_text).publish_state("None");
id(remote_pairing_status).publish_state("Idle");
else:
# ESP-NOW switched off: leave the stack down, but still surface the
# retained pairing so the user can see it is remembered.
- lambda: |-
if (id(remote_paired)) {
char mac[18];
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
id(remote_mac)[0], id(remote_mac)[1],
id(remote_mac)[2], id(remote_mac)[3],
id(remote_mac)[4], id(remote_mac)[5]);
id(remote_paired_text).publish_state(mac);
} else {
id(remote_paired_text).publish_state("None");
}
id(remote_pairing_status).publish_state("Disabled");
- if:
condition:
and:
- lambda: 'return id(bluetooth_proxy_enabled);'
- api.connected:
then:
- esp32_ble_tracker.start_scan:
continuous: true
else:
- esp32_ble_tracker.stop_scan:
esp32:
board: esp32-c3-devkitm-1
flash_size: 4MB
variant: ESP32C3
framework:
type: esp-idf
version: recommended
sdkconfig_options:
# @grigi found in testing that these options resulted in better responsiveness.
# BLE 4.2 is supported by ALL ESP32 boards that have bluetooth, the original and derivatives.
CONFIG_BT_BLE_42_FEATURES_SUPPORTED: y
# Also enable this on any derivative boards (S2, C3 etc) but not the original ESP32.
CONFIG_BT_BLE_50_FEATURES_SUPPORTED: y
# Extend the watchdog timeout, so the device reboots if the device appears locked up for over 10 seconds.
CONFIG_ESP_TASK_WDT_TIMEOUT_S: "10"
preferences:
flash_write_interval: 1min
api:
# reboot_timeout: 0s
# Only enable BLE tracking when wifi is up and api is connected
# Gives single-core ESP32-C3 devices time to manage wifi and authenticate with api
on_client_connected:
- if:
condition:
lambda: 'return id(bluetooth_proxy_enabled);'
then:
- esp32_ble_tracker.start_scan:
continuous: true
# Disable BLE tracking when there are no api connections live
on_client_disconnected:
if:
condition:
not:
api.connected:
then:
- esp32_ble_tracker.stop_scan:
ota:
- platform: esphome
id: ota_esphome
# Enables OTA firmware flashing from a URL (used by the update component below)
- platform: http_request
id: ota_http_request
# Required by the ota http_request platform and the update component.
# verify_ssl: false skips TLS cert validation to reduce heap/RAM pressure during
# the download; the manifest's MD5 still verifies firmware integrity before flashing.
http_request:
id: http_request_component
verify_ssl: false
update:
# Managed updates via HTTP request: periodically checks the published manifest
# and exposes a "Firmware Update" entity, pointing at this device's GitHub Pages
# manifest. Pages URLs avoid the redirect/buffer issues of Release download URLs.
- platform: http_request
id: update_http_request
name: "Firmware Update"
source: https://athom-tech.github.io/esp32-configs/firmware/athom-rgbcw-light.manifest.json
# update_interval defaults to 6h (how often it checks, not installs)
logger:
baud_rate: 0 # 0 Enables logging, but disables serial-port logging to free CPU and memory
level: ${log_level}
mdns:
disabled: false
web_server:
port: 80
network:
enable_ipv6: ${ipv6_enable}
wifi:
# This spawns an AP with the device name and mac address with no password.
ap: {}
# Allow rapid re-connection to previously connect WiFi SSID, skipping scan of all SSID
fast_connect: "${wifi_fast_connect}"
# Define dns domain / suffix to add to hostname
domain: "${dns_domain}"
captive_portal:
esp32_improv:
authorizer: none
espnow:
id: espnow_component
auto_add_peer: false
# Startup is driven by the "ESP-NOW" switch via the on_boot automation above,
# so the stack is never brought up only to be torn down again.
enable_on_boot: false
on_unknown_peer:
- lambda: |-
const char *const TAG = "espnow_remote";
const bool valid_espnow_packet = size == 13 && (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80);
if (!valid_espnow_packet) {
ESP_LOGD(TAG, "Ignoring unknown ESP-NOW packet from %s, size=%u",
format_mac_address_pretty(info.src_addr).c_str(), size);
return;
}
char src[18];
snprintf(src, sizeof(src), "%02X:%02X:%02X:%02X:%02X:%02X",
info.src_addr[0], info.src_addr[1], info.src_addr[2],
info.src_addr[3], info.src_addr[4], info.src_addr[5]);
id(remote_last_seen).publish_state(src);
id(remote_battery).publish_state(data[8]);
const bool is_saved_remote =
id(remote_paired) &&
memcmp(id(remote_mac).data(), info.src_addr, id(remote_mac).size()) == 0;
if (is_saved_remote) {
ESP_LOGI(TAG, "Restoring saved ESP-NOW remote peer %s", src);
return;
}
if (!id(remote_pairing)) {
ESP_LOGD(TAG, "Saw unpaired remote %s; press Pair ESP-NOW Remote to bind it", src);
return;
}
for (size_t i = 0; i < id(remote_mac).size(); i++) {
id(remote_mac)[i] = info.src_addr[i];
}
id(remote_paired) = true;
id(remote_pairing) = false;
id(remote_paired_text).publish_state(src);
id(remote_pairing_status).publish_state("Paired");
ESP_LOGI(TAG, "Paired ESP-NOW remote %s", src);
- if:
condition:
lambda: |-
const bool valid_espnow_packet = size == 13 && (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80);
return valid_espnow_packet && id(remote_paired) &&
memcmp(id(remote_mac).data(), info.src_addr, id(remote_mac).size()) == 0;
then:
- espnow.peer.add:
id: espnow_component
address: !lambda |-
return std::array<uint8_t, 6>{info.src_addr[0], info.src_addr[1], info.src_addr[2],
info.src_addr[3], info.src_addr[4], info.src_addr[5]};
on_receive:
- if:
condition:
lambda: |-
const char *const TAG = "espnow_remote";
const bool valid_espnow_packet = size == 13 && (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80);
if (!valid_espnow_packet) return false;
if (!id(remote_paired) ||
memcmp(id(remote_mac).data(), info.src_addr, id(remote_mac).size()) != 0) {
ESP_LOGD(TAG, "Ignoring ESP-NOW packet from unpaired sender %s",
format_mac_address_pretty(info.src_addr).c_str());
return false;
}
const uint32_t seq = uint32_t(data[1]) | (uint32_t(data[2]) << 8) |
(uint32_t(data[3]) << 16) | (uint32_t(data[4]) << 24);
const uint8_t button = data[6];
id(remote_battery).publish_state(data[8]);
if (seq == id(remote_last_seq)) return false;
id(remote_last_seq) = seq;
id(remote_button) = button;
ESP_LOGD(TAG, "ESP-NOW remote button=%u seq=%lu battery=%u",
unsigned(button), static_cast<unsigned long>(seq), unsigned(data[8]));
return true;
then:
- script.execute:
id: remote_handle_button
button: !lambda 'return id(remote_button);'
on_broadcast:
- if:
condition:
lambda: |-
const char *const TAG = "espnow_remote";
const bool valid_espnow_packet = size == 13 && (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80);
if (!valid_espnow_packet) return false;
if (!id(remote_paired) ||
memcmp(id(remote_mac).data(), info.src_addr, id(remote_mac).size()) != 0) {
ESP_LOGD(TAG, "Ignoring ESP-NOW packet from unpaired sender %s",
format_mac_address_pretty(info.src_addr).c_str());
return false;
}
const uint32_t seq = uint32_t(data[1]) | (uint32_t(data[2]) << 8) |
(uint32_t(data[3]) << 16) | (uint32_t(data[4]) << 24);
const uint8_t button = data[6];
id(remote_battery).publish_state(data[8]);
if (seq == id(remote_last_seq)) return false;
id(remote_last_seq) = seq;
id(remote_button) = button;
ESP_LOGD(TAG, "ESP-NOW remote button=%u seq=%lu battery=%u",
unsigned(button), static_cast<unsigned long>(seq), unsigned(data[8]));
return true;
then:
- script.execute:
id: remote_handle_button
button: !lambda 'return id(remote_button);'
esp32_ble_tracker:
scan_parameters:
# Don't auto start BLE scanning, we control it in the `api` block's automation.
continuous: false
active: true # send scan-request packets to gather more info, like device name for some devices.
interval: 320ms # default 320ms - how long to spend on each advert channel
window: 300ms # default 30ms - how long to actually "listen" in each interval. Reduce this if device is unstable.
# If the device cannot keep up or becomes unstable, reduce the "window" setting. This may be
# required if your device is controlling other sensors or doing PWM for lights etc.
bluetooth_proxy:
active: true
dashboard_import:
package_import_url: github://athom-tech/esp32-configs/athom-rgbcw-light.yaml
switch:
- platform: template
name: "Bluetooth Proxy"
id: bluetooth_proxy_switch
icon: mdi:bluetooth
entity_category: config
restore_mode: DISABLED
lambda: 'return id(bluetooth_proxy_enabled);'
turn_on_action:
- globals.set:
id: bluetooth_proxy_enabled
value: "true"
- if:
condition:
api.connected:
then:
- esp32_ble_tracker.start_scan:
continuous: true
- lambda: 'ESP_LOGI("bluetooth_proxy_switch", "Bluetooth proxy scanning enabled");'
turn_off_action:
- globals.set:
id: bluetooth_proxy_enabled
value: "false"
- esp32_ble_tracker.stop_scan:
- lambda: 'ESP_LOGI("bluetooth_proxy_switch", "Bluetooth proxy scanning disabled");'
- platform: template
name: "ESP-NOW"
id: espnow_switch
icon: mdi:remote
entity_category: config
restore_mode: DISABLED
lambda: 'return id(espnow_enabled);'
turn_on_action:
- globals.set:
id: espnow_enabled
value: "true"
# enable() first: add_peer() is rejected with ESP_ERR_ESPNOW_NOT_INIT while disabled.
- lambda: 'id(espnow_component)->enable();'
- if:
condition:
lambda: 'return id(remote_paired);'
then:
- espnow.peer.add:
id: espnow_component
address: !lambda |-
return id(remote_mac);
- lambda: 'id(remote_pairing_status).publish_state("Paired");'
else:
- lambda: 'id(remote_pairing_status).publish_state("Idle");'
- lambda: 'ESP_LOGI("espnow_remote", "ESP-NOW enabled");'
turn_off_action:
- globals.set:
id: espnow_enabled
value: "false"
# Close any open pairing window so it cannot fire once ESP-NOW comes back.
- lambda: 'id(remote_pairing) = false;'
# Drop the peer while the stack is still up (del_peer() is rejected once disabled).
# The pairing itself lives in remote_mac/remote_paired and is retained, so turning
# the switch back on re-adds the same remote without re-pairing.
- if:
condition:
lambda: 'return id(remote_paired);'
then:
- espnow.peer.delete:
id: espnow_component
address: !lambda |-
return id(remote_mac);
- lambda: |-
id(espnow_component)->disable();
id(remote_pairing_status).publish_state("Disabled");
ESP_LOGI("espnow_remote", "ESP-NOW disabled");
binary_sensor:
- platform: status
name: "Status"
entity_category: diagnostic
sensor:
- platform: uptime
name: "Uptime Sensor"
id: uptime_sensor
type:
timestamp
entity_category: "diagnostic"
- platform: wifi_signal
name: "WiFi Signal dB"
id: wifi_signal_db
update_interval: 60s
entity_category: "diagnostic"
- platform: copy
source_id: wifi_signal_db
name: "WiFi Signal Percent"
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "Signal %"
entity_category: "diagnostic"
device_class: ""
- platform: template
name: "ESP-NOW Remote Battery"
id: remote_battery
unit_of_measurement: "%"
accuracy_decimals: 0
update_interval: never
device_class: battery
entity_category: diagnostic
button:
- platform: restart
name: "Restart"
entity_category: config
- platform: factory_reset
name: "Factory Reset"
id: Reset
entity_category: config
- platform: safe_mode
name: "Safe Mode"
internal: false
entity_category: config
- platform: template
name: "Pair ESP-NOW Remote"
id: pair_espnow_remote
entity_category: config
on_press:
then:
- if:
condition:
lambda: 'return !id(espnow_enabled);'
then:
- lambda: |-
id(remote_pairing_status).publish_state("Disabled");
ESP_LOGW("espnow_remote", "ESP-NOW is disabled; turn on the ESP-NOW switch before pairing");
else:
- lambda: |-
id(remote_pairing) = true;
id(remote_pair_deadline) = millis() + 60000;
id(remote_pairing_status).publish_state("Pairing for 60 seconds");
ESP_LOGI("espnow_remote", "Pairing enabled for 60 seconds; press a ESP-NOW remote button");
- script.execute: remote_pairing_timeout
- platform: template
name: "Clear ESP-NOW Remote"
id: clear_espnow_remote
entity_category: config
on_press:
then:
- if:
condition:
lambda: 'return !id(espnow_enabled);'
then:
- lambda: |-
id(remote_pairing_status).publish_state("Disabled");
ESP_LOGW("espnow_remote", "ESP-NOW is disabled; turn on the ESP-NOW switch before clearing the remote");
else:
- if:
condition:
lambda: 'return id(remote_paired);'
then:
- espnow.peer.delete:
id: espnow_component
address: !lambda |-
return id(remote_mac);
- lambda: |-
id(remote_mac) = std::array<uint8_t, 6>{0, 0, 0, 0, 0, 0};
id(remote_paired) = false;
id(remote_pairing) = false;
id(remote_last_seq) = 0xFFFFFFFF;
id(remote_paired_text).publish_state("None");
id(remote_pairing_status).publish_state("Idle");
ESP_LOGI("espnow_remote", "Cleared paired ESP-NOW remote");
output:
- platform: ledc
id: red_output
frequency: 9765
pin: GPIO6
min_power: 0
max_power: 1
- platform: ledc
id: green_output
frequency: 9765
pin: GPIO7
min_power: 0
max_power: 1
- platform: ledc
id: blue_output
frequency: 9765
pin: GPIO5
min_power: 0
max_power: 1
- platform: ledc
id: white_output
frequency: 9765
pin: GPIO3
min_power: 0
max_power: 0.95
- platform: ledc
id: warm_white_output
frequency: 9765
pin: GPIO4
min_power: 0
max_power: 0.95
light:
- platform: rgbww
id: rgbww_light
name: "RGBCW_Bulb"
restore_mode: ${light_restore_mode}
red: red_output
green: green_output
blue: blue_output
cold_white: white_output
warm_white: warm_white_output
cold_white_color_temperature: 6500 K
warm_white_color_temperature: 3000 K
color_interlock: ${color_interlock}
constant_brightness: True
text_sensor:
- platform: wifi_info
ip_address:
name: "IP Address"
id: ip_address
entity_category: diagnostic
ssid:
name: "Connected SSID"
id: ssid
entity_category: diagnostic
mac_address:
name: "Mac Address"
id: mac_address
entity_category: diagnostic
- platform: template
name: "Last Restart"
id: device_last_restart
icon: mdi:clock
entity_category: diagnostic
device_class: timestamp
- platform: template
name: "Paired ESP-NOW Remote"
id: remote_paired_text
icon: mdi:remote
update_interval: never
entity_category: diagnostic
- platform: template
name: "Last ESP-NOW Remote"
id: remote_last_seen
icon: mdi:remote
update_interval: never
entity_category: diagnostic
- platform: template
name: "ESP-NOW Pairing Status"
id: remote_pairing_status
icon: mdi:wifi
update_interval: never
entity_category: diagnostic
time:
- platform: sntp
id: sntp_time
# Define the timezone of the device
timezone: "${timezone}"
# Change sync interval from default 5min to 6 hours (or as set in substitutions)
update_interval: ${sntp_update_interval}
# Set specific sntp servers to use
servers:
- "${sntp_server_1}"
- "${sntp_server_2}"
- "${sntp_server_3}"
# Publish the time the device was last restarted
on_time_sync:
then:
# Update last restart time, but only once.
- if:
condition:
lambda: 'return id(device_last_restart).state == "";'
then:
- text_sensor.template.publish:
id: device_last_restart
state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");'
script:
- id: remote_pairing_timeout
mode: restart
then:
- delay: 60s
- lambda: |-
if (id(remote_pairing) && int32_t(millis() - id(remote_pair_deadline)) >= 0) {
id(remote_pairing) = false;
id(remote_pairing_status).publish_state("Idle");
ESP_LOGI("espnow_remote", "ESP-NOW remote pairing window expired");
}
- id: remote_handle_button
mode: queued
max_runs: 4
parameters:
button: uint8_t
then:
- if:
condition:
lambda: 'return button == 1 || button == 100;' #ON
then:
- script.execute: remote_on
- if:
condition:
lambda: 'return button == 2 || button == 101;' #OFF
then:
- script.execute: remote_off
- if:
condition:
lambda: 'return button == 3;' #Night
then:
- script.execute:
id: remote_set_cwww
cold_white: 0.0
warm_white: 1.0
brightness: 0.2
- if:
condition:
lambda: 'return button == 8 || button == 103;' #Brightness -
then:
- script.execute:
id: remote_brightness_step
increase: false
- if:
condition:
lambda: 'return button == 9 || button == 102;' #Brightness +
then:
- script.execute:
id: remote_brightness_step
increase: true
- if:
condition:
lambda: 'return button == 16;' #P1
then:
- script.execute:
id: remote_set_cwww
cold_white: 0.0
warm_white: 1.0
brightness: 1.0
- if:
condition:
lambda: 'return button == 17;' #P2
then:
- script.execute:
id: remote_set_cwww
cold_white: 1.0
warm_white: 0.0
brightness: 1.0
- if:
condition:
lambda: 'return button == 18;' #P3
then:
- script.execute:
id: remote_set_rgb
red: 1.0
green: 0.0
blue: 0.0
brightness: 1.0
- if:
condition:
lambda: 'return button == 19;' #P4
then:
- script.execute:
id: remote_set_rgb
red: 0.0
green: 1.0
blue: 0.0
brightness: 1.0
- if:
condition:
lambda: 'return button == 20;' #P5
then:
- script.execute:
id: remote_set_rgb
red: 0.0
green: 0.0
blue: 1.0
brightness: 1.0
- if:
condition:
lambda: 'return button == 21;' #P6
then:
- script.execute:
id: remote_set_rgb
red: 0.65
green: 0.0
blue: 1.0
brightness: 0.85
- if:
condition:
lambda: 'return button == 22;' #P7
then:
- script.execute:
id: remote_set_cwww
cold_white: 0.35
warm_white: 0.65
brightness: 0.65
- if:
condition:
lambda: |-
switch (button) {
case 1:
case 2:
case 3:
case 8:
case 9:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 100:
case 101:
case 102:
case 103:
return false;
default:
return true;
}
then:
- lambda: 'ESP_LOGD("espnow_remote", "Unhandled ESP-NOW remote button %u", unsigned(button));'
- id: remote_on
mode: restart
then:
- lambda: |-
auto call = id(rgbww_light).turn_on();
call.set_transition_length(700);
call.perform();
- id: remote_off
mode: restart
then:
- lambda: |-
auto call = id(rgbww_light).turn_off();
call.set_transition_length(700);
call.perform();
- id: remote_set_rgb
mode: restart
parameters:
red: float
green: float
blue: float
brightness: float
then:
- lambda: |-
auto call = id(rgbww_light).turn_on();
call.set_transition_length(700);
call.set_color_mode_if_supported(ColorMode::RGB);
call.set_brightness(brightness);
call.set_rgb(red, green, blue);
call.perform();
- id: remote_set_cwww
mode: restart
parameters:
cold_white: float
warm_white: float
brightness: float
then:
- lambda: |-
auto call = id(rgbww_light).turn_on();
call.set_transition_length(700);
call.set_color_mode_if_supported(ColorMode::COLD_WARM_WHITE);
call.set_brightness(brightness);
call.set_cold_white(cold_white);
call.set_warm_white(warm_white);
call.perform();
- id: remote_brightness_step
mode: restart
parameters:
increase: bool
then:
- lambda: |-
static const uint8_t steps[] = {6, 9, 14, 22, 33, 50, 75, 113, 170, 255};
if (!id(rgbww_light).current_values.is_on() && !increase) return;
uint8_t current = uint8_t(id(rgbww_light).current_values.get_brightness() * 255.0f + 0.5f);
uint8_t target = steps[0];
if (increase) {
target = steps[sizeof(steps) / sizeof(steps[0]) - 1];
for (uint8_t step : steps) {
if (step > current) {
target = step;
break;
}
}
} else {
for (int i = int(sizeof(steps) / sizeof(steps[0])) - 1; i >= 0; i--) {
if (steps[i] < current) {
target = steps[i];
break;
}
}
}
auto call = id(rgbww_light).turn_on();
call.set_transition_length(120);
call.set_brightness(float(target) / 255.0f);
call.perform();
- id: fast_boot_script
then:
- if:
condition:
lambda: return ( id(fast_boot) >= 3 );
then:
- lambda: |-
ESP_LOGD("athom-rgbww-light.yaml", "Now the counter is greater than or equal to 3, perform reset device and reboot");
id(fast_boot) = 0;
fast_boot->loop();
global_preferences->sync();
auto call = id(rgbww_light).turn_on();
call.set_transition_length(500);
call.set_brightness(1.0);
call.set_color_mode(ColorMode::RGB);
call.set_rgb(0.0, 0.0, 1.0);
call.perform();
- delay: 5s
- button.press: Reset
- lambda: |-
id(fast_boot) += 1;
fast_boot->loop();
global_preferences->sync();
ESP_LOGD("athom-rgbww-light.yaml", "Now the counter is %d. Reset the device when the counter is greater than or equal to 3", id(fast_boot));
- delay: 10s
- lambda: |-
ESP_LOGD("athom-rgbww-light.yaml", "Reset counter");
id(fast_boot) = 0;
fast_boot->loop();
global_preferences->sync();