From f8099406e828cbebdead2af852021879df5f38e3 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 9 Jun 2026 22:20:06 +1200 Subject: [PATCH] Update appliance monitoring configuration --- esphome/.device-builder.json | 2755 ++++++++++++++++++++ packages/appliance_monitor_processor.yaml | 763 ++++++ packages/appliances_status_monitoring.yaml | 255 ++ 3 files changed, 3773 insertions(+) create mode 100644 esphome/.device-builder.json create mode 100644 packages/appliance_monitor_processor.yaml create mode 100644 packages/appliances_status_monitoring.yaml diff --git a/esphome/.device-builder.json b/esphome/.device-builder.json new file mode 100644 index 0000000..e9baebc --- /dev/null +++ b/esphome/.device-builder.json @@ -0,0 +1,2755 @@ +{ + "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" + }, + "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": "41113c499335", + "configuration": "esp-centralstairs-top.yaml", + "job_type": "upload", + "status": "completed", + "created_at": "2026-06-09T09:53:08.269304+00:00", + "started_at": "2026-06-09T09:56:03.960069+00:00", + "completed_at": "2026-06-09T09:56:16.824331+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "e8a0dc3df7ee", + "dependency_released": true, + "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": "e8a0dc3df7ee", + "configuration": "esp-centralstairs-top.yaml", + "job_type": "compile", + "status": "completed", + "created_at": "2026-06-09T09:53:08.269262+00:00", + "started_at": "2026-06-09T09:53:08.269733+00:00", + "completed_at": "2026-06-09T09:56:03.957642+00:00", + "exit_code": 0, + "error": null, + "port": "", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "1e40be3ec915", + "configuration": "esp-centralstairs-bottom.yaml", + "job_type": "upload", + "status": "completed", + "created_at": "2026-06-09T09:49:57.889780+00:00", + "started_at": "2026-06-09T09:52:48.099065+00:00", + "completed_at": "2026-06-09T09:52:59.909485+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "288d2fd20526", + "dependency_released": true, + "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": "288d2fd20526", + "configuration": "esp-centralstairs-bottom.yaml", + "job_type": "compile", + "status": "completed", + "created_at": "2026-06-09T09:49:57.889737+00:00", + "started_at": "2026-06-09T09:49:57.893793+00:00", + "completed_at": "2026-06-09T09:52:48.093273+00:00", + "exit_code": 0, + "error": null, + "port": "", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "cf2fcc93f935", + "configuration": "esp-3dprinterpow.yaml", + "job_type": "upload", + "status": "completed", + "created_at": "2026-06-09T09:33:50.613915+00:00", + "started_at": "2026-06-09T09:37:22.154998+00:00", + "completed_at": "2026-06-09T09:37:37.552492+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "7e48e753ed0b", + "dependency_released": true, + "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": "7e48e753ed0b", + "configuration": "esp-3dprinterpow.yaml", + "job_type": "compile", + "status": "completed", + "created_at": "2026-06-09T09:33:50.613813+00:00", + "started_at": "2026-06-09T09:33:50.614419+00:00", + "completed_at": "2026-06-09T09:37:22.153948+00:00", + "exit_code": 0, + "error": null, + "port": "", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "af97c828d58a", + "configuration": "esp-downstkitchlights.yaml", + "job_type": "upload", + "status": "completed", + "created_at": "2026-06-05T04:25:30.974561+00:00", + "started_at": "2026-06-05T04:25:44.710401+00:00", + "completed_at": "2026-06-05T04:25:58.902563+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "bd7bbeb99660", + "dependency_released": true, + "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": "bd7bbeb99660", + "configuration": "esp-downstkitchlights.yaml", + "job_type": "compile", + "status": "completed", + "created_at": "2026-06-05T04:25:30.974521+00:00", + "started_at": "2026-06-05T04:25:30.977331+00:00", + "completed_at": "2026-06-05T04:25:44.702151+00:00", + "exit_code": 0, + "error": null, + "port": "", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "03f644942f51", + "configuration": "esp-ledmatrix1.yaml", + "job_type": "upload", + "status": "completed", + "created_at": "2026-06-04T08:57:16.073756+00:00", + "started_at": "2026-06-04T09:01:37.971417+00:00", + "completed_at": "2026-06-04T09:02:14.927761+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "1ebb77f84d00", + "dependency_released": false, + "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": "1ebb77f84d00", + "configuration": "esp-ledmatrix1.yaml", + "job_type": "compile", + "status": "completed", + "created_at": "2026-06-04T08:57:16.073691+00:00", + "started_at": "2026-06-04T08:57:16.077874+00:00", + "completed_at": "2026-06-04T09:01:37.966674+00:00", + "exit_code": 0, + "error": null, + "port": "", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "c7846a63cc3b", + "configuration": "esp-ledmatrix1.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T12:03:34.253854+00:00", + "started_at": "2026-06-01T12:03:34.254126+00:00", + "completed_at": "2026-06-01T12:06:01.062909+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "806186443ff2", + "configuration": "esp-entbtproxy.yaml", + "job_type": "install", + "status": "cancelled", + "created_at": "2026-06-01T11:21:42.771723+00:00", + "started_at": "2026-06-01T11:21:42.772227+00:00", + "completed_at": "2026-06-01T11:21:53.743481+00:00", + "exit_code": -15, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "80ef4ab140f9", + "configuration": "esp-underhouselights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.470443+00:00", + "started_at": "2026-06-01T08:24:58.246476+00:00", + "completed_at": "2026-06-01T08:27:25.931721+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "a8b8f023de6a", + "configuration": "esp-spare1-athomv1.yaml", + "job_type": "install", + "status": "failed", + "created_at": "2026-06-01T04:19:41.468291+00:00", + "started_at": "2026-06-01T08:22:22.841716+00:00", + "completed_at": "2026-06-01T08:24:58.242760+00:00", + "exit_code": 1, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "841b61799089", + "configuration": "esp-gasheater.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.466041+00:00", + "started_at": "2026-06-01T08:19:50.594744+00:00", + "completed_at": "2026-06-01T08:22:22.835917+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "26895803d863", + "configuration": "esp-rgblampbulb1.yaml", + "job_type": "install", + "status": "failed", + "created_at": "2026-06-01T04:19:41.462994+00:00", + "started_at": "2026-06-01T08:17:16.278510+00:00", + "completed_at": "2026-06-01T08:19:50.591115+00:00", + "exit_code": 1, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "401e802b42fc", + "configuration": "esp-6buttontest-pmb.yaml", + "job_type": "install", + "status": "failed", + "created_at": "2026-06-01T04:19:41.459431+00:00", + "started_at": "2026-06-01T08:12:57.414682+00:00", + "completed_at": "2026-06-01T08:17:16.274357+00:00", + "exit_code": 1, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "9bb91caf6ea7", + "configuration": "esp-officeusbhubpower.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.456943+00:00", + "started_at": "2026-06-01T08:10:33.258386+00:00", + "completed_at": "2026-06-01T08:12:57.408266+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "b7806031ac6a", + "configuration": "esp-occupancyoffice.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.453167+00:00", + "started_at": "2026-06-01T08:05:31.637954+00:00", + "completed_at": "2026-06-01T08:10:33.251836+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "592ab6848d85", + "configuration": "esp-officelights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.450208+00:00", + "started_at": "2026-06-01T08:03:09.126799+00:00", + "completed_at": "2026-06-01T08:05:31.580525+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "904e327c3334", + "configuration": "esp-officedeskrightgpo.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.447067+00:00", + "started_at": "2026-06-01T08:00:39.486657+00:00", + "completed_at": "2026-06-01T08:03:09.121293+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "fe00864c5cf7", + "configuration": "esp-officeelvcontrol.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.440981+00:00", + "started_at": "2026-06-01T07:58:13.213564+00:00", + "completed_at": "2026-06-01T08:00:39.481628+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "7eb7c9ee1e7a", + "configuration": "esp-officeduallights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.436490+00:00", + "started_at": "2026-06-01T07:55:36.673660+00:00", + "completed_at": "2026-06-01T07:58:13.208090+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "1ee6e3d397b3", + "configuration": "esp-leafbattery.yaml", + "job_type": "install", + "status": "failed", + "created_at": "2026-06-01T04:19:41.433502+00:00", + "started_at": "2026-06-01T07:53:19.409094+00:00", + "completed_at": "2026-06-01T07:55:36.669241+00:00", + "exit_code": 1, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "99d5d125fe98", + "configuration": "esp-nspanel1masterbdrm.yaml", + "job_type": "install", + "status": "failed", + "created_at": "2026-06-01T04:19:41.430708+00:00", + "started_at": "2026-06-01T07:49:10.912145+00:00", + "completed_at": "2026-06-01T07:53:19.401079+00:00", + "exit_code": 1, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "717fc9bd271e", + "configuration": "esp-bedrm1arlecbulb.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.426977+00:00", + "started_at": "2026-06-01T07:46:31.727391+00:00", + "completed_at": "2026-06-01T07:49:10.906782+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "6721b096c9cc", + "configuration": "esp-mainbathunderfloorheat.yaml", + "job_type": "install", + "status": "failed", + "created_at": "2026-06-01T04:19:41.423999+00:00", + "started_at": "2026-06-01T07:41:43.564425+00:00", + "completed_at": "2026-06-01T07:46:31.721784+00:00", + "exit_code": 1, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "1fbb6614600d", + "configuration": "esp-loungepelmetleds2.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.421677+00:00", + "started_at": "2026-06-01T07:39:44.439769+00:00", + "completed_at": "2026-06-01T07:41:43.559868+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "3cd900181342", + "configuration": "esp-loungecabinetleds.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.418890+00:00", + "started_at": "2026-06-01T07:37:14.286920+00:00", + "completed_at": "2026-06-01T07:39:44.422464+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "b6ba858a3159", + "configuration": "esp-loungebookshelfleds.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.415987+00:00", + "started_at": "2026-06-01T07:34:36.246523+00:00", + "completed_at": "2026-06-01T07:37:14.276981+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "4e9eb1428aaf", + "configuration": "esp-garageentrylights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.413080+00:00", + "started_at": "2026-06-01T07:31:40.393791+00:00", + "completed_at": "2026-06-01T07:34:36.239519+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "deaf8d652e71", + "configuration": "esp-downstairskitchleds.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.407992+00:00", + "started_at": "2026-06-01T07:29:08.025306+00:00", + "completed_at": "2026-06-01T07:31:40.388086+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "9848928e8aa9", + "configuration": "esp-downstbathtowelrail.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.405522+00:00", + "started_at": "2026-06-01T07:26:27.671710+00:00", + "completed_at": "2026-06-01T07:29:08.010393+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "d5e36440263a", + "configuration": "esp-breakfastbarleds.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.402992+00:00", + "started_at": "2026-06-01T07:23:55.881866+00:00", + "completed_at": "2026-06-01T07:26:27.631594+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "ec29ee60dd79", + "configuration": "esp-bedrm3lights.yaml", + "job_type": "install", + "status": "failed", + "created_at": "2026-06-01T04:19:41.398433+00:00", + "started_at": "2026-06-01T07:21:37.141074+00:00", + "completed_at": "2026-06-01T07:23:55.875367+00:00", + "exit_code": 1, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "63daa7565ece", + "configuration": "esp-bedrm2ceilingfan.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.395840+00:00", + "started_at": "2026-06-01T07:18:54.167927+00:00", + "completed_at": "2026-06-01T07:21:37.135975+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "8710d7279d9b", + "configuration": "esp-bedrm1airfilter.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.393392+00:00", + "started_at": "2026-06-01T07:16:23.704106+00:00", + "completed_at": "2026-06-01T07:18:54.161630+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "41dade37ff9e", + "configuration": "esp-attobattery.yaml", + "job_type": "install", + "status": "failed", + "created_at": "2026-06-01T04:19:41.386769+00:00", + "started_at": "2026-06-01T07:13:48.541824+00:00", + "completed_at": "2026-06-01T07:16:23.699593+00:00", + "exit_code": 1, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "c5670718a679", + "configuration": "esp-bedrm3ceilingfan.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.383986+00:00", + "started_at": "2026-06-01T07:11:02.907847+00:00", + "completed_at": "2026-06-01T07:13:48.507785+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "d966329dcc80", + "configuration": "esp-lounge6chdimmer.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.375097+00:00", + "started_at": "2026-06-01T07:08:23.389553+00:00", + "completed_at": "2026-06-01T07:11:02.891633+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "a5daff23ff71", + "configuration": "esp-3dprinterpow.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.372468+00:00", + "started_at": "2026-06-01T07:05:37.057632+00:00", + "completed_at": "2026-06-01T07:08:23.383298+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "ee2810a84787", + "configuration": "esp-masterbathtowelrail.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.368857+00:00", + "started_at": "2026-06-01T07:03:07.909454+00:00", + "completed_at": "2026-06-01T07:05:37.052138+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "6abfa3374f55", + "configuration": "esp-weatherstation.yaml", + "job_type": "install", + "status": "failed", + "created_at": "2026-06-01T04:19:41.360994+00:00", + "started_at": "2026-06-01T07:01:57.079055+00:00", + "completed_at": "2026-06-01T07:03:07.905749+00:00", + "exit_code": 1, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "0eb6aa1b52c0", + "configuration": "esp-mainkitchenlights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.355990+00:00", + "started_at": "2026-06-01T06:59:33.114291+00:00", + "completed_at": "2026-06-01T07:01:57.073945+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "cda0a2c7d6c2", + "configuration": "esp-mainpowermonitor.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.351382+00:00", + "started_at": "2026-06-01T06:57:03.395869+00:00", + "completed_at": "2026-06-01T06:59:33.102439+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "7ad86a25c5ec", + "configuration": "esp-mainhallwaynorthlightswitch.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.344971+00:00", + "started_at": "2026-06-01T06:54:42.436787+00:00", + "completed_at": "2026-06-01T06:57:03.347772+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "ecd7a128260f", + "configuration": "esp-mainhallwaynightlights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.341990+00:00", + "started_at": "2026-06-01T06:51:32.428274+00:00", + "completed_at": "2026-06-01T06:54:42.347776+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "b3d9dc3860bd", + "configuration": "esp-mainhallwaymainlights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.336451+00:00", + "started_at": "2026-06-01T06:49:09.394408+00:00", + "completed_at": "2026-06-01T06:51:32.423796+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "1ad119398728", + "configuration": "esp-entrancelightswitch.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.331503+00:00", + "started_at": "2026-06-01T06:46:37.014368+00:00", + "completed_at": "2026-06-01T06:49:09.380081+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "3188938a371d", + "configuration": "esp-maindishwasherpower.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.323982+00:00", + "started_at": "2026-06-01T06:39:28.089290+00:00", + "completed_at": "2026-06-01T06:46:37.007922+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "e3336c69c748", + "configuration": "esp-mainbathroomlights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.320954+00:00", + "started_at": "2026-06-01T06:35:10.468057+00:00", + "completed_at": "2026-06-01T06:39:28.082733+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "28f417ca8773", + "configuration": "esp-mainbathfancombo.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.317589+00:00", + "started_at": "2026-06-01T06:32:47.871855+00:00", + "completed_at": "2026-06-01T06:35:10.425499+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "7d6aa3700c5a", + "configuration": "esp-loungewestswitch.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.314985+00:00", + "started_at": "2026-06-01T06:30:21.382837+00:00", + "completed_at": "2026-06-01T06:32:47.832193+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "09e51ad51881", + "configuration": "esp-loungesouthrightswitch.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.308913+00:00", + "started_at": "2026-06-01T06:28:01.575603+00:00", + "completed_at": "2026-06-01T06:30:21.375996+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "3b3640dc6cfc", + "configuration": "esp-loungesouthleftswitch.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.303567+00:00", + "started_at": "2026-06-01T06:25:26.577307+00:00", + "completed_at": "2026-06-01T06:28:01.468360+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "99a17e9ab129", + "configuration": "esp-nspanel2lounge.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.300486+00:00", + "started_at": "2026-06-01T06:20:26.930884+00:00", + "completed_at": "2026-06-01T06:25:26.569055+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "af5e15644d36", + "configuration": "esp-laundrylights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.289971+00:00", + "started_at": "2026-06-01T06:13:22.397593+00:00", + "completed_at": "2026-06-01T06:15:42.312385+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "4c41a70b1788", + "configuration": "esp-laundryenv.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.287773+00:00", + "started_at": "2026-06-01T06:11:03.333994+00:00", + "completed_at": "2026-06-01T06:13:22.392347+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "3eff66dc7505", + "configuration": "esp-laundrydrypow.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.285392+00:00", + "started_at": "2026-06-01T06:08:28.542523+00:00", + "completed_at": "2026-06-01T06:11:03.330174+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "86d463083b20", + "configuration": "esp-laundryplugpow.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.282947+00:00", + "started_at": "2026-06-01T06:05:56.626658+00:00", + "completed_at": "2026-06-01T06:08:28.537601+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "e6572e3a476a", + "configuration": "esp-garagelights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.280497+00:00", + "started_at": "2026-06-01T06:03:31.695984+00:00", + "completed_at": "2026-06-01T06:05:56.620777+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "28fc0643b0e5", + "configuration": "esp-garageextcornerlight.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.278648+00:00", + "started_at": "2026-06-01T06:01:06.374080+00:00", + "completed_at": "2026-06-01T06:03:31.690656+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "73f7b65cdd7f", + "configuration": "esp-garagedbcontrols.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.276252+00:00", + "started_at": "2026-06-01T05:58:33.131479+00:00", + "completed_at": "2026-06-01T06:01:06.229215+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "b177505bfa87", + "configuration": "esp-entranceoutsideledlights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.273838+00:00", + "started_at": "2026-06-01T05:55:50.543587+00:00", + "completed_at": "2026-06-01T05:58:33.115040+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "f6cd32e7d905", + "configuration": "esp-flysprayer1.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.268127+00:00", + "started_at": "2026-06-01T05:53:06.428517+00:00", + "completed_at": "2026-06-01T05:55:50.526619+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "5bf3a0415eca", + "configuration": "esp-entrancebathrmlights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.265940+00:00", + "started_at": "2026-06-01T05:50:47.184842+00:00", + "completed_at": "2026-06-01T05:53:06.423671+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "339d6dfe81fd", + "configuration": "esp-downstmasterbedrmlights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.264201+00:00", + "started_at": "2026-06-01T05:48:19.072246+00:00", + "completed_at": "2026-06-01T05:50:47.180106+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "59eb9c1b3f6b", + "configuration": "esp-downstloungeoutside.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.262158+00:00", + "started_at": "2026-06-01T05:45:58.403037+00:00", + "completed_at": "2026-06-01T05:48:19.053106+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "b3bb7b0592b6", + "configuration": "esp-downstloungeentry.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.258987+00:00", + "started_at": "2026-06-01T05:43:37.418940+00:00", + "completed_at": "2026-06-01T05:45:58.349334+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "7cf7445bdb57", + "configuration": "esp-downstkitchlights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.252112+00:00", + "started_at": "2026-06-01T05:41:08.452386+00:00", + "completed_at": "2026-06-01T05:43:37.411438+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "f6a9b2b5ebdf", + "configuration": "esp-downstairsdishwasher.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.248910+00:00", + "started_at": "2026-06-01T05:38:34.411826+00:00", + "completed_at": "2026-06-01T05:41:08.384662+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "71f38d5b17e2", + "configuration": "esp-downstbedrm2lights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.246083+00:00", + "started_at": "2026-06-01T05:36:05.517194+00:00", + "completed_at": "2026-06-01T05:38:34.371613+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "678010c77357", + "configuration": "esp-downstbathswitch.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.238598+00:00", + "started_at": "2026-06-01T05:33:37.180225+00:00", + "completed_at": "2026-06-01T05:36:05.507099+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "fa4e47ae6747", + "configuration": "esp-datacupboardpower-left.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.236837+00:00", + "started_at": "2026-06-01T05:31:10.108403+00:00", + "completed_at": "2026-06-01T05:33:37.175681+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "87ea46b214cf", + "configuration": "esp-datacupboardfans.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.234917+00:00", + "started_at": "2026-06-01T05:28:42.167771+00:00", + "completed_at": "2026-06-01T05:31:10.104136+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "ed04e1a2268d", + "configuration": "esp-centralstairs-top.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.232634+00:00", + "started_at": "2026-06-01T05:26:11.202581+00:00", + "completed_at": "2026-06-01T05:28:42.159922+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "b27a71fa6f9c", + "configuration": "esp-centralstairs-bottom.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.230916+00:00", + "started_at": "2026-06-01T05:23:43.347967+00:00", + "completed_at": "2026-06-01T05:26:11.196582+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "6aa869f37e2b", + "configuration": "esp-bedrm2lights.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.227732+00:00", + "started_at": "2026-06-01T05:21:03.796202+00:00", + "completed_at": "2026-06-01T05:23:43.341178+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "3098b43a1966", + "configuration": "esp-bedrm2fanswitch.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.226046+00:00", + "started_at": "2026-06-01T05:18:34.253696+00:00", + "completed_at": "2026-06-01T05:21:03.792392+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "3d21bce1f0d7", + "configuration": "esp-arcademachine1.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.224127+00:00", + "started_at": "2026-06-01T05:15:56.607659+00:00", + "completed_at": "2026-06-01T05:18:34.248079+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "ae4c700747c7", + "configuration": "esp-laundrywashpow.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.222082+00:00", + "started_at": "2026-06-01T05:13:19.349695+00:00", + "completed_at": "2026-06-01T05:15:56.602795+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "e710c1c575ee", + "configuration": "esp-garagebtproxy.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.220091+00:00", + "started_at": "2026-06-01T05:08:29.838253+00:00", + "completed_at": "2026-06-01T05:13:19.335120+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "bb777067bf2f", + "configuration": "esp-downstloungemain.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.218186+00:00", + "started_at": "2026-06-01T05:05:51.689928+00:00", + "completed_at": "2026-06-01T05:08:29.822644+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "493417088612", + "configuration": "esp-datacupboardpower-right.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.215725+00:00", + "started_at": "2026-06-01T05:03:11.804359+00:00", + "completed_at": "2026-06-01T05:05:51.684910+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "8a5d39489f1e", + "configuration": "esp-occupancystair.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.213955+00:00", + "started_at": "2026-06-01T04:58:26.392118+00:00", + "completed_at": "2026-06-01T05:03:11.798440+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "2bcb831b7ed2", + "configuration": "esp-rocktumbler.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.212251+00:00", + "started_at": "2026-06-01T04:55:43.968599+00:00", + "completed_at": "2026-06-01T04:58:26.386495+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "25274c12214e", + "configuration": "esp-poolpumppower.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.210457+00:00", + "started_at": "2026-06-01T04:49:44.043451+00:00", + "completed_at": "2026-06-01T04:55:43.957948+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "dd006a8cb5f8", + "configuration": "esp-poollightpower2.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.208532+00:00", + "started_at": "2026-06-01T04:46:54.066706+00:00", + "completed_at": "2026-06-01T04:49:44.037947+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "808ee3474e43", + "configuration": "esp-entmulti.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.206272+00:00", + "started_at": "2026-06-01T04:41:38.157621+00:00", + "completed_at": "2026-06-01T04:46:54.057075+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "98b518fd7deb", + "configuration": "esp-loungenorthswitch.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.202280+00:00", + "started_at": "2026-06-01T04:31:50.021073+00:00", + "completed_at": "2026-06-01T04:34:29.776467+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "4e9147b9aba3", + "configuration": "esp-loungeenvironment.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.197618+00:00", + "started_at": "2026-06-01T04:23:09.183099+00:00", + "completed_at": "2026-06-01T04:31:50.013969+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "6e3f6f6d11e2", + "configuration": "esp-bedrm3fanswitch.yaml", + "job_type": "install", + "status": "completed", + "created_at": "2026-06-01T04:19:41.194888+00:00", + "started_at": "2026-06-01T04:19:41.195147+00:00", + "completed_at": "2026-06-01T04:23:09.177841+00:00", + "exit_code": 0, + "error": null, + "port": "OTA", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "0d9882f767e4", + "configuration": "esp-ledmatrix1.yaml", + "job_type": "clean", + "status": "completed", + "created_at": "2026-06-01T11:27:18.782204+00:00", + "started_at": "2026-06-01T11:27:18.782662+00:00", + "completed_at": "2026-06-01T11:27:20.136530+00:00", + "exit_code": 0, + "error": null, + "port": "", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "3be5eba32760", + "configuration": "esp-entbtproxy.yaml", + "job_type": "clean", + "status": "completed", + "created_at": "2026-06-01T09:32:39.673871+00:00", + "started_at": "2026-06-01T09:32:39.674388+00:00", + "completed_at": "2026-06-01T09:32:40.967000+00:00", + "exit_code": 0, + "error": null, + "port": "", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "caeff2ee984b", + "configuration": "", + "job_type": "reset_build_env", + "status": "completed", + "created_at": "2026-06-01T04:18:48.122127+00:00", + "started_at": "2026-06-01T04:18:48.122426+00:00", + "completed_at": "2026-06-01T04:19:11.229921+00:00", + "exit_code": 0, + "error": null, + "port": "", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "89273e97de03", + "configuration": "esp-officelights.yaml", + "job_type": "clean", + "status": "completed", + "created_at": "2026-05-31T21:27:58.149553+00:00", + "started_at": "2026-05-31T21:27:58.149802+00:00", + "completed_at": "2026-05-31T21:27:59.353763+00:00", + "exit_code": 0, + "error": null, + "port": "", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "56d376896863", + "configuration": "esp-occupancyoffice.yaml", + "job_type": "clean", + "status": "completed", + "created_at": "2026-05-31T21:18:20.951861+00:00", + "started_at": "2026-05-31T21:18:20.952106+00:00", + "completed_at": "2026-05-31T21:18:22.290042+00:00", + "exit_code": 0, + "error": null, + "port": "", + "new_name": "", + "depends_on": "", + "dependency_released": false, + "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": "64:E8:33:84:FD:C8" + }, + "esp-mainbathunderfloorheat.yaml": { + "board_id": "generic-esp32" + }, + "esp-ledmatrix1 copy.yaml": { + "board_id": "generic-esp32c3", + "mac_address": "64:E8:33:84:FD:C8" + }, + "_board_id_user_set_migrated": true, + "_dashboard_identity": { + "dashboard_id": "vhamVDnWEnx-FvAa24uVv49Wsddurh84" + } +} \ No newline at end of file diff --git a/packages/appliance_monitor_processor.yaml b/packages/appliance_monitor_processor.yaml new file mode 100644 index 0000000..3afc46f --- /dev/null +++ b/packages/appliance_monitor_processor.yaml @@ -0,0 +1,763 @@ +################################################################################ +# PACKAGE: Appliance Monitor Processor +################################################################################ +# +# Version: 1.2 +# Date: 2026-06-09 +# +# Purpose: +# Shared appliance power monitoring processor. +# +# This script is called by appliances_status_monitoring.yaml. It reads the +# previous appliance monitor state from the appliance monitor MQTT sensor, +# calculates the next state and cycle totals, publishes retained JSON state +# back to MQTT, and calls the View Road announcement router when a cycle +# finishes. +# +# Design: +# - One shared processing script. +# - MQTT retained JSON state per appliance. +# - One MQTT sensor per appliance. +# - Timestamp-based energy and cost calculation. +# - Rolling average state detection. +# +# Default values: +# debug_flow: false +# resolution: 7 +# standby_power: 2 +# operating_power_min: 12 +# paid_tariff_start: "00:00" +# paid_tariff_end: "21:00" +# paid_tariff_cost: 0.2023 +# offpeak_tariff_cost: 0.0 +# max_sample_gap_seconds: 900 +# min_cycle_notify_seconds: 300 +# +# States: +# Off +# Standby +# Operating +# Finished +# +# Notes: +# Version 1.2: +# - Added min_cycle_notify_seconds. +# - Finished cycles shorter than this are still recorded, but do not send +# notifications. +# - Added MQTT attributes showing whether notification was allowed or +# suppressed. +# +# Version 1.1: +# - Accepts lower-case retained states from previous package versions, such +# as standby, operating, and finished. +# +################################################################################ +# FINISHED ANNOUNCEMENT +# The finishing script calls the package view_road_announcement_router.yaml. +# If you want to use your own announcement system, it will occur at the end +# at am_cycle_notify_allowed being true, so change to your own announcement +# method there. +# +# Announcements can use: +# am_announcement_channels +# am_announcement_title +# am_short_announcement +# am_long_announcement +# am_matrix_indicator +# +################################################################################ + +script: + appliance_monitor_process_sample: + alias: Appliance Monitor - Process Sample + icon: mdi:meter-electric + mode: queued + max: 50 + + fields: + appliance_id: + name: Appliance ID + description: Short unique ID, for example washing_machine. + selector: + text: + + appliance_name: + name: Appliance Name + description: Human readable appliance name. + selector: + text: + + appliance_action: + name: Appliance Action + description: Human readable action, for example washing. + selector: + text: + + power_w: + name: Power W + description: Current instantaneous appliance power in watts. + selector: + number: + min: 0 + max: 10000 + step: 0.1 + unit_of_measurement: W + + monitor_sensor: + name: Monitor Sensor + description: MQTT monitor sensor used to read previous state. + selector: + entity: + domain: sensor + + state_topic: + name: MQTT State Topic + description: Retained MQTT topic used to publish monitor state JSON. + selector: + text: + + min_cycle_notify_seconds: + name: Minimum Cycle Notify Seconds + description: Finished cycles shorter than this are recorded but do not send notifications. + default: 300 + selector: + number: + min: 0 + max: 86400 + step: 1 + unit_of_measurement: s + + sequence: + ########################################################################## + # CORE DEFAULTS AND PASSED VALUES + ########################################################################## + + - variables: + am_appliance_id: "{{ appliance_id | default('appliance', true) | string }}" + am_appliance_name: "{{ appliance_name | default('Appliance', true) | string }}" + am_appliance_action: "{{ appliance_action | default('running', true) | string }}" + am_power_w: "{{ power_w | default(0, true) | float(0) }}" + am_monitor_sensor: "{{ monitor_sensor | default('', true) | string }}" + am_state_topic: "{{ state_topic | default('', true) | string }}" + + am_debug_flow: "{{ debug_flow | default(false, true) | bool(false) }}" + am_resolution: "{{ resolution | default(7, true) | int(7) }}" + am_standby_power: "{{ standby_power | default(2, true) | float(2) }}" + am_operating_power_min: "{{ operating_power_min | default(12, true) | float(12) }}" + + am_paid_tariff_start: "{{ paid_tariff_start | default('00:00', true) | string }}" + am_paid_tariff_end: "{{ paid_tariff_end | default('21:00', true) | string }}" + am_paid_tariff_cost: "{{ paid_tariff_cost | default(0.2023, true) | float(0.2023) }}" + am_offpeak_tariff_cost: "{{ offpeak_tariff_cost | default(0.0, true) | float(0.0) }}" + + am_max_sample_gap_seconds: "{{ max_sample_gap_seconds | default(900, true) | int(900) }}" + am_min_cycle_notify_seconds: "{{ min_cycle_notify_seconds | default(300, true) | int(300) }}" + + ########################################################################## + # ANNOUNCEMENT DEFAULTS AND PASSED VALUES + ########################################################################## + + - variables: + am_announcement_channels: >- + {{ announcement_channels | default('pushover_zorruno, sony_tv_lounge, lounge_google_home_voice, led_matrix_1', true) | string }} + + am_short_announcement: >- + {{ short_announcement | default((am_appliance_action | title) ~ ' complete', true) | string }} + + am_long_announcement_override: >- + {{ long_announcement | default('', true) | string }} + + am_announcement_title: >- + {{ title | default(am_appliance_name ~ ' Notification', true) | string }} + + am_matrix_indicator: "{{ matrix_indicator | default('', true) | string }}" + + ########################################################################## + # PREVIOUS STATE FROM MQTT MONITOR SENSOR ATTRIBUTES + ########################################################################## + + - variables: + am_now_ts: "{{ as_timestamp(now()) }}" + + am_previous_state: >- + {%- set s = states(am_monitor_sensor) | string | lower | trim -%} + {{ {'operating': 'Operating', 'finished': 'Finished', 'standby': 'Standby', 'off': 'Off'}.get(s, 'Off') }} + + am_last_power_w: "{{ state_attr(am_monitor_sensor, 'last_power_w') | float(am_power_w) }}" + am_last_sample_ts: "{{ state_attr(am_monitor_sensor, 'last_sample_ts') | float(0) }}" + + am_existing_cycle_start_ts: "{{ state_attr(am_monitor_sensor, 'cycle_start_ts') | float(0) }}" + am_existing_cycle_stop_ts: "{{ state_attr(am_monitor_sensor, 'cycle_stop_ts') | float(0) }}" + + am_existing_cycle_energy_kwh: "{{ state_attr(am_monitor_sensor, 'cycle_energy_kwh') | float(0) }}" + am_existing_cycle_paid_energy_kwh: "{{ state_attr(am_monitor_sensor, 'cycle_paid_energy_kwh') | float(0) }}" + am_existing_cycle_free_energy_kwh: "{{ state_attr(am_monitor_sensor, 'cycle_free_energy_kwh') | float(0) }}" + am_existing_cycle_cost: "{{ state_attr(am_monitor_sensor, 'cycle_cost') | float(0) }}" + + am_previous_recent_samples_json: >- + {% set raw = state_attr(am_monitor_sensor, 'recent_samples_json') | string | trim %} + {{ raw if raw.startswith('[') else '[]' }} + + ########################################################################## + # ELAPSED TIME + ########################################################################## + + - variables: + am_elapsed_sec_raw: >- + {% if am_last_sample_ts | float(0) > 0 %} + {{ (am_now_ts | float(0)) - (am_last_sample_ts | float(0)) }} + {% else %} + 0 + {% endif %} + + am_effective_elapsed_sec: >- + {% set elapsed = am_elapsed_sec_raw | float(0) %} + {% if elapsed <= 0 %} + 0 + {% elif elapsed > (am_max_sample_gap_seconds | int(900)) %} + {{ am_max_sample_gap_seconds | int(900) }} + {% else %} + {{ elapsed }} + {% endif %} + + ########################################################################## + # ROLLING AVERAGE + ########################################################################## + + - variables: + am_previous_recent_samples_list: >- + {% set raw_json = state_attr(am_monitor_sensor, 'recent_samples_json') %} + {% set raw_list = state_attr(am_monitor_sensor, 'recent_samples') %} + {% if raw_json is string %} + {{ raw_json | from_json(default=[]) }} + {% elif raw_json is iterable and raw_json is not string %} + {{ raw_json | list }} + {% elif raw_list is iterable and raw_list is not string %} + {{ raw_list | list }} + {% else %} + [] + {% endif %} + + am_recent_samples_list: >- + {% set old = am_previous_recent_samples_list %} + {% set ns = namespace(items=[am_power_w | float(0)]) %} + {% for item in old %} + {% if loop.index < (am_resolution | int(7)) %} + {% set ns.items = ns.items + [item | float(0)] %} + {% endif %} + {% endfor %} + {{ ns.items }} + + am_recent_samples_json: >- + {{ am_recent_samples_list | to_json }} + + am_average_power_w: >- + {% set samples = am_recent_samples_list %} + {% if samples | count > 0 %} + {{ ((samples | sum) / (samples | count)) | round(3) }} + {% else %} + 0 + {% endif %} + + ########################################################################## + # STATE MACHINE + ########################################################################## + + - variables: + am_new_state: >- + {% set avg = am_average_power_w | float(0) %} + {% set standby = am_standby_power | float(2) %} + {% set operate = am_operating_power_min | float(12) %} + {% set prev = am_previous_state | string %} + {% if prev == 'Operating' and avg < operate %} + Finished + {% elif avg < standby %} + Off + {% elif avg >= operate %} + Operating + {% elif avg >= standby and prev in ['Off', 'Finished'] %} + Standby + {% else %} + {{ prev }} + {% endif %} + + am_state_changed: "{{ (am_new_state | string) != (am_previous_state | string) }}" + am_cycle_started: "{{ am_new_state == 'Operating' and am_previous_state != 'Operating' }}" + am_cycle_finished: "{{ am_new_state == 'Finished' and am_previous_state == 'Operating' }}" + + ########################################################################## + # ACCUMULATION WINDOW + ########################################################################## + + - variables: + am_accumulation_seconds: >- + {% set elapsed = am_effective_elapsed_sec | float(0) %} + {% if elapsed <= 0 %} + 0 + {% elif am_previous_state == 'Operating' and am_new_state == 'Operating' %} + {{ elapsed }} + {% elif am_previous_state != 'Operating' and am_new_state == 'Operating' %} + {{ elapsed / 2 }} + {% elif am_previous_state == 'Operating' and am_new_state == 'Finished' %} + {{ elapsed / 2 }} + {% else %} + 0 + {% endif %} + + am_accumulation_average_power_w: >- + {% set last = am_last_power_w | float(0) %} + {% set current = am_power_w | float(0) %} + {% set operate = am_operating_power_min | float(12) %} + {% if am_previous_state == 'Operating' and am_new_state == 'Operating' %} + {{ ((last + current) / 2) | round(3) }} + {% elif am_previous_state != 'Operating' and am_new_state == 'Operating' %} + {{ ((operate + current) / 2) | round(3) }} + {% elif am_previous_state == 'Operating' and am_new_state == 'Finished' %} + {{ ((last + operate) / 2) | round(3) }} + {% else %} + 0 + {% endif %} + + am_accumulation_start_ts: >- + {% set elapsed = am_effective_elapsed_sec | float(0) %} + {% set accum = am_accumulation_seconds | float(0) %} + {% if accum <= 0 %} + {{ am_now_ts | float(0) }} + {% elif am_previous_state == 'Operating' and am_new_state == 'Operating' %} + {{ (am_now_ts | float(0)) - elapsed }} + {% elif am_previous_state != 'Operating' and am_new_state == 'Operating' %} + {{ (am_now_ts | float(0)) - accum }} + {% elif am_previous_state == 'Operating' and am_new_state == 'Finished' %} + {{ (am_now_ts | float(0)) - elapsed }} + {% else %} + {{ am_now_ts | float(0) }} + {% endif %} + + am_accumulation_stop_ts: >- + {% set elapsed = am_effective_elapsed_sec | float(0) %} + {% set accum = am_accumulation_seconds | float(0) %} + {% if accum <= 0 %} + {{ am_now_ts | float(0) }} + {% elif am_previous_state == 'Operating' and am_new_state == 'Operating' %} + {{ am_now_ts | float(0) }} + {% elif am_previous_state != 'Operating' and am_new_state == 'Operating' %} + {{ am_now_ts | float(0) }} + {% elif am_previous_state == 'Operating' and am_new_state == 'Finished' %} + {{ (am_now_ts | float(0)) - elapsed + accum }} + {% else %} + {{ am_now_ts | float(0) }} + {% endif %} + + am_interval_mid_ts: >- + {% set start = am_accumulation_start_ts | float(0) %} + {% set accum = am_accumulation_seconds | float(0) %} + {% if accum > 0 %} + {{ start + (accum / 2) }} + {% else %} + {{ am_now_ts | float(0) }} + {% endif %} + + ########################################################################## + # TARIFF CALCULATION + ########################################################################## + + - variables: + am_paid_start_minutes: >- + {% set p = (am_paid_tariff_start | string).split(':') %} + {% set hh = p[0] if p | count > 0 else 0 %} + {% set mm = p[1] if p | count > 1 else 0 %} + {{ (hh | int(0)) * 60 + (mm | int(0)) }} + + am_paid_end_minutes: >- + {% set p = (am_paid_tariff_end | string).split(':') %} + {% set hh = p[0] if p | count > 0 else 0 %} + {% set mm = p[1] if p | count > 1 else 0 %} + {{ (hh | int(0)) * 60 + (mm | int(0)) }} + + am_interval_mid_minutes: >- + {% set h = am_interval_mid_ts | float(0) | timestamp_custom('%H', true) | int(0) %} + {% set m = am_interval_mid_ts | float(0) | timestamp_custom('%M', true) | int(0) %} + {{ h * 60 + m }} + + am_is_paid_interval: >- + {% set start = am_paid_start_minutes | int(0) %} + {% set end = am_paid_end_minutes | int(0) %} + {% set mid = am_interval_mid_minutes | int(0) %} + {% if start == end %} + true + {% elif start < end %} + {{ mid >= start and mid < end }} + {% else %} + {{ mid >= start or mid < end }} + {% endif %} + + am_tariff_rate: >- + {% if am_is_paid_interval | bool(false) %} + {{ am_paid_tariff_cost | float(0.2023) }} + {% else %} + {{ am_offpeak_tariff_cost | float(0.0) }} + {% endif %} + + ########################################################################## + # INTERVAL ENERGY AND COST + ########################################################################## + + - variables: + am_interval_energy_kwh: >- + {{ + ( + (am_accumulation_average_power_w | float(0)) + * (am_accumulation_seconds | float(0)) + / 3600000 + ) | round(6) + }} + + am_interval_cost: >- + {{ ((am_interval_energy_kwh | float(0)) * (am_tariff_rate | float(0))) | round(6) }} + + am_should_accumulate: "{{ (am_accumulation_seconds | float(0)) > 0 }}" + + ########################################################################## + # CYCLE TOTAL BASES + ########################################################################## + + - variables: + am_cycle_energy_base_kwh: >- + {% if am_cycle_started | bool(false) %} + 0 + {% else %} + {{ am_existing_cycle_energy_kwh | float(0) }} + {% endif %} + + am_cycle_paid_energy_base_kwh: >- + {% if am_cycle_started | bool(false) %} + 0 + {% else %} + {{ am_existing_cycle_paid_energy_kwh | float(0) }} + {% endif %} + + am_cycle_free_energy_base_kwh: >- + {% if am_cycle_started | bool(false) %} + 0 + {% else %} + {{ am_existing_cycle_free_energy_kwh | float(0) }} + {% endif %} + + am_cycle_cost_base: >- + {% if am_cycle_started | bool(false) %} + 0 + {% else %} + {{ am_existing_cycle_cost | float(0) }} + {% endif %} + + ########################################################################## + # CYCLE TOTALS + ########################################################################## + + - variables: + am_cycle_energy_new_kwh: >- + {% set add_kwh = am_interval_energy_kwh | float(0) if am_should_accumulate | bool(false) else 0 %} + {{ ((am_cycle_energy_base_kwh | float(0)) + add_kwh) | round(6) }} + + am_cycle_cost_new: >- + {% set add_cost = am_interval_cost | float(0) if am_should_accumulate | bool(false) else 0 %} + {{ ((am_cycle_cost_base | float(0)) + add_cost) | round(6) }} + + am_cycle_paid_energy_new_kwh: >- + {% set add_kwh = am_interval_energy_kwh | float(0) if (am_should_accumulate | bool(false) and am_is_paid_interval | bool(false)) else 0 %} + {{ ((am_cycle_paid_energy_base_kwh | float(0)) + add_kwh) | round(6) }} + + am_cycle_free_energy_new_kwh: >- + {% set add_kwh = am_interval_energy_kwh | float(0) if (am_should_accumulate | bool(false) and not (am_is_paid_interval | bool(false))) else 0 %} + {{ ((am_cycle_free_energy_base_kwh | float(0)) + add_kwh) | round(6) }} + + ########################################################################## + # CYCLE TIMES + ########################################################################## + + - variables: + am_cycle_start_ts_new: >- + {% if am_cycle_started | bool(false) %} + {{ am_accumulation_start_ts | float(0) }} + {% elif am_existing_cycle_start_ts | float(0) > 0 %} + {{ am_existing_cycle_start_ts | float(0) }} + {% else %} + {{ am_now_ts | float(0) }} + {% endif %} + + am_cycle_stop_ts_new: >- + {% if am_cycle_finished | bool(false) %} + {{ am_accumulation_stop_ts | float(0) }} + {% elif am_cycle_started | bool(false) %} + {{ am_accumulation_start_ts | float(0) }} + {% elif am_existing_cycle_stop_ts | float(0) > 0 %} + {{ am_existing_cycle_stop_ts | float(0) }} + {% else %} + {{ am_now_ts | float(0) }} + {% endif %} + + am_cycle_duration_seconds_new: >- + {% set start = am_cycle_start_ts_new | float(0) %} + {% if am_new_state == 'Operating' %} + {% set stop = am_now_ts | float(0) %} + {% else %} + {% set stop = am_cycle_stop_ts_new | float(0) %} + {% endif %} + {% if start > 0 and stop > start %} + {{ (stop - start) | int(0) }} + {% else %} + 0 + {% endif %} + + ########################################################################## + # FORMATTED VALUES + ########################################################################## + + - variables: + am_cycle_energy_formatted: >- + {% set kwh = am_cycle_energy_new_kwh | float(0) %} + {% if kwh >= 1 %} + {{ '%.1f' | format(kwh) }}kWh + {% elif kwh < 0.001 %} + <1Wh + {% else %} + {{ '%.1f' | format(kwh * 1000) }}Wh + {% endif %} + + am_cycle_cost_formatted: >- + {% set val = am_cycle_cost_new | float(0) %} + {% if val < 0.01 %} + <1c + {% elif val < 1 %} + {{ (val * 100) | round(0) | int(0) }}c + {% else %} + ${{ '%.2f' | format(val) }} + {% endif %} + + am_cycle_offpeak_savings: >- + {% set val = ((am_cycle_energy_new_kwh | float(0)) * (am_paid_tariff_cost | float(0.2023))) - (am_cycle_cost_new | float(0)) %} + {{ ([0, val] | max) | round(4) }} + + am_cycle_offpeak_savings_formatted: >- + {% set val = am_cycle_offpeak_savings | float(0) %} + {% if val < 0.01 %} + <1c + {% elif val < 1 %} + {{ (val * 100) | round(0) | int(0) }}c + {% else %} + ${{ '%.2f' | format(val) }} + {% endif %} + + am_cycle_duration_formatted: >- + {% set d = am_cycle_duration_seconds_new | int(0) %} + {% set h = (d // 3600) | int(0) %} + {% set m = ((d % 3600) // 60) | int(0) %} + {% if h < 1 %} + {{ '%02dmin' | format(m) }} + {% else %} + {{ '%02dh %02dmin' | format(h, m) }} + {% endif %} + + am_cycle_start_time_formatted: >- + {{ am_cycle_start_ts_new | float(0) | timestamp_custom('%H:%M', true) }} + + am_cycle_stop_time_formatted: >- + {{ am_cycle_stop_ts_new | float(0) | timestamp_custom('%H:%M', true) }} + + am_cycle_start_local: >- + {{ am_cycle_start_ts_new | float(0) | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }} + + am_cycle_stop_local: >- + {{ am_cycle_stop_ts_new | float(0) | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }} + + am_last_sample_local: >- + {{ am_now_ts | float(0) | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }} + + ########################################################################## + # SUMMARY STRINGS + ########################################################################## + + - variables: + am_summary_short: >- + Your {{ am_appliance_action }} is complete. + + am_summary: >- + Your {{ am_appliance_action }} is complete. + It started at {{ am_cycle_start_time_formatted | trim }}, + finished at {{ am_cycle_stop_time_formatted | trim }}, + and used {{ am_cycle_energy_formatted | trim }}, + taking {{ am_cycle_duration_formatted | trim }} + at a cost of {{ am_cycle_cost_formatted | trim }} + (Off-peak savings of {{ am_cycle_offpeak_savings_formatted | trim }}). + + am_last_summary_new: >- + {% if am_cycle_started | bool(false) %} + Cycle running + {% elif am_cycle_finished | bool(false) %} + {{ am_summary }} + {% else %} + {{ state_attr(am_monitor_sensor, 'last_summary') | default('No cycle recorded', true) }} + {% endif %} + + am_long_announcement: >- + {% if am_long_announcement_override | trim | length > 0 %} + {{ am_long_announcement_override }} + {% else %} + {{ am_summary }} + {% endif %} + + ########################################################################## + # NOTIFICATION DECISION + ########################################################################## + # + # Very short cycles are still recorded, but no announcement is sent. + # Default minimum is 300 seconds / 5 minutes. + # + ########################################################################## + + - variables: + am_cycle_notify_allowed: >- + {{ + am_cycle_finished | bool(false) + and (am_cycle_duration_seconds_new | int(0)) >= (am_min_cycle_notify_seconds | int(300)) + }} + + am_cycle_notification_suppressed: >- + {{ + am_cycle_finished | bool(false) + and not (am_cycle_notify_allowed | bool(false)) + }} + + am_cycle_notification_suppressed_reason: >- + {% if am_cycle_notification_suppressed | bool(false) %} + Cycle was shorter than {{ am_min_cycle_notify_seconds | int(300) }} seconds + {% endif %} + + ########################################################################## + # PUBLISH RETAINED MQTT STATE + ########################################################################## + + - action: mqtt.publish + data: + topic: "{{ am_state_topic }}" + retain: true + qos: 0 + payload: >- + {{ + dict( + appliance_id=am_appliance_id, + appliance_name=am_appliance_name, + appliance_action=am_appliance_action, + + state=am_new_state, + previous_state=am_previous_state, + state_changed=am_state_changed | bool(false), + + power_w=am_power_w | float(0), + last_power_w=am_power_w | float(0), + previous_power_w=am_last_power_w | float(0), + average_power_w=am_average_power_w | float(0), + recent_samples=am_recent_samples_list, + recent_samples_json=am_recent_samples_json, + + last_sample_ts=am_now_ts | float(0), + last_sample_local=am_last_sample_local, + + cycle_start_ts=am_cycle_start_ts_new | float(0), + cycle_stop_ts=am_cycle_stop_ts_new | float(0), + cycle_start_local=am_cycle_start_local, + cycle_stop_local=am_cycle_stop_local, + + cycle_duration_seconds=am_cycle_duration_seconds_new | int(0), + cycle_duration_formatted=am_cycle_duration_formatted | trim, + + min_cycle_notify_seconds=am_min_cycle_notify_seconds | int(300), + cycle_notify_allowed=am_cycle_notify_allowed | bool(false), + cycle_notification_suppressed=am_cycle_notification_suppressed | bool(false), + cycle_notification_suppressed_reason=am_cycle_notification_suppressed_reason | trim, + + cycle_energy_kwh=am_cycle_energy_new_kwh | float(0), + cycle_paid_energy_kwh=am_cycle_paid_energy_new_kwh | float(0), + cycle_free_energy_kwh=am_cycle_free_energy_new_kwh | float(0), + cycle_energy_formatted=am_cycle_energy_formatted | trim, + + cycle_cost=am_cycle_cost_new | float(0), + cycle_cost_formatted=am_cycle_cost_formatted | trim, + + cycle_offpeak_savings=am_cycle_offpeak_savings | float(0), + cycle_offpeak_savings_formatted=am_cycle_offpeak_savings_formatted | trim, + + paid_tariff_start=am_paid_tariff_start, + paid_tariff_end=am_paid_tariff_end, + paid_tariff_cost=am_paid_tariff_cost | float(0), + offpeak_tariff_cost=am_offpeak_tariff_cost | float(0), + + accumulation_seconds=am_accumulation_seconds | float(0), + accumulation_average_power_w=am_accumulation_average_power_w | float(0), + interval_energy_kwh=am_interval_energy_kwh | float(0), + interval_cost=am_interval_cost | float(0), + is_paid_interval=am_is_paid_interval | bool(false), + + summary_short=am_summary_short, + summary=am_summary, + last_summary=am_last_summary_new + ) | to_json + }} + + ########################################################################## + # DEBUG LOGBOOK ENTRY + ########################################################################## + + - if: + - condition: template + value_template: "{{ am_debug_flow | bool(false) }}" + then: + - action: logbook.log + data: + name: "Appliance Monitor" + message: >- + {{ am_appliance_name }}: {{ am_previous_state }} -> {{ am_new_state }}, + power {{ am_power_w | round(1) }}W, + average {{ am_average_power_w | round(1) }}W, + cycle {{ am_cycle_energy_new_kwh | round(3) }}kWh, + cost {{ am_cycle_cost_new | round(4) }} + + ########################################################################## + # SHORT CYCLE SUPPRESSION LOG + ########################################################################## + + - if: + - condition: template + value_template: "{{ am_cycle_notification_suppressed | bool(false) }}" + then: + - action: logbook.log + data: + name: "Appliance Monitor" + message: >- + {{ am_appliance_name }} finished after + {{ am_cycle_duration_formatted | trim }}, below the + {{ am_min_cycle_notify_seconds | int(300) }} second notification + threshold. No announcement was sent. + + ########################################################################## + # FINISHED ANNOUNCEMENT + ########################################################################## + # This script is in additional package view_road_announcement_router.yaml. + # If you want to use your own announcement system, it will occur here + # at am_cycle_notify_allowed being true. + # + # Change to your own announcement method here if needed. + ########################################################################## + + - if: + - condition: template + value_template: "{{ am_cycle_notify_allowed | bool(false) }}" + then: + - action: script.view_road_announcement + data: + channels: "{{ am_announcement_channels }}" + title: "{{ am_announcement_title }}" + short_announcement: "{{ am_short_announcement }}" + long_announcement: "{{ am_long_announcement }}" + payload: "" + indicator: "{{ am_matrix_indicator }}" diff --git a/packages/appliances_status_monitoring.yaml b/packages/appliances_status_monitoring.yaml new file mode 100644 index 0000000..a3ceff7 --- /dev/null +++ b/packages/appliances_status_monitoring.yaml @@ -0,0 +1,255 @@ +################################################################################ +# PACKAGE: Appliances Status Monitoring +################################################################################ +# +# Version: 1.4 +# Date: 2026-06-09 +# +# Purpose: +# Appliance status monitoring package for multiple appliances. +# +# This package defines a central appliance registry and one automation that: +# +# 1. Publishes MQTT discovery config for each appliance monitor sensor. +# 2. Samples appliance power sensors once per minute. +# 3. Calls script.appliance_monitor_process_sample. +# +# Processor package required: +# appliance_monitor_processor.yaml +# +# Announcement router required: +# view_road_announcement_router.yaml +# +# MQTT: +# MQTT is used only as retained state storage for appliance monitor sensors. +# Sensor entities are created using MQTT discovery. +# +# Adding another appliance: +# Add one entry to the am_appliances list. +# +# Version 1.4: +# Added min_cycle_notify_seconds support. +# Default is 300 seconds, so cycles shorter than 5 minutes are recorded but +# do not send finished notifications. +# Per-appliance overrides can be set in the am_appliances list. +# +# Version 1.3: +# Removed the is_number gate before calling the processor. The processor is +# now always called once per appliance per sample, and power is safely converted +# to 0 if the source sensor is unavailable or non-numeric. +# +################################################################################ + +automation: + - id: appliances_status_monitoring_process_samples + alias: Appliances Status Monitoring - Process Samples + description: Publish MQTT discovery, sample appliance power sensors, and process appliance status/cycle data. + mode: queued + max: 20 + + trigger: + - platform: homeassistant + event: start + id: ha_start + + - platform: time_pattern + minutes: "/1" + id: periodic_sample + + variables: + ########################################################################## + # MQTT LOCAL CONTROLS + ########################################################################## + + mqtt_device_name: "appliance_monitor" + mqtt_local_status_topic: !secret mqtt_status_main_topic + mqtt_discovery_prefix: "homeassistant" + + ########################################################################## + # DEFAULTS + ########################################################################## + + am_default_debug_flow: false + am_default_resolution: 2 + am_default_standby_power: 2 + am_default_operating_power_min: 12 + am_default_min_cycle_notify_seconds: 300 + + #am_default_announcement_channels: "pushover_zorruno, sony_tv_lounge, lounge_google_home_voice, led_matrix_1" + am_default_announcement_channels: "pushover_zorruno" + + # Optional appliance-specific overrides available: + # resolution: 4 + # The number of samples for the average, with one sample per minute. + # + # standby_power: 3 + # Below this value, the appliance will show "Off". + # Between this value and operating_power_min, it will show "Standby". + # + # operating_power_min: 20 + # The minimum average power needed for the appliance to show "Operating". + # + # min_cycle_notify_seconds: 600 + # Finished cycles shorter than this are recorded, but no notification + # is sent. Default is 300 seconds. + # + # announcement_channels: "pushover_zorruno" + # Announcement channels for this appliance. + # + # long_announcement: "The device has finished. Please empty it when convenient." + # Override the long announcement. + # + # min_cycle_notify_seconds: 600 + # Minimum time for an appliance to be operating before a completion announcement generated. + + ########################################################################## + # APPLIANCE REGISTRY + ########################################################################## + + am_appliances: + - appliance_id: washing_machine + appliance_name: "Washing Machine" + appliance_action: "washing2" + power_entity: "sensor.esp_laundrywashpow_load_power" + icon: "mdi:washing-machine" + short_announcement: "/s/sWashing complete" + matrix_indicator: "wash,1,15,10,6,5,1,0" + # Optional washing-machine-specific overrides + resolution: 5 + standby_power: 3 + operating_power_min: 20 + announcement_channels: "pushover_zorruno" + + - appliance_id: dryer + appliance_name: "Dryer" + appliance_action: "drying2" + power_entity: "sensor.esp_laundrydrypow_load_power" + icon: "mdi:tumble-dryer" + short_announcement: "/s/sDryer complete" + matrix_indicator: "dry,1,15,10,6,5,1,0" + # Optional dryer-specific overrides + resolution: 4 + standby_power: 3 + operating_power_min: 20 + announcement_channels: "pushover_zorruno" + + - appliance_id: main_dishwasher + appliance_name: "Main Dishwasher" + appliance_action: "dishwashing2" + power_entity: "sensor.esp_maindishwasherpower_power" + icon: "mdi:dishwasher" + short_announcement: "/sDishwasher complete" + matrix_indicator: "dish,1,15,10,6,5,1,0" + + action: + ########################################################################## + # PUBLISH / REFRESH MQTT DISCOVERY CONFIG + ########################################################################## + + - repeat: + for_each: "{{ am_appliances }}" + sequence: + - variables: + am_state_topic: >- + {{ mqtt_local_status_topic }}/{{ mqtt_device_name }}/{{ repeat.item.appliance_id }}/state + + am_discovery_topic: >- + {{ mqtt_discovery_prefix }}/sensor/{{ mqtt_device_name }}_{{ repeat.item.appliance_id }}/config + + am_unique_id: >- + {{ repeat.item.appliance_id }}_monitor + + am_object_id: >- + {{ mqtt_device_name }}_{{ repeat.item.appliance_id }}_monitor + + - action: mqtt.publish + data: + topic: "{{ am_discovery_topic }}" + retain: true + qos: 0 + payload: >- + {{ + dict( + name=repeat.item.appliance_name ~ ' Monitor', + unique_id=am_unique_id, + object_id=am_object_id, + icon=repeat.item.icon | default('mdi:power-plug'), + state_topic=am_state_topic, + value_template='{{ value_json.state | default("Off") }}', + json_attributes_topic=am_state_topic, + device=dict( + identifiers=[mqtt_device_name], + name='Appliance Monitor', + manufacturer='View Road Home Assistant', + model='Shared appliance power monitor' + ) + ) | to_json + }} + + ########################################################################## + # PROCESS SAMPLES + ########################################################################## + # + # Always process every appliance. The processor receives power_w as a safe + # float value, so unavailable/non-numeric sensors become 0 W. + # + ########################################################################## + + - repeat: + for_each: "{{ am_appliances }}" + sequence: + - variables: + am_state_topic: >- + {{ mqtt_local_status_topic }}/{{ mqtt_device_name }}/{{ repeat.item.appliance_id }}/state + + am_monitor_sensor: >- + sensor.{{ mqtt_device_name }}_{{ repeat.item.appliance_id }}_monitor + + am_title: >- + {{ repeat.item.title | default(repeat.item.appliance_name ~ ' Notification', true) }} + + am_announcement_channels: >- + {{ repeat.item.announcement_channels | default(am_default_announcement_channels, true) }} + + am_debug_flow: >- + {{ repeat.item.debug_flow | default(am_default_debug_flow, true) }} + + am_resolution: >- + {{ repeat.item.resolution | default(am_default_resolution, true) }} + + am_standby_power: >- + {{ repeat.item.standby_power | default(am_default_standby_power, true) }} + + am_operating_power_min: >- + {{ repeat.item.operating_power_min | default(am_default_operating_power_min, true) }} + + am_min_cycle_notify_seconds: >- + {{ repeat.item.min_cycle_notify_seconds | default(am_default_min_cycle_notify_seconds, true) }} + + am_power_w: >- + {{ states(repeat.item.power_entity) | float(0) }} + + am_long_announcement: >- + {{ repeat.item.long_announcement | default('', true) }} + + - action: script.appliance_monitor_process_sample + data: + appliance_id: "{{ repeat.item.appliance_id }}" + appliance_name: "{{ repeat.item.appliance_name }}" + appliance_action: "{{ repeat.item.appliance_action }}" + + power_w: "{{ am_power_w }}" + monitor_sensor: "{{ am_monitor_sensor }}" + state_topic: "{{ am_state_topic }}" + + debug_flow: "{{ am_debug_flow }}" + resolution: "{{ am_resolution }}" + standby_power: "{{ am_standby_power }}" + operating_power_min: "{{ am_operating_power_min }}" + min_cycle_notify_seconds: "{{ am_min_cycle_notify_seconds }}" + + announcement_channels: "{{ am_announcement_channels }}" + short_announcement: "{{ repeat.item.short_announcement }}" + long_announcement: "{{ am_long_announcement }}" + title: "{{ am_title }}" + matrix_indicator: "{{ repeat.item.matrix_indicator }}"