From 92d3d03e50b2f130a8c6b8dbdd8111b2f7d8b41c Mon Sep 17 00:00:00 2001 From: m038 Date: Tue, 26 May 2026 22:34:15 +0200 Subject: [PATCH] Update flow files --- flows.json | 222 ++++++++++++++++++++++++++--------------------------- 1 file changed, 111 insertions(+), 111 deletions(-) diff --git a/flows.json b/flows.json index e4ca8d6..089e7ab 100644 --- a/flows.json +++ b/flows.json @@ -97,11 +97,6 @@ "type": "tab", "label": "Temperature & climate" }, - { - "id": "6dfa989bb120e6c6", - "type": "tab", - "label": "presence" - }, { "id": "e52c44dc.71cb5", "type": "subflow", @@ -22041,21 +22036,31 @@ [] ] }, + { + "type": "tab", + "label": "Home Presence", + "id": "6dfa989bb120e6c6" + }, { "id": "pres_c_homemode", "type": "comment", "z": "6dfa989bb120e6c6", "name": "── Home Mode ──", + "wires": [], "info": "", "x": 130, - "y": 60, - "wires": [] + "y": 60 }, { "id": "pres001a2b3c4d5e", "type": "server-state-changed", "z": "6dfa989bb120e6c6", "name": "Mischa presence", + "wires": [ + [ + "pres002a2b3c4d5e" + ] + ], "server": "657c7463.48e1e4", "version": 6, "outputs": 1, @@ -22102,18 +22107,21 @@ } ], "x": 120, - "y": 100, - "wires": [ - [ - "pres002a2b3c4d5e" - ] - ] + "y": 100 }, { "id": "pres002a2b3c4d5e", "type": "switch", "z": "6dfa989bb120e6c6", "name": "Home or Away?", + "wires": [ + [ + "pres003a2b3c4d5e" + ], + [ + "pres004a2b3c4d5e" + ] + ], "property": "payload", "propertyType": "msg", "rules": [ @@ -22132,21 +22140,16 @@ "repair": false, "outputs": 2, "x": 400, - "y": 100, - "wires": [ - [ - "pres003a2b3c4d5e" - ], - [ - "pres004a2b3c4d5e" - ] - ] + "y": 100 }, { "id": "pres003a2b3c4d5e", "type": "api-call-service", "z": "6dfa989bb120e6c6", "name": "Set Home", + "wires": [ + [] + ], "server": "657c7463.48e1e4", "version": 7, "debugenabled": false, @@ -22168,16 +22171,16 @@ "domain": "input_select", "service": "select_option", "x": 660, - "y": 60, - "wires": [ - [] - ] + "y": 60 }, { "id": "pres004a2b3c4d5e", "type": "api-call-service", "z": "6dfa989bb120e6c6", "name": "Set Away", + "wires": [ + [] + ], "server": "657c7463.48e1e4", "version": 7, "debugenabled": false, @@ -22199,76 +22202,78 @@ "domain": "input_select", "service": "select_option", "x": 660, - "y": 140, - "wires": [ - [] - ] + "y": 140 }, { "id": "pres_sm_c_header", "type": "comment", "z": "6dfa989bb120e6c6", "name": "── Room Presence State Machine ──", + "wires": [], "info": "", "x": 190, - "y": 300, - "wires": [] + "y": 300 }, { "id": "pres_sm_c_person", "type": "comment", "z": "6dfa989bb120e6c6", "name": "Person", + "wires": [], "info": "", "x": 90, - "y": 360, - "wires": [] + "y": 360 }, { "id": "pres_sm_c_hall", "type": "comment", "z": "6dfa989bb120e6c6", "name": "Hallway (direction + state)", + "wires": [], "info": "", "x": 150, - "y": 480, - "wires": [] + "y": 480 }, { "id": "pres_sm_c_rooms", "type": "comment", "z": "6dfa989bb120e6c6", "name": "Room Motion Sensors", + "wires": [], "info": "", "x": 140, - "y": 760, - "wires": [] + "y": 760 }, { "id": "pres_sm_c_sm", "type": "comment", "z": "6dfa989bb120e6c6", "name": "State Machine", + "wires": [], "info": "", "x": 450, - "y": 580, - "wires": [] + "y": 580 }, { "id": "pres_sm_c_out", "type": "comment", "z": "6dfa989bb120e6c6", "name": "Outputs", + "wires": [], "info": "", "x": 730, - "y": 580, - "wires": [] + "y": 580 }, { "id": "pres_sm_person", "type": "server-state-changed", "z": "6dfa989bb120e6c6", "name": "Person (room SM)", + "wires": [ + [ + "pres_sm_func" + ] + ], "server": "657c7463.48e1e4", "version": 6, "outputs": 1, @@ -22315,18 +22320,18 @@ } ], "x": 130, - "y": 400, - "wires": [ - [ - "pres_sm_func" - ] - ] + "y": 400 }, { "id": "pres_sm_hall1", "type": "server-state-changed", "z": "6dfa989bb120e6c6", "name": "Hallway S1 (corner/front door)", + "wires": [ + [ + "pres_sm_func" + ] + ], "server": "657c7463.48e1e4", "version": 6, "outputs": 1, @@ -22373,18 +22378,18 @@ } ], "x": 160, - "y": 520, - "wires": [ - [ - "pres_sm_func" - ] - ] + "y": 520 }, { "id": "pres_sm_hall2", "type": "server-state-changed", "z": "6dfa989bb120e6c6", "name": "Hallway S2 (near living room)", + "wires": [ + [ + "pres_sm_func" + ] + ], "server": "657c7463.48e1e4", "version": 6, "outputs": 1, @@ -22431,18 +22436,18 @@ } ], "x": 160, - "y": 580, - "wires": [ - [ - "pres_sm_func" - ] - ] + "y": 580 }, { "id": "pres_sm_hall3", "type": "server-state-changed", "z": "6dfa989bb120e6c6", "name": "Hallway S3 (near kitchen)", + "wires": [ + [ + "pres_sm_func" + ] + ], "server": "657c7463.48e1e4", "version": 6, "outputs": 1, @@ -22489,18 +22494,18 @@ } ], "x": 150, - "y": 640, - "wires": [ - [ - "pres_sm_func" - ] - ] + "y": 640 }, { "id": "pres_sm_hallg", "type": "server-state-changed", "z": "6dfa989bb120e6c6", "name": "Hallway (group)", + "wires": [ + [ + "pres_sm_func" + ] + ], "server": "657c7463.48e1e4", "version": 6, "outputs": 1, @@ -22547,18 +22552,18 @@ } ], "x": 120, - "y": 700, - "wires": [ - [ - "pres_sm_func" - ] - ] + "y": 700 }, { "id": "pres_sm_lr", "type": "server-state-changed", "z": "6dfa989bb120e6c6", "name": "Living Room Motion", + "wires": [ + [ + "pres_sm_func" + ] + ], "server": "657c7463.48e1e4", "version": 6, "outputs": 1, @@ -22605,18 +22610,18 @@ } ], "x": 130, - "y": 800, - "wires": [ - [ - "pres_sm_func" - ] - ] + "y": 800 }, { "id": "pres_sm_bed", "type": "server-state-changed", "z": "6dfa989bb120e6c6", "name": "Bedroom Motion", + "wires": [ + [ + "pres_sm_func" + ] + ], "server": "657c7463.48e1e4", "version": 6, "outputs": 1, @@ -22663,18 +22668,18 @@ } ], "x": 120, - "y": 860, - "wires": [ - [ - "pres_sm_func" - ] - ] + "y": 860 }, { "id": "pres_sm_bath", "type": "server-state-changed", "z": "6dfa989bb120e6c6", "name": "Bathroom Motion", + "wires": [ + [ + "pres_sm_func" + ] + ], "server": "657c7463.48e1e4", "version": 6, "outputs": 1, @@ -22721,18 +22726,18 @@ } ], "x": 120, - "y": 920, - "wires": [ - [ - "pres_sm_func" - ] - ] + "y": 920 }, { "id": "pres_sm_kit", "type": "server-state-changed", "z": "6dfa989bb120e6c6", "name": "Kitchen Motion", + "wires": [ + [ + "pres_sm_func" + ] + ], "server": "657c7463.48e1e4", "version": 6, "outputs": 1, @@ -22779,18 +22784,21 @@ } ], "x": 120, - "y": 980, - "wires": [ - [ - "pres_sm_func" - ] - ] + "y": 980 }, { "id": "pres_sm_func", "type": "function", "z": "6dfa989bb120e6c6", "name": "Room Presence SM", + "wires": [ + [ + "pres_sm_api" + ], + [ + "pres_sm_dbg" + ] + ], "func": "// === ROOM PRESENCE STATE MACHINE ===\n// msg.topic = triggering entity_id (from triggerId output property)\n// msg.payload = entity state string\n// msg.data = full HASC event data\n\nconst entityId = (msg.data && msg.data.entity_id) ? msg.data.entity_id : (msg.topic || '');\nconst newState = (msg.data && msg.data.new_state) ? msg.data.new_state.state : msg.payload;\n\n// Guest mode guard — multi-person breaks single-occupant assumptions\nconst haStates = (global.get('homeassistant') || {}).homeAssistantLatest\n ? global.get('homeassistant').homeAssistantLatest.states : {};\nconst guestMode = (haStates['input_boolean.guest_mode'] || {}).state;\nif (guestMode === 'on') return null;\n\n// Current state from flow context\nlet currentRoom = flow.get('currentRoom') || 'unknown';\n\n// ── Helpers ────────────────────────────────────────────────────────────────\n\nfunction capitalize(s) {\n const map = {\n unknown: 'Unknown', away: 'Away', hallway: 'Hallway',\n living_room: 'Livingroom', bedroom: 'Bedroom',\n bathroom: 'Bathroom', kitchen: 'Kitchen', balcony: 'Balcony'\n };\n return map[s] || (s.charAt(0).toUpperCase() + s.slice(1));\n}\n\nfunction cancelDestTimer() {\n const h = flow.get('destTimerHandle');\n if (h) { clearTimeout(h); flow.set('destTimerHandle', null); }\n}\n\nfunction cancelBalconyTimer() {\n const h = flow.get('balconyTimerHandle');\n if (h) { clearTimeout(h); flow.set('balconyTimerHandle', null); }\n}\n\nfunction setDestTimer() {\n cancelDestTimer();\n const h = setTimeout(function () {\n const lr = flow.get('lastRoom') || 'unknown';\n flow.set('currentRoom', lr);\n flow.set('destTimerHandle', null);\n node.send([\n { payload: capitalize(lr) },\n { payload: '[presence] dest-timer expired → reverted to ' + lr }\n ]);\n }, 90000);\n flow.set('destTimerHandle', h);\n}\n\nfunction setBalconyTimer() {\n cancelBalconyTimer();\n const h = setTimeout(function () {\n const cr = flow.get('currentRoom');\n if (cr === 'living_room') {\n flow.set('currentRoom', 'balcony');\n flow.set('balconyTimerHandle', null);\n node.send([\n { payload: 'Balcony' },\n { payload: '[presence] balcony timer fired → Balcony' }\n ]);\n }\n }, 900000); // 15 minutes\n flow.set('balconyTimerHandle', h);\n}\n\nfunction setState(newRoom) {\n const prev = flow.get('currentRoom') || 'unknown';\n if (newRoom === prev) return null; // no change needed\n flow.set('lastRoom', prev);\n flow.set('currentRoom', newRoom);\n return [\n { payload: capitalize(newRoom) },\n { payload: '[presence] ' + prev + ' → ' + newRoom + ' (via ' + entityId + ')' }\n ];\n}\n\nfunction updateHallwaySequence(sensorNum) {\n let seq = flow.get('hallwaySequence') || [];\n const now = Date.now();\n seq = seq.filter(function (e) { return now - e.time < 15000; });\n seq.push({ sensor: sensorNum, time: now });\n flow.set('hallwaySequence', seq);\n flow.set('lastHallwayTime', now);\n}\n\n// ── Transitions ────────────────────────────────────────────────────────────\n\n// 1. Person home / away\nif (entityId === 'person.mischa_gorinskat') {\n if (newState === 'not_home') {\n cancelDestTimer();\n cancelBalconyTimer();\n return setState('away');\n }\n if (newState === 'home') {\n return setState('unknown');\n }\n return null;\n}\n\n// Ignore all motion when person is away\nif (currentRoom === 'away') return null;\n\n// 2. Individual hallway sensors — direction tracking only, no state change\nif (entityId === 'binary_sensor.hallway_motion_sensor_1_occupancy') {\n if (newState === 'on') updateHallwaySequence(1);\n return null;\n}\nif (entityId === 'binary_sensor.hallway_motion_sensor_2_occupancy') {\n if (newState === 'on') updateHallwaySequence(2);\n return null;\n}\nif (entityId === 'binary_sensor.hallway_motion_sensor_3_occupancy') {\n if (newState === 'on') updateHallwaySequence(3);\n return null;\n}\n\n// 3. Hallway group — primary state change trigger\nif (entityId === 'binary_sensor.hallway_occupancy') {\n if (newState === 'on') {\n cancelBalconyTimer();\n flow.set('lastRoom', currentRoom); // save room before entering hallway\n setDestTimer(); // 90s: if no room fires → revert\n return setState('hallway');\n }\n return null; // hallway turning off doesn't trigger a state change\n}\n\n// 4. Room sensors\nconst roomMap = {\n 'binary_sensor.livingroom_motion_sensor_occupancy': 'living_room',\n 'binary_sensor.bedroom_motion_sensor_occupancy': 'bedroom',\n 'binary_sensor.bathroom_motion_occupancy': 'bathroom',\n 'binary_sensor.kitchen_motion_sensor_occupancy': 'kitchen'\n};\n\nconst targetRoom = roomMap[entityId];\nif (targetRoom) {\n if (newState === 'on') {\n cancelDestTimer(); // confirmed destination\n cancelBalconyTimer();\n\n // Return from balcony via living room motion\n if (targetRoom === 'living_room' && currentRoom === 'balcony') {\n return setState('living_room');\n }\n // Accept if we came through hallway, are re-confirming same room, or state is unknown\n if (currentRoom === 'hallway' || currentRoom === targetRoom || currentRoom === 'unknown') {\n return setState(targetRoom);\n }\n return null;\n }\n\n // LR motion off → start balcony detection (15 min no-hallway = balcony assumed)\n if (newState === 'off' && targetRoom === 'living_room' && currentRoom === 'living_room') {\n setBalconyTimer();\n }\n return null;\n}\n\nreturn null;", "outputs": 2, "timeout": 0, @@ -22799,21 +22807,16 @@ "finalize": "", "libs": [], "x": 480, - "y": 620, - "wires": [ - [ - "pres_sm_api" - ], - [ - "pres_sm_dbg" - ] - ] + "y": 620 }, { "id": "pres_sm_api", "type": "api-call-service", "z": "6dfa989bb120e6c6", "name": "Set Room Presence", + "wires": [ + [] + ], "server": "657c7463.48e1e4", "version": 7, "debugenabled": false, @@ -22835,16 +22838,14 @@ "domain": "input_select", "service": "select_option", "x": 780, - "y": 620, - "wires": [ - [] - ] + "y": 620 }, { "id": "pres_sm_dbg", "type": "debug", "z": "6dfa989bb120e6c6", "name": "Presence log", + "wires": [], "active": true, "tosidebar": true, "console": false, @@ -22854,7 +22855,6 @@ "statusVal": "", "statusType": "auto", "x": 750, - "y": 680, - "wires": [] + "y": 680 } ] \ No newline at end of file