additional esphome devices and fixes

This commit is contained in:
root
2026-05-23 23:53:04 +12:00
parent 5e941eea06
commit 7eb81efd93
61 changed files with 7756 additions and 354 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

+1 -1
View File
@@ -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}
+114 -1
View File
@@ -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
-10
View File
@@ -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л
+732
View File
@@ -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"
}
}
+1
View File
@@ -0,0 +1 @@
{"pid": 76431, "lock_format_version": 1, "device_builder_version": "0.1.0b51", "start_ts": 1779063562.6364732}
+130
View File
@@ -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
+73 -40
View File
@@ -1,104 +1,129 @@
############################################################################################
# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS
# If NOT using a secrets file, just replace
# these with the values (in quotes)
###########################################################################################
#:########################################################################################:#
# TITLE: COMMON SNTP TIME SOURCE
# zorruno.com common ESPHome include
#:########################################################################################:#
# 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:
timezone: "Pacific/Auckland"
sntp_update_interval: 6h # Set the duration between the sntp service polling
# Network time servers https://www.ntppool.org/zone/@
sntp_update_interval: 6h
# Network time servers
# https://www.ntppool.org/zone/@
sntp_server_1: !secret ntp_server_1
sntp_server_2: !secret ntp_server_2
sntp_server_3: !secret ntp_server_3
###########################################################################################
# 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: Internal clock fallback support
#:########################################################################################:#
globals:
- id: current_mins
type: int
restore_value: no
initial_value: "720" # 720 is 12:00 Noon
restore_value: false
initial_value: "720" # 720 minutes from midnight is 12:00 noon.
#:########################################################################################:#
# INTERVAL: Keep current_mins updated
#:########################################################################################:#
interval:
- interval: 60s
then:
- lambda: |-
// If SNTP valid, store minutes since midnight.
// If SNTP is valid, store real minutes since midnight.
auto now = id(sntp_time).now();
if (now.is_valid()) {
id(current_mins) = (now.hour * 60) + now.minute;
} else {
// Fallback: minutes since boot.
id(current_mins) = (int)(millis() / 60000UL);
// Fallback: increment from the assumed startup time.
// 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
# If it's invalid, we fall back to an internal clock
#:########################################################################################:#
# TIME: Real time clock source for ESPHome
# https://esphome.io/components/time/index.html
# https://esphome.io/components/time/sntp
###########################################################################################
#:########################################################################################:#
time:
- platform: sntp
id: sntp_time
# Define the timezone of the device
timezone: "${timezone}"
# Change sync interval from default 5min to 6 hours (or as set in substitutions)
update_interval: ${sntp_update_interval}
# Set specific sntp servers to use
servers:
- "${sntp_server_1}"
- "${sntp_server_2}"
- "${sntp_server_3}"
# Publish the time the device was last restarted
on_time_sync:
then:
- logger.log: "Synchronised SNTP clock"
- text_sensor.template.publish:
id: time_sync
state: "SNTP clock Syncd"
# Update last restart time, but only once.
state: "SNTP clock synced"
# Update last restart time once only, after the first successful SNTP sync.
- if:
condition:
lambda: 'return id(device_last_restart).state == "";'
lambda: |-
return id(device_last_restart).state.empty();
then:
- text_sensor.template.publish:
id: device_last_restart
#state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");'
state: !lambda |-
// grab the current SNTP time
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");
#:########################################################################################:#
# TEXT SENSOR COMPONENT:
# https://esphome.io/components/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
name: "Time: Last Restart"
id: device_last_restart
icon: mdi:clock
entity_category: diagnostic
#device_class: timestamp
update_interval: never
# Shows the current SNTP time if valid, otherwise the internal fallback time.
- platform: template
name: "Time: Internal Time"
id: time_text
update_interval: "1min"
icon: mdi:clock-outline
update_interval: 1min
entity_category: diagnostic
lambda: |-
// If SNTP time is valid, show real time/date.
if (id(sntp_time).now().is_valid()) {
auto t = id(sntp_time).now().strftime("%H:%M:%S - %d-%m-%Y");
return { t };
}
// Fallback: show internal clock based on current_mins (minutes from midnight).
int mins = id(current_mins);
if (mins < 0) mins = 0;
if (mins >= 1440) mins = mins % 1440;
@@ -110,8 +135,16 @@ text_sensor:
snprintf(buff, sizeof(buff), "%02d:%02d (fallback)", hour, minute);
return { std::string(buff) };
# Shows whether the device is using SNTP or the fallback clock.
- platform: template
name: "Time: Sync Status"
id: time_sync
update_interval: "1min"
icon: mdi:clock-check-outline
update_interval: 1min
entity_category: diagnostic
lambda: |-
if (id(sntp_time).now().is_valid()) {
return { std::string("SNTP clock synced") };
}
return { std::string("Using fallback internal clock") };
+818
View File
@@ -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);
}
+154
View File
@@ -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
+316
View File
@@ -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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+13
View File
@@ -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>&copy; 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>
-14
View File
@@ -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
+389
View File
@@ -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)"
+12 -11
View File
@@ -17,14 +17,14 @@ automation:
entity_id: input_button.announcement_test
action:
- action: script.view_road_announcement
data:
channels: "sony_tv_lounge"
title: "View Road Test"
short_announcement: "Test announcement"
long_announcement: "This is a test announcement from the package test button."
payload: "On"
indicator: ""
# - action: script.view_road_announcement
# data:
# channels: "sony_tv_lounge"
# title: "View Road Test"
# short_announcement: "Test announcement"
# long_announcement: "This is a test announcement from the package test button."
# payload: "On"
# indicator: ""
#- action: script.view_road_announcement
# data:
@@ -34,6 +34,7 @@ automation:
- action: script.view_road_announcement
data:
channels: "lounge_google_home_voice"
title: "View Road Test"
long_announcement: "This is a test announcement on the lounge Google Home."
channels: "lounge_google_home_voice, sony_tv_lounge"
title: "View Road "
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"
+40 -18
View File
@@ -1,20 +1,26 @@
###############################################################################
# Bedroom 1 Ikea Air Filter Package
# File: /config/packages/bedroom_1_ikea_air_filter.yaml
# Version: 1.0
# Date: 2026-04-29
# Version: 1.1
# Date: 2026-05-08
#
# Purpose:
# - 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.
#
# Auto priority order:
# 1. Quiet time on: fan speed 2
# 2. Bedside light on: fan speed 2
# 3. Free power time, 21:00 to midnight: fan speed 5
# 4. Daytime, 09:00 to 15:00: fan speed 4
# 5. Default: fan speed 2
# Behaviour notes:
# - Quiet time turning on sets fan speed to 2.
# - Bedside lamp turning on sets fan speed to 2.
# - Bedside lamp turning off does not change the fan speed.
# - There is no 10-minute re-check, so the fan will not ramp back up just
# 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:
@@ -68,13 +74,17 @@ automation:
- trigger: homeassistant
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
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
entity_id: light.master_bedroom_bedside_lamp_arlec_bulb_master_bedroom_bedside_lamp_arlec_bulb
to: "on"
# Main timing boundaries.
- trigger: time
@@ -84,10 +94,6 @@ automation:
- "15:00:00"
- "21:00:00"
# Safety/re-check trigger, especially for the bedside lamp rule.
- trigger: time_pattern
minutes: "/10"
conditions:
# Manual dropdown modes disable automatic control.
- condition: state
@@ -96,10 +102,26 @@ automation:
actions:
- 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: >-
{% if is_state('input_boolean.quiet_time', 'on') %}
{% if bedside_lamp_on_trigger %}
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
{% elif now().hour >= 21 %}
5
@@ -142,7 +164,7 @@ automation:
entity_id: automation.bedroom_1_ikea_air_filter_auto_control
# 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
data:
target_speed: 2
+37 -8
View File
@@ -3,6 +3,9 @@
###############################################################################
#
# VERSION:
# 1.4 - 2026-05-21
# - Added delayed lounge NSPanel touchscreen brightness reduction to 5.
#
# 1.3 - 2026-05-07
# - Added downstairs lights all off script.
# - Added main hallway nightlights 60 minute bedtime timer.
@@ -29,6 +32,7 @@
# - climate entities are turned off if they are not already "off".
# - 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.
# - Lounge NSPanel touchscreen brightness is set to 5 after 20 seconds.
#
###############################################################################
@@ -94,6 +98,18 @@ automation:
delay_seconds: 0
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.lounge_set_scene
@@ -104,15 +120,10 @@ automation:
target:
entity_id: input_boolean.quiet_time
- service: switch.turn_on
# Reduce the lounge NSPanel screen brightness after 20 seconds.
- service: script.turn_on
target:
entity_id: switch.main_hallway_nightlights_1_relay_1_main_hallway_nightlights
- service: timer.start
target:
entity_id: timer.main_hallway_nightlights_bedtime
data:
duration: "01:00:00"
entity_id: script.bedtime_mode_set_lounge_nspanel_brightness_after_delay
- repeat:
for_each: "{{ bedtime_delayed_off_targets }}"
@@ -232,3 +243,21 @@ script:
mode: parallel
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
-24
View File
@@ -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
+35 -12
View File
@@ -4,6 +4,12 @@
#
# 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
# - Removed group.downstairs_flat_lights from this package to avoid duplicate
# 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 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
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
###############################################################################
@@ -169,18 +201,9 @@ script:
- choose:
- conditions:
- condition: template
value_template: >
{{
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')
}}
- condition: state
entity_id: binary_sensor.downstairs_flat_any_lights_on
state: "on"
sequence:
- action: homeassistant.turn_off
target:
-35
View File
@@ -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)
}}
-105
View File
@@ -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
+299
View File
@@ -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.
+368
View File
@@ -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
+57 -9
View File
@@ -46,8 +46,10 @@ input_select:
- "Select Scene:"
- Bright
- TV General
- Balanced
- Movie
- Reading On/Off
- Dining On/Off
- Night Light
- Warm Cozy
- All Off
@@ -106,6 +108,7 @@ script:
excluded_scenes:
- "Select Scene:"
- "Reading On/Off"
- "Dining On/Off"
#- "Night Light"
#####################################################################
@@ -120,18 +123,20 @@ script:
light.esp_lounge6chdimmer_lounge_downlights_centre: 100
light.esp_lounge6chdimmer_lounge_downlights_south: 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_loungecabinetleds2_lounge_cabinet_leds: 90
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 90
switch.lounge_cupboard_dual_usb_xus09_l2: "on"
switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: "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"
number.esp_loungepelmetleds2_lounge_pelmet_leds_a_output_set_0_100: 100
number.esp_loungepelmetleds2_lounge_pelmet_leds_b_output_set_0_100: 100
input_number.openhasp_1_backlight_level: 255
number.lounge_nspanel_touchscreen_display_brightness: 100
TV General:
light.esp_lounge6chdimmer_couch_spots_left: 60
@@ -143,7 +148,8 @@ script:
light.esp_breakfastbarleds_breakfast_bar_leds: 60
light.esp_loungecabinetleds2_lounge_cabinet_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.esp_loungesouthleftswitch_relay_1_wall_washer_left: "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_b_output_set_0_100: 60
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:
light.esp_lounge6chdimmer_couch_spots_left: 20
@@ -162,7 +190,8 @@ script:
light.esp_breakfastbarleds_breakfast_bar_leds: 40
light.esp_loungecabinetleds2_lounge_cabinet_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.esp_loungesouthleftswitch_relay_1_wall_washer_left: "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_b_output_set_0_100: 40
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:
light.esp_lounge6chdimmer_couch_spots_left: "toggle_75"
@@ -190,14 +230,16 @@ script:
light.esp_breakfastbarleds_breakfast_bar_leds: 5
light.esp_loungecabinetleds2_lounge_cabinet_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.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: 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:
light.esp_lounge6chdimmer_couch_spots_left: 20
@@ -206,8 +248,9 @@ script:
light.esp_breakfastbarleds_breakfast_bar_leds: 25
light.esp_loungecabinetleds2_lounge_cabinet_leds: 30
light.esp_loungebookshelfleds_lounge_bookshelf_leds: 30
light.tasmo_h801_loungeled1_6180_a: 25
light.tasmo_h801_loungeled1_6180_b: 25
#light.tasmo_h801_loungeled1_6180_a: 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.esp_loungesouthleftswitch_relay_1_wall_washer_left: "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_b_output_set_0_100: 20
input_number.openhasp_1_backlight_level: 12
number.lounge_nspanel_touchscreen_display_brightness: 40
All Off:
light.esp_lounge6chdimmer_couch_spots_left: 0
@@ -223,7 +267,8 @@ script:
light.esp_lounge6chdimmer_lounge_downlights_centre: 0
light.esp_lounge6chdimmer_lounge_downlights_south: 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_loungecabinetleds2_lounge_cabinet_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_b_output_set_0_100: 0
#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
-20
View File
@@ -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
-23
View File
@@ -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
+732
View File
@@ -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
File diff suppressed because it is too large Load Diff
+123
View File
@@ -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 }}"
-4
View File
@@ -1,4 +0,0 @@
# Text to speech
tts:
platform: google_translate
service_name: google_say
@@ -343,6 +343,31 @@ script:
- condition: template
value_template: "{{ ann_voice_message | string | trim | length > 0 }}"
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
data:
entity_id: "{{ lounge_google_home_voice_media_player }}"