additional esphome devices and fixes
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 273 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 930 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 13 KiB |
@@ -1 +1 @@
|
|||||||
{"pid": 67, "version": 1, "ha_version": "2026.5.0", "start_ts": 1778146972.604623}
|
{"pid": 67, "version": 1, "ha_version": "2026.5.4", "start_ts": 1779529638.1563158}
|
||||||
@@ -1 +1,114 @@
|
|||||||
[]
|
- id: '1778927514490'
|
||||||
|
alias: NSPanel Easy Configuration (v2026.5.5)
|
||||||
|
description: ''
|
||||||
|
use_blueprint:
|
||||||
|
path: edwardtfn/nspanel_easy_blueprint.yaml
|
||||||
|
input:
|
||||||
|
nspanel_name: 369e58c3779ff3dd9a0b4c59fadeac4f
|
||||||
|
weather_entity: weather.astroweather_backyard
|
||||||
|
indoortemp: sensor.lounge_inside_temperature
|
||||||
|
- id: '1778927924212'
|
||||||
|
alias: NSPanel Easy Configuration (v2026.5.5)
|
||||||
|
description: ''
|
||||||
|
use_blueprint:
|
||||||
|
path: edwardtfn/nspanel_easy_blueprint.yaml
|
||||||
|
input:
|
||||||
|
nspanel_name: 369e58c3779ff3dd9a0b4c59fadeac4f
|
||||||
|
button_page01_label: Lounge Scenes
|
||||||
|
button_pages_icon_size: '8'
|
||||||
|
entity01: script.nspanel_lounge_scene_bright
|
||||||
|
entity01_name: Bright
|
||||||
|
entity01_icon: mdi:brightness-7
|
||||||
|
entity01_confirm: false
|
||||||
|
entity02: script.nspanel_lounge_scene_tv_general
|
||||||
|
entity02_name: TV General
|
||||||
|
entity02_icon: mdi:television
|
||||||
|
entity02_confirm: false
|
||||||
|
entity03: script.nspanel_lounge_scene_movie
|
||||||
|
entity03_name: Movie
|
||||||
|
entity03_icon: mdi:movie-open
|
||||||
|
entity03_confirm: false
|
||||||
|
entity04: script.nspanel_lounge_scene_balanced
|
||||||
|
entity04_name: Balanced
|
||||||
|
entity04_icon: mdi:scale-balance
|
||||||
|
entity04_confirm: false
|
||||||
|
entity05: script.nspanel_lounge_scene_warm_cozy
|
||||||
|
entity05_name: Warm Cozy
|
||||||
|
entity05_icon: mdi:fireplace
|
||||||
|
entity05_confirm: false
|
||||||
|
entity06: script.nspanel_lounge_scene_reading
|
||||||
|
entity06_name: Reading
|
||||||
|
entity06_icon: mdi:book-open-page-variant
|
||||||
|
entity06_confirm: false
|
||||||
|
entity07: script.nspanel_lounge_scene_dining
|
||||||
|
entity07_name: Dining
|
||||||
|
entity07_icon: mdi:silverware-fork-knife
|
||||||
|
entity07_confirm: false
|
||||||
|
entity08: script.nspanel_lounge_scene_all_off
|
||||||
|
entity08_name: All Off
|
||||||
|
entity08_icon: mdi:power
|
||||||
|
entity08_confirm: false
|
||||||
|
mode: single
|
||||||
|
- id: '1778929633433'
|
||||||
|
alias: NSPanel Easy Configuration (v2026.5.5)
|
||||||
|
description: ''
|
||||||
|
use_blueprint:
|
||||||
|
path: edwardtfn/nspanel_easy_blueprint.yaml
|
||||||
|
input:
|
||||||
|
nspanel_name: 369e58c3779ff3dd9a0b4c59fadeac4f
|
||||||
|
button_page01_label: Lounge Scenes
|
||||||
|
button_pages_icon_size: '8'
|
||||||
|
entity01: script.nspanel_lounge_scene_bright
|
||||||
|
entity01_name: Bright
|
||||||
|
entity01_icon: mdi:brightness-7
|
||||||
|
entity01_confirm: false
|
||||||
|
entity02: script.nspanel_lounge_scene_tv_general
|
||||||
|
entity02_name: TV General
|
||||||
|
entity02_icon: mdi:television
|
||||||
|
entity02_confirm: false
|
||||||
|
entity03: script.nspanel_lounge_scene_movie
|
||||||
|
entity03_name: Movie
|
||||||
|
entity03_icon: mdi:movie-open
|
||||||
|
entity03_confirm: false
|
||||||
|
entity04: script.nspanel_lounge_scene_balanced
|
||||||
|
entity04_name: Balanced
|
||||||
|
entity04_icon: mdi:scale-balance
|
||||||
|
entity04_confirm: false
|
||||||
|
entity05: script.nspanel_lounge_scene_warm_cozy
|
||||||
|
entity05_name: Warm Cozy
|
||||||
|
entity05_icon: mdi:fireplace
|
||||||
|
entity05_confirm: false
|
||||||
|
entity06: script.nspanel_lounge_scene_reading
|
||||||
|
entity06_name: Reading
|
||||||
|
entity06_icon: mdi:book-open-page-variant
|
||||||
|
entity06_confirm: false
|
||||||
|
entity07: script.nspanel_lounge_scene_dining
|
||||||
|
entity07_name: Dining
|
||||||
|
entity07_icon: mdi:silverware-fork-knife
|
||||||
|
entity07_confirm: false
|
||||||
|
entity08: script.nspanel_lounge_scene_all_off
|
||||||
|
entity08_name: All Off
|
||||||
|
entity08_icon: mdi:power
|
||||||
|
entity08_confirm: false
|
||||||
|
mode: single
|
||||||
|
- id: '1778930023427'
|
||||||
|
alias: NSPanel Lounge Controller
|
||||||
|
description: ''
|
||||||
|
use_blueprint:
|
||||||
|
path: edwardtfn/nspanel_easy_blueprint.yaml
|
||||||
|
input:
|
||||||
|
nspanel_name: 369e58c3779ff3dd9a0b4c59fadeac4f
|
||||||
|
- id: '1778930202677'
|
||||||
|
alias: NSPanel Lounge Controller
|
||||||
|
description: ''
|
||||||
|
use_blueprint:
|
||||||
|
path: edwardtfn/nspanel_easy_blueprint.yaml
|
||||||
|
input:
|
||||||
|
nspanel_name: 369e58c3779ff3dd9a0b4c59fadeac4f
|
||||||
|
- id: '1778930948144'
|
||||||
|
alias: Lounge NSPanel Controls
|
||||||
|
description: ''
|
||||||
|
use_blueprint:
|
||||||
|
path: edwardtfn/nspanel_easy_blueprint.yaml
|
||||||
|
input:
|
||||||
|
nspanel_name: 369e58c3779ff3dd9a0b4c59fadeac4f
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
- id: quiet_time_settings_to_mqtt
|
|
||||||
alias: Publish quiet time value to mqtt
|
|
||||||
trigger:
|
|
||||||
platform: state
|
|
||||||
entity_id: input_boolean.quiet_time
|
|
||||||
action:
|
|
||||||
service: mqtt.publish
|
|
||||||
data_template:
|
|
||||||
payload: "{{trigger.to_state.state}}"
|
|
||||||
topic: viewroad-status/homeassistant/quiet-time
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
х(vтOьш╚3Вяm0л
|
||||||
@@ -0,0 +1,732 @@
|
|||||||
|
{
|
||||||
|
"esp-entbtproxy.yaml": {
|
||||||
|
"board_id": "generic-esp32",
|
||||||
|
"mac_address": "0C:B8:15:F5:2A:CC"
|
||||||
|
},
|
||||||
|
"esp-spare1-athomv1.yaml": {
|
||||||
|
"board_id": "esp8285"
|
||||||
|
},
|
||||||
|
"esp-centralstairs-top.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "48:3F:DA:16:51:20"
|
||||||
|
},
|
||||||
|
"esp-officeelvcontrol.yaml": {
|
||||||
|
"board_id": "d1-mini",
|
||||||
|
"mac_address": "5C:CF:7F:BD:7B:42"
|
||||||
|
},
|
||||||
|
"esp-gasheater.yaml": {
|
||||||
|
"board_id": "generic-esp8266"
|
||||||
|
},
|
||||||
|
"esp-bedrm1arlecbulb.yaml": {
|
||||||
|
"board_id": "generic-esp8266"
|
||||||
|
},
|
||||||
|
"esp-maindishwasherpower.yaml": {
|
||||||
|
"board_id": "generic-esp32c3",
|
||||||
|
"mac_address": "24:EC:4A:B0:C9:AC"
|
||||||
|
},
|
||||||
|
"esp-downstbathtowelrail.yaml": {
|
||||||
|
"board_id": "d1-mini"
|
||||||
|
},
|
||||||
|
"esp-bedrm2fanswitch.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "24:62:AB:05:A3:24"
|
||||||
|
},
|
||||||
|
"esp-downstmasterbedrmlights.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "E8:DB:84:92:DE:1C"
|
||||||
|
},
|
||||||
|
"esp-loungenorthswitch.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "EC:FA:BC:5C:4C:8B"
|
||||||
|
},
|
||||||
|
"esp-garagelights.yaml": {
|
||||||
|
"board_id": "d1-mini",
|
||||||
|
"mac_address": "5C:CF:7F:3B:C1:97"
|
||||||
|
},
|
||||||
|
"esp-underhouselights.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "60:01:94:84:70:87"
|
||||||
|
},
|
||||||
|
"esp-mainbathfancombo.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "8C:AA:B5:E0:7D:19"
|
||||||
|
},
|
||||||
|
"esp-entranceoutsideledlights.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "60:01:94:6F:91:75"
|
||||||
|
},
|
||||||
|
"esp-centralstairs-bottom.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "48:3F:DA:16:86:A8"
|
||||||
|
},
|
||||||
|
"esp-arcademachine1.yaml": {
|
||||||
|
"board_id": "esp8285",
|
||||||
|
"mac_address": "10:52:1C:FF:D9:8E"
|
||||||
|
},
|
||||||
|
"esp-officedeskrightgpo.yaml": {
|
||||||
|
"board_id": "d1-mini",
|
||||||
|
"mac_address": "2C:3A:E8:0F:4E:0E"
|
||||||
|
},
|
||||||
|
"esp-mainhallwaymainlights.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "50:02:91:43:0B:7C"
|
||||||
|
},
|
||||||
|
"esp-downstbedrm2lights.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "50:02:91:43:0C:40"
|
||||||
|
},
|
||||||
|
"esp-mainhallwaynorthlightswitch.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "CC:50:E3:EE:5E:45"
|
||||||
|
},
|
||||||
|
"esp-garageextcornerlight.yaml": {
|
||||||
|
"board_id": "d1-mini",
|
||||||
|
"mac_address": "2C:3A:E8:0F:54:90"
|
||||||
|
},
|
||||||
|
"esp-downstairsdishwasher.yaml": {
|
||||||
|
"board_id": "esp8285",
|
||||||
|
"mac_address": "78:42:1C:F2:4E:AD"
|
||||||
|
},
|
||||||
|
"esp-entrancebathrmlights.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "8C:AA:B5:E0:A1:2E"
|
||||||
|
},
|
||||||
|
"esp-bedrm2lights.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "DC:4F:22:72:0E:C1"
|
||||||
|
},
|
||||||
|
"esp-weatherstation.yaml": {
|
||||||
|
"board_id": "d1-mini"
|
||||||
|
},
|
||||||
|
"esp-garagedbcontrols.yaml": {
|
||||||
|
"board_id": "esp8285",
|
||||||
|
"mac_address": "60:01:94:88:DD:AA"
|
||||||
|
},
|
||||||
|
"esp-datacupboardfans.yaml": {
|
||||||
|
"board_id": "aspen_asp_200_smart_window_fan",
|
||||||
|
"mac_address": "50:02:91:5F:D6:A7"
|
||||||
|
},
|
||||||
|
"esp-mainkitchenlights.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "8C:AA:B5:DF:B7:DE"
|
||||||
|
},
|
||||||
|
"esp-loungepelmetleds2.yaml": {
|
||||||
|
"board_id": "generic-esp8266"
|
||||||
|
},
|
||||||
|
"esp-entmulti.yaml": {
|
||||||
|
"board_id": "generic-esp32",
|
||||||
|
"mac_address": "E4:65:B8:77:76:EC"
|
||||||
|
},
|
||||||
|
"esp-occupancystair.yaml": {
|
||||||
|
"board_id": "generic-esp32",
|
||||||
|
"mac_address": "0C:B8:15:C1:F1:0C"
|
||||||
|
},
|
||||||
|
"esp-datacupboardpower-left.yaml": {
|
||||||
|
"board_id": "esp8285",
|
||||||
|
"mac_address": "78:42:1C:F2:70:20"
|
||||||
|
},
|
||||||
|
"esp-officelights.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "EC:FA:BC:48:9E:A6"
|
||||||
|
},
|
||||||
|
"esp-mainbathroomlights.yaml": {
|
||||||
|
"board_id": "generic-bk7231n-qfn32-tuya",
|
||||||
|
"mac_address": "CC:8C:BF:2D:B1:C4"
|
||||||
|
},
|
||||||
|
"esp-loungesouthrightswitch.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "84:CC:A8:8C:52:32"
|
||||||
|
},
|
||||||
|
"esp-bedrm3ceilingfan.yaml": {
|
||||||
|
"board_id": "d1-mini"
|
||||||
|
},
|
||||||
|
"esp-laundryplugpow.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "2C:3A:E8:07:5C:88"
|
||||||
|
},
|
||||||
|
"esp-mainhallwaynightlights.yaml": {
|
||||||
|
"board_id": "generic-bk7231n-qfn32-tuya",
|
||||||
|
"mac_address": "50:8A:06:67:3E:4A"
|
||||||
|
},
|
||||||
|
"esp-datacupboardpower-right.yaml": {
|
||||||
|
"board_id": "esp8285",
|
||||||
|
"mac_address": "78:42:1C:F2:6F:8B"
|
||||||
|
},
|
||||||
|
"esp-poolpumppower.yaml": {
|
||||||
|
"board_id": "generic-esp32c3",
|
||||||
|
"mac_address": "24:EC:4A:B0:C9:88"
|
||||||
|
},
|
||||||
|
"esp-laundrydrypow.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "5C:CF:7F:92:35:96"
|
||||||
|
},
|
||||||
|
"esp-loungecabinetleds.yaml": {
|
||||||
|
"board_id": "generic-esp8266"
|
||||||
|
},
|
||||||
|
"esp-6buttontest-pmb.yaml": {
|
||||||
|
"board_id": "generic-esp32"
|
||||||
|
},
|
||||||
|
"esp-bedrm3lights.yaml": {
|
||||||
|
"board_id": "generic-esp8266"
|
||||||
|
},
|
||||||
|
"esp-laundrywashpow.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "5C:CF:7F:B4:A7:A5"
|
||||||
|
},
|
||||||
|
"esp-breakfastbarleds.yaml": {
|
||||||
|
"board_id": "generic-esp8266"
|
||||||
|
},
|
||||||
|
"esp-laundryenv.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "5C:CF:7F:92:41:F5"
|
||||||
|
},
|
||||||
|
"esp-occupancyoffice.yaml": {
|
||||||
|
"board_id": "generic-esp32",
|
||||||
|
"mac_address": "0C:B8:15:C0:E7:00"
|
||||||
|
},
|
||||||
|
"esp-flysprayer1.yaml": {
|
||||||
|
"board_id": "esp8285",
|
||||||
|
"mac_address": "2C:F4:32:E5:22:5D"
|
||||||
|
},
|
||||||
|
"esp-3dprinterpow.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "5C:CF:7F:A0:36:73"
|
||||||
|
},
|
||||||
|
"esp-rocktumbler.yaml": {
|
||||||
|
"board_id": "esp8285",
|
||||||
|
"mac_address": "78:42:1C:F2:5A:E7"
|
||||||
|
},
|
||||||
|
"esp-rgblampbulb1.yaml": {
|
||||||
|
"board_id": "generic-esp8266"
|
||||||
|
},
|
||||||
|
"esp-downstloungeentry.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "50:02:91:43:0D:A3"
|
||||||
|
},
|
||||||
|
"esp-downstloungeoutside.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "24:62:AB:05:9B:7A"
|
||||||
|
},
|
||||||
|
"esp-masterbathtowelrail.yaml": {
|
||||||
|
"board_id": "d1-mini"
|
||||||
|
},
|
||||||
|
"esp-loungeenvironment.yaml": {
|
||||||
|
"board_id": "generic-esp32c3",
|
||||||
|
"mac_address": "8C:D0:B2:A9:72:E5"
|
||||||
|
},
|
||||||
|
"esp-loungewestswitch.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "EC:FA:BC:5C:4C:03"
|
||||||
|
},
|
||||||
|
"esp-lounge6chdimmer.yaml": {
|
||||||
|
"board_id": "d1-mini-pro",
|
||||||
|
"mac_address": "C8:C9:A3:3B:0B:59"
|
||||||
|
},
|
||||||
|
"esp-downstbathswitch.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "84:CC:A8:8B:44:9D"
|
||||||
|
},
|
||||||
|
"esp-loungemiddleswitch.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "24:62:AB:05:A2:BE"
|
||||||
|
},
|
||||||
|
"esp-officeusbhubpower.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "2C:3A:E8:0F:53:52"
|
||||||
|
},
|
||||||
|
"esp-leafbattery.yaml": {
|
||||||
|
"board_id": "d1-mini"
|
||||||
|
},
|
||||||
|
"esp-garagebtproxy.yaml": {
|
||||||
|
"board_id": "generic-esp32",
|
||||||
|
"mac_address": "10:06:1C:86:D0:1C"
|
||||||
|
},
|
||||||
|
"esp-bedrm1airfilter.yaml": {
|
||||||
|
"board_id": "d1-mini",
|
||||||
|
"mac_address": "E8:9F:6D:87:C1:5D"
|
||||||
|
},
|
||||||
|
"esp-downstkitchlights.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "24:62:AB:05:A8:90"
|
||||||
|
},
|
||||||
|
"esp-garageentrylights.yaml": {
|
||||||
|
"board_id": "generic-bk7231n-qfn32-tuya"
|
||||||
|
},
|
||||||
|
"esp-mainpowermonitor.yaml": {
|
||||||
|
"board_id": "d1-mini",
|
||||||
|
"mac_address": "2C:F4:32:4B:BC:70"
|
||||||
|
},
|
||||||
|
"esp-loungebookshelfleds.yaml": {
|
||||||
|
"board_id": "generic-esp8266"
|
||||||
|
},
|
||||||
|
"esp-officeduallights.yaml": {
|
||||||
|
"board_id": "generic-esp8266"
|
||||||
|
},
|
||||||
|
"esp-poollightpower2.yaml": {
|
||||||
|
"board_id": "esp8285",
|
||||||
|
"mac_address": "78:42:1C:F2:50:87"
|
||||||
|
},
|
||||||
|
"esp-laundrylights.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "E8:DB:84:92:D8:44"
|
||||||
|
},
|
||||||
|
"esp-downstloungemain.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "24:62:AB:05:A2:C3"
|
||||||
|
},
|
||||||
|
"esp-loungesouthleftswitch.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "8C:AA:B5:DF:F5:ED"
|
||||||
|
},
|
||||||
|
"esp-attobattery.yaml": {
|
||||||
|
"board_id": "d1-mini"
|
||||||
|
},
|
||||||
|
"esp-downstairskitchleds.yaml": {
|
||||||
|
"board_id": "generic-esp8266"
|
||||||
|
},
|
||||||
|
"esp-entrancelightswitch.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "40:F5:20:E0:44:DA"
|
||||||
|
},
|
||||||
|
"esp-bedrm3fanswitch.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "84:F3:EB:EC:6E:3A"
|
||||||
|
},
|
||||||
|
"esp-bedrm2ceilingfan.yaml": {
|
||||||
|
"board_id": "d1-mini"
|
||||||
|
},
|
||||||
|
"_remote_build": {
|
||||||
|
"dashboard_id": "vhamVDnWEnx-FvAa24uVv49Wsddurh84"
|
||||||
|
},
|
||||||
|
"esp-entbtproxy copy.yaml": {
|
||||||
|
"board_id": "generic-esp32"
|
||||||
|
},
|
||||||
|
"esp-nspanel2lounge.yaml": {
|
||||||
|
"board_id": "generic-esp32",
|
||||||
|
"mac_address": "88:13:BF:68:39:2C"
|
||||||
|
},
|
||||||
|
"_firmware_jobs": [
|
||||||
|
{
|
||||||
|
"job_id": "126762467ae7",
|
||||||
|
"configuration": "esp-nspanel1masterbdrm.yaml",
|
||||||
|
"job_type": "install",
|
||||||
|
"status": "completed",
|
||||||
|
"created_at": "2026-05-17T10:36:36.272476+00:00",
|
||||||
|
"started_at": "2026-05-17T10:36:36.272693+00:00",
|
||||||
|
"completed_at": "2026-05-17T10:37:14.499200+00:00",
|
||||||
|
"exit_code": 0,
|
||||||
|
"output": [
|
||||||
|
"\\033[32mINFO ESPHome 2026.5.0b1\\033[0m\n",
|
||||||
|
"\\033[32mINFO Reading configuration /config/esphome/esp-nspanel1masterbdrm.yaml...\\033[0m\n",
|
||||||
|
"\\033[32mINFO Detected timezone 'Pacific/Auckland'\\033[0m\n",
|
||||||
|
"\\033[33mWARNING Found and merged multiple configurations for ota platform esphome port(s) [3232]\\033[0m\n",
|
||||||
|
"\\033[32mINFO Generating C++ source...\\033[0m\n",
|
||||||
|
"\\033[32mINFO Setting CONFIG_LWIP_MAX_SOCKETS to 13 (TCP=6 [api=3, captive_portal=3], UDP=3 [captive_portal=1, mdns=2], TCP_LISTEN=4 [api=1, ota=2, web_server_base=1])\\033[0m\n",
|
||||||
|
"\\033[32mINFO Compiling app... Build path: /data/build/esp-nspanel1masterbdrm\\033[0m\n",
|
||||||
|
"Processing \u001b[36m\u001b[1mesp-nspanel1masterbdrm\u001b[0m (board: esp32dev; framework: espidf; platform: https://github.com/pioarduino/platform-espressif32/releases/download/55.03.38-1/platform-espressif32.zip)\n",
|
||||||
|
"\u001b[1m--------------------------------------------------------------------------------\u001b[0m\n",
|
||||||
|
"\u001b[0mHARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash\n",
|
||||||
|
"\u001b[0m - contrib-piohome @ 3.4.4 \n",
|
||||||
|
"\u001b[0m - framework-espidf @ 3.50504.0 (5.5.4) \n",
|
||||||
|
"\u001b[0m - tool-cmake @ 4.0.3 \n",
|
||||||
|
"\u001b[0m - tool-esp-rom-elfs @ 2024.10.11 \n",
|
||||||
|
"\u001b[0m - tool-esptoolpy @ 5.2.0 \n",
|
||||||
|
"\u001b[0m - tool-ninja @ 1.13.1 \n",
|
||||||
|
"\u001b[0m - tool-scons @ 4.40801.0 (4.8.1) \n",
|
||||||
|
"\u001b[0m - tool-xtensa-esp-elf-gdb @ 16.3.0+20250913 \n",
|
||||||
|
"\u001b[0m - toolchain-xtensa-esp-elf @ 14.2.0+20260121\n",
|
||||||
|
"\u001b[33m\u001b[2mUsing Python 3.12.10 environment at: /root/.platformio/penv/.espidf-5.5.4\u001b[0m\n",
|
||||||
|
"\u001b[0mReading CMake configuration...\n",
|
||||||
|
"\u001b[0mNo dependencies\n",
|
||||||
|
"\u001b[0mRAM: [== ] 19.9% (used 65232 bytes from 327680 bytes)\n",
|
||||||
|
"\u001b[0mFlash: [====== ] 61.5% (used 1127679 bytes from 1835008 bytes)\n",
|
||||||
|
"========================= [\u001b[32m\u001b[1mSUCCESS\u001b[0m] Took 20.43 seconds =========================\u001b[0m\n",
|
||||||
|
"\\033[32mINFO Build Info: config_hash=0xb6775f3e build_time_str=2026-05-17 22:24:40 +1200\\033[0m\n",
|
||||||
|
"\\033[32mINFO Successfully compiled program.\\033[0m\n",
|
||||||
|
"\\033[32mINFO Connecting to 172.31.11.183 port 3232...\\033[0m\n",
|
||||||
|
"\\033[32mINFO Connected to 172.31.11.183\\033[0m\n",
|
||||||
|
"\\033[32mINFO Uploading /data/build/esp-nspanel1masterbdrm/.pioenvs/esp-nspanel1masterbdrm/firmware.bin (1128080 bytes)\\033[0m\n",
|
||||||
|
"\r",
|
||||||
|
"Uploading: [ ] 0% \r",
|
||||||
|
"Uploading: [= ] 1% \r",
|
||||||
|
"Uploading: [= ] 2% \r",
|
||||||
|
"Uploading: [== ] 3% \r",
|
||||||
|
"Uploading: [=== ] 4% \r",
|
||||||
|
"Uploading: [=== ] 5% \r",
|
||||||
|
"Uploading: [==== ] 6% \r",
|
||||||
|
"Uploading: [==== ] 7% \r",
|
||||||
|
"Uploading: [===== ] 8% \r",
|
||||||
|
"Uploading: [====== ] 9% \r",
|
||||||
|
"Uploading: [====== ] 10% \r",
|
||||||
|
"Uploading: [======= ] 11% \r",
|
||||||
|
"Uploading: [======= ] 12% \r",
|
||||||
|
"Uploading: [======== ] 13% \r",
|
||||||
|
"Uploading: [========= ] 14% \r",
|
||||||
|
"Uploading: [========= ] 15% \r",
|
||||||
|
"Uploading: [========== ] 16% \r",
|
||||||
|
"Uploading: [========== ] 17% \r",
|
||||||
|
"Uploading: [=========== ] 18% \r",
|
||||||
|
"Uploading: [============ ] 19% \r",
|
||||||
|
"Uploading: [============ ] 20% \r",
|
||||||
|
"Uploading: [============= ] 21% \r",
|
||||||
|
"Uploading: [============== ] 22% \r",
|
||||||
|
"Uploading: [============== ] 23% \r",
|
||||||
|
"Uploading: [=============== ] 24% \r",
|
||||||
|
"Uploading: [=============== ] 25% \r",
|
||||||
|
"Uploading: [================ ] 26% \r",
|
||||||
|
"Uploading: [================= ] 27% \r",
|
||||||
|
"Uploading: [================= ] 28% \r",
|
||||||
|
"Uploading: [================= ] 29% \r",
|
||||||
|
"Uploading: [================== ] 30% \r",
|
||||||
|
"Uploading: [=================== ] 31% \r",
|
||||||
|
"Uploading: [==================== ] 32% \r",
|
||||||
|
"Uploading: [==================== ] 33% \r",
|
||||||
|
"Uploading: [==================== ] 34% \r",
|
||||||
|
"Uploading: [===================== ] 35% \r",
|
||||||
|
"Uploading: [====================== ] 36% \r",
|
||||||
|
"Uploading: [====================== ] 37% \r",
|
||||||
|
"Uploading: [======================= ] 38% \r",
|
||||||
|
"Uploading: [======================== ] 39% \r",
|
||||||
|
"Uploading: [======================== ] 40% \r",
|
||||||
|
"Uploading: [========================= ] 41% \r",
|
||||||
|
"Uploading: [========================= ] 42% \r",
|
||||||
|
"Uploading: [========================== ] 43% \r",
|
||||||
|
"Uploading: [=========================== ] 44% \r",
|
||||||
|
"Uploading: [=========================== ] 45% \r",
|
||||||
|
"Uploading: [============================ ] 46% \r",
|
||||||
|
"Uploading: [============================ ] 47% \r",
|
||||||
|
"Uploading: [============================= ] 48% \r",
|
||||||
|
"Uploading: [============================== ] 49% \r",
|
||||||
|
"Uploading: [============================== ] 50% \r",
|
||||||
|
"Uploading: [=============================== ] 51% \r",
|
||||||
|
"Uploading: [=============================== ] 52% \r",
|
||||||
|
"Uploading: [================================ ] 53% \r",
|
||||||
|
"Uploading: [================================= ] 54% \r",
|
||||||
|
"Uploading: [================================= ] 55% \r",
|
||||||
|
"Uploading: [================================== ] 56% \r",
|
||||||
|
"Uploading: [================================== ] 57% \r",
|
||||||
|
"Uploading: [=================================== ] 58% \r",
|
||||||
|
"Uploading: [==================================== ] 59% \r",
|
||||||
|
"Uploading: [==================================== ] 60% \r",
|
||||||
|
"Uploading: [===================================== ] 61% \r",
|
||||||
|
"Uploading: [===================================== ] 62% \r",
|
||||||
|
"Uploading: [====================================== ] 63% \r",
|
||||||
|
"Uploading: [======================================= ] 64% \r",
|
||||||
|
"Uploading: [======================================= ] 65% \r",
|
||||||
|
"Uploading: [======================================== ] 66% \r",
|
||||||
|
"Uploading: [========================================= ] 67% \r",
|
||||||
|
"Uploading: [========================================= ] 68% \r",
|
||||||
|
"Uploading: [========================================== ] 69% \r",
|
||||||
|
"Uploading: [========================================== ] 70% \r",
|
||||||
|
"Uploading: [=========================================== ] 71% \r",
|
||||||
|
"Uploading: [============================================ ] 72% \r",
|
||||||
|
"Uploading: [============================================ ] 73% \r",
|
||||||
|
"Uploading: [============================================ ] 74% \r",
|
||||||
|
"Uploading: [============================================= ] 75% \r",
|
||||||
|
"Uploading: [============================================== ] 76% \r",
|
||||||
|
"Uploading: [=============================================== ] 77% \r",
|
||||||
|
"Uploading: [=============================================== ] 78% \r",
|
||||||
|
"Uploading: [=============================================== ] 79% \r",
|
||||||
|
"Uploading: [================================================ ] 80% \r",
|
||||||
|
"Uploading: [================================================= ] 81% \r",
|
||||||
|
"Uploading: [================================================= ] 82% \r",
|
||||||
|
"Uploading: [================================================== ] 83% \r",
|
||||||
|
"Uploading: [=================================================== ] 84% \r",
|
||||||
|
"Uploading: [=================================================== ] 85% \r",
|
||||||
|
"Uploading: [==================================================== ] 86% \r",
|
||||||
|
"Uploading: [==================================================== ] 87% \r",
|
||||||
|
"Uploading: [===================================================== ] 88% \r",
|
||||||
|
"Uploading: [====================================================== ] 89% \r",
|
||||||
|
"Uploading: [====================================================== ] 90% \r",
|
||||||
|
"Uploading: [======================================================= ] 91% \r",
|
||||||
|
"Uploading: [======================================================= ] 92% \r",
|
||||||
|
"Uploading: [======================================================== ] 93% \r",
|
||||||
|
"Uploading: [========================================================= ] 94% \r",
|
||||||
|
"Uploading: [========================================================= ] 95% \r",
|
||||||
|
"Uploading: [========================================================== ] 96% \r",
|
||||||
|
"Uploading: [========================================================== ] 97% \r",
|
||||||
|
"Uploading: [=========================================================== ] 98% \r",
|
||||||
|
"Uploading: [============================================================] 99% \r",
|
||||||
|
"Uploading: [============================================================] 100% Done...\r\n",
|
||||||
|
"\n",
|
||||||
|
"\\033[32mINFO Upload took 7.41 seconds, waiting for result...\\033[0m\n",
|
||||||
|
"\\033[32mINFO OTA successful\\033[0m\n",
|
||||||
|
"\\033[32mINFO Successfully uploaded program.\\033[0m\n"
|
||||||
|
],
|
||||||
|
"error": null,
|
||||||
|
"port": "OTA",
|
||||||
|
"new_name": "",
|
||||||
|
"progress": 100,
|
||||||
|
"remote_peer": "",
|
||||||
|
"remote_job_id": "",
|
||||||
|
"remote_peer_label": "",
|
||||||
|
"device_name": "",
|
||||||
|
"device_friendly_name": "",
|
||||||
|
"source": "local",
|
||||||
|
"source_pin_sha256": "",
|
||||||
|
"source_label": "",
|
||||||
|
"source_esphome_version": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"job_id": "0eb2b3a49a5f",
|
||||||
|
"configuration": "esp-nspanel2lounge.yaml",
|
||||||
|
"job_type": "compile",
|
||||||
|
"status": "cancelled",
|
||||||
|
"created_at": "2026-05-17T08:44:50.516947+00:00",
|
||||||
|
"started_at": "2026-05-17T08:44:50.517123+00:00",
|
||||||
|
"completed_at": "2026-05-17T08:47:51.180084+00:00",
|
||||||
|
"exit_code": -15,
|
||||||
|
"output": [
|
||||||
|
"\\033[32mINFO ESPHome 2026.5.0b1\\033[0m\n",
|
||||||
|
"\\033[32mINFO Reading configuration /config/esphome/esp-nspanel2lounge.yaml...\\033[0m\n",
|
||||||
|
"\\033[32mINFO Updating https://github.com/edwardtfn/NSPanel-Easy@v2026.5.5\\033[0m\n",
|
||||||
|
"\\033[32mINFO Updating https://github.com/edwardtfn/NSPanel-Easy@v2026.5.5\\033[0m\n",
|
||||||
|
"\\033[32mINFO Detected timezone 'Pacific/Auckland'\\033[0m\n",
|
||||||
|
"\\033[33mWARNING Found and merged multiple configurations for ota platform esphome port(s) [3232]\\033[0m\n",
|
||||||
|
"\\033[32mINFO Generating C++ source...\\033[0m\n",
|
||||||
|
"\\033[32mINFO Setting CONFIG_LWIP_MAX_SOCKETS to 13 (TCP=6 [api=3, captive_portal=3], UDP=3 [captive_portal=1, mdns=2], TCP_LISTEN=4 [api=1, ota=2, web_server_base=1])\\033[0m\n",
|
||||||
|
"\\033[32mINFO Compiling app... Build path: /data/build/esp-nspanel2lounge\\033[0m\n",
|
||||||
|
"Processing \u001b[36m\u001b[1mesp-nspanel2lounge\u001b[0m (board: esp32dev; framework: espidf; platform: https://github.com/pioarduino/platform-espressif32/releases/download/55.03.38-1/platform-espressif32.zip)\n",
|
||||||
|
"\u001b[1m--------------------------------------------------------------------------------\u001b[0m\n",
|
||||||
|
"\u001b[0mHARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash\n",
|
||||||
|
"\u001b[0m - contrib-piohome @ 3.4.4 \n",
|
||||||
|
"\u001b[0m - framework-espidf @ 3.50504.0 (5.5.4) \n",
|
||||||
|
"\u001b[0m - tool-cmake @ 4.0.3 \n",
|
||||||
|
"\u001b[0m - tool-esp-rom-elfs @ 2024.10.11 \n",
|
||||||
|
"\u001b[0m - tool-esptoolpy @ 5.2.0 \n",
|
||||||
|
"\u001b[0m - tool-ninja @ 1.13.1 \n",
|
||||||
|
"\u001b[0m - tool-scons @ 4.40801.0 (4.8.1) \n",
|
||||||
|
"\u001b[0m - tool-xtensa-esp-elf-gdb @ 16.3.0+20250913 \n",
|
||||||
|
"\u001b[0m - toolchain-xtensa-esp-elf @ 14.2.0+20260121\n",
|
||||||
|
"\u001b[33m\u001b[2mUsing Python 3.12.10 environment at: /root/.platformio/penv/.espidf-5.5.4\u001b[0m\n",
|
||||||
|
"\u001b[0mReading CMake configuration...\n",
|
||||||
|
"\u001b[0mGenerating assembly for certificate bundle...\n",
|
||||||
|
"\u001b[0mNo dependencies\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/adc/adc_sensor_common.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/adc/adc_sensor_esp32.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/api/api_buffer.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/api/api_connection.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/api/api_frame_helper.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/api/api_frame_helper_plaintext.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/api/api_overflow_buffer.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/api/api_pb2.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/api/api_pb2_service.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/api/api_server.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/api/list_entities.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/api/proto.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/api/subscribe_state.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/api/user_services.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/binary_sensor/automation.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/binary_sensor/binary_sensor.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/binary_sensor/filter.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/button/button.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/captive_portal/captive_portal.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/captive_portal/dns_server_esp32_idf.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/display/display.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/display/display_buffer.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/display/rect.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/esp32/core.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/esp32/crash_handler.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/esp32/gpio.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/esp32/hal.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/esp32/helpers.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/esp32/preferences.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/esp32/printf_stubs.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/esp32/throw_stubs.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/esphome/ota/ota_esphome.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/gpio/switch/gpio_switch.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/homeassistant/time/homeassistant_time.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/ledc/ledc_output.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/logger/logger.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/logger/logger_esp32.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/logger/task_log_buffer_esp32.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/md5/md5.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/mdns/mdns_component.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/mdns/mdns_esp32.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/network/util.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nextion/nextion.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nextion/nextion_commands.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nextion/nextion_component.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nextion/nextion_upload.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nextion/nextion_upload_esp32.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nextion/text_sensor/nextion_textsensor.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/addon_climate.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/addon_display_light.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/addon_upload_tft.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/base.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/chips.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/ha_components.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/hw_display.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/nextion_components.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/page_climate.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/page_entities.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/page_media_player.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/page_notification.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/page_popup_select.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/page_screensaver.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/page_utilities.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/pages.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/text.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/versioning.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/nspanel_easy/weather.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/ntc/ntc.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/number/automation.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/number/number.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/number/number_call.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/number/number_traits.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/ota/ota_backend.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/ota/ota_backend_esp_idf.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/ota/ota_bootloader_esp_idf.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/ota/ota_partitions_esp_idf.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/output/automation.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/output/float_output.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/psram/psram.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/resistance/resistance_sensor.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/restart/button/restart_button.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/rtttl/rtttl.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/safe_mode/safe_mode.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/script/script.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/select/select.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/select/select_call.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/select/select_traits.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/sensor/automation.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/sensor/filter.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/sensor/sensor.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/sha256/sha256.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/socket/bsd_sockets_impl.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/socket/socket.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/switch/automation.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/switch/switch.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/template/binary_sensor/template_binary_sensor.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/template/number/template_number.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/template/select/template_select.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/template/switch/template_switch.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/template/text_sensor/template_text_sensor.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/text_sensor/filter.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/text_sensor/text_sensor.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/time/automation.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/time/posix_tz.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/time/real_time_clock.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/uart/uart.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/uart/uart_component.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/uart/uart_component_esp_idf.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/uart/uart_debugger.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/watchdog/watchdog.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/web_server/ota/ota_web_server.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/web_server_base/web_server_base.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/web_server_idf/multipart.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/web_server_idf/utils.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/web_server_idf/web_server_idf.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/wifi/wifi_component.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/components/wifi/wifi_component_esp_idf.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/core/alloc_helpers.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/core/application.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/core/build_info_data.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/core/color.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/core/component.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/core/component_iterator.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/core/controller_registry.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/core/entity_base.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/core/gpio.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/core/helpers.cpp.o\n",
|
||||||
|
"\u001b[0mCompiling .pioenvs/esp-nspanel2lounge/src/esphome/core/log.cpp.o\n"
|
||||||
|
],
|
||||||
|
"error": null,
|
||||||
|
"port": "",
|
||||||
|
"new_name": "",
|
||||||
|
"progress": null,
|
||||||
|
"remote_peer": "",
|
||||||
|
"remote_job_id": "",
|
||||||
|
"remote_peer_label": "",
|
||||||
|
"device_name": "",
|
||||||
|
"device_friendly_name": "",
|
||||||
|
"source": "local",
|
||||||
|
"source_pin_sha256": "",
|
||||||
|
"source_label": "",
|
||||||
|
"source_esphome_version": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"job_id": "e4433a434baf",
|
||||||
|
"configuration": "esp-nspanel1masterbdrm.yaml",
|
||||||
|
"job_type": "clean",
|
||||||
|
"status": "completed",
|
||||||
|
"created_at": "2026-05-17T09:55:46.641871+00:00",
|
||||||
|
"started_at": "2026-05-17T09:55:46.642053+00:00",
|
||||||
|
"completed_at": "2026-05-17T09:55:49.036615+00:00",
|
||||||
|
"exit_code": 0,
|
||||||
|
"output": [
|
||||||
|
"\\033[32mINFO ESPHome 2026.5.0b1\\033[0m\n",
|
||||||
|
"\\033[32mINFO Reading configuration /config/esphome/esp-nspanel1masterbdrm.yaml...\\033[0m\n",
|
||||||
|
"\\033[32mINFO Detected timezone 'Pacific/Auckland'\\033[0m\n",
|
||||||
|
"\\033[33mWARNING Found and merged multiple configurations for ota platform esphome port(s) [3232]\\033[0m\n",
|
||||||
|
"\\033[32mINFO Deleting /data/build/esp-nspanel1masterbdrm/.pioenvs\\033[0m\n",
|
||||||
|
"\\033[32mINFO Deleting /data/build/esp-nspanel1masterbdrm/.piolibdeps\\033[0m\n",
|
||||||
|
"\\033[32mINFO Deleting /data/build/esp-nspanel1masterbdrm/dependencies.lock\\033[0m\n",
|
||||||
|
"\\033[32mINFO Deleting /data/build/esp-nspanel1masterbdrm/managed_components\\033[0m\n",
|
||||||
|
"\\033[32mINFO Deleting PlatformIO cache /data/cache/platformio/cache\\033[0m\n",
|
||||||
|
"\\033[32mINFO Done!\\033[0m\n"
|
||||||
|
],
|
||||||
|
"error": null,
|
||||||
|
"port": "",
|
||||||
|
"new_name": "",
|
||||||
|
"progress": null,
|
||||||
|
"remote_peer": "",
|
||||||
|
"remote_job_id": "",
|
||||||
|
"remote_peer_label": "",
|
||||||
|
"device_name": "",
|
||||||
|
"device_friendly_name": "",
|
||||||
|
"source": "local",
|
||||||
|
"source_pin_sha256": "",
|
||||||
|
"source_label": "",
|
||||||
|
"source_esphome_version": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"job_id": "1cb834d6b311",
|
||||||
|
"configuration": "esp-nspanel1masterbdrm.yaml",
|
||||||
|
"job_type": "clean",
|
||||||
|
"status": "completed",
|
||||||
|
"created_at": "2026-05-17T09:30:13.803940+00:00",
|
||||||
|
"started_at": "2026-05-17T09:30:13.804128+00:00",
|
||||||
|
"completed_at": "2026-05-17T09:30:16.052388+00:00",
|
||||||
|
"exit_code": 0,
|
||||||
|
"output": [
|
||||||
|
"\\033[32mINFO ESPHome 2026.5.0b1\\033[0m\n",
|
||||||
|
"\\033[32mINFO Reading configuration /config/esphome/esp-nspanel1masterbdrm.yaml...\\033[0m\n",
|
||||||
|
"\\033[32mINFO Detected timezone 'Pacific/Auckland'\\033[0m\n",
|
||||||
|
"\\033[33mWARNING Found and merged multiple configurations for ota platform esphome port(s) [3232]\\033[0m\n",
|
||||||
|
"\\033[32mINFO Deleting /data/build/esp-nspanel1masterbdrm/.pioenvs\\033[0m\n",
|
||||||
|
"\\033[32mINFO Deleting /data/build/esp-nspanel1masterbdrm/dependencies.lock\\033[0m\n",
|
||||||
|
"\\033[32mINFO Deleting /data/build/esp-nspanel1masterbdrm/managed_components\\033[0m\n",
|
||||||
|
"\\033[32mINFO Deleting PlatformIO cache /data/cache/platformio/cache\\033[0m\n",
|
||||||
|
"\\033[32mINFO Done!\\033[0m\n"
|
||||||
|
],
|
||||||
|
"error": null,
|
||||||
|
"port": "",
|
||||||
|
"new_name": "",
|
||||||
|
"progress": null,
|
||||||
|
"remote_peer": "",
|
||||||
|
"remote_job_id": "",
|
||||||
|
"remote_peer_label": "",
|
||||||
|
"device_name": "",
|
||||||
|
"device_friendly_name": "",
|
||||||
|
"source": "local",
|
||||||
|
"source_pin_sha256": "",
|
||||||
|
"source_label": "",
|
||||||
|
"source_esphome_version": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"esp-nspanel2lounge copy.yaml": {
|
||||||
|
"board_id": "generic-esp32",
|
||||||
|
"mac_address": "88:13:BF:68:39:2C"
|
||||||
|
},
|
||||||
|
"esp-nspanel1masterbdrm.yaml": {
|
||||||
|
"board_id": "generic-esp32",
|
||||||
|
"mac_address": "24:D7:EB:0D:E7:FC"
|
||||||
|
},
|
||||||
|
"esp-ledmatrix1.yaml": {
|
||||||
|
"board_id": "generic-esp8266",
|
||||||
|
"mac_address": "5C:CF:7F:A0:36:73"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"pid": 76431, "lock_format_version": 1, "device_builder_version": "0.1.0b51", "start_ts": 1779063562.6364732}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
substitutions:
|
||||||
|
############################################################################################
|
||||||
|
# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS
|
||||||
|
# If NOT using a secrets file, just replace these with the passwords etc (in quotes)
|
||||||
|
###########################################################################################
|
||||||
|
wifi_ssid: !secret ha_wifi_ssid
|
||||||
|
wifi_password: !secret ha_wifi_password
|
||||||
|
fallback_ap_password: !secret fallback_ap_password
|
||||||
|
|
||||||
|
# Enables faster network connections, with last connected SSID being connected to and no full scan for SSID being undertaken
|
||||||
|
wifi_fast_connect: "false"
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
|
||||||
|
# Automatically add the mac address to the name
|
||||||
|
# eg so you can use a single firmware for all devices
|
||||||
|
add_mac_suffix: "false"
|
||||||
|
|
||||||
|
# Enable or disable the use of IPv6 networking on the device
|
||||||
|
ipv6_enable: "false"
|
||||||
|
|
||||||
|
# Add these if we are giving it a static ip, or remove them in the Wifi section
|
||||||
|
static_ip_subnet: !secret ha_wifi_subnet
|
||||||
|
static_ip_gateway: !secret ha_wifi_gateway
|
||||||
|
static_ip_dns1: !secret ha_wifi_dns1
|
||||||
|
static_ip_dns2: !secret ha_wifi_dns2
|
||||||
|
|
||||||
|
# Network reconnect every x hours to ensure best access point
|
||||||
|
base_interval_hours: "23" # Base interval in hours
|
||||||
|
random_offset_max_minutes: "59" # Max random offset in minutes
|
||||||
|
|
||||||
|
###########################################################################################
|
||||||
|
# Common Wifi Settings
|
||||||
|
# https://esphome.io/components/wifi.html
|
||||||
|
#
|
||||||
|
# Power Save mode (can reduce wifi reliability)
|
||||||
|
# NONE (least power saving, Default for ESP8266)
|
||||||
|
# LIGHT (Default for ESP32)
|
||||||
|
# HIGH (most power saving)
|
||||||
|
###########################################################################################
|
||||||
|
wifi:
|
||||||
|
networks:
|
||||||
|
- ssid: ${wifi_ssid}
|
||||||
|
password: ${wifi_password}
|
||||||
|
manual_ip: # optional static IP address
|
||||||
|
static_ip: ${local_static_ip_address}
|
||||||
|
gateway: ${static_ip_gateway}
|
||||||
|
subnet: ${static_ip_subnet}
|
||||||
|
dns1: ${static_ip_dns1}
|
||||||
|
dns2: ${static_ip_dns2}
|
||||||
|
|
||||||
|
#enable_rrm: true # (ESP32 only) enable 802.11k Radio Resource Management
|
||||||
|
#enable_btm: true # (ESP32 only) enable 802.11v BSS Transition Management
|
||||||
|
power_save_mode: none # https://esphome.io/components/wifi.html#wifi-power-save-mode
|
||||||
|
use_address: ${local_current_ip_address}
|
||||||
|
ap: # Details for fallback hotspot in case wifi connection fails https://esphome.io/components/wifi.html#access-point-mode
|
||||||
|
ssid: ${local_device_name}
|
||||||
|
password: ${fallback_ap_password}
|
||||||
|
ap_timeout: 10min # Time until it brings up fallback AP. default is 1min
|
||||||
|
|
||||||
|
# Allow rapid re-connection to previously connected WiFi SSID, skipping scan of all SSIDs
|
||||||
|
fast_connect: ${wifi_fast_connect}
|
||||||
|
|
||||||
|
# Define dns domain / suffix to add to hostname
|
||||||
|
domain: ${dns_domain}
|
||||||
|
min_auth_mode: WPA2
|
||||||
|
|
||||||
|
# Reboot eventually when Wi-Fi is down (default is 15min)
|
||||||
|
reboot_timeout: 56h
|
||||||
|
|
||||||
|
captive_portal: # extra fallback mechanism for when connecting if the configured WiFi fails
|
||||||
|
|
||||||
|
###########################################################################################
|
||||||
|
# Enable Over the Air Update Capability
|
||||||
|
# https://esphome.io/components/ota.html?highlight=ota
|
||||||
|
###########################################################################################
|
||||||
|
ota:
|
||||||
|
- platform: esphome
|
||||||
|
password: ${local_ota_pass}
|
||||||
|
version: 2
|
||||||
|
#- platform: web_server # Uncomment if you want to be able to do OTA with the web interface
|
||||||
|
|
||||||
|
###########################################################################################
|
||||||
|
# Safe Mode
|
||||||
|
# Safe mode will detect boot loops
|
||||||
|
# https://esphome.io/components/safe_mode
|
||||||
|
###########################################################################################
|
||||||
|
safe_mode:
|
||||||
|
|
||||||
|
###########################################################################################
|
||||||
|
# Network
|
||||||
|
# global configuration for all types of networks
|
||||||
|
# https://esphome.io/components/network.html
|
||||||
|
###########################################################################################
|
||||||
|
network:
|
||||||
|
enable_ipv6: ${ipv6_enable}
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Interval
|
||||||
|
# Restart Networking every x hours + rand mins
|
||||||
|
# This ensure that the device is connected to the best AP
|
||||||
|
##########################################################################################
|
||||||
|
#script:
|
||||||
|
# - id: random_reconnect
|
||||||
|
# mode: restart
|
||||||
|
# then:
|
||||||
|
# - lambda: |-
|
||||||
|
# // Compute total delay: base hours + random offset minutes
|
||||||
|
# uint32_t extra;
|
||||||
|
# #if defined(ESP32)
|
||||||
|
# // ESP32 (both Arduino & IDF builds) uses esp_random()
|
||||||
|
# extra = esp_random() % (${random_offset_max_minutes} + 1);
|
||||||
|
# #elif defined(ESP8266)
|
||||||
|
# // ESP8266 Arduino core
|
||||||
|
# extra = os_random() % (${random_offset_max_minutes} + 1);
|
||||||
|
# #else
|
||||||
|
# // Fallback to esp_random() on other platforms
|
||||||
|
# extra = esp_random() % (${random_offset_max_minutes} + 1);
|
||||||
|
# #endif
|
||||||
|
# uint32_t total_s = ${base_interval_hours} * 3600 + extra * 60;
|
||||||
|
# ESP_LOGI("random_reconnect", "Next reconnect in %u seconds", total_s);
|
||||||
|
# // Delay inside lambda (blocks script execution but OK for reconnect timing)
|
||||||
|
# delay(total_s * 1000);
|
||||||
|
# - logger.log: "network_check: performing reconnect"
|
||||||
|
# - wifi.disable: {}
|
||||||
|
# - delay: 1s
|
||||||
|
# - wifi.enable: {}
|
||||||
|
# - script.execute: random_reconnect
|
||||||
|
|
||||||
@@ -1,104 +1,129 @@
|
|||||||
############################################################################################
|
#:########################################################################################:#
|
||||||
# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS
|
# TITLE: COMMON SNTP TIME SOURCE
|
||||||
# If NOT using a secrets file, just replace
|
# zorruno.com common ESPHome include
|
||||||
# these with the values (in quotes)
|
#:########################################################################################:#
|
||||||
###########################################################################################
|
# FILE:
|
||||||
|
# common/sntp_common.yaml
|
||||||
|
#:########################################################################################:#
|
||||||
|
# VERSIONS:
|
||||||
|
# V1.1 2026-05-23 Fixed offline fallback clock so it increments from assumed noon boot time
|
||||||
|
# V1.0 Initial common SNTP time source and diagnostic sensors
|
||||||
|
#:########################################################################################:#
|
||||||
|
# PURPOSE:
|
||||||
|
# - Provides an SNTP time source for ESPHome devices.
|
||||||
|
# - Stores the current time as minutes since midnight in current_mins.
|
||||||
|
# - Provides a simple fallback clock if SNTP is not available.
|
||||||
|
# - Publishes diagnostic text sensors for last restart, current/internal time, and sync status.
|
||||||
|
#:########################################################################################:#
|
||||||
|
# OPERATION NOTES:
|
||||||
|
# - SNTP time is stored in id(sntp_time).
|
||||||
|
# - Current minutes since midnight are stored in id(current_mins).
|
||||||
|
# - If SNTP is valid, current_mins follows the real SNTP time.
|
||||||
|
# - If SNTP is invalid, current_mins increments once per minute from the assumed boot time.
|
||||||
|
# - The fallback assumes the device was powered on at 12:00 noon.
|
||||||
|
# - If accurate offline time is needed, power-cycle the device at 12:00 noon.
|
||||||
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# SUBSTITUTIONS: Specific SNTP variable substitutions
|
||||||
|
# If NOT using a secrets file, replace these values directly in quotes.
|
||||||
|
#:########################################################################################:#
|
||||||
substitutions:
|
substitutions:
|
||||||
timezone: "Pacific/Auckland"
|
timezone: "Pacific/Auckland"
|
||||||
sntp_update_interval: 6h # Set the duration between the sntp service polling
|
sntp_update_interval: 6h
|
||||||
# Network time servers https://www.ntppool.org/zone/@
|
|
||||||
|
# Network time servers
|
||||||
|
# https://www.ntppool.org/zone/@
|
||||||
sntp_server_1: !secret ntp_server_1
|
sntp_server_1: !secret ntp_server_1
|
||||||
sntp_server_2: !secret ntp_server_2
|
sntp_server_2: !secret ntp_server_2
|
||||||
sntp_server_3: !secret ntp_server_3
|
sntp_server_3: !secret ntp_server_3
|
||||||
|
|
||||||
###########################################################################################
|
#:########################################################################################:#
|
||||||
# Internal clock fallback support
|
# GLOBALS: Internal clock fallback support
|
||||||
# If SNTP is invalid, we fall back to a simple internal minute counter
|
#:########################################################################################:#
|
||||||
# We assume user powers on the device at 12:00 noon
|
|
||||||
# => 12 * 60 = 720 minutes from midnight.
|
|
||||||
# Not restored, so it resets each boot.
|
|
||||||
# Therefore, if no network and you still need timing functions, switch on ay noon.
|
|
||||||
###########################################################################################
|
|
||||||
globals:
|
globals:
|
||||||
- id: current_mins
|
- id: current_mins
|
||||||
type: int
|
type: int
|
||||||
restore_value: no
|
restore_value: false
|
||||||
initial_value: "720" # 720 is 12:00 Noon
|
initial_value: "720" # 720 minutes from midnight is 12:00 noon.
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# INTERVAL: Keep current_mins updated
|
||||||
|
#:########################################################################################:#
|
||||||
interval:
|
interval:
|
||||||
- interval: 60s
|
- interval: 60s
|
||||||
then:
|
then:
|
||||||
- lambda: |-
|
- lambda: |-
|
||||||
// If SNTP valid, store minutes since midnight.
|
// If SNTP is valid, store real minutes since midnight.
|
||||||
auto now = id(sntp_time).now();
|
auto now = id(sntp_time).now();
|
||||||
if (now.is_valid()) {
|
if (now.is_valid()) {
|
||||||
id(current_mins) = (now.hour * 60) + now.minute;
|
id(current_mins) = (now.hour * 60) + now.minute;
|
||||||
} else {
|
} else {
|
||||||
// Fallback: minutes since boot.
|
// Fallback: increment from the assumed startup time.
|
||||||
id(current_mins) = (int)(millis() / 60000UL);
|
// Initial value is 720, so offline boot assumes 12:00 noon.
|
||||||
|
id(current_mins) = (id(current_mins) + 1) % 1440;
|
||||||
}
|
}
|
||||||
|
|
||||||
###########################################################################################
|
#:########################################################################################:#
|
||||||
# Real time clock time source for ESPHome
|
# TIME: Real time clock source for ESPHome
|
||||||
# If it's invalid, we fall back to an internal clock
|
|
||||||
# https://esphome.io/components/time/index.html
|
# https://esphome.io/components/time/index.html
|
||||||
# https://esphome.io/components/time/sntp
|
# https://esphome.io/components/time/sntp
|
||||||
###########################################################################################
|
#:########################################################################################:#
|
||||||
time:
|
time:
|
||||||
- platform: sntp
|
- platform: sntp
|
||||||
id: sntp_time
|
id: sntp_time
|
||||||
# Define the timezone of the device
|
|
||||||
timezone: "${timezone}"
|
timezone: "${timezone}"
|
||||||
# Change sync interval from default 5min to 6 hours (or as set in substitutions)
|
|
||||||
update_interval: ${sntp_update_interval}
|
update_interval: ${sntp_update_interval}
|
||||||
# Set specific sntp servers to use
|
|
||||||
servers:
|
servers:
|
||||||
- "${sntp_server_1}"
|
- "${sntp_server_1}"
|
||||||
- "${sntp_server_2}"
|
- "${sntp_server_2}"
|
||||||
- "${sntp_server_3}"
|
- "${sntp_server_3}"
|
||||||
# Publish the time the device was last restarted
|
|
||||||
on_time_sync:
|
on_time_sync:
|
||||||
then:
|
then:
|
||||||
- logger.log: "Synchronised SNTP clock"
|
- logger.log: "Synchronised SNTP clock"
|
||||||
|
|
||||||
- text_sensor.template.publish:
|
- text_sensor.template.publish:
|
||||||
id: time_sync
|
id: time_sync
|
||||||
state: "SNTP clock Syncd"
|
state: "SNTP clock synced"
|
||||||
# Update last restart time, but only once.
|
|
||||||
|
# Update last restart time once only, after the first successful SNTP sync.
|
||||||
- if:
|
- if:
|
||||||
condition:
|
condition:
|
||||||
lambda: 'return id(device_last_restart).state == "";'
|
lambda: |-
|
||||||
|
return id(device_last_restart).state.empty();
|
||||||
then:
|
then:
|
||||||
- text_sensor.template.publish:
|
- text_sensor.template.publish:
|
||||||
id: device_last_restart
|
id: device_last_restart
|
||||||
#state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");'
|
|
||||||
state: !lambda |-
|
state: !lambda |-
|
||||||
// grab the current SNTP time
|
|
||||||
auto now = id(sntp_time).now();
|
auto now = id(sntp_time).now();
|
||||||
// format it as e.g. "Fri 23 May 2025 - 03:45:12 PM"
|
|
||||||
return now.strftime("%a %d %b %Y - %I:%M:%S %p");
|
return now.strftime("%a %d %b %Y - %I:%M:%S %p");
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# TEXT SENSOR COMPONENT:
|
||||||
|
# https://esphome.io/components/text_sensor/
|
||||||
|
#:########################################################################################:#
|
||||||
text_sensor:
|
text_sensor:
|
||||||
# Creates a sensor showing when the device was last restarted
|
# Shows when the device was last restarted, based on the first successful SNTP sync.
|
||||||
- platform: template
|
- platform: template
|
||||||
name: "Time: Last Restart"
|
name: "Time: Last Restart"
|
||||||
id: device_last_restart
|
id: device_last_restart
|
||||||
icon: mdi:clock
|
icon: mdi:clock
|
||||||
entity_category: diagnostic
|
entity_category: diagnostic
|
||||||
#device_class: timestamp
|
update_interval: never
|
||||||
|
|
||||||
|
# Shows the current SNTP time if valid, otherwise the internal fallback time.
|
||||||
- platform: template
|
- platform: template
|
||||||
name: "Time: Internal Time"
|
name: "Time: Internal Time"
|
||||||
id: time_text
|
id: time_text
|
||||||
update_interval: "1min"
|
icon: mdi:clock-outline
|
||||||
|
update_interval: 1min
|
||||||
entity_category: diagnostic
|
entity_category: diagnostic
|
||||||
lambda: |-
|
lambda: |-
|
||||||
// If SNTP time is valid, show real time/date.
|
|
||||||
if (id(sntp_time).now().is_valid()) {
|
if (id(sntp_time).now().is_valid()) {
|
||||||
auto t = id(sntp_time).now().strftime("%H:%M:%S - %d-%m-%Y");
|
auto t = id(sntp_time).now().strftime("%H:%M:%S - %d-%m-%Y");
|
||||||
return { t };
|
return { t };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback: show internal clock based on current_mins (minutes from midnight).
|
|
||||||
int mins = id(current_mins);
|
int mins = id(current_mins);
|
||||||
if (mins < 0) mins = 0;
|
if (mins < 0) mins = 0;
|
||||||
if (mins >= 1440) mins = mins % 1440;
|
if (mins >= 1440) mins = mins % 1440;
|
||||||
@@ -110,8 +135,16 @@ text_sensor:
|
|||||||
snprintf(buff, sizeof(buff), "%02d:%02d (fallback)", hour, minute);
|
snprintf(buff, sizeof(buff), "%02d:%02d (fallback)", hour, minute);
|
||||||
return { std::string(buff) };
|
return { std::string(buff) };
|
||||||
|
|
||||||
|
# Shows whether the device is using SNTP or the fallback clock.
|
||||||
- platform: template
|
- platform: template
|
||||||
name: "Time: Sync Status"
|
name: "Time: Sync Status"
|
||||||
id: time_sync
|
id: time_sync
|
||||||
update_interval: "1min"
|
icon: mdi:clock-check-outline
|
||||||
|
update_interval: 1min
|
||||||
entity_category: diagnostic
|
entity_category: diagnostic
|
||||||
|
lambda: |-
|
||||||
|
if (id(sntp_time).now().is_valid()) {
|
||||||
|
return { std::string("SNTP clock synced") };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { std::string("Using fallback internal clock") };
|
||||||
@@ -0,0 +1,818 @@
|
|||||||
|
#:########################################################################################:#
|
||||||
|
# TITLE: LED MATRIX 1
|
||||||
|
# zorruno.com layout v1.1 2026
|
||||||
|
# ESP32-C3 SuperMini MAX7219 LED matrix clock and scroll display.
|
||||||
|
# Original Project Reference https://github.com/RealDeco/matrixclock-esphome
|
||||||
|
#:########################################################################################:#
|
||||||
|
# REPO:
|
||||||
|
# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-ledmatrix1.yaml
|
||||||
|
#:########################################################################################:#
|
||||||
|
# VERSIONS:
|
||||||
|
# V1.1 2026-05-23 Updated yaml to zorruno layout V1.1, cleaned comments, fixed SNTP time IDs,
|
||||||
|
# added current_mins fallback display, removed unused MQTT topic, and fixed
|
||||||
|
# blank scroll handling.
|
||||||
|
# V1.0 2026-05-23 Initial Version
|
||||||
|
#:########################################################################################:#
|
||||||
|
# HARDWARE:
|
||||||
|
# - ESP32-C3 SuperMini.
|
||||||
|
# - MAX7219 4-chip LED matrix display, typically 32 x 8 pixels.
|
||||||
|
# - SPI wiring configured below:
|
||||||
|
# - MOSI: GPIO8
|
||||||
|
# - CS: GPIO9
|
||||||
|
# - SCK: GPIO10
|
||||||
|
# - Power note: 4 MAX7219 modules may need a suitable external 5 V supply.
|
||||||
|
# - Keep ESP32-C3 GND and matrix power supply GND connected together.
|
||||||
|
#:########################################################################################:#
|
||||||
|
# FONTS:
|
||||||
|
# Dragon Font: https://www.freebestfonts.com/eight-bit-dragon-font
|
||||||
|
# 5x8 Font: https://developer.lasec.com.mx/armando/rpi-rgb-led-matrix/-/blob/master/fonts/5x8.bdf
|
||||||
|
#:########################################################################################:#
|
||||||
|
# OPERATION NOTES:
|
||||||
|
# - Displays the current time from common/sntp_common.yaml using id(sntp_time).
|
||||||
|
# - If SNTP is invalid, the display falls back to id(current_mins) from common/sntp_common.yaml.
|
||||||
|
# - 12h/24h display mode is selectable from Home Assistant or MQTT.
|
||||||
|
# - Display brightness is exposed as a Home Assistant light entity.
|
||||||
|
# - Brightness accepts values 0..15 where 0 turns the display off and 1..15 sets intensity.
|
||||||
|
# - Scroll Text is exposed as a Home Assistant text entity and clears itself after use.
|
||||||
|
# - Before any scroll starts, the clock slides down and off the display.
|
||||||
|
# - After scroll ends, the selected re-entry effect runs: Slide up, Slide down, or Pixel fall.
|
||||||
|
# - Pixel fall hides the clock until the effect finishes, avoiding a clock-under-particles look.
|
||||||
|
# - Scroll speed is adjustable using the Scroll Delay number entity.
|
||||||
|
#:########################################################################################:#
|
||||||
|
# MQTT COMMANDS:
|
||||||
|
# - ${mqtt_command_topic}/scroll : Text payload to scroll once across the display.
|
||||||
|
# - ${mqtt_command_topic}/mode : Payload 12 or 24 to select clock format.
|
||||||
|
# - ${mqtt_command_topic}/bright : Payload 0 turns display off, 1-15 sets brightness.
|
||||||
|
# - ${mqtt_status_topic}/status : Publishes online/offline status.
|
||||||
|
#:########################################################################################:#
|
||||||
|
# OFFLINE NOTES:
|
||||||
|
# a) Home Assistant offline, but WiFi/network and MQTT online:
|
||||||
|
# - Clock display should continue using SNTP if the NTP servers are reachable.
|
||||||
|
# - MQTT scroll, brightness, and 12h/24h mode commands should still work.
|
||||||
|
#
|
||||||
|
# b) MQTT offline, but WiFi/network and Home Assistant API online:
|
||||||
|
# - Home Assistant text, light, number, and select entities should still work.
|
||||||
|
# - Clock display should continue using SNTP if the NTP servers are reachable.
|
||||||
|
#
|
||||||
|
# c) Entire WiFi/network offline:
|
||||||
|
# - SNTP will not be available after boot.
|
||||||
|
# - Clock display will use the current_mins fallback from common/sntp_common.yaml.
|
||||||
|
# - Accurate time is needed for the clock, so fallback time will drift.
|
||||||
|
# - For a rough reset, power-cycle the device at 12:00 noon.
|
||||||
|
# - Home Assistant and MQTT controls will not be available while offline.
|
||||||
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# SUBSTITUTIONS: Specific device variable substitutions
|
||||||
|
# If NOT using a secrets file, just replace these with the passwords etc in quotes.
|
||||||
|
#:########################################################################################:#
|
||||||
|
substitutions:
|
||||||
|
# Device Naming
|
||||||
|
device_name: "esp-ledmatrix1"
|
||||||
|
friendly_name: "LED Matrix Display"
|
||||||
|
description_comment: "LED Matrix Display (Layout V1.1)"
|
||||||
|
device_area: "Lounge" # Allows ESP device to be automatically linked to an Area in Home Assistant.
|
||||||
|
|
||||||
|
# Project Naming
|
||||||
|
project_name: "Generic.ESP32 Supermini"
|
||||||
|
project_version: "v1.1"
|
||||||
|
|
||||||
|
# Passwords & Secrets
|
||||||
|
api_key: !secret esp-api_key
|
||||||
|
ota_pass: !secret esp-ota_pass
|
||||||
|
static_ip_address: !secret esp-ledmatrix1_ip # Substitutions cannot be used inside secret names.
|
||||||
|
mqtt_command_main_topic: !secret mqtt_command_main_topic
|
||||||
|
mqtt_status_main_topic: !secret mqtt_status_main_topic
|
||||||
|
|
||||||
|
# If changing IP addresses, update current_ip_address here, otherwise it remains static_ip_address.
|
||||||
|
# Do not forget to switch it back when the address change is complete.
|
||||||
|
current_ip_address: ${static_ip_address}
|
||||||
|
|
||||||
|
# MQTT LOCAL Controls
|
||||||
|
mqtt_device_name: "ledmatrix1"
|
||||||
|
mqtt_command_topic: "${mqtt_command_main_topic}/${mqtt_device_name}"
|
||||||
|
mqtt_status_topic: "${mqtt_status_main_topic}/${mqtt_device_name}"
|
||||||
|
|
||||||
|
# Device Settings
|
||||||
|
log_level: "INFO" # NONE, ERROR, WARN, INFO, DEBUG, VERBOSE, VERY_VERBOSE
|
||||||
|
update_interval: "60s"
|
||||||
|
|
||||||
|
# Matrix Display Settings
|
||||||
|
pin_mosi: GPIO8
|
||||||
|
pin_cs: GPIO9
|
||||||
|
pin_sck: GPIO10
|
||||||
|
num_chips: "4"
|
||||||
|
scroll_delay_ms: "15" # ms between scroll steps
|
||||||
|
y_offset: "0"
|
||||||
|
y_scroll_offset: "0"
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# PACKAGES: Included Common Packages
|
||||||
|
# https://esphome.io/components/packages.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
packages:
|
||||||
|
#### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode ####
|
||||||
|
common_wifi: !include
|
||||||
|
file: common/network_common.yaml
|
||||||
|
vars:
|
||||||
|
local_device_name: "${device_name}"
|
||||||
|
local_static_ip_address: "${static_ip_address}"
|
||||||
|
local_ota_pass: "${ota_pass}"
|
||||||
|
local_current_ip_address: "${current_ip_address}"
|
||||||
|
|
||||||
|
#### HOME ASSISTANT API (choose encryption or no encryption options) ####
|
||||||
|
common_api: !include
|
||||||
|
file: common/api_common.yaml
|
||||||
|
#file: common/api_common_noencryption.yaml
|
||||||
|
vars:
|
||||||
|
local_api_key: "${api_key}"
|
||||||
|
|
||||||
|
#### MQTT ####
|
||||||
|
common_mqtt: !include
|
||||||
|
file: common/mqtt_common.yaml
|
||||||
|
vars:
|
||||||
|
local_device_name: "${device_name}"
|
||||||
|
|
||||||
|
#### WEB PORTAL ####
|
||||||
|
common_webportal: !include common/webportal_common.yaml
|
||||||
|
|
||||||
|
#### SNTP (Needed for the clock display) ####
|
||||||
|
common_sntp: !include common/sntp_common.yaml
|
||||||
|
|
||||||
|
#### DIAGNOSTICS Sensors ####
|
||||||
|
diag_basic: !include common/include_basic_diag_sensors.yaml
|
||||||
|
#diag_more: !include common/include_more_diag_sensors.yaml
|
||||||
|
#diag_debug: !include common/include_debug_diag_sensors.yaml
|
||||||
|
#diag_resetcount: !include common/include_resetcount_diag_sensors.yaml
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# ESPHOME:
|
||||||
|
# https://esphome.io/components/esphome.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
esphome:
|
||||||
|
name: "${device_name}"
|
||||||
|
friendly_name: "${friendly_name}"
|
||||||
|
comment: "${description_comment}" # Appears on the ESPHome page in Home Assistant.
|
||||||
|
area: "${device_area}"
|
||||||
|
project:
|
||||||
|
name: "${project_name}"
|
||||||
|
version: "${project_version}"
|
||||||
|
on_boot:
|
||||||
|
priority: 600
|
||||||
|
then:
|
||||||
|
# Ensure Home Assistant shows the text box as empty rather than unknown.
|
||||||
|
- delay: 500ms
|
||||||
|
- lambda: |-
|
||||||
|
id(ha_scroll_text).publish_state("");
|
||||||
|
- component.update: matrix
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# ESP PLATFORM AND FRAMEWORK:
|
||||||
|
# https://esphome.io/components/esp32/
|
||||||
|
#:########################################################################################:#
|
||||||
|
esp32:
|
||||||
|
variant: esp32c3
|
||||||
|
framework:
|
||||||
|
type: esp-idf
|
||||||
|
version: recommended
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# LOGGER: ESPHome Logging Enable
|
||||||
|
# https://esphome.io/components/logger.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
logger:
|
||||||
|
level: "${log_level}" # INFO suggested, or DEBUG for testing.
|
||||||
|
#baud_rate: 0 # Set to 0 for no UART logging if UART is used for another device.
|
||||||
|
#esp8266_store_log_strings_in_flash: false
|
||||||
|
#tx_buffer_size: 64
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# GLOBALS:
|
||||||
|
# https://esphome.io/components/globals.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
globals:
|
||||||
|
# Text currently being scrolled across the matrix.
|
||||||
|
- id: scroll_text
|
||||||
|
type: std::string
|
||||||
|
initial_value: ""
|
||||||
|
|
||||||
|
# Current X position of the scrolling text.
|
||||||
|
- id: scroll_x
|
||||||
|
type: int
|
||||||
|
initial_value: '0'
|
||||||
|
|
||||||
|
# True while a scroll message is active.
|
||||||
|
- id: scrolling
|
||||||
|
type: bool
|
||||||
|
initial_value: 'false'
|
||||||
|
|
||||||
|
# False = 24h mode, true = 12h mode.
|
||||||
|
- id: use_12h_mode
|
||||||
|
type: bool
|
||||||
|
restore_value: true
|
||||||
|
initial_value: 'false'
|
||||||
|
|
||||||
|
# Runtime scroll delay, controlled by the Scroll Delay number entity.
|
||||||
|
- id: scroll_delay_runtime
|
||||||
|
type: int
|
||||||
|
restore_value: true
|
||||||
|
initial_value: '${scroll_delay_ms}'
|
||||||
|
|
||||||
|
# MAX7219 intensity: 0=OFF, 1..15=ON. Driven by the HA light entity.
|
||||||
|
- id: matrix_intensity
|
||||||
|
type: int
|
||||||
|
restore_value: false
|
||||||
|
initial_value: '2'
|
||||||
|
|
||||||
|
# Brightness sync loop protection for HA light <-> MQTT brightness updates.
|
||||||
|
- id: suppress_mqtt_bright_sync
|
||||||
|
type: bool
|
||||||
|
restore_value: false
|
||||||
|
initial_value: 'false'
|
||||||
|
|
||||||
|
- id: target_mqtt_bright
|
||||||
|
type: int
|
||||||
|
restore_value: false
|
||||||
|
initial_value: '-1'
|
||||||
|
|
||||||
|
- id: last_mqtt_bright
|
||||||
|
type: int
|
||||||
|
restore_value: false
|
||||||
|
initial_value: '-1'
|
||||||
|
|
||||||
|
# Re-entry effect after scrolling: 0=Slide up, 1=Slide down, 2=Pixel fall.
|
||||||
|
- id: transition_mode
|
||||||
|
type: int
|
||||||
|
restore_value: true
|
||||||
|
initial_value: '0'
|
||||||
|
|
||||||
|
# Slide transition state.
|
||||||
|
- id: transition_active
|
||||||
|
type: bool
|
||||||
|
restore_value: false
|
||||||
|
initial_value: 'false'
|
||||||
|
|
||||||
|
- id: transition_y
|
||||||
|
type: int
|
||||||
|
restore_value: false
|
||||||
|
initial_value: '0'
|
||||||
|
|
||||||
|
# Pixel-fall transition state.
|
||||||
|
- id: pixel_fall_active
|
||||||
|
type: bool
|
||||||
|
restore_value: false
|
||||||
|
initial_value: 'false'
|
||||||
|
|
||||||
|
- id: pixel_fall_gen
|
||||||
|
type: int
|
||||||
|
restore_value: false
|
||||||
|
initial_value: '0'
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# FONT COMPONENT:
|
||||||
|
# https://esphome.io/components/font/
|
||||||
|
#:########################################################################################:#
|
||||||
|
font:
|
||||||
|
# Clock digits. Keep glyphs limited to reduce firmware size.
|
||||||
|
- file: "fonts/Eight-Bit-Dragon.ttf"
|
||||||
|
id: digit5
|
||||||
|
size: 8
|
||||||
|
glyphs: ["0123456789: -"]
|
||||||
|
|
||||||
|
# General 5x8 font for scroll text.
|
||||||
|
- file: "fonts/5x8.bdf"
|
||||||
|
id: font5x8
|
||||||
|
size: 8
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# SPI COMPONENT:
|
||||||
|
# https://esphome.io/components/spi.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
spi:
|
||||||
|
clk_pin: ${pin_sck}
|
||||||
|
mosi_pin: ${pin_mosi}
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# MQTT: Device-specific MQTT command triggers
|
||||||
|
# This adds device-specific MQTT command triggers to the common MQTT configuration.
|
||||||
|
#:########################################################################################:#
|
||||||
|
mqtt:
|
||||||
|
discovery: false
|
||||||
|
birth_message:
|
||||||
|
topic: "${mqtt_status_topic}/status"
|
||||||
|
payload: "online"
|
||||||
|
qos: 0
|
||||||
|
retain: true
|
||||||
|
will_message:
|
||||||
|
topic: "${mqtt_status_topic}/status"
|
||||||
|
payload: "offline"
|
||||||
|
qos: 0
|
||||||
|
retain: true
|
||||||
|
on_message:
|
||||||
|
# Scroll a text payload once across the matrix.
|
||||||
|
- topic: "${mqtt_command_topic}/scroll"
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
std::string s = x.c_str();
|
||||||
|
s.erase(std::remove(s.begin(), s.end(), '\r'), s.end());
|
||||||
|
s.erase(std::remove(s.begin(), s.end(), '\n'), s.end());
|
||||||
|
s.erase(std::remove_if(s.begin(), s.end(),
|
||||||
|
[](unsigned char c){ return c < 0x20; }), s.end());
|
||||||
|
|
||||||
|
// Ignore empty MQTT scroll commands completely.
|
||||||
|
if (s.empty()) return;
|
||||||
|
|
||||||
|
id(scroll_text) = s;
|
||||||
|
id(scroll_x) = ${num_chips} * 8;
|
||||||
|
id(start_scroll_sequence).execute();
|
||||||
|
|
||||||
|
# Set 12h or 24h clock mode from MQTT.
|
||||||
|
- topic: "${mqtt_command_topic}/mode"
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
if (x == "12") {
|
||||||
|
id(use_12h_mode) = true;
|
||||||
|
} else if (x == "24") {
|
||||||
|
id(use_12h_mode) = false;
|
||||||
|
}
|
||||||
|
- component.update: clock_format_select
|
||||||
|
- component.update: matrix
|
||||||
|
|
||||||
|
# Brightness from MQTT. 0=OFF, 1..15=ON brightness level.
|
||||||
|
- topic: "${mqtt_command_topic}/bright"
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
std::string s = x.c_str();
|
||||||
|
s.erase(std::remove_if(s.begin(), s.end(),
|
||||||
|
[](unsigned char c){ return c < 0x20 || c == 0x7F; }), s.end());
|
||||||
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
|
||||||
|
[](unsigned char ch){ return !std::isspace(ch); }));
|
||||||
|
s.erase(std::find_if(s.rbegin(), s.rend(),
|
||||||
|
[](unsigned char ch){ return !std::isspace(ch); }).base(), s.end());
|
||||||
|
|
||||||
|
if (s.empty() || !std::all_of(s.begin(), s.end(),
|
||||||
|
[](unsigned char c){ return std::isdigit(c); })) return;
|
||||||
|
|
||||||
|
int v = atoi(s.c_str());
|
||||||
|
if (v < 0) v = 0;
|
||||||
|
if (v > 15) v = 15;
|
||||||
|
|
||||||
|
id(suppress_mqtt_bright_sync) = true;
|
||||||
|
|
||||||
|
if (v == 0) {
|
||||||
|
id(matrix_light).turn_off().perform();
|
||||||
|
} else {
|
||||||
|
auto call = id(matrix_light).turn_on();
|
||||||
|
call.set_brightness((float) v / 15.0f);
|
||||||
|
call.perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
id(last_mqtt_bright) = v;
|
||||||
|
id(suppress_mqtt_bright_sync) = false;
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# TEXT COMPONENT:
|
||||||
|
# https://esphome.io/components/text/template/
|
||||||
|
#:########################################################################################:#
|
||||||
|
text:
|
||||||
|
- platform: template
|
||||||
|
id: ha_scroll_text
|
||||||
|
name: "${friendly_name} Scroll Text"
|
||||||
|
icon: "mdi:message-text-outline"
|
||||||
|
mode: text
|
||||||
|
max_length: 80
|
||||||
|
optimistic: false
|
||||||
|
set_action:
|
||||||
|
- lambda: |-
|
||||||
|
std::string s = x.c_str();
|
||||||
|
|
||||||
|
s.erase(std::remove(s.begin(), s.end(), '\r'), s.end());
|
||||||
|
s.erase(std::remove(s.begin(), s.end(), '\n'), s.end());
|
||||||
|
s.erase(std::remove_if(s.begin(), s.end(),
|
||||||
|
[](unsigned char c){ return c < 0x20; }), s.end());
|
||||||
|
|
||||||
|
// Publish the cleaned text so the HA UI updates immediately.
|
||||||
|
id(ha_scroll_text).publish_state(s.c_str());
|
||||||
|
|
||||||
|
// Empty text only clears the entity. It should not start a scroll.
|
||||||
|
if (s.empty()) return;
|
||||||
|
|
||||||
|
id(scroll_text) = s;
|
||||||
|
id(scroll_x) = ${num_chips} * 8;
|
||||||
|
id(start_scroll_sequence).execute();
|
||||||
|
id(clear_scroll_text_box).execute();
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# NUMBER COMPONENT:
|
||||||
|
# https://esphome.io/components/number/template/
|
||||||
|
#:########################################################################################:#
|
||||||
|
number:
|
||||||
|
- platform: template
|
||||||
|
id: scroll_delay_number
|
||||||
|
name: "${friendly_name} Scroll Delay"
|
||||||
|
icon: "mdi:timer-outline"
|
||||||
|
unit_of_measurement: "ms"
|
||||||
|
min_value: 1
|
||||||
|
max_value: 100
|
||||||
|
step: 1
|
||||||
|
restore_value: true
|
||||||
|
initial_value: ${scroll_delay_ms}
|
||||||
|
optimistic: true
|
||||||
|
set_action:
|
||||||
|
- lambda: |-
|
||||||
|
id(scroll_delay_runtime) = (int) x;
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# OUTPUT COMPONENT:
|
||||||
|
# https://esphome.io/components/output/
|
||||||
|
#:########################################################################################:#
|
||||||
|
output:
|
||||||
|
# Template output lets the HA light slider control MAX7219 intensity.
|
||||||
|
- platform: template
|
||||||
|
id: matrix_brightness_out
|
||||||
|
type: float
|
||||||
|
write_action:
|
||||||
|
- lambda: |-
|
||||||
|
int pub = 0;
|
||||||
|
|
||||||
|
if (state <= 0.001f) {
|
||||||
|
id(matrix_intensity) = 0;
|
||||||
|
id(matrix).turn_on_off(false);
|
||||||
|
pub = 0;
|
||||||
|
} else {
|
||||||
|
int v = (int) lroundf(state * 15.0f);
|
||||||
|
if (v < 1) v = 1;
|
||||||
|
if (v > 15) v = 15;
|
||||||
|
|
||||||
|
id(matrix_intensity) = v;
|
||||||
|
id(matrix).turn_on_off(true);
|
||||||
|
pub = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
id(target_mqtt_bright) = pub;
|
||||||
|
|
||||||
|
- component.update: matrix
|
||||||
|
|
||||||
|
# Publish brightness back to MQTT unless this update came from MQTT.
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: |-
|
||||||
|
return !id(suppress_mqtt_bright_sync)
|
||||||
|
&& (id(target_mqtt_bright) != id(last_mqtt_bright));
|
||||||
|
then:
|
||||||
|
- mqtt.publish:
|
||||||
|
topic: "${mqtt_command_topic}/bright"
|
||||||
|
payload: !lambda |-
|
||||||
|
char buf[6];
|
||||||
|
snprintf(buf, sizeof(buf), "%d", id(target_mqtt_bright));
|
||||||
|
return std::string(buf);
|
||||||
|
qos: 0
|
||||||
|
retain: true
|
||||||
|
- lambda: |-
|
||||||
|
id(last_mqtt_bright) = id(target_mqtt_bright);
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# LIGHT COMPONENT:
|
||||||
|
# https://esphome.io/components/light/monochromatic/
|
||||||
|
#:########################################################################################:#
|
||||||
|
light:
|
||||||
|
- platform: monochromatic
|
||||||
|
id: matrix_light
|
||||||
|
name: "${friendly_name} Display"
|
||||||
|
icon: "mdi:brightness-6"
|
||||||
|
output: matrix_brightness_out
|
||||||
|
gamma_correct: 1.0
|
||||||
|
default_transition_length: 0s
|
||||||
|
restore_mode: RESTORE_DEFAULT_ON
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# SELECT COMPONENT:
|
||||||
|
# https://esphome.io/components/select/template/
|
||||||
|
#:########################################################################################:#
|
||||||
|
select:
|
||||||
|
- platform: template
|
||||||
|
id: clock_format_select
|
||||||
|
name: "${friendly_name} Clock Format"
|
||||||
|
icon: "mdi:clock-time-three-outline"
|
||||||
|
options:
|
||||||
|
- "24"
|
||||||
|
- "12"
|
||||||
|
lambda: |-
|
||||||
|
return esphome::optional<std::string>(std::string(id(use_12h_mode) ? "12" : "24"));
|
||||||
|
set_action:
|
||||||
|
- lambda: |-
|
||||||
|
id(use_12h_mode) = (x == "12");
|
||||||
|
- component.update: clock_format_select
|
||||||
|
- component.update: matrix
|
||||||
|
|
||||||
|
- platform: template
|
||||||
|
id: transition_select
|
||||||
|
name: "${friendly_name} Transition Effect"
|
||||||
|
icon: "mdi:transition"
|
||||||
|
options:
|
||||||
|
- "Slide up"
|
||||||
|
- "Slide down"
|
||||||
|
- "Pixel fall"
|
||||||
|
lambda: |-
|
||||||
|
if (id(transition_mode) == 2) return std::string("Pixel fall");
|
||||||
|
if (id(transition_mode) == 1) return std::string("Slide down");
|
||||||
|
return std::string("Slide up");
|
||||||
|
set_action:
|
||||||
|
- lambda: |-
|
||||||
|
if (x == "Pixel fall") id(transition_mode) = 2;
|
||||||
|
else if (x == "Slide down") id(transition_mode) = 1;
|
||||||
|
else id(transition_mode) = 0;
|
||||||
|
- component.update: transition_select
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# SCRIPT COMPONENT:
|
||||||
|
# https://esphome.io/components/script.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
script:
|
||||||
|
# Clear the HA text box shortly after a scroll request has been accepted.
|
||||||
|
- id: clear_scroll_text_box
|
||||||
|
mode: restart
|
||||||
|
then:
|
||||||
|
- delay: 400ms
|
||||||
|
- lambda: |-
|
||||||
|
id(ha_scroll_text).publish_state("");
|
||||||
|
|
||||||
|
# Sequence: exit slide-down -> scroll -> selected re-entry.
|
||||||
|
- id: start_scroll_sequence
|
||||||
|
mode: restart
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(scrolling) = false;
|
||||||
|
id(pixel_fall_active) = false;
|
||||||
|
- component.update: matrix
|
||||||
|
- script.execute: clock_exit_down
|
||||||
|
- script.wait: clock_exit_down
|
||||||
|
- lambda: |-
|
||||||
|
id(scrolling) = true;
|
||||||
|
- script.execute: do_scroll
|
||||||
|
|
||||||
|
# Scroll the stored text until it has moved fully off the left side.
|
||||||
|
- id: do_scroll
|
||||||
|
mode: restart
|
||||||
|
then:
|
||||||
|
- while:
|
||||||
|
condition:
|
||||||
|
lambda: |-
|
||||||
|
return id(scrolling);
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(scroll_x) -= 1;
|
||||||
|
const int end_limit = - (int(id(scroll_text).length()) * 6);
|
||||||
|
if (id(scroll_x) < end_limit) {
|
||||||
|
id(scrolling) = false;
|
||||||
|
|
||||||
|
if (id(transition_mode) == 1) {
|
||||||
|
id(clock_slide_down_entry).execute();
|
||||||
|
} else if (id(transition_mode) == 2) {
|
||||||
|
id(clock_pixel_fall_transition).execute();
|
||||||
|
} else {
|
||||||
|
id(clock_slide_up_entry).execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- component.update: matrix
|
||||||
|
- delay: !lambda |-
|
||||||
|
return (uint32_t) id(scroll_delay_runtime);
|
||||||
|
|
||||||
|
# Exit: slide clock down off-screen and hold it there to prevent a one-frame flash.
|
||||||
|
- id: clock_exit_down
|
||||||
|
mode: restart
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(transition_active) = true;
|
||||||
|
id(transition_y) = ${y_offset};
|
||||||
|
- repeat:
|
||||||
|
count: 9
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(transition_y) += 1;
|
||||||
|
- component.update: matrix
|
||||||
|
- delay: 45ms
|
||||||
|
- lambda: |-
|
||||||
|
id(transition_active) = true;
|
||||||
|
id(transition_y) = 8;
|
||||||
|
- component.update: matrix
|
||||||
|
|
||||||
|
# Re-entry: clock slides down into place from above.
|
||||||
|
- id: clock_slide_down_entry
|
||||||
|
mode: restart
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(transition_active) = true;
|
||||||
|
id(transition_y) = -8;
|
||||||
|
- repeat:
|
||||||
|
count: 9
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(transition_y) += 1;
|
||||||
|
- component.update: matrix
|
||||||
|
- delay: 60ms
|
||||||
|
- lambda: |-
|
||||||
|
id(transition_active) = false;
|
||||||
|
id(transition_y) = ${y_offset};
|
||||||
|
- component.update: matrix
|
||||||
|
|
||||||
|
# Re-entry: clock slides up into place from below.
|
||||||
|
- id: clock_slide_up_entry
|
||||||
|
mode: restart
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(transition_active) = true;
|
||||||
|
id(transition_y) = 8;
|
||||||
|
- repeat:
|
||||||
|
count: 9
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(transition_y) -= 1;
|
||||||
|
- component.update: matrix
|
||||||
|
- delay: 60ms
|
||||||
|
- lambda: |-
|
||||||
|
id(transition_active) = false;
|
||||||
|
id(transition_y) = ${y_offset};
|
||||||
|
- component.update: matrix
|
||||||
|
|
||||||
|
# Re-entry: falling pixels effect before the clock redraws.
|
||||||
|
- id: clock_pixel_fall_transition
|
||||||
|
mode: restart
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(transition_active) = false;
|
||||||
|
id(transition_y) = ${y_offset};
|
||||||
|
id(pixel_fall_active) = true;
|
||||||
|
id(pixel_fall_gen) += 1;
|
||||||
|
- repeat:
|
||||||
|
count: 18
|
||||||
|
then:
|
||||||
|
- component.update: matrix
|
||||||
|
- delay: 55ms
|
||||||
|
- lambda: |-
|
||||||
|
id(pixel_fall_active) = false;
|
||||||
|
id(transition_active) = false;
|
||||||
|
id(transition_y) = ${y_offset};
|
||||||
|
- component.update: matrix
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# DISPLAY COMPONENT:
|
||||||
|
# https://esphome.io/components/display/max7219digit/
|
||||||
|
#:########################################################################################:#
|
||||||
|
display:
|
||||||
|
- platform: max7219digit
|
||||||
|
id: matrix
|
||||||
|
cs_pin: ${pin_cs}
|
||||||
|
num_chips: ${num_chips}
|
||||||
|
intensity: 2
|
||||||
|
update_interval: 500ms
|
||||||
|
rotate_chip: 0
|
||||||
|
reverse_enable: false
|
||||||
|
flip_x: false
|
||||||
|
|
||||||
|
lambda: |-
|
||||||
|
// Apply brightness only when it changes to reduce flicker.
|
||||||
|
static int last_brightness = -1;
|
||||||
|
if (id(matrix_intensity) != last_brightness) {
|
||||||
|
if (id(matrix_intensity) > 0) {
|
||||||
|
int v = id(matrix_intensity);
|
||||||
|
if (v > 15) v = 15;
|
||||||
|
it.intensity((uint8_t) v);
|
||||||
|
}
|
||||||
|
last_brightness = id(matrix_intensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id(matrix_intensity) == 0) return;
|
||||||
|
|
||||||
|
it.clear();
|
||||||
|
|
||||||
|
// Scroll text has priority over clock display.
|
||||||
|
if (id(scrolling)) {
|
||||||
|
it.print(id(scroll_x), ${y_scroll_offset}, id(font5x8), id(scroll_text).c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pixel fall shows only particles while active.
|
||||||
|
if (id(pixel_fall_active)) {
|
||||||
|
static int last_gen = -1;
|
||||||
|
static int px[24];
|
||||||
|
static int py[24];
|
||||||
|
static uint32_t rng = 1;
|
||||||
|
|
||||||
|
auto rand_u32 = [&]() -> uint32_t {
|
||||||
|
rng = rng * 1664525u + 1013904223u;
|
||||||
|
return rng;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (last_gen != id(pixel_fall_gen)) {
|
||||||
|
last_gen = id(pixel_fall_gen);
|
||||||
|
rng = 0xA5A5A5A5u ^ (uint32_t) id(pixel_fall_gen);
|
||||||
|
for (int i = 0; i < 24; i++) {
|
||||||
|
px[i] = (int)(rand_u32() % 32);
|
||||||
|
py[i] = - (int)(rand_u32() % 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 24; i++) {
|
||||||
|
int spd = 1 + (int)(rand_u32() % 2);
|
||||||
|
py[i] += spd;
|
||||||
|
|
||||||
|
if (py[i] > 10) {
|
||||||
|
px[i] = (int)(rand_u32() % 32);
|
||||||
|
py[i] = - (int)(rand_u32() % 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int t = 0; t < 2; t++) {
|
||||||
|
int yy = py[i] - t;
|
||||||
|
int xx = px[i];
|
||||||
|
if (xx >= 0 && xx <= 31 && yy >= 0 && yy <= 7) {
|
||||||
|
it.draw_pixel_at(xx, yy, Color::WHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prefer real SNTP time. Fall back to current_mins from common/sntp_common.yaml.
|
||||||
|
auto now = id(sntp_time).now();
|
||||||
|
bool time_valid = now.is_valid();
|
||||||
|
|
||||||
|
int raw_hour = 0;
|
||||||
|
int minute_to_show = 0;
|
||||||
|
int second_to_show = 0;
|
||||||
|
|
||||||
|
if (time_valid) {
|
||||||
|
raw_hour = now.hour;
|
||||||
|
minute_to_show = now.minute;
|
||||||
|
second_to_show = now.second;
|
||||||
|
} else {
|
||||||
|
int mins = id(current_mins);
|
||||||
|
if (mins < 0) mins = 0;
|
||||||
|
if (mins >= 1440) mins = mins % 1440;
|
||||||
|
|
||||||
|
raw_hour = mins / 60;
|
||||||
|
minute_to_show = mins % 60;
|
||||||
|
second_to_show = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hour_to_show = raw_hour;
|
||||||
|
if (id(use_12h_mode)) {
|
||||||
|
hour_to_show = raw_hour % 12;
|
||||||
|
if (hour_to_show == 0) hour_to_show = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
char hh[3], mm[3];
|
||||||
|
snprintf(hh, sizeof(hh), "%02d", hour_to_show);
|
||||||
|
snprintf(mm, sizeof(mm), "%02d", minute_to_show);
|
||||||
|
|
||||||
|
const int x_h1 = 3;
|
||||||
|
const int x_h2 = 9;
|
||||||
|
const int x_m1 = 17;
|
||||||
|
const int x_m2 = 23;
|
||||||
|
|
||||||
|
const int y = (id(transition_active) ? id(transition_y) : ${y_offset});
|
||||||
|
|
||||||
|
char ch[2] = { hh[0], 0 };
|
||||||
|
it.print(x_h1, y, id(digit5), ch);
|
||||||
|
ch[0] = hh[1];
|
||||||
|
it.print(x_h2, y, id(digit5), ch);
|
||||||
|
|
||||||
|
ch[0] = mm[0];
|
||||||
|
it.print(x_m1, y, id(digit5), ch);
|
||||||
|
ch[0] = mm[1];
|
||||||
|
it.print(x_m2, y, id(digit5), ch);
|
||||||
|
|
||||||
|
// In 12h mode, draw a tiny A or P indicator at the far right.
|
||||||
|
if (id(use_12h_mode)) {
|
||||||
|
const bool is_pm = raw_hour >= 12;
|
||||||
|
|
||||||
|
const uint8_t A_rows[4] = { 2, 5, 7, 5 };
|
||||||
|
const uint8_t P_rows[4] = { 6, 5, 6, 4 };
|
||||||
|
const uint8_t *L = is_pm ? P_rows : A_rows;
|
||||||
|
|
||||||
|
const int x_ampm = 29;
|
||||||
|
const int y_ampm = y + 4;
|
||||||
|
|
||||||
|
for (int r = 0; r < 4; r++) {
|
||||||
|
uint8_t row = L[r];
|
||||||
|
for (int c = 0; c < 3; c++) {
|
||||||
|
if (row & (1 << (2 - c))) {
|
||||||
|
int xx = x_ampm + c;
|
||||||
|
int yy = y_ampm + r;
|
||||||
|
if (yy >= 0 && yy <= 7 && xx >= 0 && xx <= 31) {
|
||||||
|
it.draw_pixel_at(xx, yy, Color::WHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blink the colon when SNTP is valid. Keep it solid during fallback time.
|
||||||
|
const bool colon_on = time_valid ? ((second_to_show % 2) == 0) : true;
|
||||||
|
if (colon_on) {
|
||||||
|
const int x_col = (x_h2 + x_m1) / 2 + 2;
|
||||||
|
int y1 = y + 2;
|
||||||
|
int y2 = y + 5;
|
||||||
|
if (y1 >= 0 && y1 <= 7) it.draw_pixel_at(x_col, y1, Color::WHITE);
|
||||||
|
if (y2 >= 0 && y2 <= 7) it.draw_pixel_at(x_col, y2, Color::WHITE);
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
#:########################################################################################:#
|
||||||
|
# TITLE: MASTER BEDROOM NSPANEL 1
|
||||||
|
# zorruno.com layout v1.1 2026
|
||||||
|
#:########################################################################################:#
|
||||||
|
# REPO:
|
||||||
|
#
|
||||||
|
#:########################################################################################:#
|
||||||
|
# VERSIONS:
|
||||||
|
# V1.0 2026-05-16 Initial version
|
||||||
|
#:########################################################################################:#
|
||||||
|
# HARDWARE:
|
||||||
|
# - Sonoff NS Panel
|
||||||
|
#:########################################################################################:#
|
||||||
|
# OPERATION NOTES:
|
||||||
|
# -
|
||||||
|
#:########################################################################################:#
|
||||||
|
# OFFLINE NOTES:
|
||||||
|
#
|
||||||
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# SUBSTITUTIONS: Specific device variable substitutions
|
||||||
|
# If NOT using a secrets file, just replace these with the passwords etc (in quotes)
|
||||||
|
#:########################################################################################:#
|
||||||
|
substitutions:
|
||||||
|
# Device Naming
|
||||||
|
device_name: "esp-nspanel1masterbdrm"
|
||||||
|
friendly_name: "Master Bedroom NSPanel Touchscreen"
|
||||||
|
description_comment: "Master Bedroom NSPanel Touchscreen"
|
||||||
|
device_area: "Master Bedroom" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant.
|
||||||
|
|
||||||
|
# Removed as the remote package will pull this in correctly for the blueprint
|
||||||
|
# Project Naming
|
||||||
|
#project_name: "Lounge NSPanel Touchscreen.Sonoff NS Panel"
|
||||||
|
#project_version: "v1.0"
|
||||||
|
|
||||||
|
# Passwords & Secrets (unfortunately you can't use substitutions inside secrets names)
|
||||||
|
api_key: !secret esp-api_key
|
||||||
|
ota_pass: !secret esp-ota_pass
|
||||||
|
ota_password: "${ota_pass}" #this is for NSPanel Only as a workaround
|
||||||
|
static_ip_address: !secret esp-nspanel1masterbdrm_ip
|
||||||
|
|
||||||
|
# If we are changing IP addresses, you must update the current IP address here, otherwise it remains
|
||||||
|
# Don't forget to switch it back when changed.
|
||||||
|
current_ip_address: ${static_ip_address}
|
||||||
|
|
||||||
|
# Device Settings
|
||||||
|
log_level: "INFO" # NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE
|
||||||
|
update_interval: "60s" # update time for general sensors etc
|
||||||
|
|
||||||
|
## NSPanel Specifics
|
||||||
|
upload_tft_automatically: true
|
||||||
|
boot_sound: false
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# PACKAGES: Included Common Packages
|
||||||
|
# https://esphome.io/components/packages.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
packages:
|
||||||
|
#### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode ####
|
||||||
|
common_wifi: !include
|
||||||
|
file: common/network_common_esp32.yaml
|
||||||
|
vars:
|
||||||
|
local_device_name: "${device_name}"
|
||||||
|
local_static_ip_address: "${static_ip_address}"
|
||||||
|
local_ota_pass: "${ota_pass}"
|
||||||
|
local_current_ip_address: "${current_ip_address}"
|
||||||
|
|
||||||
|
#### HOME ASSISTANT API (choose encryption or no encryption options) ####
|
||||||
|
#common_api: !include
|
||||||
|
# file: common/api_common.yaml
|
||||||
|
# #file: common/api_common_noencryption.yaml
|
||||||
|
# vars:
|
||||||
|
# local_api_key: "${api_key}"
|
||||||
|
|
||||||
|
#### MQTT ####
|
||||||
|
#common_mqtt: !include
|
||||||
|
# file: common/mqtt_common.yaml
|
||||||
|
# vars:
|
||||||
|
# local_device_name: "${device_name}"
|
||||||
|
|
||||||
|
#### WEB PORTAL ####
|
||||||
|
#common_webportal: !include common/webportal_common.yaml
|
||||||
|
|
||||||
|
#### SNTP (Only use if you want/need accurate timeclocks) ####
|
||||||
|
#common_sntp: !include common/sntp_common.yaml
|
||||||
|
|
||||||
|
#### DIAGNOSTICS Sensors ####
|
||||||
|
#diag_basic: !include common/include_basic_diag_sensors.yaml
|
||||||
|
#diag_more: !include common/include_more_diag_sensors.yaml
|
||||||
|
#diag_debug: !include common/include_debug_diag_sensors.yaml
|
||||||
|
#diag_resetcount: !include common/include_resetcount_diag_sensors.yaml
|
||||||
|
|
||||||
|
# Core and optional configurations
|
||||||
|
remote_package:
|
||||||
|
url: https://github.com/edwardtfn/NSPanel-Easy
|
||||||
|
ref: v2026.5.5
|
||||||
|
refresh: 300s
|
||||||
|
files:
|
||||||
|
- nspanel_esphome.yaml # Basic package
|
||||||
|
# Optional advanced and add-on configurations
|
||||||
|
# - esphome/nspanel_esphome_addon_climate_cool.yaml
|
||||||
|
# - esphome/nspanel_esphome_addon_climate_heat.yaml
|
||||||
|
# - esphome/nspanel_esphome_addon_climate_dual.yaml
|
||||||
|
# - esphome/nspanel_esphome_addon_cover.yaml
|
||||||
|
# - esphome/nspanel_esphome_addon_display_light.yaml # Show the display as a light in Home Assistant
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# ESPHOME:
|
||||||
|
# https://esphome.io/components/esphome.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
esphome:
|
||||||
|
name: "${device_name}"
|
||||||
|
friendly_name: "${friendly_name}"
|
||||||
|
comment: "${description_comment}" # appears on the esphome page in HA
|
||||||
|
area: "${device_area}"
|
||||||
|
min_version: 2024.6.0
|
||||||
|
#project:
|
||||||
|
# name: "${project_name}"
|
||||||
|
# version: "${project_version}"
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# ESP PLATFORM AND FRAMEWORK:
|
||||||
|
# https://esphome.io/components/esp32.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
esp32:
|
||||||
|
board: esp32dev
|
||||||
|
framework:
|
||||||
|
type: esp-idf # Suggested ESP-IDF framework
|
||||||
|
version: recommended
|
||||||
|
advanced:
|
||||||
|
#minimum_chip_revision: "3.1" # This makes the binary slightly smaller
|
||||||
|
sram1_as_iram: true
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# LOGGING:
|
||||||
|
# https://esphome.io/components/logger.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
logger:
|
||||||
|
level: "${log_level}"
|
||||||
|
#baud_rate: 0 # set to 0 for no logging via UART if you want
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# BLUETOOTH:
|
||||||
|
# https://esphome.io/components/bluetooth_proxy.html
|
||||||
|
# https://esphome.io/components/esp32_ble_tracker.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
#bluetooth_proxy:
|
||||||
|
# active: true
|
||||||
|
|
||||||
|
#esp32_ble_tracker:
|
||||||
|
# scan_parameters:
|
||||||
|
# # Defaults used so Bluetooth can co-exist with WiFi
|
||||||
|
# active: true
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
#:########################################################################################:#
|
||||||
|
# TITLE: LOUNGE NSPANEL 2
|
||||||
|
# zorruno.com layout v1.1 2026
|
||||||
|
#:########################################################################################:#
|
||||||
|
# REPO:
|
||||||
|
#
|
||||||
|
#:########################################################################################:#
|
||||||
|
# VERSIONS:
|
||||||
|
# V1.0 2026-05-16 Initial version
|
||||||
|
#:########################################################################################:#
|
||||||
|
# HARDWARE:
|
||||||
|
# - Sonoff NS Panel
|
||||||
|
#:########################################################################################:#
|
||||||
|
# OPERATION NOTES:
|
||||||
|
# -
|
||||||
|
#:########################################################################################:#
|
||||||
|
# OFFLINE NOTES:
|
||||||
|
#
|
||||||
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# SUBSTITUTIONS: Specific device variable substitutions
|
||||||
|
# If NOT using a secrets file, just replace these with the passwords etc (in quotes)
|
||||||
|
#:########################################################################################:#
|
||||||
|
substitutions:
|
||||||
|
# Device Naming
|
||||||
|
device_name: "esp-nspanel2lounge"
|
||||||
|
friendly_name: "Lounge NSPanel Touchscreen"
|
||||||
|
description_comment: "D1 Mini ESP32 outside entranceway with BT Proxy (Layout V1.1)"
|
||||||
|
device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant.
|
||||||
|
|
||||||
|
# Removed as the remote package will pull this in correctly for the blueprint
|
||||||
|
# Project Naming
|
||||||
|
#project_name: "Lounge NSPanel Touchscreen.Sonoff NS Panel"
|
||||||
|
#project_version: "v1.0"
|
||||||
|
|
||||||
|
# Passwords & Secrets (unfortunately you can't use substitutions inside secrets names)
|
||||||
|
api_key: !secret esp-api_key
|
||||||
|
ota_pass: !secret esp-ota_pass
|
||||||
|
ota_password: "${ota_pass}" #this is for NSPanel Only as a workaround
|
||||||
|
static_ip_address: !secret esp-nspanel2lounge_ip
|
||||||
|
|
||||||
|
# If we are changing IP addresses, you must update the current IP address here, otherwise it remains
|
||||||
|
# Don't forget to switch it back when changed.
|
||||||
|
current_ip_address: ${static_ip_address}
|
||||||
|
|
||||||
|
# Device Settings
|
||||||
|
log_level: "INFO" # NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE
|
||||||
|
update_interval: "60s" # update time for general sensors etc
|
||||||
|
|
||||||
|
## NSPanel Specifics
|
||||||
|
upload_tft_automatically: true
|
||||||
|
boot_sound: false
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# PACKAGES: Included Common Packages
|
||||||
|
# https://esphome.io/components/packages.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
packages:
|
||||||
|
#### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode ####
|
||||||
|
common_wifi: !include
|
||||||
|
file: common/network_common_esp32.yaml
|
||||||
|
vars:
|
||||||
|
local_device_name: "${device_name}"
|
||||||
|
local_static_ip_address: "${static_ip_address}"
|
||||||
|
local_ota_pass: "${ota_pass}"
|
||||||
|
local_current_ip_address: "${current_ip_address}"
|
||||||
|
|
||||||
|
#### HOME ASSISTANT API (choose encryption or no encryption options) ####
|
||||||
|
#common_api: !include
|
||||||
|
# file: common/api_common.yaml
|
||||||
|
#file: common/api_common_noencryption.yaml
|
||||||
|
# vars:
|
||||||
|
# local_api_key: "${api_key}"
|
||||||
|
|
||||||
|
#### MQTT ####
|
||||||
|
#common_mqtt: !include
|
||||||
|
# file: common/mqtt_common.yaml
|
||||||
|
# vars:
|
||||||
|
# local_device_name: "${device_name}"
|
||||||
|
|
||||||
|
#### WEB PORTAL ####
|
||||||
|
#common_webportal: !include common/webportal_common.yaml
|
||||||
|
|
||||||
|
#### SNTP (Only use if you want/need accurate timeclocks) ####
|
||||||
|
#common_sntp: !include common/sntp_common.yaml
|
||||||
|
|
||||||
|
#### DIAGNOSTICS Sensors ####
|
||||||
|
#diag_basic: !include common/include_basic_diag_sensors.yaml
|
||||||
|
#diag_more: !include common/include_more_diag_sensors.yaml
|
||||||
|
#diag_debug: !include common/include_debug_diag_sensors.yaml
|
||||||
|
#diag_resetcount: !include common/include_resetcount_diag_sensors.yaml
|
||||||
|
|
||||||
|
# Core and optional configurations
|
||||||
|
remote_package:
|
||||||
|
url: https://github.com/edwardtfn/NSPanel-Easy
|
||||||
|
ref: v2026.5.5
|
||||||
|
refresh: 300s
|
||||||
|
files:
|
||||||
|
- nspanel_esphome.yaml # Basic package
|
||||||
|
# Optional advanced and add-on configurations
|
||||||
|
# - esphome/nspanel_esphome_addon_climate_cool.yaml
|
||||||
|
# - esphome/nspanel_esphome_addon_climate_heat.yaml
|
||||||
|
# - esphome/nspanel_esphome_addon_climate_dual.yaml
|
||||||
|
# - esphome/nspanel_esphome_addon_cover.yaml
|
||||||
|
# - esphome/nspanel_esphome_addon_display_light.yaml # Show the display as a light in Home Assistant
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# ESPHOME:
|
||||||
|
# https://esphome.io/components/esphome.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
esphome:
|
||||||
|
name: "${device_name}"
|
||||||
|
friendly_name: "${friendly_name}"
|
||||||
|
comment: "${description_comment}" # appears on the esphome page in HA
|
||||||
|
area: "${device_area}"
|
||||||
|
min_version: 2024.6.0
|
||||||
|
#project:
|
||||||
|
# name: "${project_name}"
|
||||||
|
# version: "${project_version}"
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# ESP PLATFORM AND FRAMEWORK:
|
||||||
|
# https://esphome.io/components/esp32.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
esp32:
|
||||||
|
board: esp32dev
|
||||||
|
framework:
|
||||||
|
type: esp-idf # Suggested ESP-IDF framework
|
||||||
|
version: recommended
|
||||||
|
advanced:
|
||||||
|
minimum_chip_revision: "3.1" # This makes the binary slightly smaller
|
||||||
|
sram1_as_iram: true
|
||||||
|
|
||||||
|
|
||||||
|
#uart:
|
||||||
|
# id: tf_uart
|
||||||
|
# tx_pin: GPIO16
|
||||||
|
# rx_pin: GPIO17
|
||||||
|
# baud_rate: 115200
|
||||||
|
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# LOGGING:
|
||||||
|
# https://esphome.io/components/logger.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
logger:
|
||||||
|
level: "${log_level}"
|
||||||
|
#baud_rate: 0 # set to 0 for no logging via UART if you want
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# HOME ASSISTANT STATE IMPORT:
|
||||||
|
# Import the last remembered lounge scene from Home Assistant.
|
||||||
|
#:########################################################################################:#
|
||||||
|
text_sensor:
|
||||||
|
- platform: homeassistant
|
||||||
|
id: lounge_last_scene
|
||||||
|
entity_id: input_text.lounge_last_scene
|
||||||
|
internal: true
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# NSPANEL BUTTON / RELAY LABELS:
|
||||||
|
# Extend existing NSPanel Easy entities rather than redefining GPIOs.
|
||||||
|
#:########################################################################################:#
|
||||||
|
binary_sensor:
|
||||||
|
- id: !extend right_button
|
||||||
|
name: "Lounge Stair Downlights Button"
|
||||||
|
|
||||||
|
switch:
|
||||||
|
- id: !extend relay_2
|
||||||
|
name: "Lounge Stair Downlights"
|
||||||
|
|
||||||
|
- platform: template
|
||||||
|
id: nspanel_ha_loss_test
|
||||||
|
name: "HA Loss Test"
|
||||||
|
optimistic: true
|
||||||
|
restore_mode: RESTORE_DEFAULT_OFF
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# NSPANEL HARDWARE BUTTON LOCAL / HA ACTIONS:
|
||||||
|
#
|
||||||
|
# Behaviour:
|
||||||
|
# - HA connected and HA Loss Test OFF:
|
||||||
|
# - Left button toggles lounge scene between Bright and All Off
|
||||||
|
# - Left relay is forced ON
|
||||||
|
# - Right button toggles Relay 2 / Lounge Stair Downlights
|
||||||
|
#
|
||||||
|
# - HA disconnected OR HA Loss Test ON:
|
||||||
|
# - Left button toggles Relay 1
|
||||||
|
# - Right button toggles Relay 2 / Lounge Stair Downlights
|
||||||
|
#
|
||||||
|
# Notes:
|
||||||
|
# - Uses NSPanel Easy script IDs and relay IDs.
|
||||||
|
# - Avoid enabling Relay 1 local mode in the NSPanel blueprint, otherwise the package
|
||||||
|
# may toggle Relay 1 before this custom logic can handle the press.
|
||||||
|
#:########################################################################################:#
|
||||||
|
script:
|
||||||
|
- id: nspanel_lounge_force_left_relay_on_when_ha_connected
|
||||||
|
mode: restart
|
||||||
|
then:
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: |-
|
||||||
|
const bool actual_ha_online =
|
||||||
|
wifi_component->is_connected() &&
|
||||||
|
api_server->is_connected_with_state_subscription();
|
||||||
|
|
||||||
|
const bool effective_ha_online =
|
||||||
|
actual_ha_online && !id(nspanel_ha_loss_test).state;
|
||||||
|
|
||||||
|
return effective_ha_online;
|
||||||
|
then:
|
||||||
|
- switch.turn_on: relay_1
|
||||||
|
|
||||||
|
- id: nspanel_lounge_left_button_action
|
||||||
|
mode: restart
|
||||||
|
then:
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: |-
|
||||||
|
const bool actual_ha_online =
|
||||||
|
wifi_component->is_connected() &&
|
||||||
|
api_server->is_connected_with_state_subscription();
|
||||||
|
|
||||||
|
const bool effective_ha_online =
|
||||||
|
actual_ha_online && !id(nspanel_ha_loss_test).state;
|
||||||
|
|
||||||
|
return effective_ha_online;
|
||||||
|
then:
|
||||||
|
- script.execute: nspanel_lounge_force_left_relay_on_when_ha_connected
|
||||||
|
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: |-
|
||||||
|
return id(lounge_last_scene).has_state() &&
|
||||||
|
id(lounge_last_scene).state != "All Off";
|
||||||
|
then:
|
||||||
|
- homeassistant.action:
|
||||||
|
action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "All Off"
|
||||||
|
else:
|
||||||
|
- homeassistant.action:
|
||||||
|
action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Bright"
|
||||||
|
|
||||||
|
else:
|
||||||
|
- lambda: |-
|
||||||
|
const bool actual_ha_online =
|
||||||
|
wifi_component->is_connected() &&
|
||||||
|
api_server->is_connected_with_state_subscription();
|
||||||
|
|
||||||
|
// If NSPanel Easy relay local mode already handled the press, do not double toggle.
|
||||||
|
if (id(hardware_settings).relay1_local) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is a real HA/API outage and NSPanel Easy fallback already handled it,
|
||||||
|
// do not double toggle. HA Loss Test still toggles here because HA is actually online.
|
||||||
|
if (id(hardware_settings).relay1_fallback && !actual_ha_online) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
relay_1->toggle();
|
||||||
|
|
||||||
|
- id: nspanel_lounge_right_button_action
|
||||||
|
mode: restart
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
const bool actual_ha_online =
|
||||||
|
wifi_component->is_connected() &&
|
||||||
|
api_server->is_connected_with_state_subscription();
|
||||||
|
|
||||||
|
// If NSPanel Easy relay local mode already handled the press, do not double toggle.
|
||||||
|
if (id(hardware_settings).relay2_local) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is a real HA/API outage and NSPanel Easy fallback already handled it,
|
||||||
|
// do not double toggle. HA Loss Test still toggles here because HA is actually online.
|
||||||
|
if (id(hardware_settings).relay2_fallback && !actual_ha_online) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
relay_2->toggle();
|
||||||
|
|
||||||
|
- id: !extend button_left_press_short
|
||||||
|
then:
|
||||||
|
- script.execute: nspanel_lounge_left_button_action
|
||||||
|
|
||||||
|
- id: !extend button_right_press_short
|
||||||
|
then:
|
||||||
|
- script.execute: nspanel_lounge_right_button_action
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# INTERVAL:
|
||||||
|
# Keep Relay 1 ON whenever Home Assistant is effectively connected.
|
||||||
|
#:########################################################################################:#
|
||||||
|
interval:
|
||||||
|
- interval: 5s
|
||||||
|
then:
|
||||||
|
- script.execute: nspanel_lounge_force_left_relay_on_when_ha_connected
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# BLUETOOTH:
|
||||||
|
# https://esphome.io/components/bluetooth_proxy.html
|
||||||
|
# https://esphome.io/components/esp32_ble_tracker.html
|
||||||
|
#:########################################################################################:#
|
||||||
|
#bluetooth_proxy:
|
||||||
|
# active: true
|
||||||
|
|
||||||
|
#esp32_ble_tracker:
|
||||||
|
# scan_parameters:
|
||||||
|
# # Defaults used so Bluetooth can co-exist with WiFi
|
||||||
|
# active: true
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><link rel="canonical" href="https://www.freebestfonts.com/eight-bit-dragon-font"/>
|
||||||
|
|
||||||
|
<title>Eight Bit Dragon free font</title><link href="/Content/Site.css" rel="stylesheet" type="text/css">
|
||||||
|
<meta name="description" content="Eight Bit Dragon font download " />
|
||||||
|
<meta name="keywords" content="Eight Bit Dragon, Eight Bit Dragon font, Eight Bit Dragon fonts, Eight Bit Dragon font download, Eight Bit Dragon free font" />
|
||||||
|
<link rel="shortcut icon" href="/favicon.ico"><link rel="dns-prefetch" href="https://www.freebestfonts.com"><link rel="dns-prefetch" href="//ajax.googleapis.com"><link rel="dns-prefetch" href="https://pagead2.googlesyndication.com"><link rel="dns-prefetch" href="https://www.google.com"><link rel="dns-prefetch" href="https://www.googletagservices.com"><link rel="dns-prefetch" href="https://securepubads.g.doubleclick.net"><link rel="dns-prefetch" href="https://fonts.googleapis.com"><link rel="dns-prefetch" href="https://cdn.insurads.com"><link rel="dns-prefetch" href="https://cdnjs.cloudflare.com"><link rel="dns-prefetch" href="https://tpc.googlesyndication.com">
|
||||||
|
</head><body>
|
||||||
|
<form action="/eight-bit-dragon-font" enctype="multipart/form-data" method="post"><header><div class="logoZe"><a href="/" class="logo" title="free best fonts"><img src="/images/best-free-fonts.jpg" width="159" height="156" alt="Free Best Fonts"/></a></div><div class="loYa"><div class="arama"><label><input name="araText" id="araText" type="text" placeholder="" tabindex="0"/></label><input id="Button1" type="submit" value="Search"/></div><nav class="menuUl"><a href="/new-fonts" title="New Fonts">New Fonts</a><a href="/free-fonts-1001" title="1001 Free Fonts">1001 Free Fonts</a><a href="/fonts-google" title="Google Fonts">Google Fonts</a><a href="/free-font-family" title="Font Family">Font Family</a></nav></div></header><div class="fontOrta"><div class="oniz"><table><tr><th>Preview</th><th>Size</th><th>Fonts</th><th></th></tr><tr><td><input name="oniz" id="oniz" type="text" placeholder="Text" value="" /></td><td><select id="fontSz" name="fontSz"><option value="30">Small</option><option value="60" selected>Medium</option><option value="85">Large</option></select></td><td><select id="rowsCount" name="rowsCount" ><option value="12" >12</option><option value="24" >24</option><option value="48" >48</option></select></td><td><input id="Button1" type="submit" /></td></tr></table></div><div class="fntLst01"><div class="sonE"><h3 class="sola"><strong>Eight Bit Dragon</strong> - .TTF</h3><a class='sola' href="lcd-free-fonts"> Lcd - Modern</a><span class='sola'></span><div class="fntSag"><span class="say">13279 Downloads</span><a class="down" href="/download?fn=7414" title="Eight Bit Dragon download"> Download</a></div></div><div class="fntLst03"><div class="prev1" style="background-image:url(/yone/fontsim/Eight-Bit-Dragon.jpg);"></div></div></div><div class="aciklama"><h1>Eight Bit Dragon Lcd - Modern</h1><h2>Eight Bit Dragon font</h2><img loading="lazy" width="950" height="550" alt='Eight Bit Dragon font' src='/yone/prev/eight-bit-dragon.jpg'/><img loading="lazy" width="950" height="550" alt='Eight Bit Dragon font big' src='/yone/prev/eight-bit-dragon-b.jpg'/><img loading="lazy" width="950" height="550" alt='Eight Bit Dragon font text' src='/yone/prev/eight-bit-dragon-text.jpg'/><img loading="lazy" width="950" height="550" alt='Eight Bit Dragon font 1' src='/yone/prev/eight-bit-dragon-1.jpg'/><table><tr><th><strong>Font Name</strong></th><th><strong>Date</strong></th><th><strong>File Size</strong></th></tr><tr><td>eight_bit_dragon.png</td><td> 2018-10-10</td><td> 8 KB</td></tr><tr><td>Eight-Bit-Dragon.ttf</td><td> 2018-10-10</td><td> 34 KB</td></tr></table></div><hr /><div class="aciklama"><div class="prev2" style="background-image:url(https://www.freebestfonts.com/yone/fontharf/Eight-Bit-Dragon.jpg);"></div><hr /><h2>Font Details</h2><p>Concielian Classic version 2 Truetype Font for Windows<br><br><br><br>2017 Iconian Fonts - Daniel Zadorozny<br><br>http://www.iconian.com/<br><br><br><br>This font comes with the following 5 versions: Regular, Bold, Condensed, Expanded and 3d.<br><br><br>This font may be freely distributed and is free for all non-commercial uses. Use of the fonts are at your own risk.<br><br>For commercial use of the font please visit http://iconian.com/commercial.html for additional information.<br><br>or e-mail me at iconian@aol.com<br></p> Eight Bit Dragonfont download, Eight Bit Dragon font.</div></div></form>;
|
||||||
|
<div class="reklam04_1"></div>
|
||||||
|
<div class="reklam05_1"></div>
|
||||||
|
<footer><p>© 2026 - Best Free Fonts - Best Fonts</p></footer>
|
||||||
|
<!-- Global site tag (gtag.js) - Google Analytics --><script async src="https://www.googletagmanager.com/gtag/js?id=UA-131832151-1"></script><script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-131832151-1');</script><script data-ad-client="ca-pub-2059603307933699" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> </body>
|
||||||
|
</html>
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
downstairs_flat_lights:
|
|
||||||
name: Downstairs Flat Lights
|
|
||||||
# All the lights in the Downstairs flat
|
|
||||||
# Doesn't include the outdoor switch lights, or bedroom wardrobe light
|
|
||||||
entities:
|
|
||||||
- switch.esp_downstloungemain_relay_1_main_lights # Lounge Main Lights
|
|
||||||
- switch.esp_downstloungemain_relay_2_back_wall_lights # Lounge Back Wall Lights
|
|
||||||
- switch.esp_downstmasterbedrmlights_relay_1_main_lights # Main Bedroom, Main Lights
|
|
||||||
- switch.esp_downstbedrm2lights_relay_1_main_lights # Small Bedroom Room Lights
|
|
||||||
- switch.esp_downstkitchlights_relay_2_kitchen_light # Kitchen Lights
|
|
||||||
- switch.esp_downstkitchlights_relay_1_dining_light # Dining Lights
|
|
||||||
- switch.esp_downstbathswitch_relay_1_main_lights # Bathroom main lights
|
|
||||||
- switch.esp_downstbathswitch_relay_2_cabinet_light # Bathroom Cabinet Lights
|
|
||||||
|
|
||||||
@@ -0,0 +1,389 @@
|
|||||||
|
# yaml-language-server: $schema=null
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# PACKAGE: 16A EV Charger Control
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# VERSION:
|
||||||
|
# V1.1 2026-05-15
|
||||||
|
# - Reworked 1hr topup logic to use a hard deadline and watchdog.
|
||||||
|
# - Removed dependency on timer.finished event for relay shutoff.
|
||||||
|
# - Offpeak until charged now continues past offpeak end until charging stops.
|
||||||
|
# - 1hr topup now now rolls into Normal Offpeak if the hour ends during
|
||||||
|
# the offpeak window, without switching the relay off and back on.
|
||||||
|
#
|
||||||
|
# V1.0 2026-05-11
|
||||||
|
# - Initial package for 16A EV charger offpeak and charge-until-full control.
|
||||||
|
#
|
||||||
|
# PACKAGE SETTINGS:
|
||||||
|
# Car display name:
|
||||||
|
# - Leaf
|
||||||
|
#
|
||||||
|
# Charger relay output:
|
||||||
|
# - switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
#
|
||||||
|
# Vehicle charging sensor:
|
||||||
|
# - binary_sensor.garage_db_control_16a_wallcharger_charging
|
||||||
|
#
|
||||||
|
# Default offpeak period:
|
||||||
|
# - Start: 21:00:00
|
||||||
|
# - End: 00:00:00
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
input_datetime:
|
||||||
|
ev_16a_offpeak_start:
|
||||||
|
name: 16A EV Offpeak Start
|
||||||
|
has_date: false
|
||||||
|
has_time: true
|
||||||
|
initial: "21:00:00"
|
||||||
|
|
||||||
|
ev_16a_offpeak_end:
|
||||||
|
name: 16A EV Offpeak End
|
||||||
|
has_date: false
|
||||||
|
has_time: true
|
||||||
|
initial: "00:00:00"
|
||||||
|
|
||||||
|
ev_16a_1hr_topup_until:
|
||||||
|
name: 16A EV 1hr topup until
|
||||||
|
has_date: true
|
||||||
|
has_time: true
|
||||||
|
initial: "2000-01-01 00:00:00"
|
||||||
|
|
||||||
|
input_select:
|
||||||
|
ev_16a_charge_mode:
|
||||||
|
name: Leaf EV charge mode
|
||||||
|
icon: mdi:ev-station
|
||||||
|
options:
|
||||||
|
- "Normal (Offpeak)"
|
||||||
|
- "Offpeak until charged"
|
||||||
|
- "1hr topup now"
|
||||||
|
- "Charge now until full"
|
||||||
|
- "Stop charging now"
|
||||||
|
initial: "Normal (Offpeak)"
|
||||||
|
|
||||||
|
automation:
|
||||||
|
#############################################################################
|
||||||
|
# OFFPEAK START
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
- id: ev_16a_charger_offpeak_start
|
||||||
|
alias: "16A EV Charger - Offpeak Start"
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- trigger: time
|
||||||
|
at: input_datetime.ev_16a_offpeak_start
|
||||||
|
|
||||||
|
conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: >
|
||||||
|
{{ states('input_select.ev_16a_charge_mode') in
|
||||||
|
['Normal (Offpeak)', 'Offpeak until charged'] }}
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- action: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
|
||||||
|
- choose:
|
||||||
|
- conditions:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
state: "Offpeak until charged"
|
||||||
|
sequence:
|
||||||
|
# If the car never starts charging, or is already full, turn off
|
||||||
|
# after a 5 minute grace period.
|
||||||
|
- delay: "00:05:00"
|
||||||
|
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
state: "Offpeak until charged"
|
||||||
|
|
||||||
|
- condition: state
|
||||||
|
entity_id: binary_sensor.garage_db_control_16a_wallcharger_charging
|
||||||
|
state: "off"
|
||||||
|
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
|
||||||
|
- action: input_select.select_option
|
||||||
|
target:
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
data:
|
||||||
|
option: "Normal (Offpeak)"
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# OFFPEAK END
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
- id: ev_16a_charger_offpeak_end
|
||||||
|
alias: "16A EV Charger - Offpeak End"
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- trigger: time
|
||||||
|
at: input_datetime.ev_16a_offpeak_end
|
||||||
|
|
||||||
|
conditions:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
state: "Normal (Offpeak)"
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# USER CHARGE MODE SELECTIONS
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
- id: ev_16a_charger_charge_mode_selected
|
||||||
|
alias: "16A EV Charger - Charge Mode Selected"
|
||||||
|
mode: restart
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- trigger: state
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- variables:
|
||||||
|
selected_mode: "{{ trigger.to_state.state }}"
|
||||||
|
is_offpeak_now: >
|
||||||
|
{% set start = states('input_datetime.ev_16a_offpeak_start') %}
|
||||||
|
{% set end = states('input_datetime.ev_16a_offpeak_end') %}
|
||||||
|
{% set now_time = now().strftime('%H:%M:%S') %}
|
||||||
|
{% if start == end %}
|
||||||
|
{{ true }}
|
||||||
|
{% elif start < end %}
|
||||||
|
{{ start <= now_time < end }}
|
||||||
|
{% else %}
|
||||||
|
{{ now_time >= start or now_time < end }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
- choose:
|
||||||
|
#####################################################################
|
||||||
|
# NORMAL OFFPEAK
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ selected_mode == 'Normal (Offpeak)' }}"
|
||||||
|
sequence:
|
||||||
|
# No immediate action.
|
||||||
|
# Normal mode only acts when the offpeak start/end triggers fire.
|
||||||
|
- stop: "Normal offpeak mode selected."
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# OFFPEAK UNTIL CHARGED
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ selected_mode == 'Offpeak until charged' }}"
|
||||||
|
sequence:
|
||||||
|
- if:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ is_offpeak_now }}"
|
||||||
|
then:
|
||||||
|
- action: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
|
||||||
|
# If the car never starts charging, or is already full, turn
|
||||||
|
# off after a 5 minute grace period.
|
||||||
|
- delay: "00:05:00"
|
||||||
|
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
state: "Offpeak until charged"
|
||||||
|
|
||||||
|
- condition: state
|
||||||
|
entity_id: binary_sensor.garage_db_control_16a_wallcharger_charging
|
||||||
|
state: "off"
|
||||||
|
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
|
||||||
|
- action: input_select.select_option
|
||||||
|
target:
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
data:
|
||||||
|
option: "Normal (Offpeak)"
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# 1 HOUR TOPUP NOW
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ selected_mode == '1hr topup now' }}"
|
||||||
|
sequence:
|
||||||
|
- action: input_datetime.set_datetime
|
||||||
|
target:
|
||||||
|
entity_id: input_datetime.ev_16a_1hr_topup_until
|
||||||
|
data:
|
||||||
|
datetime: >
|
||||||
|
{{ (as_timestamp(now()) + 3600)
|
||||||
|
| timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}
|
||||||
|
|
||||||
|
- action: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# CHARGE NOW UNTIL FULL
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ selected_mode == 'Charge now until full' }}"
|
||||||
|
sequence:
|
||||||
|
- action: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
|
||||||
|
# If the car never starts charging, or is already full, turn off
|
||||||
|
# after a 5 minute grace period.
|
||||||
|
- delay: "00:05:00"
|
||||||
|
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
state: "Charge now until full"
|
||||||
|
|
||||||
|
- condition: state
|
||||||
|
entity_id: binary_sensor.garage_db_control_16a_wallcharger_charging
|
||||||
|
state: "off"
|
||||||
|
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
|
||||||
|
- action: input_select.select_option
|
||||||
|
target:
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
data:
|
||||||
|
option: "Normal (Offpeak)"
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# STOP CHARGING NOW
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ selected_mode == 'Stop charging now' }}"
|
||||||
|
sequence:
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
|
||||||
|
- action: input_select.select_option
|
||||||
|
target:
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
data:
|
||||||
|
option: "Normal (Offpeak)"
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# 1 HOUR TOPUP WATCHDOG
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
- id: ev_16a_charger_1hr_topup_watchdog
|
||||||
|
alias: "16A EV Charger - 1hr Topup Watchdog"
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- trigger: time_pattern
|
||||||
|
minutes: "/1"
|
||||||
|
|
||||||
|
- trigger: homeassistant
|
||||||
|
event: start
|
||||||
|
|
||||||
|
conditions:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
state: "1hr topup now"
|
||||||
|
|
||||||
|
- condition: template
|
||||||
|
value_template: >
|
||||||
|
{{ as_timestamp(now()) >=
|
||||||
|
as_timestamp(states('input_datetime.ev_16a_1hr_topup_until')) }}
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- variables:
|
||||||
|
is_offpeak_now: >
|
||||||
|
{% set start = states('input_datetime.ev_16a_offpeak_start') %}
|
||||||
|
{% set end = states('input_datetime.ev_16a_offpeak_end') %}
|
||||||
|
{% set now_time = now().strftime('%H:%M:%S') %}
|
||||||
|
{% if start == end %}
|
||||||
|
{{ true }}
|
||||||
|
{% elif start < end %}
|
||||||
|
{{ start <= now_time < end }}
|
||||||
|
{% else %}
|
||||||
|
{{ now_time >= start or now_time < end }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
- action: input_select.select_option
|
||||||
|
target:
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
data:
|
||||||
|
option: "Normal (Offpeak)"
|
||||||
|
|
||||||
|
- choose:
|
||||||
|
# If the 1 hour topup finishes during offpeak, do not flick the relay.
|
||||||
|
# Leave it on and let the Normal Offpeak end automation turn it off.
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ is_offpeak_now }}"
|
||||||
|
sequence:
|
||||||
|
- if:
|
||||||
|
- condition: state
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
state: "off"
|
||||||
|
then:
|
||||||
|
- action: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
|
||||||
|
default:
|
||||||
|
- if:
|
||||||
|
- condition: state
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
state: "on"
|
||||||
|
then:
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# CHARGING COMPLETE MONITOR
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
- id: ev_16a_charger_stop_when_charging_complete
|
||||||
|
alias: "16A EV Charger - Stop When Charging Complete"
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- trigger: state
|
||||||
|
entity_id: binary_sensor.garage_db_control_16a_wallcharger_charging
|
||||||
|
to: "off"
|
||||||
|
for: "00:05:00"
|
||||||
|
|
||||||
|
conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: >
|
||||||
|
{{ states('input_select.ev_16a_charge_mode') in
|
||||||
|
['Offpeak until charged', 'Charge now until full'] }}
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.garage_db_control_16a_wallcharger_operation
|
||||||
|
|
||||||
|
- action: input_select.select_option
|
||||||
|
target:
|
||||||
|
entity_id: input_select.ev_16a_charge_mode
|
||||||
|
data:
|
||||||
|
option: "Normal (Offpeak)"
|
||||||
@@ -17,14 +17,14 @@ automation:
|
|||||||
entity_id: input_button.announcement_test
|
entity_id: input_button.announcement_test
|
||||||
|
|
||||||
action:
|
action:
|
||||||
- action: script.view_road_announcement
|
# - action: script.view_road_announcement
|
||||||
data:
|
# data:
|
||||||
channels: "sony_tv_lounge"
|
# channels: "sony_tv_lounge"
|
||||||
title: "View Road Test"
|
# title: "View Road Test"
|
||||||
short_announcement: "Test announcement"
|
# short_announcement: "Test announcement"
|
||||||
long_announcement: "This is a test announcement from the package test button."
|
# long_announcement: "This is a test announcement from the package test button."
|
||||||
payload: "On"
|
# payload: "On"
|
||||||
indicator: ""
|
# indicator: ""
|
||||||
|
|
||||||
#- action: script.view_road_announcement
|
#- action: script.view_road_announcement
|
||||||
# data:
|
# data:
|
||||||
@@ -34,6 +34,7 @@ automation:
|
|||||||
|
|
||||||
- action: script.view_road_announcement
|
- action: script.view_road_announcement
|
||||||
data:
|
data:
|
||||||
channels: "lounge_google_home_voice"
|
channels: "lounge_google_home_voice, sony_tv_lounge"
|
||||||
title: "View Road Test"
|
title: "View Road "
|
||||||
long_announcement: "This is a test announcement on the lounge Google Home."
|
short_announcement: "9pm, Free Power time"
|
||||||
|
long_announcement: "It is 9pm."
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
################################################################################
|
||||||
|
# PACKAGE: Underhouse Entrance Auto Lights
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Version:
|
||||||
|
# 1.2 - 2026-05-12
|
||||||
|
# - Added fast Zigbee2MQTT FP1-style event triggers:
|
||||||
|
# sensor.underhouse_mmwave_sensor_x23ms_presence_event = enter
|
||||||
|
# sensor.underhouse_mmwave_sensor_x23ms_presence_event = approach
|
||||||
|
# - Keeps binary presence as a backup trigger and as the clear/off condition.
|
||||||
|
# - This should behave closer to the previous Node-RED automation.
|
||||||
|
#
|
||||||
|
# Notes:
|
||||||
|
# - The UI may show the binary sensor as "Detected", but the YAML state is
|
||||||
|
# normally "on".
|
||||||
|
# - The presence_event sensor can react earlier than the binary presence sensor.
|
||||||
|
# - The event sensor is used to turn lights on quickly, but not to decide when
|
||||||
|
# the area is clear, because it may remain on its last event value.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
automation:
|
||||||
|
- id: underhouse_entrance_auto_lights
|
||||||
|
alias: "Underhouse Entrance - Auto Lights"
|
||||||
|
description: "Turns underhouse entrance lights on from Zigbee2MQTT mmWave enter/approach/presence, then off 400 seconds after presence clears."
|
||||||
|
mode: restart
|
||||||
|
max_exceeded: silent
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id: sensor.underhouse_mmwave_sensor_x23ms_presence_event
|
||||||
|
to: "enter"
|
||||||
|
|
||||||
|
- platform: state
|
||||||
|
entity_id: sensor.underhouse_mmwave_sensor_x23ms_presence_event
|
||||||
|
to: "approach"
|
||||||
|
|
||||||
|
- platform: state
|
||||||
|
entity_id: binary_sensor.underhouse_mmwave_sensor_x23ms_presence
|
||||||
|
to: "on"
|
||||||
|
|
||||||
|
action:
|
||||||
|
- alias: "Turn on the underhouse entrance lights"
|
||||||
|
action: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_entrance_lights
|
||||||
|
|
||||||
|
- alias: "Wait until the mmWave presence sensor is clear"
|
||||||
|
wait_template: >
|
||||||
|
{{ is_state('binary_sensor.underhouse_mmwave_sensor_x23ms_presence', 'off') }}
|
||||||
|
|
||||||
|
- alias: "Keep lights on for 400 seconds after presence clears"
|
||||||
|
delay:
|
||||||
|
seconds: 400
|
||||||
|
|
||||||
|
- alias: "Only continue if presence is still clear"
|
||||||
|
condition: state
|
||||||
|
entity_id: binary_sensor.underhouse_mmwave_sensor_x23ms_presence
|
||||||
|
state: "off"
|
||||||
|
|
||||||
|
- alias: "Turn off the underhouse entrance lights"
|
||||||
|
action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_entrance_lights
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
#:########################################################################################:#
|
||||||
|
# TITLE: UNDERHOUSE STORAGE LIGHTS AUTO LIGHTS PACKAGE
|
||||||
|
#:########################################################################################:#
|
||||||
|
# DESCRIPTION:
|
||||||
|
# Replaces the Node-RED automation for the underhouse storage lights.
|
||||||
|
# Doors, PIR sensors, a remote switch, and local relay changes can start or
|
||||||
|
# extend a 1 hour lighting timer.
|
||||||
|
#
|
||||||
|
# VERSION:
|
||||||
|
# V1.0 2026-05-12
|
||||||
|
# - Initial Home Assistant package version.
|
||||||
|
#
|
||||||
|
# EDIT NOTES:
|
||||||
|
# - Add future door contacts in BOTH places marked FUTURE DOOR.
|
||||||
|
# - Add future PIR sensors in the PIR group marked FUTURE PIR.
|
||||||
|
# - The generated group entities used below should be:
|
||||||
|
# binary_sensor.underhouse_storage_door_contacts
|
||||||
|
# binary_sensor.underhouse_storage_pir_presence
|
||||||
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
- platform: group
|
||||||
|
name: Underhouse Storage Door Contacts
|
||||||
|
unique_id: underhouse_storage_door_contacts
|
||||||
|
device_class: door
|
||||||
|
all: false
|
||||||
|
entities:
|
||||||
|
- binary_sensor.underhouse_stealth_door_x07rs_contact
|
||||||
|
- binary_sensor.underhouse_north_door_door
|
||||||
|
# FUTURE DOOR: add the next underhouse storage door contact here.
|
||||||
|
# - binary_sensor.underhouse_future_door_contact
|
||||||
|
|
||||||
|
- platform: group
|
||||||
|
name: Underhouse Storage PIR Presence
|
||||||
|
unique_id: underhouse_storage_pir_presence
|
||||||
|
device_class: occupancy
|
||||||
|
all: false
|
||||||
|
entities:
|
||||||
|
- binary_sensor.underhouse_pir_sensor_south_occupancy
|
||||||
|
# FUTURE PIR: uncomment this when the north PIR exists.
|
||||||
|
# - binary_sensor.underhouse_pir_sensor_north_occupancy
|
||||||
|
|
||||||
|
timer:
|
||||||
|
underhouse_storage_lights_runtime:
|
||||||
|
name: Underhouse Storage Lights Runtime
|
||||||
|
duration: "01:00:00"
|
||||||
|
restore: true
|
||||||
|
icon: mdi:timer-outline
|
||||||
|
|
||||||
|
script:
|
||||||
|
underhouse_storage_lights_start_runtime:
|
||||||
|
alias: Underhouse Storage Lights - Start Or Extend Runtime
|
||||||
|
mode: restart
|
||||||
|
sequence:
|
||||||
|
- choose:
|
||||||
|
- conditions:
|
||||||
|
- condition: state
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_storage_lights
|
||||||
|
state: "off"
|
||||||
|
sequence:
|
||||||
|
- action: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_storage_lights
|
||||||
|
|
||||||
|
- action: timer.start
|
||||||
|
target:
|
||||||
|
entity_id: timer.underhouse_storage_lights_runtime
|
||||||
|
data:
|
||||||
|
duration: "0:20:00"
|
||||||
|
|
||||||
|
underhouse_storage_lights_stop_runtime:
|
||||||
|
alias: Underhouse Storage Lights - Stop Runtime
|
||||||
|
mode: restart
|
||||||
|
sequence:
|
||||||
|
- choose:
|
||||||
|
- conditions:
|
||||||
|
- condition: state
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_storage_lights
|
||||||
|
state: "on"
|
||||||
|
sequence:
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_storage_lights
|
||||||
|
|
||||||
|
- choose:
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: >-
|
||||||
|
{{ not is_state('timer.underhouse_storage_lights_runtime', 'idle') }}
|
||||||
|
sequence:
|
||||||
|
- action: timer.cancel
|
||||||
|
target:
|
||||||
|
entity_id: timer.underhouse_storage_lights_runtime
|
||||||
|
|
||||||
|
automation:
|
||||||
|
- id: underhouse_storage_lights_start_extend_runtime
|
||||||
|
alias: Underhouse Storage Lights - Start Or Extend Runtime
|
||||||
|
description: >-
|
||||||
|
Turns the storage lights on and starts or restarts the 1 hour timer when
|
||||||
|
a door opens, PIR detects occupancy, or the remote switch is pressed.
|
||||||
|
mode: restart
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id: binary_sensor.underhouse_storage_door_contacts
|
||||||
|
to: "on"
|
||||||
|
- platform: state
|
||||||
|
entity_id: binary_sensor.underhouse_storage_pir_presence
|
||||||
|
to: "on"
|
||||||
|
- platform: state
|
||||||
|
entity_id: binary_sensor.esp_underhouselights_underhouse_storage_lights_remote_switch
|
||||||
|
to: "on"
|
||||||
|
action:
|
||||||
|
- action: script.underhouse_storage_lights_start_runtime
|
||||||
|
|
||||||
|
- id: underhouse_storage_lights_start_timer_when_relay_turned_on
|
||||||
|
alias: Underhouse Storage Lights - Start Timer When Relay Turned On
|
||||||
|
description: >-
|
||||||
|
Starts the timer if the relay is turned on locally by ESPHome or
|
||||||
|
by another Home Assistant automation.
|
||||||
|
mode: restart
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_storage_lights
|
||||||
|
to: "on"
|
||||||
|
action:
|
||||||
|
- action: timer.start
|
||||||
|
target:
|
||||||
|
entity_id: timer.underhouse_storage_lights_runtime
|
||||||
|
data:
|
||||||
|
duration: "00:20:00"
|
||||||
|
|
||||||
|
- id: underhouse_storage_lights_timer_finished
|
||||||
|
alias: Underhouse Storage Lights - Timer Finished
|
||||||
|
description: >-
|
||||||
|
Turns the storage lights off after the runtime expires, even if a
|
||||||
|
door has been left open.
|
||||||
|
mode: single
|
||||||
|
trigger:
|
||||||
|
- platform: event
|
||||||
|
event_type: timer.finished
|
||||||
|
event_data:
|
||||||
|
entity_id: timer.underhouse_storage_lights_runtime
|
||||||
|
action:
|
||||||
|
- choose:
|
||||||
|
- conditions:
|
||||||
|
- condition: state
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_storage_lights
|
||||||
|
state: "on"
|
||||||
|
sequence:
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_storage_lights
|
||||||
|
|
||||||
|
- id: underhouse_storage_lights_cancel_timer_when_relay_off
|
||||||
|
alias: Underhouse Storage Lights - Cancel Timer When Relay Off
|
||||||
|
description: >-
|
||||||
|
Keeps the timer helper tidy if the relay is turned off manually, locally,
|
||||||
|
or by another automation.
|
||||||
|
mode: restart
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_storage_lights
|
||||||
|
to: "off"
|
||||||
|
condition:
|
||||||
|
- condition: template
|
||||||
|
value_template: >-
|
||||||
|
{{ not is_state('timer.underhouse_storage_lights_runtime', 'idle') }}
|
||||||
|
action:
|
||||||
|
- action: timer.cancel
|
||||||
|
target:
|
||||||
|
entity_id: timer.underhouse_storage_lights_runtime
|
||||||
|
|
||||||
|
- id: underhouse_storage_lights_all_doors_closed
|
||||||
|
alias: Underhouse Storage Lights - All Doors Closed
|
||||||
|
description: >-
|
||||||
|
When all door contacts are closed, turn the lights off immediately if no
|
||||||
|
PIR occupancy is active. If PIR is still active, the PIR clear automation
|
||||||
|
below will turn them off after 60 seconds without occupancy.
|
||||||
|
mode: restart
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id: binary_sensor.underhouse_storage_door_contacts
|
||||||
|
from: "on"
|
||||||
|
to: "off"
|
||||||
|
condition:
|
||||||
|
- condition: state
|
||||||
|
entity_id: binary_sensor.underhouse_storage_pir_presence
|
||||||
|
state: "off"
|
||||||
|
action:
|
||||||
|
- action: script.underhouse_storage_lights_stop_runtime
|
||||||
|
|
||||||
|
- id: underhouse_storage_lights_individual_door_closed_check
|
||||||
|
alias: Underhouse Storage Lights - Individual Door Closed No Motion Check
|
||||||
|
description: >-
|
||||||
|
When a real door contact closes, wait 60 seconds and then turn the relay
|
||||||
|
off only if all doors are closed and there is no PIR occupancy.
|
||||||
|
mode: restart
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id:
|
||||||
|
- binary_sensor.underhouse_stealth_door_x07rs_contact
|
||||||
|
- binary_sensor.underhouse_north_door_door
|
||||||
|
# FUTURE DOOR: add the next underhouse storage door contact here too.
|
||||||
|
# - binary_sensor.underhouse_future_door_contact
|
||||||
|
from: "on"
|
||||||
|
to: "off"
|
||||||
|
action:
|
||||||
|
- delay: "00:01:00"
|
||||||
|
- condition: state
|
||||||
|
entity_id: binary_sensor.underhouse_storage_door_contacts
|
||||||
|
state: "off"
|
||||||
|
- condition: state
|
||||||
|
entity_id: binary_sensor.underhouse_storage_pir_presence
|
||||||
|
state: "off"
|
||||||
|
- condition: state
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_storage_lights
|
||||||
|
state: "on"
|
||||||
|
- action: script.underhouse_storage_lights_stop_runtime
|
||||||
|
|
||||||
|
- id: underhouse_storage_lights_pir_clear_after_doors_closed
|
||||||
|
alias: Underhouse Storage Lights - PIR Clear After Doors Closed
|
||||||
|
description: >-
|
||||||
|
If the doors are closed and PIR occupancy clears for 60 seconds, turn the
|
||||||
|
storage lights off.
|
||||||
|
mode: restart
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id: binary_sensor.underhouse_storage_pir_presence
|
||||||
|
to: "off"
|
||||||
|
for: "00:01:00"
|
||||||
|
condition:
|
||||||
|
- condition: state
|
||||||
|
entity_id: binary_sensor.underhouse_storage_door_contacts
|
||||||
|
state: "off"
|
||||||
|
- condition: state
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_storage_lights
|
||||||
|
state: "on"
|
||||||
|
action:
|
||||||
|
- action: script.underhouse_storage_lights_stop_runtime
|
||||||
|
|
||||||
|
- id: underhouse_storage_lights_startup_sync
|
||||||
|
alias: Underhouse Storage Lights - Startup Sync
|
||||||
|
description: >-
|
||||||
|
On Home Assistant startup, re-sync the package state so an already-open
|
||||||
|
door or already-active PIR still controls the lights after a restart.
|
||||||
|
mode: single
|
||||||
|
trigger:
|
||||||
|
- platform: homeassistant
|
||||||
|
event: start
|
||||||
|
action:
|
||||||
|
- delay: "00:00:20"
|
||||||
|
- choose:
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: >-
|
||||||
|
{{
|
||||||
|
is_state('binary_sensor.underhouse_storage_door_contacts', 'on')
|
||||||
|
or is_state('binary_sensor.underhouse_storage_pir_presence', 'on')
|
||||||
|
or is_state('binary_sensor.esp_underhouselights_underhouse_storage_lights_remote_switch', 'on')
|
||||||
|
}}
|
||||||
|
sequence:
|
||||||
|
- action: script.underhouse_storage_lights_start_runtime
|
||||||
|
|
||||||
|
- conditions:
|
||||||
|
- condition: state
|
||||||
|
entity_id: switch.esp_underhouselights_underhouse_storage_lights
|
||||||
|
state: "on"
|
||||||
|
- condition: state
|
||||||
|
entity_id: timer.underhouse_storage_lights_runtime
|
||||||
|
state: "idle"
|
||||||
|
sequence:
|
||||||
|
- action: timer.start
|
||||||
|
target:
|
||||||
|
entity_id: timer.underhouse_storage_lights_runtime
|
||||||
|
data:
|
||||||
|
duration: "00:20:00"
|
||||||
@@ -1,20 +1,26 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# Bedroom 1 Ikea Air Filter Package
|
# Bedroom 1 Ikea Air Filter Package
|
||||||
# File: /config/packages/bedroom_1_ikea_air_filter.yaml
|
# File: /config/packages/bedroom_1_ikea_air_filter.yaml
|
||||||
# Version: 1.0
|
# Version: 1.1
|
||||||
# Date: 2026-04-29
|
# Date: 2026-05-08
|
||||||
#
|
#
|
||||||
# Purpose:
|
# Purpose:
|
||||||
# - Creates a dropdown helper called "Bedroom 1 Ikea Fan".
|
# - Creates a dropdown helper called "Bedroom 1 Ikea Fan".
|
||||||
# - Auto mode controls the Bedroom 1 Ikea air filter speed by priority.
|
# - Auto mode controls the Bedroom 1 Ikea air filter speed by event and timing.
|
||||||
# - Manual dropdown modes set a fixed fan speed and disable auto control.
|
# - Manual dropdown modes set a fixed fan speed and disable auto control.
|
||||||
#
|
#
|
||||||
# Auto priority order:
|
# Behaviour notes:
|
||||||
# 1. Quiet time on: fan speed 2
|
# - Quiet time turning on sets fan speed to 2.
|
||||||
# 2. Bedside light on: fan speed 2
|
# - Bedside lamp turning on sets fan speed to 2.
|
||||||
# 3. Free power time, 21:00 to midnight: fan speed 5
|
# - Bedside lamp turning off does not change the fan speed.
|
||||||
# 4. Daytime, 09:00 to 15:00: fan speed 4
|
# - There is no 10-minute re-check, so the fan will not ramp back up just
|
||||||
# 5. Default: fan speed 2
|
# because the bedside lamp was switched off.
|
||||||
|
# - Time boundaries can still change the fan speed later.
|
||||||
|
#
|
||||||
|
# Auto timing:
|
||||||
|
# - 21:00 to midnight: fan speed 5
|
||||||
|
# - 09:00 to 15:00: fan speed 4
|
||||||
|
# - Default: fan speed 2
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
input_select:
|
input_select:
|
||||||
@@ -68,13 +74,17 @@ automation:
|
|||||||
- trigger: homeassistant
|
- trigger: homeassistant
|
||||||
event: start
|
event: start
|
||||||
|
|
||||||
# Highest priority condition.
|
# Quiet time only forces low when it turns on.
|
||||||
|
# Turning quiet time off does not automatically ramp the fan back up.
|
||||||
- trigger: state
|
- trigger: state
|
||||||
entity_id: input_boolean.quiet_time
|
entity_id: input_boolean.quiet_time
|
||||||
|
to: "on"
|
||||||
|
|
||||||
# Bedside lamp should force low speed while on.
|
# Bedside lamp only forces low when it turns on.
|
||||||
|
# Turning the lamp off does not change the fan speed.
|
||||||
- trigger: state
|
- trigger: state
|
||||||
entity_id: light.master_bedroom_bedside_lamp_arlec_bulb_master_bedroom_bedside_lamp_arlec_bulb
|
entity_id: light.master_bedroom_bedside_lamp_arlec_bulb_master_bedroom_bedside_lamp_arlec_bulb
|
||||||
|
to: "on"
|
||||||
|
|
||||||
# Main timing boundaries.
|
# Main timing boundaries.
|
||||||
- trigger: time
|
- trigger: time
|
||||||
@@ -84,10 +94,6 @@ automation:
|
|||||||
- "15:00:00"
|
- "15:00:00"
|
||||||
- "21:00:00"
|
- "21:00:00"
|
||||||
|
|
||||||
# Safety/re-check trigger, especially for the bedside lamp rule.
|
|
||||||
- trigger: time_pattern
|
|
||||||
minutes: "/10"
|
|
||||||
|
|
||||||
conditions:
|
conditions:
|
||||||
# Manual dropdown modes disable automatic control.
|
# Manual dropdown modes disable automatic control.
|
||||||
- condition: state
|
- condition: state
|
||||||
@@ -96,10 +102,26 @@ automation:
|
|||||||
|
|
||||||
actions:
|
actions:
|
||||||
- variables:
|
- variables:
|
||||||
|
trigger_entity: "{{ trigger.entity_id | default('') }}"
|
||||||
|
bedside_lamp_entity: light.master_bedroom_bedside_lamp_arlec_bulb_master_bedroom_bedside_lamp_arlec_bulb
|
||||||
|
bedside_lamp_on_trigger: >-
|
||||||
|
{{
|
||||||
|
trigger_entity == bedside_lamp_entity
|
||||||
|
and trigger.to_state is defined
|
||||||
|
and trigger.to_state.state == 'on'
|
||||||
|
}}
|
||||||
|
quiet_time_on_trigger: >-
|
||||||
|
{{
|
||||||
|
trigger_entity == 'input_boolean.quiet_time'
|
||||||
|
and trigger.to_state is defined
|
||||||
|
and trigger.to_state.state == 'on'
|
||||||
|
}}
|
||||||
auto_target_speed: >-
|
auto_target_speed: >-
|
||||||
{% if is_state('input_boolean.quiet_time', 'on') %}
|
{% if bedside_lamp_on_trigger %}
|
||||||
2
|
2
|
||||||
{% elif is_state('light.master_bedroom_bedside_lamp_arlec_bulb_master_bedroom_bedside_lamp_arlec_bulb', 'on') %}
|
{% elif quiet_time_on_trigger %}
|
||||||
|
2
|
||||||
|
{% elif is_state('input_boolean.quiet_time', 'on') %}
|
||||||
2
|
2
|
||||||
{% elif now().hour >= 21 %}
|
{% elif now().hour >= 21 %}
|
||||||
5
|
5
|
||||||
@@ -142,7 +164,7 @@ automation:
|
|||||||
entity_id: automation.bedroom_1_ikea_air_filter_auto_control
|
entity_id: automation.bedroom_1_ikea_air_filter_auto_control
|
||||||
|
|
||||||
# Auto starts at speed 2, then immediately evaluates the
|
# Auto starts at speed 2, then immediately evaluates the
|
||||||
# current priority rules.
|
# current timing rules.
|
||||||
- action: script.bedroom_1_ikea_air_filter_set_speed_if_needed
|
- action: script.bedroom_1_ikea_air_filter_set_speed_if_needed
|
||||||
data:
|
data:
|
||||||
target_speed: 2
|
target_speed: 2
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
#
|
#
|
||||||
# VERSION:
|
# VERSION:
|
||||||
|
# 1.4 - 2026-05-21
|
||||||
|
# - Added delayed lounge NSPanel touchscreen brightness reduction to 5.
|
||||||
|
#
|
||||||
# 1.3 - 2026-05-07
|
# 1.3 - 2026-05-07
|
||||||
# - Added downstairs lights all off script.
|
# - Added downstairs lights all off script.
|
||||||
# - Added main hallway nightlights 60 minute bedtime timer.
|
# - Added main hallway nightlights 60 minute bedtime timer.
|
||||||
@@ -29,6 +32,7 @@
|
|||||||
# - climate entities are turned off if they are not already "off".
|
# - climate entities are turned off if they are not already "off".
|
||||||
# - Main hallway nightlights are turned on for 60 minutes when bedtime mode runs.
|
# - Main hallway nightlights are turned on for 60 minutes when bedtime mode runs.
|
||||||
# - If the main hallway nightlights are turned off manually, the timer is cancelled.
|
# - If the main hallway nightlights are turned off manually, the timer is cancelled.
|
||||||
|
# - Lounge NSPanel touchscreen brightness is set to 5 after 20 seconds.
|
||||||
#
|
#
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
@@ -94,6 +98,18 @@ automation:
|
|||||||
delay_seconds: 0
|
delay_seconds: 0
|
||||||
|
|
||||||
action:
|
action:
|
||||||
|
# Turn hallway nightlights on immediately before any other bedtime actions.
|
||||||
|
- service: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: switch.main_hallway_nightlights_1_relay_1_main_hallway_nightlights
|
||||||
|
|
||||||
|
# Start or restart the 60 minute bedtime nightlight timer.
|
||||||
|
- service: timer.start
|
||||||
|
target:
|
||||||
|
entity_id: timer.main_hallway_nightlights_bedtime
|
||||||
|
data:
|
||||||
|
duration: "01:00:00"
|
||||||
|
|
||||||
- service: script.downstairs_lights_all_off
|
- service: script.downstairs_lights_all_off
|
||||||
|
|
||||||
- service: script.lounge_set_scene
|
- service: script.lounge_set_scene
|
||||||
@@ -104,15 +120,10 @@ automation:
|
|||||||
target:
|
target:
|
||||||
entity_id: input_boolean.quiet_time
|
entity_id: input_boolean.quiet_time
|
||||||
|
|
||||||
- service: switch.turn_on
|
# Reduce the lounge NSPanel screen brightness after 20 seconds.
|
||||||
|
- service: script.turn_on
|
||||||
target:
|
target:
|
||||||
entity_id: switch.main_hallway_nightlights_1_relay_1_main_hallway_nightlights
|
entity_id: script.bedtime_mode_set_lounge_nspanel_brightness_after_delay
|
||||||
|
|
||||||
- service: timer.start
|
|
||||||
target:
|
|
||||||
entity_id: timer.main_hallway_nightlights_bedtime
|
|
||||||
data:
|
|
||||||
duration: "01:00:00"
|
|
||||||
|
|
||||||
- repeat:
|
- repeat:
|
||||||
for_each: "{{ bedtime_delayed_off_targets }}"
|
for_each: "{{ bedtime_delayed_off_targets }}"
|
||||||
@@ -232,3 +243,21 @@ script:
|
|||||||
|
|
||||||
mode: parallel
|
mode: parallel
|
||||||
max: 50
|
max: 50
|
||||||
|
|
||||||
|
bedtime_mode_set_lounge_nspanel_brightness_after_delay:
|
||||||
|
alias: "Bedtime Mode - Set Lounge NSPanel Brightness After Delay"
|
||||||
|
description: >
|
||||||
|
Waits 20 seconds after bedtime mode starts, then sets the lounge NSPanel
|
||||||
|
touchscreen display brightness to 5.
|
||||||
|
|
||||||
|
sequence:
|
||||||
|
- delay:
|
||||||
|
seconds: 20
|
||||||
|
|
||||||
|
- service: number.set_value
|
||||||
|
target:
|
||||||
|
entity_id: number.lounge_nspanel_touchscreen_display_brightness
|
||||||
|
data:
|
||||||
|
value: 1
|
||||||
|
|
||||||
|
mode: restart
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
mqtt:
|
|
||||||
switch:
|
|
||||||
- unique_id: lounge_blinds_control
|
|
||||||
name: "Lounge Blinds Control"
|
|
||||||
state_topic: "viewroad-status/blinds/lounge-verticalblinds"
|
|
||||||
command_topic: "viewroad-commands/blinds/lounge-verticalblinds"
|
|
||||||
payload_off: "off"
|
|
||||||
payload_on: "on"
|
|
||||||
state_on: "on"
|
|
||||||
state_off: "off"
|
|
||||||
icon: mdi:blinds
|
|
||||||
retain: false
|
|
||||||
|
|
||||||
automation:
|
|
||||||
- id: lounge_blinds_control_switch
|
|
||||||
alias: Publish lounge blind control to mqtt
|
|
||||||
trigger:
|
|
||||||
platform: state
|
|
||||||
entity_id: input_boolean.lounge_blinds
|
|
||||||
action:
|
|
||||||
service: mqtt.publish
|
|
||||||
data_template:
|
|
||||||
payload: "{{trigger.to_state.state}}"
|
|
||||||
topic: viewroad-status/blinds/lounge-verticalblinds
|
|
||||||
@@ -4,6 +4,12 @@
|
|||||||
#
|
#
|
||||||
# VERSION HISTORY
|
# VERSION HISTORY
|
||||||
#
|
#
|
||||||
|
# 2026-05-07 - v1.0.2
|
||||||
|
# - Added binary_sensor.downstairs_flat_any_lights_on.
|
||||||
|
# - Updated all-on/all-off script to use the new binary sensor.
|
||||||
|
# - Kept direct entity lists instead of using a Home Assistant group, to avoid
|
||||||
|
# package merge errors from duplicate group/name keys.
|
||||||
|
#
|
||||||
# 2026-05-07 - v1.0.1
|
# 2026-05-07 - v1.0.1
|
||||||
# - Removed group.downstairs_flat_lights from this package to avoid duplicate
|
# - Removed group.downstairs_flat_lights from this package to avoid duplicate
|
||||||
# group/name package merge errors.
|
# group/name package merge errors.
|
||||||
@@ -30,6 +36,11 @@
|
|||||||
# - downstairs_light_toggle_all_group turns all listed lights OFF if any are ON.
|
# - downstairs_light_toggle_all_group turns all listed lights OFF if any are ON.
|
||||||
# - downstairs_light_toggle_all_group turns all listed lights ON if they are all OFF.
|
# - downstairs_light_toggle_all_group turns all listed lights ON if they are all OFF.
|
||||||
#
|
#
|
||||||
|
# - binary_sensor.downstairs_flat_any_lights_on:
|
||||||
|
# - ON when any listed downstairs light is ON.
|
||||||
|
# - OFF when all listed downstairs lights are OFF.
|
||||||
|
# - This replaces the need for a group.downstairs_flat_lights entity.
|
||||||
|
#
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@@ -41,6 +52,27 @@ input_boolean:
|
|||||||
name: Downstairs Guest Occupied
|
name: Downstairs Guest Occupied
|
||||||
icon: mdi:home-account
|
icon: mdi:home-account
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# TEMPLATE SENSORS
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
template:
|
||||||
|
- binary_sensor:
|
||||||
|
- name: Downstairs Flat Any Lights On
|
||||||
|
unique_id: downstairs_flat_any_lights_on
|
||||||
|
icon: mdi:lightbulb-group
|
||||||
|
state: >
|
||||||
|
{{
|
||||||
|
is_state('switch.esp_downstloungemain_relay_1_main_lights', 'on')
|
||||||
|
or is_state('switch.esp_downstloungemain_relay_2_back_wall_lights', 'on')
|
||||||
|
or is_state('switch.esp_downstmasterbedrmlights_relay_1_main_lights', 'on')
|
||||||
|
or is_state('switch.esp_downstbedrm2lights_relay_1_main_lights', 'on')
|
||||||
|
or is_state('switch.esp_downstkitchlights_relay_2_kitchen_light', 'on')
|
||||||
|
or is_state('switch.esp_downstkitchlights_relay_1_dining_light', 'on')
|
||||||
|
or is_state('switch.esp_downstbathswitch_relay_1_main_lights', 'on')
|
||||||
|
or is_state('switch.esp_downstbathswitch_relay_2_cabinet_light', 'on')
|
||||||
|
}}
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# SCRIPTS
|
# SCRIPTS
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@@ -169,18 +201,9 @@ script:
|
|||||||
|
|
||||||
- choose:
|
- choose:
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: state
|
||||||
value_template: >
|
entity_id: binary_sensor.downstairs_flat_any_lights_on
|
||||||
{{
|
state: "on"
|
||||||
is_state('switch.esp_downstloungemain_relay_1_main_lights', 'on')
|
|
||||||
or is_state('switch.esp_downstloungemain_relay_2_back_wall_lights', 'on')
|
|
||||||
or is_state('switch.esp_downstmasterbedrmlights_relay_1_main_lights', 'on')
|
|
||||||
or is_state('switch.esp_downstbedrm2lights_relay_1_main_lights', 'on')
|
|
||||||
or is_state('switch.esp_downstkitchlights_relay_2_kitchen_light', 'on')
|
|
||||||
or is_state('switch.esp_downstkitchlights_relay_1_dining_light', 'on')
|
|
||||||
or is_state('switch.esp_downstbathswitch_relay_1_main_lights', 'on')
|
|
||||||
or is_state('switch.esp_downstbathswitch_relay_2_cabinet_light', 'on')
|
|
||||||
}}
|
|
||||||
sequence:
|
sequence:
|
||||||
- action: homeassistant.turn_off
|
- action: homeassistant.turn_off
|
||||||
target:
|
target:
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
mqtt:
|
|
||||||
sensor:
|
|
||||||
- unique_id: view_road_power_now
|
|
||||||
name: "Power Now"
|
|
||||||
state_topic: "viewroad-status/energy/PowerTotals"
|
|
||||||
unit_of_measurement: "kW"
|
|
||||||
- unique_id: view_road_power_now_red
|
|
||||||
name: "Power Now (Red)"
|
|
||||||
state_topic: "tele/tasmo-wemosd1-7280-powermon-1/SENSOR"
|
|
||||||
unit_of_measurement: "kW"
|
|
||||||
value_template: "{{ value_json.ENERGY.Power[0] }}"
|
|
||||||
- unique_id: view_road_power_now_white
|
|
||||||
name: "Power Now (White)"
|
|
||||||
state_topic: "tele/tasmo-wemosd1-7280-powermon-1/SENSOR"
|
|
||||||
unit_of_measurement: "kW"
|
|
||||||
value_template: "{{ value_json.ENERGY.Power[1] }}"
|
|
||||||
- unique_id: view_road_power_now_blue
|
|
||||||
name: "Power Now (Blue)"
|
|
||||||
state_topic: "tele/tasmo-wemosd1-7280-powermon-1/SENSOR"
|
|
||||||
unit_of_measurement: "kW"
|
|
||||||
value_template: "{{ value_json.ENERGY.Power[2] }}"
|
|
||||||
|
|
||||||
template:
|
|
||||||
- sensor:
|
|
||||||
- name: "Electricity Power Total"
|
|
||||||
unique_id: electricity_power_total
|
|
||||||
unit_of_measurement: "W"
|
|
||||||
device_class: power
|
|
||||||
state_class: measurement
|
|
||||||
state: >
|
|
||||||
{{
|
|
||||||
states('sensor.tasmo_wemosd1_7280_powermon_1_energy_power_0') | float(0)
|
|
||||||
+ states('sensor.tasmo_wemosd1_7280_powermon_1_energy_power_1') | float(0)
|
|
||||||
+ states('sensor.tasmo_wemosd1_7280_powermon_1_energy_power_2') | float(0)
|
|
||||||
}}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
#mqtt:
|
|
||||||
# sensor:
|
|
||||||
# - unique_id: 32a_ev_wallcharger_power
|
|
||||||
# name: "32A EV Wallcharger Power"
|
|
||||||
# device_class: power
|
|
||||||
# unit_of_measurement: kW
|
|
||||||
# state_topic: "stat/tasmo-wemosd1-7280-powermon-1/EnergyMeterCount"
|
|
||||||
# value_template: "{{ value_json.EVChargerWhCount * 2 * 60 / 1000 }}"
|
|
||||||
# - unique_id: 16a_ev_wallcharger_power
|
|
||||||
# name: "16A EV Wallcharger Power"
|
|
||||||
# device_class: power
|
|
||||||
# unit_of_measurement: kW
|
|
||||||
# state_topic: "stat/tasmo-s4chan-7594-garage-1/EnergyMeterCount"
|
|
||||||
# value_template: "{{ value_json.EVChargerWhCount * 2 * 60 / 1000 }}"
|
|
||||||
|
|
||||||
# Use the Riemann sum integral to calculate energy in kWh
|
|
||||||
# from the contimuous power measuring sensors
|
|
||||||
sensor:
|
|
||||||
- platform: integration
|
|
||||||
unique_id: 32a_ev_wallcharger_power_total
|
|
||||||
name: "EV 32A Wallcharger Power Total (Integral)"
|
|
||||||
source: sensor.main_house_3_phase_power_monitor_32a_wallcharger_power
|
|
||||||
#device_class: energy
|
|
||||||
#unit_of_measurement: Wh
|
|
||||||
#unit_time: h
|
|
||||||
#unit_prefix: k # Show in kWh
|
|
||||||
round: 0 # Only need 0 decimals accuracy
|
|
||||||
- platform: integration
|
|
||||||
unique_id: 16a_ev_wallcharger_power_total
|
|
||||||
name: "EV 16A EV Wallcharger Power Total (Integral)"
|
|
||||||
source: sensor.garage_db_control_16a_wallcharger_power
|
|
||||||
#device_class: energy
|
|
||||||
#unit_of_measurement: Wh
|
|
||||||
#unit_time: h
|
|
||||||
#unit_prefix: k
|
|
||||||
round: 0
|
|
||||||
|
|
||||||
# - platform: filter
|
|
||||||
# name: "32A EV Charger Power 1m Avg"
|
|
||||||
# unique_id: ev_charger_32a_power_1m_avg
|
|
||||||
# entity_id: sensor.main_house_3_phase_power_monitor_ev_wallcharger_power
|
|
||||||
# filters:
|
|
||||||
# - filter: time_simple_moving_average
|
|
||||||
# window_size: "00:01"
|
|
||||||
# precision: 3
|
|
||||||
|
|
||||||
input_select:
|
|
||||||
leaf_ev_charging_mode:
|
|
||||||
icon: mdi:ev-plug-type1
|
|
||||||
name: Leaf EV Charge Mode
|
|
||||||
initial: "Normal (Offpeak)"
|
|
||||||
options:
|
|
||||||
- "Normal (Offpeak)"
|
|
||||||
- "Offpeak until charged"
|
|
||||||
- "1hr top-up now"
|
|
||||||
- "Charge now until full"
|
|
||||||
- "Stop charging now"
|
|
||||||
|
|
||||||
automation:
|
|
||||||
- id: set_the_leaf_ev_charging_mode
|
|
||||||
alias: Set the Leaf EV Charging Mode
|
|
||||||
trigger:
|
|
||||||
entity_id: input_select.leaf_ev_charging_mode
|
|
||||||
platform: state
|
|
||||||
action:
|
|
||||||
service: mqtt.publish
|
|
||||||
data:
|
|
||||||
topic: viewroad-status/evcharging/leaf-chargemode
|
|
||||||
payload:
|
|
||||||
'{% set mapping = { "Normal (Offpeak)":"normal", "Offpeak until charged":"offpeak-full",
|
|
||||||
"1hr top-up now":"boost", "Charge now until full":"now-full", "Stop charging now":"stop" } %} {% set dta = trigger.to_state.state %}
|
|
||||||
{{ mapping[dta] }}
|
|
||||||
'
|
|
||||||
#template:
|
|
||||||
# - trigger:
|
|
||||||
# - platform: time_pattern
|
|
||||||
# seconds: "/10"
|
|
||||||
# - platform: homeassistant
|
|
||||||
# event: start
|
|
||||||
# binary_sensor:
|
|
||||||
# - name: "32A EV Charger Charging"
|
|
||||||
# unique_id: ev_charger_32a_charging
|
|
||||||
# icon: mdi:car-electric
|
|
||||||
# state: >-
|
|
||||||
# {{ states('sensor.32a_ev_charger_power_1m_avg') | float(0) > 0.1 }}
|
|
||||||
# delay_on:
|
|
||||||
# seconds: 60
|
|
||||||
# delay_off:
|
|
||||||
# seconds: 60
|
|
||||||
#
|
|
||||||
# - name: "16A EV Charger Charging"
|
|
||||||
# unique_id: ev_charger_16a_charging
|
|
||||||
# icon: mdi:car-electric
|
|
||||||
# state: >-
|
|
||||||
# {{ (states('sensor.16a_ev_wallcharger_power') | float(0)) > 0.1 }}
|
|
||||||
# delay_on:
|
|
||||||
# seconds: 60
|
|
||||||
# delay_off:
|
|
||||||
# seconds: 60
|
|
||||||
#
|
|
||||||
# - binary_sensor:
|
|
||||||
# - name: 32A EV Charger Charging UI
|
|
||||||
# unique_id: ev_charger_charging_ui
|
|
||||||
# state: "{{ is_state('sensor.32a_ev_charger_charging', 'on') }}"
|
|
||||||
# icon: mdi:car-electric
|
|
||||||
@@ -0,0 +1,299 @@
|
|||||||
|
###############################################################################
|
||||||
|
# PACKAGE: Free Power Time Automation
|
||||||
|
###############################################################################
|
||||||
|
# VERSION:
|
||||||
|
# 1.0.0 - 2026-05-08
|
||||||
|
# - Initial package.
|
||||||
|
# - Adds editable free power start/end times.
|
||||||
|
# - Adds master enable switch and per-action enable switches.
|
||||||
|
# - Adds announcement, gas-to-heatpump changeover, tool charger control,
|
||||||
|
# and underhouse dehumidifier control.
|
||||||
|
#
|
||||||
|
# NOTES:
|
||||||
|
# - Free power start/end times can be changed in Home Assistant.
|
||||||
|
# - Start time default is 9:00pm.
|
||||||
|
# - End time default is midnight.
|
||||||
|
# - YAML-only gas heater settings are in script.free_power_gas_heater_changeover:
|
||||||
|
# gas_heater_shutdown_delay_seconds
|
||||||
|
# heatpump_setpoint_offset_c
|
||||||
|
#
|
||||||
|
# IMPORTANT:
|
||||||
|
# - input_datetime initial values are used to provide defaults.
|
||||||
|
# - If you later want UI changes to survive every HA restart, remove the
|
||||||
|
# initial lines after the helpers have been created and set once.
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# INPUT DATETIME
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
input_datetime:
|
||||||
|
free_power_start_time:
|
||||||
|
name: Free Power - Start Time
|
||||||
|
has_date: false
|
||||||
|
has_time: true
|
||||||
|
initial: "21:00:00"
|
||||||
|
icon: mdi:clock-start
|
||||||
|
|
||||||
|
free_power_end_time:
|
||||||
|
name: Free Power - End Time
|
||||||
|
has_date: false
|
||||||
|
has_time: true
|
||||||
|
initial: "00:00:00"
|
||||||
|
icon: mdi:clock-end
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# ENABLE SWITCHES
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
input_boolean:
|
||||||
|
free_power_automation_enabled:
|
||||||
|
name: Free Power - Master Automation Enable
|
||||||
|
icon: mdi:transmission-tower
|
||||||
|
|
||||||
|
free_power_announcement_enabled:
|
||||||
|
name: Free Power - Announcement Enable
|
||||||
|
icon: mdi:bullhorn
|
||||||
|
|
||||||
|
free_power_gas_heater_changeover_enabled:
|
||||||
|
name: Free Power - Gas Heater Changeover Enable
|
||||||
|
icon: mdi:heat-pump-outline
|
||||||
|
|
||||||
|
free_power_tool_battery_chargers_enabled:
|
||||||
|
name: Free Power - Tool Battery Chargers Enable
|
||||||
|
icon: mdi:battery-charging
|
||||||
|
|
||||||
|
free_power_underhouse_dehumidifier_enabled:
|
||||||
|
name: Free Power - Underhouse Dehumidifier Enable
|
||||||
|
icon: mdi:air-humidifier
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# TEMPLATE SENSORS
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
template:
|
||||||
|
- binary_sensor:
|
||||||
|
- name: Free Power Time Active
|
||||||
|
unique_id: free_power_time_active
|
||||||
|
icon: mdi:transmission-tower
|
||||||
|
state: >-
|
||||||
|
{% set start = states('input_datetime.free_power_start_time') %}
|
||||||
|
{% set end = states('input_datetime.free_power_end_time') %}
|
||||||
|
{% set now_mins = now().hour * 60 + now().minute %}
|
||||||
|
{% set start_mins = (start[0:2] | int(0)) * 60 + (start[3:5] | int(0)) %}
|
||||||
|
{% set end_mins = (end[0:2] | int(0)) * 60 + (end[3:5] | int(0)) %}
|
||||||
|
|
||||||
|
{% if start_mins == end_mins %}
|
||||||
|
false
|
||||||
|
{% elif start_mins < end_mins %}
|
||||||
|
{{ start_mins <= now_mins < end_mins }}
|
||||||
|
{% else %}
|
||||||
|
{{ now_mins >= start_mins or now_mins < end_mins }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# SCRIPTS
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
script:
|
||||||
|
free_power_start_actions:
|
||||||
|
alias: Free Power - Start Actions
|
||||||
|
mode: single
|
||||||
|
sequence:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_boolean.free_power_automation_enabled
|
||||||
|
state: "on"
|
||||||
|
|
||||||
|
- variables:
|
||||||
|
free_power_time_label: >-
|
||||||
|
{%- set raw_time = states('input_datetime.free_power_start_time') -%}
|
||||||
|
{%- set hour = raw_time[0:2] | int(0) -%}
|
||||||
|
{%- set minute = raw_time[3:5] | int(0) -%}
|
||||||
|
{%- set suffix = 'am' if hour < 12 else 'pm' -%}
|
||||||
|
{%- set hour12 = hour % 12 -%}
|
||||||
|
{%- set hour12 = 12 if hour12 == 0 else hour12 -%}
|
||||||
|
{{- hour12 ~ suffix if minute == 0 else hour12 ~ ':' ~ '%02d' | format(minute) ~ suffix -}}
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# 1) Free Power Time Announcement
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
- if:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_boolean.free_power_announcement_enabled
|
||||||
|
state: "on"
|
||||||
|
then:
|
||||||
|
- action: script.view_road_announcement
|
||||||
|
data:
|
||||||
|
channels: "lounge_google_home_voice, sony_tv_lounge"
|
||||||
|
title: "View Road "
|
||||||
|
short_announcement: "{{ free_power_time_label }}: Free power time"
|
||||||
|
long_announcement: "It is {{ free_power_time_label }}."
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# 2) Gas Heater Changeover
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
- if:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_boolean.free_power_gas_heater_changeover_enabled
|
||||||
|
state: "on"
|
||||||
|
then:
|
||||||
|
- action: script.free_power_gas_heater_changeover
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# 3) Tool Battery Chargers On
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
- if:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_boolean.free_power_tool_battery_chargers_enabled
|
||||||
|
state: "on"
|
||||||
|
then:
|
||||||
|
- action: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id:
|
||||||
|
- switch.ryobi_charger_left_power_monitor_x17pp
|
||||||
|
- switch.ryobi_charger_right_power_monitor_x16pp
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# 4) Underhouse Dehumidifier On
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
- if:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_boolean.free_power_underhouse_dehumidifier_enabled
|
||||||
|
state: "on"
|
||||||
|
then:
|
||||||
|
- action: switch.turn_on
|
||||||
|
target:
|
||||||
|
entity_id:
|
||||||
|
- switch.underhouse_dehumidifier_power_plug_x10pp
|
||||||
|
|
||||||
|
free_power_end_actions:
|
||||||
|
alias: Free Power - End Actions
|
||||||
|
mode: single
|
||||||
|
sequence:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_boolean.free_power_automation_enabled
|
||||||
|
state: "on"
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# 3) Tool Battery Chargers Off
|
||||||
|
#
|
||||||
|
# If this action is enabled, the chargers are switched off at free power
|
||||||
|
# end even if something else turned them on.
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
- if:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_boolean.free_power_tool_battery_chargers_enabled
|
||||||
|
state: "on"
|
||||||
|
then:
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id:
|
||||||
|
- switch.ryobi_charger_left_power_monitor_x17pp
|
||||||
|
- switch.ryobi_charger_right_power_monitor_x16pp
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# 4) Underhouse Dehumidifier Off
|
||||||
|
#
|
||||||
|
# If this action is enabled, the dehumidifier is switched off at free power
|
||||||
|
# end even if something else turned it on.
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
- if:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_boolean.free_power_underhouse_dehumidifier_enabled
|
||||||
|
state: "on"
|
||||||
|
then:
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id:
|
||||||
|
- switch.underhouse_dehumidifier_power_plug_x10pp
|
||||||
|
|
||||||
|
free_power_gas_heater_changeover:
|
||||||
|
alias: Free Power - Gas Heater Changeover
|
||||||
|
mode: single
|
||||||
|
sequence:
|
||||||
|
###########################################################################
|
||||||
|
# YAML-only settings
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
- variables:
|
||||||
|
gas_heater_operation_entity: switch.rinnai_neo_gas_heater_heater_operation
|
||||||
|
gas_heater_setpoint_entity: number.rinnai_neo_gas_heater_rinnai_neo_gas_heater_setpoint
|
||||||
|
heatpump_climate_entity: climate.lounge
|
||||||
|
|
||||||
|
gas_heater_shutdown_delay_seconds: 60
|
||||||
|
heatpump_setpoint_offset_c: 0
|
||||||
|
|
||||||
|
heatpump_setpoint: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
(states(gas_heater_setpoint_entity) | float(0))
|
||||||
|
+ (heatpump_setpoint_offset_c | float(0))
|
||||||
|
) | round(1)
|
||||||
|
}}
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# Only change over if the gas heater is currently on.
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ is_state(gas_heater_operation_entity, 'on') }}"
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# Only continue if the gas setpoint can be read.
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
- condition: template
|
||||||
|
value_template: >-
|
||||||
|
{{ states(gas_heater_setpoint_entity) not in ['unknown', 'unavailable', 'none', 'None', ''] }}
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# Set the Panasonic heatpump to heat mode and match the gas heater setpoint,
|
||||||
|
# with the YAML-only offset applied.
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
- action: climate.set_temperature
|
||||||
|
target:
|
||||||
|
entity_id: climate.lounge
|
||||||
|
data:
|
||||||
|
hvac_mode: heat
|
||||||
|
temperature: "{{ heatpump_setpoint }}"
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# Give the heatpump time to start before turning the gas heater off.
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
seconds: "{{ gas_heater_shutdown_delay_seconds | int(60) }}"
|
||||||
|
|
||||||
|
- action: switch.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: switch.rinnai_neo_gas_heater_heater_operation
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# AUTOMATIONS
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
automation:
|
||||||
|
- id: free_power_time_start_actions
|
||||||
|
alias: Free Power Time - Start Actions
|
||||||
|
mode: single
|
||||||
|
triggers:
|
||||||
|
- trigger: time
|
||||||
|
at: input_datetime.free_power_start_time
|
||||||
|
actions:
|
||||||
|
- action: script.free_power_start_actions
|
||||||
|
|
||||||
|
- id: free_power_time_end_actions
|
||||||
|
alias: Free Power Time - End Actions
|
||||||
|
mode: single
|
||||||
|
triggers:
|
||||||
|
- trigger: time
|
||||||
|
at: input_datetime.free_power_end_time
|
||||||
|
actions:
|
||||||
|
- action: script.free_power_end_actions
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
mqtt:
|
|
||||||
sensor:
|
|
||||||
- unique_id: gas_heater_operating
|
|
||||||
name: "Gas Heater Operating"
|
|
||||||
state_topic: "viewroad-status/gasheater/operating"
|
|
||||||
switch:
|
|
||||||
- unique_id: gasheater_switch
|
|
||||||
name: "Gas Heater"
|
|
||||||
state_topic: "viewroad-status/gasheater/operating"
|
|
||||||
command_topic: "viewroad-commands/gasheater/onoff"
|
|
||||||
#availability:
|
|
||||||
# - topic: "home/bedroom/switch1/available"
|
|
||||||
payload_on: "ON"
|
|
||||||
payload_off: "OFF"
|
|
||||||
state_on: "ON"
|
|
||||||
state_off: "OFF"
|
|
||||||
optimistic: false
|
|
||||||
qos: 0
|
|
||||||
retain: true # need this, or fire starts on HA reboot. Could fix in Node red too.
|
|
||||||
@@ -0,0 +1,368 @@
|
|||||||
|
###############################################################################
|
||||||
|
# PACKAGE: Lounge Blinds - Sunrise / Sunset Automation
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# VERSION:
|
||||||
|
# v1.2 - 2026-05-08
|
||||||
|
# - Updated input_boolean.lounge_blinds control logic.
|
||||||
|
# - input_boolean.lounge_blinds ON now closes the blinds.
|
||||||
|
# - input_boolean.lounge_blinds OFF now opens the blinds.
|
||||||
|
# - Removed the sync guard helper.
|
||||||
|
# - Added state checks so cover feedback does not create command loops.
|
||||||
|
#
|
||||||
|
# v1.1 - 2026-05-08
|
||||||
|
# - Added input_boolean.lounge_blinds as a manual control/status helper.
|
||||||
|
# - Added cover state sync back to input_boolean.lounge_blinds.
|
||||||
|
#
|
||||||
|
# v1.0 - 2026-05-08
|
||||||
|
# - Initial package.
|
||||||
|
# - Opens lounge blinds at sunrise.
|
||||||
|
# - Closes lounge blinds at sunset.
|
||||||
|
# - Includes sunrise/sunset minute offsets.
|
||||||
|
# - Includes repeated command attempts for Zigbee reliability.
|
||||||
|
# - Opens blinds in list order: A, B, C.
|
||||||
|
# - Closes blinds in reverse list order: C, B, A.
|
||||||
|
#
|
||||||
|
# NOTES:
|
||||||
|
# - input_boolean.lounge_blinds is treated as:
|
||||||
|
# ON = blinds closed
|
||||||
|
# OFF = blinds open
|
||||||
|
#
|
||||||
|
# - Turning input_boolean.lounge_blinds ON will close the blinds.
|
||||||
|
# - Turning input_boolean.lounge_blinds OFF will open the blinds.
|
||||||
|
# - If all blinds are closed by another method, the boolean will turn ON.
|
||||||
|
# - If all blinds are opened by another method, the boolean will turn OFF.
|
||||||
|
# - If blinds are in a mixed/partial state, the boolean is left unchanged.
|
||||||
|
#
|
||||||
|
# - The blind entity list is inside:
|
||||||
|
# script.lounge_blinds_run_sequence
|
||||||
|
# script.lounge_blinds_sync_status
|
||||||
|
# automation.lounge_blinds_control_from_input_boolean
|
||||||
|
#
|
||||||
|
# - If you add more blinds, update the blind list in those three places.
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
input_boolean:
|
||||||
|
lounge_blinds:
|
||||||
|
name: Lounge Blinds Closed
|
||||||
|
icon: mdi:blinds
|
||||||
|
|
||||||
|
input_number:
|
||||||
|
lounge_blinds_sunrise_offset_minutes:
|
||||||
|
name: Lounge Blinds Sunrise Offset
|
||||||
|
icon: mdi:weather-sunset-up
|
||||||
|
min: -180
|
||||||
|
max: 180
|
||||||
|
step: 1
|
||||||
|
mode: box
|
||||||
|
unit_of_measurement: min
|
||||||
|
initial: 0
|
||||||
|
|
||||||
|
lounge_blinds_sunset_offset_minutes:
|
||||||
|
name: Lounge Blinds Sunset Offset
|
||||||
|
icon: mdi:weather-sunset-down
|
||||||
|
min: -180
|
||||||
|
max: 180
|
||||||
|
step: 1
|
||||||
|
mode: box
|
||||||
|
unit_of_measurement: min
|
||||||
|
initial: 0
|
||||||
|
|
||||||
|
lounge_blinds_per_blind_delay_seconds:
|
||||||
|
name: Lounge Blinds Per-Blind Delay
|
||||||
|
icon: mdi:timer-outline
|
||||||
|
min: 0
|
||||||
|
max: 60
|
||||||
|
step: 1
|
||||||
|
mode: box
|
||||||
|
unit_of_measurement: sec
|
||||||
|
initial: 2
|
||||||
|
|
||||||
|
lounge_blinds_command_repeats:
|
||||||
|
name: Lounge Blinds Command Repeats
|
||||||
|
icon: mdi:repeat
|
||||||
|
min: 1
|
||||||
|
max: 5
|
||||||
|
step: 1
|
||||||
|
mode: box
|
||||||
|
initial: 2
|
||||||
|
|
||||||
|
lounge_blinds_retry_delay_seconds:
|
||||||
|
name: Lounge Blinds Retry Delay
|
||||||
|
icon: mdi:timer-refresh-outline
|
||||||
|
min: 0
|
||||||
|
max: 120
|
||||||
|
step: 1
|
||||||
|
mode: box
|
||||||
|
unit_of_measurement: sec
|
||||||
|
initial: 10
|
||||||
|
|
||||||
|
input_datetime:
|
||||||
|
lounge_blinds_next_open_time:
|
||||||
|
name: Lounge Blinds Next Open Time
|
||||||
|
has_date: true
|
||||||
|
has_time: true
|
||||||
|
|
||||||
|
lounge_blinds_next_close_time:
|
||||||
|
name: Lounge Blinds Next Close Time
|
||||||
|
has_date: true
|
||||||
|
has_time: true
|
||||||
|
|
||||||
|
script:
|
||||||
|
lounge_blinds_update_sun_times:
|
||||||
|
alias: Lounge Blinds - Update Sun Times
|
||||||
|
mode: single
|
||||||
|
sequence:
|
||||||
|
- variables:
|
||||||
|
sunrise_offset_seconds: >
|
||||||
|
{{ states('input_number.lounge_blinds_sunrise_offset_minutes') | int(0) * 60 }}
|
||||||
|
sunset_offset_seconds: >
|
||||||
|
{{ states('input_number.lounge_blinds_sunset_offset_minutes') | int(0) * 60 }}
|
||||||
|
next_sunrise_timestamp: >
|
||||||
|
{{ as_timestamp(state_attr('sun.sun', 'next_rising')) + sunrise_offset_seconds }}
|
||||||
|
next_sunset_timestamp: >
|
||||||
|
{{ as_timestamp(state_attr('sun.sun', 'next_setting')) + sunset_offset_seconds }}
|
||||||
|
|
||||||
|
- action: input_datetime.set_datetime
|
||||||
|
target:
|
||||||
|
entity_id: input_datetime.lounge_blinds_next_open_time
|
||||||
|
data:
|
||||||
|
datetime: >
|
||||||
|
{{ next_sunrise_timestamp | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}
|
||||||
|
|
||||||
|
- action: input_datetime.set_datetime
|
||||||
|
target:
|
||||||
|
entity_id: input_datetime.lounge_blinds_next_close_time
|
||||||
|
data:
|
||||||
|
datetime: >
|
||||||
|
{{ next_sunset_timestamp | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}
|
||||||
|
|
||||||
|
lounge_blinds_run_sequence:
|
||||||
|
alias: Lounge Blinds - Run Open/Close Sequence
|
||||||
|
mode: queued
|
||||||
|
fields:
|
||||||
|
blind_action:
|
||||||
|
name: Blind Action
|
||||||
|
description: Use open or close.
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
select:
|
||||||
|
options:
|
||||||
|
- open
|
||||||
|
- close
|
||||||
|
|
||||||
|
sequence:
|
||||||
|
- variables:
|
||||||
|
blind_list:
|
||||||
|
- cover.lounge_blind_a_xbl11
|
||||||
|
- cover.lounge_blind_b_xbl12
|
||||||
|
- cover.lounge_blind_c_xbl13
|
||||||
|
|
||||||
|
command_repeats: >
|
||||||
|
{{ states('input_number.lounge_blinds_command_repeats') | int(2) }}
|
||||||
|
|
||||||
|
retry_delay_seconds: >
|
||||||
|
{{ states('input_number.lounge_blinds_retry_delay_seconds') | int(10) }}
|
||||||
|
|
||||||
|
per_blind_delay_seconds: >
|
||||||
|
{{ states('input_number.lounge_blinds_per_blind_delay_seconds') | int(2) }}
|
||||||
|
|
||||||
|
- repeat:
|
||||||
|
count: "{{ command_repeats }}"
|
||||||
|
sequence:
|
||||||
|
- choose:
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ blind_action == 'open' }}"
|
||||||
|
sequence:
|
||||||
|
- repeat:
|
||||||
|
for_each: "{{ blind_list }}"
|
||||||
|
sequence:
|
||||||
|
- action: cover.open_cover
|
||||||
|
target:
|
||||||
|
entity_id: "{{ repeat.item }}"
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
seconds: "{{ per_blind_delay_seconds }}"
|
||||||
|
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ blind_action == 'close' }}"
|
||||||
|
sequence:
|
||||||
|
- repeat:
|
||||||
|
for_each: "{{ blind_list | reverse | list }}"
|
||||||
|
sequence:
|
||||||
|
- action: cover.close_cover
|
||||||
|
target:
|
||||||
|
entity_id: "{{ repeat.item }}"
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
seconds: "{{ per_blind_delay_seconds }}"
|
||||||
|
|
||||||
|
- if:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ repeat.index < command_repeats }}"
|
||||||
|
then:
|
||||||
|
- delay:
|
||||||
|
seconds: "{{ retry_delay_seconds }}"
|
||||||
|
|
||||||
|
- action: script.lounge_blinds_sync_status
|
||||||
|
|
||||||
|
lounge_blinds_sync_status:
|
||||||
|
alias: Lounge Blinds - Sync Status
|
||||||
|
mode: queued
|
||||||
|
sequence:
|
||||||
|
- variables:
|
||||||
|
blind_list:
|
||||||
|
- cover.lounge_blind_a_xbl11
|
||||||
|
- cover.lounge_blind_b_xbl12
|
||||||
|
- cover.lounge_blind_c_xbl13
|
||||||
|
|
||||||
|
blind_states: >
|
||||||
|
{{ expand(blind_list) | map(attribute='state') | list }}
|
||||||
|
|
||||||
|
all_blinds_closed: >
|
||||||
|
{{ blind_states | select('eq', 'closed') | list | count == blind_list | count }}
|
||||||
|
|
||||||
|
all_blinds_open: >
|
||||||
|
{{ blind_states | select('eq', 'open') | list | count == blind_list | count }}
|
||||||
|
|
||||||
|
- choose:
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: >
|
||||||
|
{{ all_blinds_closed and is_state('input_boolean.lounge_blinds', 'off') }}
|
||||||
|
sequence:
|
||||||
|
- action: input_boolean.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: input_boolean.lounge_blinds
|
||||||
|
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: >
|
||||||
|
{{ all_blinds_open and is_state('input_boolean.lounge_blinds', 'on') }}
|
||||||
|
sequence:
|
||||||
|
- action: input_boolean.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: input_boolean.lounge_blinds
|
||||||
|
|
||||||
|
automation:
|
||||||
|
- id: lounge_blinds_update_sun_times
|
||||||
|
alias: Lounge Blinds - Update Sun Times
|
||||||
|
mode: restart
|
||||||
|
trigger:
|
||||||
|
- platform: homeassistant
|
||||||
|
event: start
|
||||||
|
|
||||||
|
- platform: time
|
||||||
|
at: "00:05:00"
|
||||||
|
|
||||||
|
- platform: state
|
||||||
|
entity_id:
|
||||||
|
- input_number.lounge_blinds_sunrise_offset_minutes
|
||||||
|
- input_number.lounge_blinds_sunset_offset_minutes
|
||||||
|
|
||||||
|
action:
|
||||||
|
- action: script.lounge_blinds_update_sun_times
|
||||||
|
|
||||||
|
- id: lounge_blinds_open_at_sunrise
|
||||||
|
alias: Lounge Blinds - Open At Sunrise
|
||||||
|
mode: single
|
||||||
|
trigger:
|
||||||
|
- platform: time
|
||||||
|
at: input_datetime.lounge_blinds_next_open_time
|
||||||
|
|
||||||
|
action:
|
||||||
|
- action: script.lounge_blinds_run_sequence
|
||||||
|
data:
|
||||||
|
blind_action: open
|
||||||
|
|
||||||
|
- id: lounge_blinds_close_at_sunset
|
||||||
|
alias: Lounge Blinds - Close At Sunset
|
||||||
|
mode: single
|
||||||
|
trigger:
|
||||||
|
- platform: time
|
||||||
|
at: input_datetime.lounge_blinds_next_close_time
|
||||||
|
|
||||||
|
action:
|
||||||
|
- action: script.lounge_blinds_run_sequence
|
||||||
|
data:
|
||||||
|
blind_action: close
|
||||||
|
|
||||||
|
- id: lounge_blinds_control_from_input_boolean
|
||||||
|
alias: Lounge Blinds - Control From Input Boolean
|
||||||
|
mode: restart
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id: input_boolean.lounge_blinds
|
||||||
|
to: "on"
|
||||||
|
|
||||||
|
- platform: state
|
||||||
|
entity_id: input_boolean.lounge_blinds
|
||||||
|
to: "off"
|
||||||
|
|
||||||
|
action:
|
||||||
|
- variables:
|
||||||
|
blind_list:
|
||||||
|
- cover.lounge_blind_a_xbl11
|
||||||
|
- cover.lounge_blind_b_xbl12
|
||||||
|
- cover.lounge_blind_c_xbl13
|
||||||
|
|
||||||
|
blind_states: >
|
||||||
|
{{ expand(blind_list) | map(attribute='state') | list }}
|
||||||
|
|
||||||
|
all_blinds_closed: >
|
||||||
|
{{ blind_states | select('eq', 'closed') | list | count == blind_list | count }}
|
||||||
|
|
||||||
|
all_blinds_open: >
|
||||||
|
{{ blind_states | select('eq', 'open') | list | count == blind_list | count }}
|
||||||
|
|
||||||
|
- choose:
|
||||||
|
- conditions:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_boolean.lounge_blinds
|
||||||
|
state: "on"
|
||||||
|
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ not all_blinds_closed }}"
|
||||||
|
sequence:
|
||||||
|
- action: script.lounge_blinds_run_sequence
|
||||||
|
data:
|
||||||
|
blind_action: close
|
||||||
|
|
||||||
|
- conditions:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_boolean.lounge_blinds
|
||||||
|
state: "off"
|
||||||
|
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ not all_blinds_open }}"
|
||||||
|
sequence:
|
||||||
|
- action: script.lounge_blinds_run_sequence
|
||||||
|
data:
|
||||||
|
blind_action: open
|
||||||
|
|
||||||
|
- id: lounge_blinds_sync_input_boolean_from_cover_states
|
||||||
|
alias: Lounge Blinds - Sync Input Boolean From Cover States
|
||||||
|
mode: restart
|
||||||
|
trigger:
|
||||||
|
- platform: homeassistant
|
||||||
|
event: start
|
||||||
|
|
||||||
|
- platform: state
|
||||||
|
entity_id:
|
||||||
|
- cover.lounge_blind_a_xbl11
|
||||||
|
- cover.lounge_blind_b_xbl12
|
||||||
|
- cover.lounge_blind_c_xbl13
|
||||||
|
to: "open"
|
||||||
|
|
||||||
|
- platform: state
|
||||||
|
entity_id:
|
||||||
|
- cover.lounge_blind_a_xbl11
|
||||||
|
- cover.lounge_blind_b_xbl12
|
||||||
|
- cover.lounge_blind_c_xbl13
|
||||||
|
to: "closed"
|
||||||
|
|
||||||
|
action:
|
||||||
|
- action: script.lounge_blinds_sync_status
|
||||||
@@ -46,8 +46,10 @@ input_select:
|
|||||||
- "Select Scene:"
|
- "Select Scene:"
|
||||||
- Bright
|
- Bright
|
||||||
- TV General
|
- TV General
|
||||||
|
- Balanced
|
||||||
- Movie
|
- Movie
|
||||||
- Reading On/Off
|
- Reading On/Off
|
||||||
|
- Dining On/Off
|
||||||
- Night Light
|
- Night Light
|
||||||
- Warm Cozy
|
- Warm Cozy
|
||||||
- All Off
|
- All Off
|
||||||
@@ -106,6 +108,7 @@ script:
|
|||||||
excluded_scenes:
|
excluded_scenes:
|
||||||
- "Select Scene:"
|
- "Select Scene:"
|
||||||
- "Reading On/Off"
|
- "Reading On/Off"
|
||||||
|
- "Dining On/Off"
|
||||||
#- "Night Light"
|
#- "Night Light"
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
@@ -120,18 +123,20 @@ script:
|
|||||||
light.esp_lounge6chdimmer_lounge_downlights_centre: 100
|
light.esp_lounge6chdimmer_lounge_downlights_centre: 100
|
||||||
light.esp_lounge6chdimmer_lounge_downlights_south: 100
|
light.esp_lounge6chdimmer_lounge_downlights_south: 100
|
||||||
light.esp_lounge6chdimmer_lounge_rafter_buttons: 100
|
light.esp_lounge6chdimmer_lounge_rafter_buttons: 100
|
||||||
switch.esp_loungemiddleswitch_relay_3_downlights_north: "on"
|
#switch.esp_loungemiddleswitch_relay_3_downlights_north: "on"
|
||||||
|
switch.lounge_nspanel_touchscreen_lounge_stair_downlights: "on" # non dimmable pair
|
||||||
light.esp_breakfastbarleds_breakfast_bar_leds: 90
|
light.esp_breakfastbarleds_breakfast_bar_leds: 90
|
||||||
light.esp_loungecabinetleds2_lounge_cabinet_leds: 90
|
light.esp_loungecabinetleds2_lounge_cabinet_leds: 90
|
||||||
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 90
|
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 90
|
||||||
switch.lounge_cupboard_dual_usb_xus09_l2: "on"
|
switch.lounge_cupboard_dual_usb_xus09_l2: "on"
|
||||||
switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: "on"
|
switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: "on"
|
||||||
switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: "on"
|
switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: "on"
|
||||||
switch.tasmo_ks811t_0702_lounge_3c: "on"
|
#switch.tasmo_ks811t_0702_lounge_3c: "on"
|
||||||
#switch.esp_loungenorthswitch_relay_1_main_lights: "on"
|
#switch.esp_loungenorthswitch_relay_1_main_lights: "on"
|
||||||
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 100
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 100
|
||||||
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 100
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 100
|
||||||
input_number.openhasp_1_backlight_level: 255
|
input_number.openhasp_1_backlight_level: 255
|
||||||
|
number.lounge_nspanel_touchscreen_display_brightness: 100
|
||||||
|
|
||||||
TV General:
|
TV General:
|
||||||
light.esp_lounge6chdimmer_couch_spots_left: 60
|
light.esp_lounge6chdimmer_couch_spots_left: 60
|
||||||
@@ -143,7 +148,8 @@ script:
|
|||||||
light.esp_breakfastbarleds_breakfast_bar_leds: 60
|
light.esp_breakfastbarleds_breakfast_bar_leds: 60
|
||||||
light.esp_loungecabinetleds2_lounge_cabinet_leds: 60
|
light.esp_loungecabinetleds2_lounge_cabinet_leds: 60
|
||||||
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 60
|
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 60
|
||||||
switch.esp_loungemiddleswitch_relay_3_downlights_north: "off" # non-dimmable pair
|
#switch.esp_loungemiddleswitch_relay_3_downlights_north: "off" # non-dimmable pair
|
||||||
|
switch.lounge_nspanel_touchscreen_lounge_stair_downlights: "off" # non dimmable pair
|
||||||
switch.lounge_cupboard_dual_usb_xus09_l2: "on"
|
switch.lounge_cupboard_dual_usb_xus09_l2: "on"
|
||||||
switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: "off"
|
switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: "off"
|
||||||
switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: "off"
|
switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: "off"
|
||||||
@@ -151,6 +157,28 @@ script:
|
|||||||
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 60
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 60
|
||||||
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 60
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 60
|
||||||
input_number.openhasp_1_backlight_level: 120
|
input_number.openhasp_1_backlight_level: 120
|
||||||
|
number.lounge_nspanel_touchscreen_display_brightness: 80
|
||||||
|
|
||||||
|
Balanced:
|
||||||
|
light.esp_lounge6chdimmer_couch_spots_left: 40
|
||||||
|
light.esp_lounge6chdimmer_couch_spots_right: 40
|
||||||
|
#light.esp_lounge6chdimmer_dining_table_light: 100
|
||||||
|
light.esp_lounge6chdimmer_lounge_downlights_centre: 40
|
||||||
|
light.esp_lounge6chdimmer_lounge_downlights_south: 40
|
||||||
|
light.esp_lounge6chdimmer_lounge_rafter_buttons: 30
|
||||||
|
light.esp_breakfastbarleds_breakfast_bar_leds: 50
|
||||||
|
light.esp_loungecabinetleds2_lounge_cabinet_leds: 50
|
||||||
|
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 50
|
||||||
|
#switch.esp_loungemiddleswitch_relay_3_downlights_north: "off" # non-dimmable pair
|
||||||
|
switch.lounge_nspanel_touchscreen_lounge_stair_downlights: "off" # non dimmable pair
|
||||||
|
switch.lounge_cupboard_dual_usb_xus09_l2: "on"
|
||||||
|
switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: "off"
|
||||||
|
switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: "off"
|
||||||
|
#switch.esp_loungenorthswitch_relay_1_main_lights: "on"
|
||||||
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 50
|
||||||
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 50
|
||||||
|
input_number.openhasp_1_backlight_level: 100
|
||||||
|
number.lounge_nspanel_touchscreen_display_brightness: 80
|
||||||
|
|
||||||
Movie:
|
Movie:
|
||||||
light.esp_lounge6chdimmer_couch_spots_left: 20
|
light.esp_lounge6chdimmer_couch_spots_left: 20
|
||||||
@@ -162,7 +190,8 @@ script:
|
|||||||
light.esp_breakfastbarleds_breakfast_bar_leds: 40
|
light.esp_breakfastbarleds_breakfast_bar_leds: 40
|
||||||
light.esp_loungecabinetleds2_lounge_cabinet_leds: 40
|
light.esp_loungecabinetleds2_lounge_cabinet_leds: 40
|
||||||
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 40
|
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 40
|
||||||
switch.esp_loungemiddleswitch_relay_3_downlights_north: "off"
|
#switch.esp_loungemiddleswitch_relay_3_downlights_north: "off"
|
||||||
|
switch.lounge_nspanel_touchscreen_lounge_stair_downlights: "off" # non dimmable pair
|
||||||
switch.lounge_cupboard_dual_usb_xus09_l2: "on"
|
switch.lounge_cupboard_dual_usb_xus09_l2: "on"
|
||||||
switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: "off"
|
switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: "off"
|
||||||
switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: "off"
|
switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: "off"
|
||||||
@@ -170,6 +199,17 @@ script:
|
|||||||
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 40
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 40
|
||||||
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 40
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 40
|
||||||
input_number.openhasp_1_backlight_level: 15
|
input_number.openhasp_1_backlight_level: 15
|
||||||
|
switch.esp_mainkitchenlights_relay_1_main_lights: "off"
|
||||||
|
switch.esp_mainkitchenlights_relay_2_benchtop_lights: "off"
|
||||||
|
number.lounge_nspanel_touchscreen_display_brightness: 40
|
||||||
|
|
||||||
|
Dining On/Off:
|
||||||
|
light.esp_lounge6chdimmer_dining_table_light: "toggle_100"
|
||||||
|
#light.esp_lounge6chdimmer_dining_table_light: 60
|
||||||
|
#light.esp_lounge6chdimmer_lounge_downlights_centre: 45
|
||||||
|
#light.esp_lounge6chdimmer_lounge_downlights_south: 35
|
||||||
|
#light.esp_lounge6chdimmer_lounge_rafter_buttons: 20
|
||||||
|
#switch.tasmo_ks811t_0702_lounge_3c: "on"
|
||||||
|
|
||||||
Reading On/Off:
|
Reading On/Off:
|
||||||
light.esp_lounge6chdimmer_couch_spots_left: "toggle_75"
|
light.esp_lounge6chdimmer_couch_spots_left: "toggle_75"
|
||||||
@@ -190,14 +230,16 @@ script:
|
|||||||
light.esp_breakfastbarleds_breakfast_bar_leds: 5
|
light.esp_breakfastbarleds_breakfast_bar_leds: 5
|
||||||
light.esp_loungecabinetleds2_lounge_cabinet_leds: 5
|
light.esp_loungecabinetleds2_lounge_cabinet_leds: 5
|
||||||
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 5
|
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 5
|
||||||
switch.esp_loungemiddleswitch_relay_3_downlights_north: "off"
|
#switch.esp_loungemiddleswitch_relay_3_downlights_north: "off"
|
||||||
|
switch.lounge_nspanel_touchscreen_lounge_stair_downlights: "off" # non dimmable pair
|
||||||
switch.lounge_cupboard_dual_usb_xus09_l2: "off"
|
switch.lounge_cupboard_dual_usb_xus09_l2: "off"
|
||||||
switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: "off"
|
switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: "off"
|
||||||
switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: "off"
|
switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: "off"
|
||||||
#switch.esp_loungenorthswitch_relay_1_main_lights: "on"
|
#switch.esp_loungenorthswitch_relay_1_main_lights: "on"
|
||||||
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 5
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 5
|
||||||
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 5
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 5
|
||||||
input_number.openhasp_1_backlight_level: 8
|
input_number.openhasp_1_backlight_level: 10
|
||||||
|
number.lounge_nspanel_touchscreen_display_brightness: 30
|
||||||
|
|
||||||
Warm Cozy:
|
Warm Cozy:
|
||||||
light.esp_lounge6chdimmer_couch_spots_left: 20
|
light.esp_lounge6chdimmer_couch_spots_left: 20
|
||||||
@@ -206,8 +248,9 @@ script:
|
|||||||
light.esp_breakfastbarleds_breakfast_bar_leds: 25
|
light.esp_breakfastbarleds_breakfast_bar_leds: 25
|
||||||
light.esp_loungecabinetleds2_lounge_cabinet_leds: 30
|
light.esp_loungecabinetleds2_lounge_cabinet_leds: 30
|
||||||
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 30
|
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 30
|
||||||
light.tasmo_h801_loungeled1_6180_a: 25
|
#light.tasmo_h801_loungeled1_6180_a: 25
|
||||||
light.tasmo_h801_loungeled1_6180_b: 25
|
#light.tasmo_h801_loungeled1_6180_b: 25
|
||||||
|
switch.lounge_nspanel_touchscreen_lounge_stair_downlights: "off" # non dimmable pair
|
||||||
switch.lounge_cupboard_dual_usb_xus09_l2: "on"
|
switch.lounge_cupboard_dual_usb_xus09_l2: "on"
|
||||||
switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: "on"
|
switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: "on"
|
||||||
switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: "on"
|
switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: "on"
|
||||||
@@ -215,6 +258,7 @@ script:
|
|||||||
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 20
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 20
|
||||||
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 20
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 20
|
||||||
input_number.openhasp_1_backlight_level: 12
|
input_number.openhasp_1_backlight_level: 12
|
||||||
|
number.lounge_nspanel_touchscreen_display_brightness: 40
|
||||||
|
|
||||||
All Off:
|
All Off:
|
||||||
light.esp_lounge6chdimmer_couch_spots_left: 0
|
light.esp_lounge6chdimmer_couch_spots_left: 0
|
||||||
@@ -223,7 +267,8 @@ script:
|
|||||||
light.esp_lounge6chdimmer_lounge_downlights_centre: 0
|
light.esp_lounge6chdimmer_lounge_downlights_centre: 0
|
||||||
light.esp_lounge6chdimmer_lounge_downlights_south: 0
|
light.esp_lounge6chdimmer_lounge_downlights_south: 0
|
||||||
light.esp_lounge6chdimmer_lounge_rafter_buttons: 0
|
light.esp_lounge6chdimmer_lounge_rafter_buttons: 0
|
||||||
switch.esp_loungemiddleswitch_relay_3_downlights_north: "off"
|
#switch.esp_loungemiddleswitch_relay_3_downlights_north: "off"
|
||||||
|
switch.lounge_nspanel_touchscreen_lounge_stair_downlights: "off" # non dimmable pair
|
||||||
light.esp_breakfastbarleds_breakfast_bar_leds: 0
|
light.esp_breakfastbarleds_breakfast_bar_leds: 0
|
||||||
light.esp_loungecabinetleds2_lounge_cabinet_leds: 0
|
light.esp_loungecabinetleds2_lounge_cabinet_leds: 0
|
||||||
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 0
|
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 0
|
||||||
@@ -234,6 +279,9 @@ script:
|
|||||||
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 0
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 0
|
||||||
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 0
|
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 0
|
||||||
#input_number.openhasp_1_backlight_level: 100
|
#input_number.openhasp_1_backlight_level: 100
|
||||||
|
#switch.esp_mainkitchenlights_relay_1_main_lights: "off"
|
||||||
|
#switch.esp_mainkitchenlights_relay_2_benchtop_lights: "off"
|
||||||
|
number.lounge_nspanel_touchscreen_display_brightness: 80
|
||||||
|
|
||||||
#########################################################################
|
#########################################################################
|
||||||
# REMEMBER LAST SCENE
|
# REMEMBER LAST SCENE
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
input_text:
|
|
||||||
teams_status:
|
|
||||||
name: Microsoft Teams status
|
|
||||||
icon: mdi:microsoft-teams
|
|
||||||
teams_activity:
|
|
||||||
name: Microsoft Teams activity
|
|
||||||
icon: mdi:phone-off
|
|
||||||
|
|
||||||
sensor:
|
|
||||||
- platform: template
|
|
||||||
sensors:
|
|
||||||
teams_status:
|
|
||||||
friendly_name: "Microsoft Teams status"
|
|
||||||
value_template: "{{states('input_text.teams_status')}}"
|
|
||||||
icon_template: "{{state_attr('input_text.teams_status','icon')}}"
|
|
||||||
unique_id: sensor.teams_status
|
|
||||||
teams_activity:
|
|
||||||
friendly_name: "Microsoft Teams activity"
|
|
||||||
value_template: "{{states('input_text.teams_activity')}}"
|
|
||||||
unique_id: sensor.teams_activity
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
template:
|
|
||||||
- light:
|
|
||||||
- name: "Inverted Quiet time as light"
|
|
||||||
unique_id: inverted_quiet_time_as_light
|
|
||||||
state: "{{ is_state('input_boolean.quiet_time', 'off') }}"
|
|
||||||
turn_on:
|
|
||||||
- service: light.turn_on
|
|
||||||
target:
|
|
||||||
entity_id: light.inverted_quiet_time_light
|
|
||||||
turn_off:
|
|
||||||
- service: light.turn_off
|
|
||||||
target:
|
|
||||||
entity_id: light.inverted_quiet_time_light
|
|
||||||
|
|
||||||
light:
|
|
||||||
- platform: group
|
|
||||||
name: "Entities to keep NSPanel Awake"
|
|
||||||
unique_id: entities_to_keep_nspanel_awake
|
|
||||||
entities:
|
|
||||||
- light.inverted_quiet_time_as_light_2
|
|
||||||
- light.master_bedroom_bedside_lamp_arlec_bulb_master_bedroom_bedside_lamp_arlec_bulb
|
|
||||||
- light.tasmo_ifan02_3793_bedrm1_1
|
|
||||||
- light.tasmo_ks811t_3647_bedrm1_1b
|
|
||||||
@@ -0,0 +1,732 @@
|
|||||||
|
# yaml-language-server: $schema=null
|
||||||
|
#:########################################################################################:#
|
||||||
|
# TITLE: NSPANEL LOUNGE CONTROLLER
|
||||||
|
# zorruno.com Home Assistant package
|
||||||
|
#:########################################################################################:#
|
||||||
|
# VERSIONS:
|
||||||
|
# V1.5 2026-05-19
|
||||||
|
# - Added Reading button brightness display.
|
||||||
|
# - Reading brightness is shown as the highest brightness percentage of either
|
||||||
|
# couch spot light.
|
||||||
|
# - Changed Balanced button icon to mdi:scale / \uE472.
|
||||||
|
# - Added startup panel page refresh before full button state refresh.
|
||||||
|
#
|
||||||
|
# V1.4 2026-05-19
|
||||||
|
# - Changed button highlighting to targeted updates.
|
||||||
|
# - Remembered scene changes update only the old scene button and new scene button.
|
||||||
|
# - Reading/Dining changes update only the Reading and Dining buttons.
|
||||||
|
# - Full refresh is only used at HA start or when manually called.
|
||||||
|
# - ON icon colour is black [0, 0, 0].
|
||||||
|
# - OFF icon colour is white [255, 255, 255].
|
||||||
|
#
|
||||||
|
# V1.3 2026-05-19
|
||||||
|
# - Tested page refresh method, but it did not reliably refresh remembered scenes.
|
||||||
|
#
|
||||||
|
# V1.2 2026-05-19
|
||||||
|
# - Added explicit NSPanel button refresh actions using esphome.esp_nspanel2lounge_button.
|
||||||
|
# - Button states were pushed to the NSPanel when lounge_last_scene or the
|
||||||
|
# Reading/Dining light states changed.
|
||||||
|
#
|
||||||
|
# V1.1 2026-05-18
|
||||||
|
# - Added template switches so remembered lighting scenes can stay highlighted
|
||||||
|
# on the NSPanel button page.
|
||||||
|
# - Updated Blueprint button entities from script.* to switch.*.
|
||||||
|
#
|
||||||
|
# V1.0 2026-05-18
|
||||||
|
# - Initial NSPanel Lounge Controller package using NSPanel Easy Blueprint.
|
||||||
|
#:########################################################################################:#
|
||||||
|
# PURPOSE:
|
||||||
|
# - Configures the Lounge NSPanel Easy button page.
|
||||||
|
# - Provides Home Assistant script wrappers for lounge lighting scene actions.
|
||||||
|
# - Provides template switches for NSPanel button state/highlighting.
|
||||||
|
# - Pushes targeted NSPanel button highlight updates when relevant states change.
|
||||||
|
#:########################################################################################:#
|
||||||
|
# OPERATION NOTES:
|
||||||
|
# - The NSPanel display is configured by the NSPanel Easy Blueprint automation.
|
||||||
|
# - The screen buttons point to switch.nspanel_lounge_scene_* entities.
|
||||||
|
# - Remembered scenes are highlighted from input_text.lounge_last_scene.
|
||||||
|
# - Reading On/Off is highlighted from either couch spot light being on.
|
||||||
|
# - Reading On/Off shows the highest couch spot brightness percentage.
|
||||||
|
# - Dining On/Off is highlighted from the dining table light being on.
|
||||||
|
# - Pressing any NSPanel touch button activates the assigned scene/action.
|
||||||
|
# - Normal remembered scene transitions update only:
|
||||||
|
# a) the previous remembered scene button to OFF
|
||||||
|
# b) the new remembered scene button to ON
|
||||||
|
#:########################################################################################:#
|
||||||
|
# DEPENDENCIES:
|
||||||
|
# - script.lounge_set_scene
|
||||||
|
# - input_text.lounge_last_scene
|
||||||
|
# - light.esp_lounge6chdimmer_couch_spots_left
|
||||||
|
# - light.esp_lounge6chdimmer_couch_spots_right
|
||||||
|
# - light.esp_lounge6chdimmer_dining_table_light
|
||||||
|
# - NSPanel Easy Blueprint:
|
||||||
|
# edwardtfn/nspanel_easy_blueprint.yaml
|
||||||
|
# - ESPHome actions:
|
||||||
|
# esphome.esp_nspanel2lounge_button
|
||||||
|
# esphome.esp_nspanel2lounge_command
|
||||||
|
#:########################################################################################:#
|
||||||
|
# NOTES:
|
||||||
|
# - This is Home Assistant package YAML, not ESPHome YAML.
|
||||||
|
# - The nspanel_name value is the Home Assistant device ID selected by the
|
||||||
|
# Blueprint dropdown. Do not replace it with an entity_id or ESPHome hostname.
|
||||||
|
# - The icon values used by esphome.esp_nspanel2lounge_button are HASP/Nextion
|
||||||
|
# icon codepoints, not mdi: icon names.
|
||||||
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# AUTOMATIONS
|
||||||
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
automation:
|
||||||
|
#:######################################################################################:#
|
||||||
|
# AUTOMATION: NSPanel Easy Blueprint Instance
|
||||||
|
#:######################################################################################:#
|
||||||
|
- id: nspanel_lounge_controller
|
||||||
|
alias: "NSPanel Lounge Controller"
|
||||||
|
description: "NSPanel Easy configuration for the lounge lighting scene panel."
|
||||||
|
use_blueprint:
|
||||||
|
path: edwardtfn/nspanel_easy_blueprint.yaml
|
||||||
|
input:
|
||||||
|
nspanel_name: 369e58c3779ff3dd9a0b4c59fadeac4f
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# BUTTON PAGE 01: Lounge Lighting Scenes
|
||||||
|
########################################################################
|
||||||
|
button_page01_label: Lounge Lighting Scenes
|
||||||
|
button_pages_icon_size: "10"
|
||||||
|
|
||||||
|
entity01: switch.nspanel_lounge_scene_bright
|
||||||
|
entity01_name: "Bright"
|
||||||
|
entity01_icon: mdi:brightness-7
|
||||||
|
entity01_confirm: false
|
||||||
|
|
||||||
|
entity02: switch.nspanel_lounge_scene_tv_general
|
||||||
|
entity02_name: "TV General"
|
||||||
|
entity02_icon: mdi:television
|
||||||
|
entity02_confirm: false
|
||||||
|
|
||||||
|
entity03: switch.nspanel_lounge_scene_movie
|
||||||
|
entity03_name: "Movie"
|
||||||
|
entity03_icon: mdi:movie-open
|
||||||
|
entity03_confirm: false
|
||||||
|
|
||||||
|
entity04: switch.nspanel_lounge_scene_balanced
|
||||||
|
entity04_name: "Balance"
|
||||||
|
entity04_icon: mdi:scale
|
||||||
|
entity04_confirm: false
|
||||||
|
|
||||||
|
entity05: switch.nspanel_lounge_scene_warm_cozy
|
||||||
|
entity05_name: "Warm Cozy"
|
||||||
|
entity05_icon: mdi:fireplace
|
||||||
|
entity05_confirm: false
|
||||||
|
|
||||||
|
entity06: switch.nspanel_lounge_scene_reading
|
||||||
|
entity06_name: "Reading On/Off"
|
||||||
|
entity06_icon: mdi:book-open-page-variant
|
||||||
|
entity06_confirm: false
|
||||||
|
|
||||||
|
entity07: switch.nspanel_lounge_scene_dining
|
||||||
|
entity07_name: "Dining On/Off"
|
||||||
|
entity07_icon: mdi:silverware-fork-knife
|
||||||
|
entity07_confirm: false
|
||||||
|
|
||||||
|
entity08: switch.nspanel_lounge_scene_all_off
|
||||||
|
entity08_name: "All Off"
|
||||||
|
entity08_icon: mdi:power
|
||||||
|
entity08_confirm: false
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
#:######################################################################################:#
|
||||||
|
# AUTOMATION: Refresh Remembered Scene Button Highlights
|
||||||
|
#
|
||||||
|
# Only updates the previous remembered scene button and the new remembered
|
||||||
|
# scene button when input_text.lounge_last_scene changes.
|
||||||
|
#:######################################################################################:#
|
||||||
|
- id: nspanel_lounge_refresh_remembered_scene_buttons
|
||||||
|
alias: "NSPanel Lounge - Refresh Remembered Scene Buttons"
|
||||||
|
description: "Update only the old and new remembered scene buttons on the NSPanel."
|
||||||
|
mode: restart
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id: input_text.lounge_last_scene
|
||||||
|
|
||||||
|
action:
|
||||||
|
- delay:
|
||||||
|
milliseconds: 500
|
||||||
|
|
||||||
|
- variables:
|
||||||
|
old_scene: "{{ trigger.from_state.state if trigger.from_state is not none else '' }}"
|
||||||
|
new_scene: "{{ trigger.to_state.state if trigger.to_state is not none else states('input_text.lounge_last_scene') }}"
|
||||||
|
remembered_scenes:
|
||||||
|
- "Bright"
|
||||||
|
- "TV General"
|
||||||
|
- "Balanced"
|
||||||
|
- "Movie"
|
||||||
|
- "Warm Cozy"
|
||||||
|
- "All Off"
|
||||||
|
|
||||||
|
- choose:
|
||||||
|
- conditions: "{{ old_scene in remembered_scenes and old_scene != new_scene }}"
|
||||||
|
sequence:
|
||||||
|
- action: script.nspanel_lounge_push_scene_button_state
|
||||||
|
data:
|
||||||
|
scene_name: "{{ old_scene }}"
|
||||||
|
button_state: false
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
milliseconds: 100
|
||||||
|
|
||||||
|
- choose:
|
||||||
|
- conditions: "{{ new_scene in remembered_scenes }}"
|
||||||
|
sequence:
|
||||||
|
- action: script.nspanel_lounge_push_scene_button_state
|
||||||
|
data:
|
||||||
|
scene_name: "{{ new_scene }}"
|
||||||
|
button_state: true
|
||||||
|
|
||||||
|
#:######################################################################################:#
|
||||||
|
# AUTOMATION: Refresh Reading And Dining Button Highlights
|
||||||
|
#
|
||||||
|
# Reading/Dining are toggle/action scenes, so they are updated from the real
|
||||||
|
# light states rather than input_text.lounge_last_scene.
|
||||||
|
#:######################################################################################:#
|
||||||
|
- id: nspanel_lounge_refresh_toggle_scene_buttons
|
||||||
|
alias: "NSPanel Lounge - Refresh Toggle Scene Buttons"
|
||||||
|
description: "Update Reading and Dining buttons when their lights change."
|
||||||
|
mode: restart
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id:
|
||||||
|
- light.esp_lounge6chdimmer_couch_spots_left
|
||||||
|
- light.esp_lounge6chdimmer_couch_spots_right
|
||||||
|
- light.esp_lounge6chdimmer_dining_table_light
|
||||||
|
|
||||||
|
- platform: state
|
||||||
|
entity_id:
|
||||||
|
- light.esp_lounge6chdimmer_couch_spots_left
|
||||||
|
- light.esp_lounge6chdimmer_couch_spots_right
|
||||||
|
- light.esp_lounge6chdimmer_dining_table_light
|
||||||
|
attribute: brightness
|
||||||
|
|
||||||
|
action:
|
||||||
|
- delay:
|
||||||
|
milliseconds: 500
|
||||||
|
|
||||||
|
- action: script.nspanel_lounge_push_scene_button_state
|
||||||
|
data:
|
||||||
|
scene_name: "Reading On/Off"
|
||||||
|
button_state: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
is_state('light.esp_lounge6chdimmer_couch_spots_left', 'on')
|
||||||
|
and (state_attr('light.esp_lounge6chdimmer_couch_spots_left', 'brightness') | int(0)) > 0
|
||||||
|
)
|
||||||
|
or
|
||||||
|
(
|
||||||
|
is_state('light.esp_lounge6chdimmer_couch_spots_right', 'on')
|
||||||
|
and (state_attr('light.esp_lounge6chdimmer_couch_spots_right', 'brightness') | int(0)) > 0
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
milliseconds: 100
|
||||||
|
|
||||||
|
- action: script.nspanel_lounge_push_scene_button_state
|
||||||
|
data:
|
||||||
|
scene_name: "Dining On/Off"
|
||||||
|
button_state: >-
|
||||||
|
{{
|
||||||
|
is_state('light.esp_lounge6chdimmer_dining_table_light', 'on')
|
||||||
|
and (state_attr('light.esp_lounge6chdimmer_dining_table_light', 'brightness') | int(0)) > 0
|
||||||
|
}}
|
||||||
|
|
||||||
|
#:######################################################################################:#
|
||||||
|
# AUTOMATION: Initial NSPanel Button Refresh
|
||||||
|
#
|
||||||
|
# Full refresh happens when HA starts, or when the NSPanel comes back online.
|
||||||
|
# Normal scene changes update only the required buttons.
|
||||||
|
#:######################################################################################:#
|
||||||
|
- id: nspanel_lounge_refresh_all_buttons_on_start
|
||||||
|
alias: "NSPanel Lounge - Refresh All Buttons On Start"
|
||||||
|
description: "Refresh all NSPanel lounge buttons when HA starts or the panel reconnects."
|
||||||
|
mode: restart
|
||||||
|
trigger:
|
||||||
|
- platform: homeassistant
|
||||||
|
event: start
|
||||||
|
|
||||||
|
- platform: state
|
||||||
|
entity_id: number.lounge_nspanel_touchscreen_display_brightness
|
||||||
|
from: "unavailable"
|
||||||
|
|
||||||
|
- platform: state
|
||||||
|
entity_id: number.lounge_nspanel_touchscreen_display_brightness
|
||||||
|
from: "unknown"
|
||||||
|
|
||||||
|
action:
|
||||||
|
- delay:
|
||||||
|
seconds: 20
|
||||||
|
|
||||||
|
- action: esphome.esp_nspanel2lounge_command
|
||||||
|
data:
|
||||||
|
cmd: "page buttonpage01"
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
seconds: 1
|
||||||
|
|
||||||
|
- action: script.nspanel_lounge_refresh_all_button_states
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# SCRIPTS
|
||||||
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
script:
|
||||||
|
#:######################################################################################:#
|
||||||
|
# SCRIPTS: NSPanel Lounge Scene Button Actions
|
||||||
|
#:######################################################################################:#
|
||||||
|
nspanel_lounge_scene_bright:
|
||||||
|
alias: "NSPanel Lounge Scene - Bright"
|
||||||
|
mode: single
|
||||||
|
sequence:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Bright"
|
||||||
|
|
||||||
|
nspanel_lounge_scene_tv_general:
|
||||||
|
alias: "NSPanel Lounge Scene - TV General"
|
||||||
|
mode: single
|
||||||
|
sequence:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "TV General"
|
||||||
|
|
||||||
|
nspanel_lounge_scene_movie:
|
||||||
|
alias: "NSPanel Lounge Scene - Movie"
|
||||||
|
mode: single
|
||||||
|
sequence:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Movie"
|
||||||
|
|
||||||
|
nspanel_lounge_scene_balanced:
|
||||||
|
alias: "NSPanel Lounge Scene - Balanced"
|
||||||
|
mode: single
|
||||||
|
sequence:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Balanced"
|
||||||
|
|
||||||
|
nspanel_lounge_scene_warm_cozy:
|
||||||
|
alias: "NSPanel Lounge Scene - Warm Cozy"
|
||||||
|
mode: single
|
||||||
|
sequence:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Warm Cozy"
|
||||||
|
|
||||||
|
nspanel_lounge_scene_reading:
|
||||||
|
alias: "NSPanel Lounge Scene - Reading"
|
||||||
|
mode: single
|
||||||
|
sequence:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Reading On/Off"
|
||||||
|
|
||||||
|
nspanel_lounge_scene_dining:
|
||||||
|
alias: "NSPanel Lounge Scene - Dining"
|
||||||
|
mode: single
|
||||||
|
sequence:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Dining On/Off"
|
||||||
|
|
||||||
|
nspanel_lounge_scene_all_off:
|
||||||
|
alias: "NSPanel Lounge Scene - All Off"
|
||||||
|
mode: single
|
||||||
|
sequence:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "All Off"
|
||||||
|
|
||||||
|
#:######################################################################################:#
|
||||||
|
# SCRIPT: Push One NSPanel Button State
|
||||||
|
#
|
||||||
|
# ON state:
|
||||||
|
# - Button highlighted
|
||||||
|
# - Icon colour black [0, 0, 0]
|
||||||
|
#
|
||||||
|
# OFF state:
|
||||||
|
# - Button not highlighted
|
||||||
|
# - Icon colour white [255, 255, 255]
|
||||||
|
#:######################################################################################:#
|
||||||
|
nspanel_lounge_push_button_state:
|
||||||
|
alias: "NSPanel Lounge - Push Button State"
|
||||||
|
mode: queued
|
||||||
|
max: 20
|
||||||
|
fields:
|
||||||
|
button_id:
|
||||||
|
description: "NSPanel button id, for example button01"
|
||||||
|
button_state:
|
||||||
|
description: "True for highlighted, false for normal"
|
||||||
|
icon_code:
|
||||||
|
description: "HASwitchPlate/Nextion icon codepoint"
|
||||||
|
button_label:
|
||||||
|
description: "Button label text"
|
||||||
|
button_bri:
|
||||||
|
description: "Optional brightness/value text shown on the NSPanel button"
|
||||||
|
sequence:
|
||||||
|
- variables:
|
||||||
|
button_is_on: >-
|
||||||
|
{{
|
||||||
|
button_state in [true, 'true', 'True', 'on', 'On', '1', 1]
|
||||||
|
}}
|
||||||
|
button_bri_text: "{{ button_bri if button_bri is defined else '' }}"
|
||||||
|
|
||||||
|
- choose:
|
||||||
|
- conditions: "{{ button_is_on }}"
|
||||||
|
sequence:
|
||||||
|
- action: esphome.esp_nspanel2lounge_button
|
||||||
|
data:
|
||||||
|
page: buttonpage01
|
||||||
|
id: "{{ button_id }}"
|
||||||
|
state: true
|
||||||
|
icon: "{{ icon_code }}"
|
||||||
|
icon_color:
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
icon_font: 10
|
||||||
|
bri: "{{ button_bri_text }}"
|
||||||
|
label: "{{ button_label }}"
|
||||||
|
is_page_render: false
|
||||||
|
|
||||||
|
default:
|
||||||
|
- action: esphome.esp_nspanel2lounge_button
|
||||||
|
data:
|
||||||
|
page: buttonpage01
|
||||||
|
id: "{{ button_id }}"
|
||||||
|
state: false
|
||||||
|
icon: "{{ icon_code }}"
|
||||||
|
icon_color:
|
||||||
|
- 255
|
||||||
|
- 255
|
||||||
|
- 255
|
||||||
|
icon_font: 10
|
||||||
|
bri: "{{ button_bri_text }}"
|
||||||
|
label: "{{ button_label }}"
|
||||||
|
is_page_render: false
|
||||||
|
|
||||||
|
#:######################################################################################:#
|
||||||
|
# SCRIPT: Push One Scene Button State
|
||||||
|
#
|
||||||
|
# Maps scene/action names to NSPanel button ids, labels and icon codepoints.
|
||||||
|
#:######################################################################################:#
|
||||||
|
nspanel_lounge_push_scene_button_state:
|
||||||
|
alias: "NSPanel Lounge - Push Scene Button State"
|
||||||
|
mode: queued
|
||||||
|
max: 20
|
||||||
|
fields:
|
||||||
|
scene_name:
|
||||||
|
description: "Lounge scene/action name"
|
||||||
|
button_state:
|
||||||
|
description: "True for highlighted, false for normal"
|
||||||
|
sequence:
|
||||||
|
- choose:
|
||||||
|
- conditions: "{{ scene_name == 'Bright' }}"
|
||||||
|
sequence:
|
||||||
|
- action: script.nspanel_lounge_push_button_state
|
||||||
|
data:
|
||||||
|
button_id: button01
|
||||||
|
button_state: "{{ button_state }}"
|
||||||
|
icon_code: "\uE0E0"
|
||||||
|
button_label: "Bright"
|
||||||
|
button_bri: ""
|
||||||
|
|
||||||
|
- conditions: "{{ scene_name == 'TV General' }}"
|
||||||
|
sequence:
|
||||||
|
- action: script.nspanel_lounge_push_button_state
|
||||||
|
data:
|
||||||
|
button_id: button02
|
||||||
|
button_state: "{{ button_state }}"
|
||||||
|
icon_code: "\uE502"
|
||||||
|
button_label: "TV General"
|
||||||
|
button_bri: ""
|
||||||
|
|
||||||
|
- conditions: "{{ scene_name == 'Movie' }}"
|
||||||
|
sequence:
|
||||||
|
- action: script.nspanel_lounge_push_button_state
|
||||||
|
data:
|
||||||
|
button_id: button03
|
||||||
|
button_state: "{{ button_state }}"
|
||||||
|
icon_code: "\uEFCE"
|
||||||
|
button_label: "Movie"
|
||||||
|
button_bri: ""
|
||||||
|
|
||||||
|
- conditions: "{{ scene_name == 'Balanced' }}"
|
||||||
|
sequence:
|
||||||
|
- action: script.nspanel_lounge_push_button_state
|
||||||
|
data:
|
||||||
|
button_id: button04
|
||||||
|
button_state: "{{ button_state }}"
|
||||||
|
icon_code: "\uE472"
|
||||||
|
button_label: "Balance"
|
||||||
|
button_bri: ""
|
||||||
|
|
||||||
|
- conditions: "{{ scene_name == 'Warm Cozy' }}"
|
||||||
|
sequence:
|
||||||
|
- action: script.nspanel_lounge_push_button_state
|
||||||
|
data:
|
||||||
|
button_id: button05
|
||||||
|
button_state: "{{ button_state }}"
|
||||||
|
icon_code: "\uEE2E"
|
||||||
|
button_label: "Warm Cozy"
|
||||||
|
button_bri: ""
|
||||||
|
|
||||||
|
- conditions: "{{ scene_name == 'Reading On/Off' }}"
|
||||||
|
sequence:
|
||||||
|
- action: script.nspanel_lounge_push_button_state
|
||||||
|
data:
|
||||||
|
button_id: button06
|
||||||
|
button_state: "{{ button_state }}"
|
||||||
|
icon_code: "\uE5DA"
|
||||||
|
button_label: "Reading On/Off"
|
||||||
|
button_bri: >-
|
||||||
|
{% set left_on = is_state('light.esp_lounge6chdimmer_couch_spots_left', 'on') %}
|
||||||
|
{% set right_on = is_state('light.esp_lounge6chdimmer_couch_spots_right', 'on') %}
|
||||||
|
{% set left_raw = state_attr('light.esp_lounge6chdimmer_couch_spots_left', 'brightness') | int(0) if left_on else 0 %}
|
||||||
|
{% set right_raw = state_attr('light.esp_lounge6chdimmer_couch_spots_right', 'brightness') | int(0) if right_on else 0 %}
|
||||||
|
{% set left_pct = ((left_raw / 255) * 100) | round(0) | int %}
|
||||||
|
{% set right_pct = ((right_raw / 255) * 100) | round(0) | int %}
|
||||||
|
{% set reading_pct = [left_pct, right_pct] | max %}
|
||||||
|
{% if reading_pct > 0 %}{{ reading_pct }}%{% else %}{% endif %}
|
||||||
|
|
||||||
|
- conditions: "{{ scene_name == 'Dining On/Off' }}"
|
||||||
|
sequence:
|
||||||
|
- action: script.nspanel_lounge_push_button_state
|
||||||
|
data:
|
||||||
|
button_id: button07
|
||||||
|
button_state: "{{ button_state }}"
|
||||||
|
icon_code: "\uEA70"
|
||||||
|
button_label: "Dining On/Off"
|
||||||
|
button_bri: ""
|
||||||
|
|
||||||
|
- conditions: "{{ scene_name == 'All Off' }}"
|
||||||
|
sequence:
|
||||||
|
- action: script.nspanel_lounge_push_button_state
|
||||||
|
data:
|
||||||
|
button_id: button08
|
||||||
|
button_state: "{{ button_state }}"
|
||||||
|
icon_code: "\uE425"
|
||||||
|
button_label: "All Off"
|
||||||
|
button_bri: ""
|
||||||
|
|
||||||
|
#:######################################################################################:#
|
||||||
|
# SCRIPT: Refresh All NSPanel Lounge Button States
|
||||||
|
#
|
||||||
|
# Use this manually after a panel restart, or automatically once at HA start.
|
||||||
|
# Normal scene changes do not call this script.
|
||||||
|
#:######################################################################################:#
|
||||||
|
nspanel_lounge_refresh_all_button_states:
|
||||||
|
alias: "NSPanel Lounge - Refresh All Button States"
|
||||||
|
mode: restart
|
||||||
|
sequence:
|
||||||
|
- action: script.nspanel_lounge_push_scene_button_state
|
||||||
|
data:
|
||||||
|
scene_name: "Bright"
|
||||||
|
button_state: "{{ is_state('switch.nspanel_lounge_scene_bright', 'on') }}"
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
milliseconds: 100
|
||||||
|
|
||||||
|
- action: script.nspanel_lounge_push_scene_button_state
|
||||||
|
data:
|
||||||
|
scene_name: "TV General"
|
||||||
|
button_state: "{{ is_state('switch.nspanel_lounge_scene_tv_general', 'on') }}"
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
milliseconds: 100
|
||||||
|
|
||||||
|
- action: script.nspanel_lounge_push_scene_button_state
|
||||||
|
data:
|
||||||
|
scene_name: "Movie"
|
||||||
|
button_state: "{{ is_state('switch.nspanel_lounge_scene_movie', 'on') }}"
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
milliseconds: 100
|
||||||
|
|
||||||
|
- action: script.nspanel_lounge_push_scene_button_state
|
||||||
|
data:
|
||||||
|
scene_name: "Balanced"
|
||||||
|
button_state: "{{ is_state('switch.nspanel_lounge_scene_balanced', 'on') }}"
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
milliseconds: 100
|
||||||
|
|
||||||
|
- action: script.nspanel_lounge_push_scene_button_state
|
||||||
|
data:
|
||||||
|
scene_name: "Warm Cozy"
|
||||||
|
button_state: "{{ is_state('switch.nspanel_lounge_scene_warm_cozy', 'on') }}"
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
milliseconds: 100
|
||||||
|
|
||||||
|
- action: script.nspanel_lounge_push_scene_button_state
|
||||||
|
data:
|
||||||
|
scene_name: "Reading On/Off"
|
||||||
|
button_state: "{{ is_state('switch.nspanel_lounge_scene_reading', 'on') }}"
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
milliseconds: 100
|
||||||
|
|
||||||
|
- action: script.nspanel_lounge_push_scene_button_state
|
||||||
|
data:
|
||||||
|
scene_name: "Dining On/Off"
|
||||||
|
button_state: "{{ is_state('switch.nspanel_lounge_scene_dining', 'on') }}"
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
milliseconds: 100
|
||||||
|
|
||||||
|
- action: script.nspanel_lounge_push_scene_button_state
|
||||||
|
data:
|
||||||
|
scene_name: "All Off"
|
||||||
|
button_state: "{{ is_state('switch.nspanel_lounge_scene_all_off', 'on') }}"
|
||||||
|
|
||||||
|
#:######################################################################################:#
|
||||||
|
# SCRIPT: Compatibility Wrapper
|
||||||
|
#
|
||||||
|
# Older versions used this script name. Keep it as a manual full refresh.
|
||||||
|
#:######################################################################################:#
|
||||||
|
nspanel_lounge_refresh_button_states:
|
||||||
|
alias: "NSPanel Lounge - Refresh Button States"
|
||||||
|
mode: restart
|
||||||
|
sequence:
|
||||||
|
- action: script.nspanel_lounge_refresh_all_button_states
|
||||||
|
|
||||||
|
#:########################################################################################:#
|
||||||
|
# TEMPLATE SWITCHES: NSPANEL BUTTON STATE AND HIGHLIGHTING
|
||||||
|
#:########################################################################################:#
|
||||||
|
|
||||||
|
template:
|
||||||
|
- switch:
|
||||||
|
##########################################################################
|
||||||
|
# Remembered scenes
|
||||||
|
# These switches stay on when input_text.lounge_last_scene matches the
|
||||||
|
# last remembered scene name. This allows the NSPanel button to remain
|
||||||
|
# highlighted for the selected remembered scene.
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
- name: "NSPanel Lounge Scene Bright"
|
||||||
|
unique_id: nspanel_lounge_scene_switch_bright
|
||||||
|
state: "{{ is_state('input_text.lounge_last_scene', 'Bright') }}"
|
||||||
|
turn_on:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Bright"
|
||||||
|
turn_off:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Bright"
|
||||||
|
|
||||||
|
- name: "NSPanel Lounge Scene TV General"
|
||||||
|
unique_id: nspanel_lounge_scene_switch_tv_general
|
||||||
|
state: "{{ is_state('input_text.lounge_last_scene', 'TV General') }}"
|
||||||
|
turn_on:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "TV General"
|
||||||
|
turn_off:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "TV General"
|
||||||
|
|
||||||
|
- name: "NSPanel Lounge Scene Balanced"
|
||||||
|
unique_id: nspanel_lounge_scene_switch_balanced
|
||||||
|
state: "{{ is_state('input_text.lounge_last_scene', 'Balanced') }}"
|
||||||
|
turn_on:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Balanced"
|
||||||
|
turn_off:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Balanced"
|
||||||
|
|
||||||
|
- name: "NSPanel Lounge Scene Movie"
|
||||||
|
unique_id: nspanel_lounge_scene_switch_movie
|
||||||
|
state: "{{ is_state('input_text.lounge_last_scene', 'Movie') }}"
|
||||||
|
turn_on:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Movie"
|
||||||
|
turn_off:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Movie"
|
||||||
|
|
||||||
|
- name: "NSPanel Lounge Scene Warm Cozy"
|
||||||
|
unique_id: nspanel_lounge_scene_switch_warm_cozy
|
||||||
|
state: "{{ is_state('input_text.lounge_last_scene', 'Warm Cozy') }}"
|
||||||
|
turn_on:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Warm Cozy"
|
||||||
|
turn_off:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Warm Cozy"
|
||||||
|
|
||||||
|
- name: "NSPanel Lounge Scene All Off"
|
||||||
|
unique_id: nspanel_lounge_scene_switch_all_off
|
||||||
|
state: "{{ is_state('input_text.lounge_last_scene', 'All Off') }}"
|
||||||
|
turn_on:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "All Off"
|
||||||
|
turn_off:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "All Off"
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# Toggle/action scenes
|
||||||
|
# These are excluded from input_text.lounge_last_scene, so their displayed
|
||||||
|
# state comes from the actual light entities they control.
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
- name: "NSPanel Lounge Scene Reading"
|
||||||
|
unique_id: nspanel_lounge_scene_switch_reading
|
||||||
|
state: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
is_state('light.esp_lounge6chdimmer_couch_spots_left', 'on')
|
||||||
|
and (state_attr('light.esp_lounge6chdimmer_couch_spots_left', 'brightness') | int(0)) > 0
|
||||||
|
)
|
||||||
|
or
|
||||||
|
(
|
||||||
|
is_state('light.esp_lounge6chdimmer_couch_spots_right', 'on')
|
||||||
|
and (state_attr('light.esp_lounge6chdimmer_couch_spots_right', 'brightness') | int(0)) > 0
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
turn_on:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Reading On/Off"
|
||||||
|
turn_off:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Reading On/Off"
|
||||||
|
|
||||||
|
- name: "NSPanel Lounge Scene Dining"
|
||||||
|
unique_id: nspanel_lounge_scene_switch_dining
|
||||||
|
state: >-
|
||||||
|
{{
|
||||||
|
is_state('light.esp_lounge6chdimmer_dining_table_light', 'on')
|
||||||
|
and (state_attr('light.esp_lounge6chdimmer_dining_table_light', 'brightness') | int(0)) > 0
|
||||||
|
}}
|
||||||
|
turn_on:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Dining On/Off"
|
||||||
|
turn_off:
|
||||||
|
- action: script.lounge_set_scene
|
||||||
|
data:
|
||||||
|
scene_name: "Dining On/Off"
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
automation:
|
||||||
|
- id: nspanel_lounge_controller
|
||||||
|
alias: "NSPanel Master Bedroom Controller"
|
||||||
|
description: ""
|
||||||
|
use_blueprint:
|
||||||
|
path: edwardtfn/nspanel_easy_blueprint.yaml
|
||||||
|
input:
|
||||||
|
nspanel_name: 084fb5b4a94e636d01244b1838156446
|
||||||
|
|
||||||
|
button_page01_label: Lounge Lighting Scenes
|
||||||
|
button_pages_icon_size: "10"
|
||||||
|
|
||||||
|
entity01: script.nspanel_lounge_scene_bright
|
||||||
|
entity01_name: "Bright"
|
||||||
|
entity01_icon: mdi:brightness-7
|
||||||
|
entity01_confirm: false
|
||||||
|
|
||||||
|
entity02: script.nspanel_lounge_scene_tv_general
|
||||||
|
entity02_name: "TV General"
|
||||||
|
entity02_icon: mdi:television
|
||||||
|
entity02_confirm: false
|
||||||
|
|
||||||
|
entity03: script.nspanel_lounge_scene_movie
|
||||||
|
entity03_name: "Movie"
|
||||||
|
entity03_icon: mdi:movie-open
|
||||||
|
entity03_confirm: false
|
||||||
|
|
||||||
|
entity04: script.nspanel_lounge_scene_balanced
|
||||||
|
entity04_name: "Balance"
|
||||||
|
entity04_icon: mdi:scale-balance
|
||||||
|
entity04_confirm: false
|
||||||
|
|
||||||
|
entity05: script.nspanel_lounge_scene_warm_cozy
|
||||||
|
entity05_name: "Warm Cozy"
|
||||||
|
entity05_icon: mdi:fireplace
|
||||||
|
entity05_confirm: false
|
||||||
|
|
||||||
|
entity06: script.nspanel_lounge_scene_reading
|
||||||
|
entity06_name: "Reading On/Off"
|
||||||
|
entity06_icon: mdi:book-open-page-variant
|
||||||
|
entity06_confirm: false
|
||||||
|
|
||||||
|
entity07: script.nspanel_lounge_scene_dining
|
||||||
|
entity07_name: "Dining On/Off"
|
||||||
|
entity07_icon: mdi:silverware-fork-knife
|
||||||
|
entity07_confirm: false
|
||||||
|
|
||||||
|
entity08: script.nspanel_lounge_scene_all_off
|
||||||
|
entity08_name: "All Off"
|
||||||
|
entity08_icon: mdi:power
|
||||||
|
entity08_confirm: false
|
||||||
|
mode: single
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
################################################################################
|
||||||
|
# Quiet Time Package
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# TITLE:
|
||||||
|
# Quiet Time
|
||||||
|
#
|
||||||
|
# VERSIONS:
|
||||||
|
# V1.2 2026-05-21
|
||||||
|
# - Added MQTT publishing when input_boolean.quiet_time changes.
|
||||||
|
# - Publishes quiet_time state to viewroad-status/homeassistant/quiet-time.
|
||||||
|
#
|
||||||
|
# V1.1 2026-05-21
|
||||||
|
# - Reduced daily reset check frequency from every minute to every 30 minutes.
|
||||||
|
# - Reduced reset dropdown options to 00:30 through 10:00 only.
|
||||||
|
#
|
||||||
|
# V1.0 2026-05-21
|
||||||
|
# - Initial package.
|
||||||
|
# - Adds input_boolean.quiet_time.
|
||||||
|
# - Adds input_select.quiet_time_daily_reset.
|
||||||
|
# - Adds daily automation to turn quiet_time OFF at the selected reset time.
|
||||||
|
#
|
||||||
|
# OPERATION NOTES:
|
||||||
|
# - input_boolean.quiet_time is the master quiet time toggle.
|
||||||
|
# - Other packages can check input_boolean.quiet_time before sending
|
||||||
|
# announcements, notifications, TTS messages, or similar.
|
||||||
|
# - input_select.quiet_time_daily_reset selects the daily time that quiet_time
|
||||||
|
# will automatically be turned OFF.
|
||||||
|
# - Default reset time is 07:00.
|
||||||
|
# - The quiet_time state is published to MQTT whenever it changes.
|
||||||
|
#
|
||||||
|
# MQTT STATUS:
|
||||||
|
# - Topic:
|
||||||
|
# viewroad-status/homeassistant/quiet-time
|
||||||
|
# - Payload:
|
||||||
|
# on
|
||||||
|
# off
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# INPUT BOOLEAN
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
input_boolean:
|
||||||
|
quiet_time:
|
||||||
|
name: Quiet Time
|
||||||
|
icon: mdi:bell-off
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# INPUT SELECT
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
input_select:
|
||||||
|
quiet_time_daily_reset:
|
||||||
|
name: Quiet time daily reset
|
||||||
|
icon: mdi:clock-end
|
||||||
|
options:
|
||||||
|
- "00:30"
|
||||||
|
- "01:00"
|
||||||
|
- "01:30"
|
||||||
|
- "02:00"
|
||||||
|
- "02:30"
|
||||||
|
- "03:00"
|
||||||
|
- "03:30"
|
||||||
|
- "04:00"
|
||||||
|
- "04:30"
|
||||||
|
- "05:00"
|
||||||
|
- "05:30"
|
||||||
|
- "06:00"
|
||||||
|
- "06:30"
|
||||||
|
- "07:00"
|
||||||
|
- "07:30"
|
||||||
|
- "08:00"
|
||||||
|
- "08:30"
|
||||||
|
- "09:00"
|
||||||
|
- "09:30"
|
||||||
|
- "10:00"
|
||||||
|
initial: "07:00"
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# AUTOMATIONS
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
automation:
|
||||||
|
- id: quiet_time_daily_reset_turn_off
|
||||||
|
alias: "Quiet Time - Daily Reset Off"
|
||||||
|
description: "Turns Quiet Time off once per day at the selected reset time."
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- trigger: time_pattern
|
||||||
|
minutes: "/30"
|
||||||
|
seconds: "0"
|
||||||
|
|
||||||
|
conditions:
|
||||||
|
- condition: state
|
||||||
|
entity_id: input_boolean.quiet_time
|
||||||
|
state: "on"
|
||||||
|
|
||||||
|
- condition: template
|
||||||
|
value_template: >
|
||||||
|
{{ states('input_select.quiet_time_daily_reset') == now().strftime('%H:%M') }}
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- action: input_boolean.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: input_boolean.quiet_time
|
||||||
|
|
||||||
|
- id: quiet_time_settings_to_mqtt
|
||||||
|
alias: "Publish quiet time value to MQTT"
|
||||||
|
description: "Publishes the Quiet Time boolean state to MQTT whenever it changes."
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- trigger: state
|
||||||
|
entity_id: input_boolean.quiet_time
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- action: mqtt.publish
|
||||||
|
data:
|
||||||
|
topic: viewroad-status/homeassistant/quiet-time
|
||||||
|
payload: "{{ trigger.to_state.state }}"
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# Text to speech
|
|
||||||
tts:
|
|
||||||
platform: google_translate
|
|
||||||
service_name: google_say
|
|
||||||
@@ -343,6 +343,31 @@ script:
|
|||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ ann_voice_message | string | trim | length > 0 }}"
|
value_template: "{{ ann_voice_message | string | trim | length > 0 }}"
|
||||||
then:
|
then:
|
||||||
|
- choose:
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ lounge_google_home_voice_suppress_cast_chime | bool(false) }}"
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ states(lounge_google_home_voice_media_player) in ['off', 'unavailable', 'unknown'] }}"
|
||||||
|
sequence:
|
||||||
|
- action: media_player.volume_set
|
||||||
|
data:
|
||||||
|
entity_id: "{{ lounge_google_home_voice_media_player }}"
|
||||||
|
volume_level: 0
|
||||||
|
|
||||||
|
- action: media_player.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: "{{ lounge_google_home_voice_media_player }}"
|
||||||
|
|
||||||
|
- wait_template: >-
|
||||||
|
{{ states(lounge_google_home_voice_media_player) in ['idle', 'paused', 'playing', 'on'] }}
|
||||||
|
timeout:
|
||||||
|
seconds: 5
|
||||||
|
continue_on_timeout: true
|
||||||
|
|
||||||
|
- delay:
|
||||||
|
seconds: 1
|
||||||
|
|
||||||
- action: media_player.volume_set
|
- action: media_player.volume_set
|
||||||
data:
|
data:
|
||||||
entity_id: "{{ lounge_google_home_voice_media_player }}"
|
entity_id: "{{ lounge_google_home_voice_media_player }}"
|
||||||
|
|||||||