From d06b0a247b551bbfc3f804fa8c48db068c445cab Mon Sep 17 00:00:00 2001 From: Tony Stork Date: Tue, 27 May 2025 21:23:57 -0400 Subject: [PATCH 1/2] Rework sunset lighting flow #32 --- flows.json | 177 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 135 insertions(+), 42 deletions(-) diff --git a/flows.json b/flows.json index 3d9b0a2..c9564fc 100644 --- a/flows.json +++ b/flows.json @@ -8715,6 +8715,7 @@ "end": "sunsetStart", "soff": 0, "eoff": "-60", + "sendAtStartup": false, "x": 130, "y": 180, "wires": [ @@ -8750,10 +8751,11 @@ } ], "x": 120, - "y": 300, + "y": 240, "wires": [ [ - "5ec63f0857df4164" + "5ec63f0857df4164", + "7fd1f3f8ccc83192" ] ] }, @@ -8878,39 +8880,6 @@ [] ] }, - { - "id": "6995391c94793f08", - "type": "server-events", - "z": "e44b1e7a8ef7ae1d", - "name": "Timer Finished", - "server": "9e87348d.9c1c48", - "version": 3, - "exposeAsEntityConfig": "", - "eventType": "timer.finished", - "eventData": "{\"entity_id\":\"timer.sunset_lighting_timer\"}", - "waitForRunning": true, - "outputProperties": [ - { - "property": "payload", - "propertyType": "msg", - "value": "0", - "valueType": "num" - }, - { - "property": "topic", - "propertyType": "msg", - "value": "timer-finished", - "valueType": "str" - } - ], - "x": 120, - "y": 240, - "wires": [ - [ - "5ec63f0857df4164" - ] - ] - }, { "id": "84d40e607426c66f", "type": "ha-binary-sensor", @@ -9341,11 +9310,11 @@ "type": "function", "z": "e44b1e7a8ef7ae1d", "name": "Processing", - "func": "//! FLOW VARIABLES DEFINED IN START TAB\n\n// Set Constants\n\nconst states = global.get('homeassistant.homeAssistant.states')\nconst holidayMode = states['input_boolean.holiday_mode'].state\nconst holidayHold = states['input_boolean.holiday_mode_hold'].state\nconst currentHoliday = states['input_select.holiday_animation'].state\nconst holiday = currentHoliday.toLowerCase()\nconst sunsetLights = states['input_boolean.sunset_lights_on'].state\nconst vacation = states['input_boolean.vacation_mode'].state\nconst upBathOcc = states['binary_sensor.upstairs_bathroom_occupied'].state\nconst deskLights = states['light.tina_desk_lights'].state\nconst luxLivingRoom = states['sensor.living_room_front_illuminance'].state\nconst luxThresholdLivingRoom = states['input_number.living_room_lux_threshold'].state\nconst luxStairwell = states['sensor.stairwell_bottom_illuminance'].state\nconst luxThresholdStairwell = states['input_number.stairwell_lux_threshold'].state\nconst adaptiveSleep = flow.get(\"adaptiveSleep\", \"diskCon\")\nconst selScenesMain = flow.get(\"selScenesMain\", \"diskCon\")\nconst selScenesTinaDesk = flow.get(\"selScenesTinaDesk\", \"diskCon\")\nconst booleanOff = flow.get(\"booleanOff\", \"diskCon\")\nconst payload = msg.payload\nnode.log(\"Time-based Automations: Constants Set\")\n\n// Set a few important variables\n\nlet time = {}\nlet topic = {}\nlet delay = {}\nlet eventCall = {}\n\nif (payload == 0) {\n time = \"night\"\n eventCall = \"on\"\n} else if (payload == 1) {\n time = \"day\"\n eventCall = \"off\"\n}\n\nif (msg.topic === 'timer-finished' || msg.topic === 'manual-trigger' || msg.topic === 'lux') {\n topic = msg.topic\n}\n\nif (topic === 'timer-finished' || topic === 'manual-trigger' || topic === 'lux') {\n delay = 'off'\n} else if (luxLivingRoom > luxThresholdLivingRoom && luxStairwell > luxThresholdStairwell) {\n delay = 'on'\n} else {\n delay = 'off'\n}\nnode.log(\"Time-based Automations: Main variables defined\")\n\n// ---------- Configuration ----------\n// Decide which nighttime lighting to turn off at sunrise\nlet lightsOff = []\n\nif (holidayHold === 'off') {\n lightsOff.push(\"light.front_porch_light\")\n}\n\nif (upBathOcc === 'off') {\n lightsOff.push(\"light.upstairs_bathroom_lights\")\n}\n\n// Sunset lights timer settings\nlet timerEntity = [\"timer.sunset_lighting_timer\"]\nlet timerDuration = \"00:30:00\"\n\n// Adaptive lighting switches to set\nlet switchAdaptive = []\nlet setAdaptive = {}\n\nif (time === 'day') {\n if (holidayHold === 'on'){\n switchAdaptive = flow.get(\"adaptiveDayHoliday\", \"diskCon\")\n } else {\n switchAdaptive = flow.get(\"adaptiveDay\", \"diskCon\")\n }\n setAdaptive = 'on'\n} else if (time === 'night') {\n switchAdaptive = flow.get(\"adaptiveNight\", \"diskCon\")\n if (holidayMode === 'on') {\n setAdaptive = 'off'\n } else {\n setAdaptive = 'on'\n }\n}\n\n// Notification settings\nlet notifyTitle = {}\nlet notifyMsg = {}\nlet sunsetStatus = {}\nif (sunsetLights === 'off') {\n notifyTitle = \"Sunset Lights SKIPPED\"\n notifyMsg = \"Lights not on due to nobody home, or toggle shutoff\"\n sunsetStatus = \"Skipped\"\n} else {\n notifyTitle = \"Sunset Lights On\"\n if (topic === 'timer-finished') {\n notifyMsg = \"Lights on because timer was finished manually\"\n sunsetStatus = \"Manual Trigger\"\n } else if (topic === 'lux') {\n notifyMsg = \"Lights on because light level dropped below threshold\"\n sunsetStatus = \"Light Level Trigger\"\n } else if (delay === 'on') {\n notifyMsg = \"Lights on after delay due to sufficient light\"\n sunsetStatus = \"Delayed\"\n } else if (delay === 'off') {\n notifyMsg = \"Lights on early due to low light\"\n sunsetStatus = \"Early\"\n }\n}\n\n// Holiday Settings\nlet setHoliday = {}\nlet switchHoliday = [\"switch.animated_scene_\" + holiday]\nif (holidayMode === 'on') {\n if (time === 'day') {\n setHoliday = 'off'\n } else if (time === 'night') {\n setHoliday = 'on'\n }\n}\n\nnode.log(\"Time-based Automations: Decision Logic Complete\")\n\n// ---------- Service Calls ----------\nlet sendLights = {\n \"payload\": {\n \"action\": \"light.turn_off\",\n \"target\": {\n \"entity_id\": lightsOff\n },\n \"data\": {}\n }\n}\n\nlet sendSleepOff = {\n \"payload\": {\n \"action\": \"switch.turn_off\",\n \"target\": {\n \"entity_id\": adaptiveSleep\n },\n \"data\": {}\n }\n}\n\nlet sendBooleanOff = {\n \"payload\": {\n \"action\": \"input_boolean.turn_off\",\n \"target\": {\n \"entity_id\": booleanOff\n },\n \"data\": {}\n }\n}\n\nlet sendAdaptive = {\n \"payload\": {\n \"action\": \"switch.turn_\" + setAdaptive,\n \"target\": {\n \"entity_id\": switchAdaptive\n },\n \"data\": {}\n }\n}\n\nlet sendSceneResetMain = {\n \"payload\": {\n \"action\": \"input_text.set_value\",\n \"target\": {\n \"entity_id\": selScenesMain\n },\n \"data\": {\n \"value\": \"Adaptive\"\n }\n }\n}\n\nlet sendSceneResetDesk = {\n \"payload\": {\n \"action\": \"input_text.set_value\",\n \"target\": {\n \"entity_id\": selScenesTinaDesk\n },\n \"data\": {\n \"value\": \"Day Mode\"\n }\n }\n}\n\nlet sendHoliday = {\n \"payload\": {\n \"action\": \"switch.turn_\" + setHoliday,\n \"target\": {\n \"entity_id\": switchHoliday\n },\n \"data\": {}\n }\n}\n\nlet sendTimer = {\n \"payload\": {\n \"action\": \"timer.start\",\n \"target\": {\n \"entity_id\": timerEntity\n },\n \"data\": {\n \"duration\": timerDuration\n }\n }\n}\n\nlet sendTimerCancel = {\n \"payload\": {\n \"action\": \"timer.cancel\",\n \"target\": {\n \"entity_id\": timerEntity\n },\n \"data\": {}\n }\n}\n\nlet sendNotifyPhone = {\n \"payload\": {\n \"action\": \"script.text_notify\",\n \"data\": {\n \"who\": \"all\",\n \"title\": notifyTitle,\n \"message\": notifyMsg,\n \"type\": \"normal\",\n \"tag\": \"sunset-lights\"\n }\n }\n}\n\nlet sendNotifyTV = {\n \"payload\": {\n \"action\": \"script.tv_notify\",\n \"data\": {\n \"who\": \"all\",\n \"title\": notifyTitle,\n \"message\": notifyMsg,\n \"data\": {\n \"fontsize\": \"large\",\n \"duration\": 3,\n \"transparency\": \"25%\"\n }\n }\n }\n}\n\nlet sendFirstFloorScene = {\n \"payload\": {\n \"action\": \"script.evening_on_first_floor\",\n \"data\": {\n \"sunset_lights\": 1\n }\n }\n}\n\nlet sendSecondFloorScene = {\n \"payload\": {\n \"action\": \"script.evening_on_second_floor\",\n \"data\": {\n \"sunset_lights\": 1\n }\n }\n}\n\nlet sendDeskScene = {\n \"payload\": {\n \"action\": \"input_select.select_option\",\n \"target\": {\n \"entity_id\": [\"input_select.tina_desk_scenes\"]\n },\n \"data\": {\n \"option\": \"Reset\"\n }\n }\n}\n\nlet sendExtraLights = {\n \"payload\": {\n \"event\": \"extraLights\",\n \"data\": {\n \"toggle\": eventCall\n }\n }\n}\n\nnode.log(\"Time-based Automations: Message Payloads Defined\")\n\nnode.log(\"----- Time-based Automations: Set Parameters\")\nnode.log(\"time: \" + time)\nnode.log(\"topic: \" + topic)\nnode.log(\"lightsOff: \" + lightsOff)\nnode.log(\"holidayMode: \" + holidayMode)\nnode.log(\"eventCall: \" + eventCall)\nif (time === 'night') {\n node.log(\"luxLivingRoom: \" + luxLivingRoom)\n node.log(\"luxThresholdLivingRoom: \" + luxThresholdLivingRoom)\n node.log(\"luxStairwell: \" + luxStairwell)\n node.log(\"luxThresholdStairwell: \" + luxThresholdStairwell)\n node.log(\"delay: \" + delay)\n node.log(\"sunsetStatus: \" + sunsetStatus)\n}\nif (holidayMode === 'on') {\n node.log(\"switchHoliday: \" + switchHoliday)\n node.log(\"holiday: \" + holiday)\n node.log(\"holidayHold: \" + holidayHold)\n node.log(\"switchHoliday: \" + switchHoliday)\n}\nnode.log(\"----- Time-based Automations: End Parameters -----\")\n\nif (vacation === 'off') {\n if (time === \"day\") {\n node.status({fill:\"green\",shape:\"dot\",text:\"Sunrise Flow\"})\n node.send([null,[sendLights,sendBooleanOff],null,sendExtraLights])\n setTimeout(() => {\n node.send([null,[sendSleepOff,sendAdaptive,sendSceneResetMain,sendSceneResetDesk],null,null])\n if (holidayMode === 'on' && holidayHold === 'off') {\n node.send([null,[sendHoliday],null,null])\n }\n }, 5000)\n } else if (time === \"night\") {\n node.status({fill:\"green\",shape:\"dot\",text:\"Sunset Flow\"})\n node.send([null,sendAdaptive,null,null])\n if (holidayMode === 'on') {\n setTimeout(() => {\n node.send([null,sendHoliday,null,null])\n }, 1000)\n }\n if (delay === 'on') {\n node.send([null,sendTimer,null,null])\n } else {\n if (topic === 'lux') {\n node.send([null,sendTimerCancel,null,null])\n }\n node.send([null,null,[sendFirstFloorScene,sendSecondFloorScene],sendExtraLights])\n if (deskLights === 'on') {\n node.send([null,sendDeskScene,null,null])\n }\n if (topic != 'manual-trigger') {\n node.send([[sendNotifyPhone,sendNotifyTV],null,null,null])\n }\n }\n }\n}\nnode.log(\"Time-based Automations: Processing Complete\")", + "func": "//! FLOW VARIABLES DEFINED IN START TAB\n\n// Set Constants\n\nconst states = global.get('homeassistant.homeAssistant.states')\nconst holidayMode = states['input_boolean.holiday_mode'].state\nconst holidayHold = states['input_boolean.holiday_mode_hold'].state\nconst currentHoliday = states['input_select.holiday_animation'].state\nconst holiday = currentHoliday.toLowerCase()\nconst sunsetLights = states['input_boolean.sunset_lights_on'].state\nconst vacation = states['input_boolean.vacation_mode'].state\nconst upBathOcc = states['binary_sensor.upstairs_bathroom_occupied'].state\nconst deskLights = states['light.tina_desk_lights'].state\nconst adaptiveSleep = flow.get(\"adaptiveSleep\", \"diskCon\")\nconst selScenesMain = flow.get(\"selScenesMain\", \"diskCon\")\nconst selScenesTinaDesk = flow.get(\"selScenesTinaDesk\", \"diskCon\")\nconst booleanOff = flow.get(\"booleanOff\", \"diskCon\")\nconst triggered = states['input_boolean.sunset_lights_triggered'].state\nconst payload = msg.payload\nconst topic = msg.topic\nnode.log(\"Time-based Automations: Constants Set\")\n\n// Set a few important variables\n\nlet time = {}\nlet eventCall = {}\n\nif (payload == 0) {\n time = \"night\"\n eventCall = \"on\"\n} else if (payload == 1) {\n time = \"day\"\n eventCall = \"off\"\n}\n\nnode.log(\"Time-based Automations: Main variables defined\")\n\n// ---------- Configuration ----------\n// Decide which nighttime lighting to turn off at sunrise\nlet lightsOff = []\n\nif (holidayHold === 'off') {\n lightsOff.push(\"light.front_porch_light\")\n}\n\nif (upBathOcc === 'off') {\n lightsOff.push(\"light.upstairs_bathroom_lights\")\n}\n\n// Sunset lights timer settings\nlet timerEntity = [\"timer.sunset_lighting_timer\"]\nlet timerDuration = \"00:30:00\"\n\n// Adaptive lighting switches to set\nlet switchAdaptive = []\nlet setAdaptive = {}\n\nif (time === 'day') {\n if (holidayHold === 'on'){\n switchAdaptive = flow.get(\"adaptiveDayHoliday\", \"diskCon\")\n } else {\n switchAdaptive = flow.get(\"adaptiveDay\", \"diskCon\")\n }\n setAdaptive = 'on'\n} else if (time === 'night') {\n switchAdaptive = flow.get(\"adaptiveNight\", \"diskCon\")\n if (holidayMode === 'on') {\n setAdaptive = 'off'\n } else {\n setAdaptive = 'on'\n }\n}\n\n// Notification settings\nlet notifyTitle = {}\nlet notifyMsg = {}\nlet sunsetStatus = {}\nif (sunsetLights === 'off') {\n notifyTitle = \"Sunset Lights SKIPPED\"\n notifyMsg = \"Lights not on due to nobody home, or toggle shutoff\"\n sunsetStatus = \"Skipped\"\n} else {\n notifyTitle = \"Sunset Lights On\"\n notifyMsg = \"It's getting dark, evening lighting is now active\"\n sunsetStatus = \"Light Level Trigger\"\n}\n\n// Holiday Settings\nlet setHoliday = {}\nlet switchHoliday = [\"switch.animated_scene_\" + holiday]\nif (holidayMode === 'on') {\n if (time === 'day') {\n setHoliday = 'off'\n } else if (time === 'night') {\n setHoliday = 'on'\n }\n}\n\nnode.log(\"Time-based Automations: Decision Logic Complete\")\n\n// ---------- Service Calls ----------\n\nlet sendTriggered = {\n \"payload\": {\n \"action\": \"input_boolean.turn_on\",\n \"target\": {\n \"entity_id\": [\"input_boolean.sunset_lights_triggered\"]\n },\n \"data\": {}\n }\n}\n\nlet sendLights = {\n \"payload\": {\n \"action\": \"light.turn_off\",\n \"target\": {\n \"entity_id\": lightsOff\n },\n \"data\": {}\n }\n}\n\nlet sendSleepOff = {\n \"payload\": {\n \"action\": \"switch.turn_off\",\n \"target\": {\n \"entity_id\": adaptiveSleep\n },\n \"data\": {}\n }\n}\n\nlet sendBooleanOff = {\n \"payload\": {\n \"action\": \"input_boolean.turn_off\",\n \"target\": {\n \"entity_id\": booleanOff\n },\n \"data\": {}\n }\n}\n\nlet sendAdaptive = {\n \"payload\": {\n \"action\": \"switch.turn_\" + setAdaptive,\n \"target\": {\n \"entity_id\": switchAdaptive\n },\n \"data\": {}\n }\n}\n\nlet sendSceneResetMain = {\n \"payload\": {\n \"action\": \"input_text.set_value\",\n \"target\": {\n \"entity_id\": selScenesMain\n },\n \"data\": {\n \"value\": \"Adaptive\"\n }\n }\n}\n\nlet sendSceneResetDesk = {\n \"payload\": {\n \"action\": \"input_text.set_value\",\n \"target\": {\n \"entity_id\": selScenesTinaDesk\n },\n \"data\": {\n \"value\": \"Day Mode\"\n }\n }\n}\n\nlet sendHoliday = {\n \"payload\": {\n \"action\": \"switch.turn_\" + setHoliday,\n \"target\": {\n \"entity_id\": switchHoliday\n },\n \"data\": {}\n }\n}\n\nlet sendNotifyPhone = {\n \"payload\": {\n \"action\": \"script.text_notify\",\n \"data\": {\n \"who\": \"all\",\n \"title\": notifyTitle,\n \"message\": notifyMsg,\n \"type\": \"normal\",\n \"tag\": \"sunset-lights\"\n }\n }\n}\n\nlet sendNotifyTV = {\n \"payload\": {\n \"action\": \"script.tv_notify\",\n \"data\": {\n \"who\": \"all\",\n \"title\": notifyTitle,\n \"message\": notifyMsg,\n \"data\": {\n \"fontsize\": \"large\",\n \"duration\": 3,\n \"transparency\": \"25%\"\n }\n }\n }\n}\n\nlet sendFirstFloorScene = {\n \"payload\": {\n \"action\": \"script.evening_on_first_floor\",\n \"data\": {\n \"sunset_lights\": 1\n }\n }\n}\n\nlet sendSecondFloorScene = {\n \"payload\": {\n \"action\": \"script.evening_on_second_floor\",\n \"data\": {\n \"sunset_lights\": 1\n }\n }\n}\n\nlet sendDeskScene = {\n \"payload\": {\n \"action\": \"input_select.select_option\",\n \"target\": {\n \"entity_id\": [\"input_select.tina_desk_scenes\"]\n },\n \"data\": {\n \"option\": \"Reset\"\n }\n }\n}\n\nlet sendExtraLights = {\n \"payload\": {\n \"event\": \"extraLights\",\n \"data\": {\n \"toggle\": eventCall\n }\n }\n}\n\nnode.log(\"Time-based Automations: Message Payloads Defined\")\n\nnode.log(\"----- Time-based Automations: Set Parameters\")\nnode.log(\"time: \" + time)\nnode.log(\"topic: \" + topic)\nnode.log(\"lightsOff: \" + lightsOff)\nnode.log(\"holidayMode: \" + holidayMode)\nnode.log(\"eventCall: \" + eventCall)\nif (time === 'night') {\n node.log(\"sunsetStatus: \" + sunsetStatus)\n}\nif (holidayMode === 'on') {\n node.log(\"switchHoliday: \" + switchHoliday)\n node.log(\"holiday: \" + holiday)\n node.log(\"holidayHold: \" + holidayHold)\n node.log(\"switchHoliday: \" + switchHoliday)\n}\nnode.log(\"----- Time-based Automations: End Parameters -----\")\n\nif (vacation === 'off') {\n if (time === \"day\") {\n node.status({fill:\"green\",shape:\"dot\",text:\"Sunrise Flow\"})\n node.send([null,[sendLights,sendBooleanOff],null,sendExtraLights])\n setTimeout(() => {\n node.send([null,[sendSleepOff,sendAdaptive,sendSceneResetMain,sendSceneResetDesk],null,null])\n if (holidayMode === 'on' && holidayHold === 'off') {\n node.send([null,[sendHoliday],null,null])\n }\n }, 5000)\n } else if (time === \"night\") {\n if (triggered === 'off') {\n node.status({fill:\"green\",shape:\"dot\",text:\"Sunset Flow\"})\n node.send([null,[sendAdaptive,sendTriggered],null,null])\n if (holidayMode === 'on') {\n setTimeout(() => {\n node.send([null,sendHoliday,null,null])\n }, 1000)\n }\n node.send([null,null,[sendFirstFloorScene,sendSecondFloorScene],sendExtraLights])\n if (deskLights === 'on') {\n node.send([null,sendDeskScene,null,null])\n }\n if (topic != 'manual-trigger') {\n node.send([[sendNotifyPhone,sendNotifyTV],null,null,null])\n }\n } else {\n node.status({fill:'green',shape:'dot',text:'Sunset Flow (Already Triggered)'})\n }\n }\n}\nnode.log(\"Time-based Automations: Processing Complete\")", "outputs": 4, "timeout": 0, "noerr": 0, - "initialize": "//! ---------- DAY MODE ----------\n// Lists of adaptive lighting switches for different scenarios\nconst adaptiveDay = [\n \"switch.adaptive_lighting_basement_studio\",\n \"switch.adaptive_lighting_downstairs_bathroom\",\n \"switch.adaptive_lighting_emma_bedroom\",\n \"switch.adaptive_lighting_kallen_bedroom\",\n \"switch.adaptive_lighting_living_room\",\n \"switch.adaptive_lighting_master_bedroom\",\n \"switch.adaptive_lighting_mud_room\",\n \"switch.adaptive_lighting_tina_lamp\",\n \"switch.adaptive_lighting_upstairs_bathroom\",\n \"switch.adaptive_lighting_upstairs_hallway\",\n \"switch.adaptive_lighting_front_porch\"\n]\n\nconst adaptiveDayHoliday = [\n \"switch.adaptive_lighting_basement_studio\",\n \"switch.adaptive_lighting_downstairs_bathroom\",\n \"switch.adaptive_lighting_emma_bedroom\",\n \"switch.adaptive_lighting_kallen_bedroom\",\n \"switch.adaptive_lighting_living_room\",\n \"switch.adaptive_lighting_master_bedroom\",\n \"switch.adaptive_lighting_mud_room\",\n \"switch.adaptive_lighting_tina_lamp\",\n \"switch.adaptive_lighting_upstairs_bathroom\",\n \"switch.adaptive_lighting_upstairs_hallway\",\n]\n\n// List of adaptive lighting sleep mode switches to turn off\nconst adaptiveSleep = [\n \"switch.adaptive_lighting_sleep_mode_basement_studio\",\n \"switch.adaptive_lighting_sleep_mode_downstairs_bathroom\",\n \"switch.adaptive_lighting_sleep_mode_emma_bedroom\",\n \"switch.adaptive_lighting_sleep_mode_kallen_bedroom\",\n \"switch.adaptive_lighting_sleep_mode_living_room\",\n \"switch.adaptive_lighting_sleep_mode_master_bedroom\",\n \"switch.adaptive_lighting_sleep_mode_mud_room\",\n \"switch.adaptive_lighting_sleep_mode_tina_lamp\",\n \"switch.adaptive_lighting_sleep_mode_upstairs_bathroom\",\n \"switch.adaptive_lighting_sleep_mode_upstairs_hallway\"\n]\n\n// List of selected scene input texts to reset to Adaptive\nconst selScenesMain = [\n \"input_text.basement_studio_selected_scene\",\n \"input_text.downstairs_bathroom_selected_scene\",\n \"input_text.emma_bedroom_selected_scene\",\n \"input_text.front_porch_selected_scene\",\n \"input_text.kallen_bedroom_selected_scene\",\n \"input_text.living_room_selected_scene\",\n \"input_text.master_bedroom_selected_scene\",\n \"input_text.mud_room_selected_scene\",\n \"input_text.tina_lamp_selected_scene\",\n \"input_text.upstairs_bathroom_selected_scene\",\n \"input_text.upstairs_hallway_selected_scene\"\n]\n\n// Tina's desk reset\nconst selScenesTinaDesk = [\"input_text.tina_desk_selected_scene\"]\n\n// List of booleans to turn off\nconst booleanOff = [\n \"input_boolean.give_me_darkness\",\n \"input_boolean.goodnight\",\n \"input_boolean.kallen_computer_updates\",\n \"input_boolean.night_mode\"\n]\n\n//! ---------- NIGHT MODE ----------\n// Booleans to turn on at night\nconst adaptiveNight = [\n \"switch.adaptive_lighting_front_porch\"\n]\n\n\nflow.set(\"adaptiveDay\", adaptiveDay, \"diskCon\")\nflow.set(\"adaptiveDayHoliday\", adaptiveDayHoliday, \"diskCon\")\nflow.set(\"adaptiveNight\", adaptiveNight, \"diskCon\")\nflow.set(\"adaptiveSleep\", adaptiveSleep, \"diskCon\")\nflow.set(\"selScenesMain\", selScenesMain, \"diskCon\")\nflow.set(\"selScenesTinaDesk\", selScenesTinaDesk, \"diskCon\")\nflow.set(\"booleanOff\", booleanOff, \"diskCon\")", + "initialize": "//! ---------- DAY MODE ----------\n// Lists of adaptive lighting switches for different scenarios\nconst adaptiveDay = [\n \"switch.adaptive_lighting_basement_studio\",\n \"switch.adaptive_lighting_downstairs_bathroom\",\n \"switch.adaptive_lighting_emma_bedroom\",\n \"switch.adaptive_lighting_kallen_bedroom\",\n \"switch.adaptive_lighting_living_room\",\n \"switch.adaptive_lighting_master_bedroom\",\n \"switch.adaptive_lighting_mud_room\",\n \"switch.adaptive_lighting_tina_lamp\",\n \"switch.adaptive_lighting_upstairs_bathroom\",\n \"switch.adaptive_lighting_upstairs_hallway\",\n \"switch.adaptive_lighting_front_porch\"\n]\n\nconst adaptiveDayHoliday = [\n \"switch.adaptive_lighting_basement_studio\",\n \"switch.adaptive_lighting_downstairs_bathroom\",\n \"switch.adaptive_lighting_emma_bedroom\",\n \"switch.adaptive_lighting_kallen_bedroom\",\n \"switch.adaptive_lighting_living_room\",\n \"switch.adaptive_lighting_master_bedroom\",\n \"switch.adaptive_lighting_mud_room\",\n \"switch.adaptive_lighting_tina_lamp\",\n \"switch.adaptive_lighting_upstairs_bathroom\",\n \"switch.adaptive_lighting_upstairs_hallway\",\n]\n\n// List of adaptive lighting sleep mode switches to turn off\nconst adaptiveSleep = [\n \"switch.adaptive_lighting_sleep_mode_basement_studio\",\n \"switch.adaptive_lighting_sleep_mode_downstairs_bathroom\",\n \"switch.adaptive_lighting_sleep_mode_emma_bedroom\",\n \"switch.adaptive_lighting_sleep_mode_kallen_bedroom\",\n \"switch.adaptive_lighting_sleep_mode_living_room\",\n \"switch.adaptive_lighting_sleep_mode_master_bedroom\",\n \"switch.adaptive_lighting_sleep_mode_mud_room\",\n \"switch.adaptive_lighting_sleep_mode_tina_lamp\",\n \"switch.adaptive_lighting_sleep_mode_upstairs_bathroom\",\n \"switch.adaptive_lighting_sleep_mode_upstairs_hallway\"\n]\n\n// List of selected scene input texts to reset to Adaptive\nconst selScenesMain = [\n \"input_text.basement_studio_selected_scene\",\n \"input_text.downstairs_bathroom_selected_scene\",\n \"input_text.emma_bedroom_selected_scene\",\n \"input_text.front_porch_selected_scene\",\n \"input_text.kallen_bedroom_selected_scene\",\n \"input_text.living_room_selected_scene\",\n \"input_text.master_bedroom_selected_scene\",\n \"input_text.mud_room_selected_scene\",\n \"input_text.tina_lamp_selected_scene\",\n \"input_text.upstairs_bathroom_selected_scene\",\n \"input_text.upstairs_hallway_selected_scene\"\n]\n\n// Tina's desk reset\nconst selScenesTinaDesk = [\"input_text.tina_desk_selected_scene\"]\n\n// List of booleans to turn off\nconst booleanOff = [\n \"input_boolean.give_me_darkness\",\n \"input_boolean.goodnight\",\n \"input_boolean.kallen_computer_updates\",\n \"input_boolean.night_mode\",\n \"input_boolean.sunset_lights_triggered\"\n]\n\n//! ---------- NIGHT MODE ----------\n// Booleans to turn on at night\nconst adaptiveNight = [\n \"switch.adaptive_lighting_front_porch\"\n]\n\n\nflow.set(\"adaptiveDay\", adaptiveDay, \"diskCon\")\nflow.set(\"adaptiveDayHoliday\", adaptiveDayHoliday, \"diskCon\")\nflow.set(\"adaptiveNight\", adaptiveNight, \"diskCon\")\nflow.set(\"adaptiveSleep\", adaptiveSleep, \"diskCon\")\nflow.set(\"selScenesMain\", selScenesMain, \"diskCon\")\nflow.set(\"selScenesTinaDesk\", selScenesTinaDesk, \"diskCon\")\nflow.set(\"booleanOff\", booleanOff, \"diskCon\")", "finalize": "", "libs": [], "x": 390, @@ -9445,7 +9414,7 @@ } ], "x": 110, - "y": 360, + "y": 300, "wires": [ [ "96b23f9fc6e83696" @@ -9457,18 +9426,21 @@ "type": "function", "z": "e44b1e7a8ef7ae1d", "name": "Light Level Filter", - "func": "const states = global.get('homeassistant.homeAssistant.states')\nconst luxThresholdLivingRoom = states['input_number.living_room_lux_threshold'].state\nconst luxThresholdStairwell = states['input_number.stairwell_lux_threshold'].state\nconst timer = states['timer.sunset_lighting_timer'].state\nconst level = msg.level\nconst room = msg.room\n\nif (timer === 'active') {\n if (room === 'living-room' && level <= luxThresholdLivingRoom) {\n node.status({fill:'green',shape:'dot',text:'Sent (Living Room)'})\n node.send(msg)\n } else if (room === 'stairwell-bottom' && level <= luxThresholdStairwell) {\n node.status({fill:'green',shape:'dot',text:'Sent (Stairwell Bottom)'})\n node.send(msg)\n }\n} else {\n node.status({fill:'red',shape:'ring',text:'Blocked'})\n}", - "outputs": 1, + "func": "const states = global.get('homeassistant.homeAssistant.states')\nconst luxThresholdLivingRoom = states['input_number.living_room_lux_threshold'].state\nconst luxThresholdStairwell = states['input_number.stairwell_lux_threshold'].state\nconst luxThresholdOutdoor = states['input_number.sunset_lights_outdoor_lux_threshold'].state\nconst evening = states['binary_sensor.evening'].state\nconst triggered = states['input_boolean.sunset_lights_triggered'].state\nconst level = msg.level\nconst room = msg.room\n\nif (evening === 'on' && triggered === 'off') {\n if (room === 'living-room' && level <= luxThresholdLivingRoom) {\n node.status({fill:'green',shape:'dot',text:'Sent (Living Room)'})\n node.send([msg,msg])\n } else if (room === 'stairwell-bottom' && level <= luxThresholdStairwell) {\n node.status({fill:'green',shape:'dot',text:'Sent (Stairwell Bottom)'})\n node.send([msg,msg])\n } else if (room === 'outdoor' && level <= luxThresholdOutdoor) {\n node.status({fill:'green',shape:'dot',text:'Sent (Outdoor)'})\n node.send([msg,msg])\n }\n} else if (evening === 'off') {\n node.status({fill:'red',shape:'ring',text:'Not Evening'})\n} else if (triggered === 'on') {\n node.status({fill:'red',shape:'ring',text:'Already Triggered'})\n} else {\n node.status({fill:'red',shape:'ring',text:'No Action'})\n}", + "outputs": 2, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 235, - "y": 360, + "y": 300, "wires": [ [ - "5ec63f0857df4164" + "dc087c5494270cc2" + ], + [ + "7fd1f3f8ccc83192" ] ], "icon": "node-red-node-suncalc/sun.png", @@ -9531,6 +9503,70 @@ } ], "x": 100, + "y": 360, + "wires": [ + [ + "96b23f9fc6e83696" + ] + ] + }, + { + "id": "9672b9b9c58b8d84", + "type": "server-state-changed", + "z": "e44b1e7a8ef7ae1d", + "name": "Outdoor", + "server": "9e87348d.9c1c48", + "version": 6, + "outputs": 1, + "exposeAsEntityConfig": "", + "entities": { + "entity": [ + "sensor.home_tempest_illuminance" + ], + "substring": [], + "regex": [] + }, + "outputInitially": false, + "stateType": "num", + "ifState": "", + "ifStateType": "num", + "ifStateOperator": "is", + "outputOnlyOnStateChange": true, + "for": "0", + "forType": "num", + "forUnits": "minutes", + "ignorePrevStateNull": false, + "ignorePrevStateUnknown": false, + "ignorePrevStateUnavailable": false, + "ignoreCurrentStateUnknown": true, + "ignoreCurrentStateUnavailable": true, + "outputProperties": [ + { + "property": "level", + "propertyType": "msg", + "value": "", + "valueType": "entityState" + }, + { + "property": "topic", + "propertyType": "msg", + "value": "lux", + "valueType": "str" + }, + { + "property": "room", + "propertyType": "msg", + "value": "outdoor", + "valueType": "str" + }, + { + "property": "payload", + "propertyType": "msg", + "value": "0", + "valueType": "num" + } + ], + "x": 100, "y": 420, "wires": [ [ @@ -9538,6 +9574,63 @@ ] ] }, + { + "id": "7fd1f3f8ccc83192", + "type": "api-call-service", + "z": "e44b1e7a8ef7ae1d", + "name": "Sunset Lights Triggered", + "server": "9e87348d.9c1c48", + "version": 7, + "debugenabled": false, + "action": "input_boolean.turn_on", + "floorId": [], + "areaId": [], + "deviceId": [], + "entityId": [ + "input_boolean.sunset_lights_triggered" + ], + "labelId": [], + "data": "", + "dataType": "jsonata", + "mergeContext": "", + "mustacheAltTags": false, + "outputProperties": [], + "queue": "none", + "blockInputOverrides": true, + "domain": "input_boolean", + "service": "turn_on", + "x": 630, + "y": 400, + "wires": [ + [] + ] + }, + { + "id": "dc087c5494270cc2", + "type": "delay", + "z": "e44b1e7a8ef7ae1d", + "name": "", + "pauseType": "delay", + "timeout": "1", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 285, + "y": 240, + "wires": [ + [ + "5ec63f0857df4164" + ] + ], + "l": false + }, { "id": "134433d6e21dab5b", "type": "server-state-changed", From 80e756e19c511ac13601769d53eb15ea77208a16 Mon Sep 17 00:00:00 2001 From: Tony Stork Date: Thu, 29 May 2025 17:20:40 -0400 Subject: [PATCH 2/2] Use early night mode instead of evening, lights were triggering early #32 --- flows.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flows.json b/flows.json index c9564fc..6bc5473 100644 --- a/flows.json +++ b/flows.json @@ -9426,7 +9426,7 @@ "type": "function", "z": "e44b1e7a8ef7ae1d", "name": "Light Level Filter", - "func": "const states = global.get('homeassistant.homeAssistant.states')\nconst luxThresholdLivingRoom = states['input_number.living_room_lux_threshold'].state\nconst luxThresholdStairwell = states['input_number.stairwell_lux_threshold'].state\nconst luxThresholdOutdoor = states['input_number.sunset_lights_outdoor_lux_threshold'].state\nconst evening = states['binary_sensor.evening'].state\nconst triggered = states['input_boolean.sunset_lights_triggered'].state\nconst level = msg.level\nconst room = msg.room\n\nif (evening === 'on' && triggered === 'off') {\n if (room === 'living-room' && level <= luxThresholdLivingRoom) {\n node.status({fill:'green',shape:'dot',text:'Sent (Living Room)'})\n node.send([msg,msg])\n } else if (room === 'stairwell-bottom' && level <= luxThresholdStairwell) {\n node.status({fill:'green',shape:'dot',text:'Sent (Stairwell Bottom)'})\n node.send([msg,msg])\n } else if (room === 'outdoor' && level <= luxThresholdOutdoor) {\n node.status({fill:'green',shape:'dot',text:'Sent (Outdoor)'})\n node.send([msg,msg])\n }\n} else if (evening === 'off') {\n node.status({fill:'red',shape:'ring',text:'Not Evening'})\n} else if (triggered === 'on') {\n node.status({fill:'red',shape:'ring',text:'Already Triggered'})\n} else {\n node.status({fill:'red',shape:'ring',text:'No Action'})\n}", + "func": "const states = global.get('homeassistant.homeAssistant.states')\nconst luxThresholdLivingRoom = states['input_number.living_room_lux_threshold'].state\nconst luxThresholdStairwell = states['input_number.stairwell_lux_threshold'].state\nconst luxThresholdOutdoor = states['input_number.sunset_lights_outdoor_lux_threshold'].state\nconst earlyNight = states['binary_sensor.early_night_mode'].state\nconst triggered = states['input_boolean.sunset_lights_triggered'].state\nconst level = msg.level\nconst room = msg.room\n\nif (earlyNight === 'on' && triggered === 'off') {\n if (room === 'living-room' && level <= luxThresholdLivingRoom) {\n node.status({fill:'green',shape:'dot',text:'Sent (Living Room)'})\n node.send([msg,msg])\n } else if (room === 'stairwell-bottom' && level <= luxThresholdStairwell) {\n node.status({fill:'green',shape:'dot',text:'Sent (Stairwell Bottom)'})\n node.send([msg,msg])\n } else if (room === 'outdoor' && level <= luxThresholdOutdoor) {\n node.status({fill:'green',shape:'dot',text:'Sent (Outdoor)'})\n node.send([msg,msg])\n }\n} else if (earlyNight === 'off') {\n node.status({fill:'red',shape:'ring',text:'Not Evening'})\n} else if (triggered === 'on') {\n node.status({fill:'red',shape:'ring',text:'Already Triggered'})\n} else {\n node.status({fill:'red',shape:'ring',text:'No Action'})\n}", "outputs": 2, "timeout": 0, "noerr": 0,