ESPresence Automations
What is ESPresence?
On this page you will see all the automations I created around room-level presence detection. Being able to track individuals at a room level requires supported bluetooth devices to be present on the person which can be annoying but the trade off is a home automation experience that is tailored specific to the individual. Check out the video below where I give an overview of my thoughts with ESPresence.
Room Occupancy
The following automation uses both the ESPresence and Ring Motion sensor to detect if someone is in a room. At first I built this automation to only use Motion Sensor but it did not work the way I wanted since Motion Sensors have difficulty picking up small motion. As a result my wife would get upset because the room would go dark while she is reading. 😅 The automation you see below is the improved version that uses ESPresence to determine if a person is in currently in a room by tracking specific bluetooth enabled devices such as our phones.
Prerequisites
These automations require the following additional equipment and software
Motion sensors (any kind compatible with Home Assistant should do)
How it works
The first node triggers whenever the Ring Motion Sensor triggers.
Preserve Motion Data:simply stores the payload of the motion sensor state in a separate property so i don't lose it
Motion Gate Enabled:This is a helper switch in home assistant to act as deadman switch. If the switch is on, the automation is free to execute, otherwise the automation will stop. This is used prevent the automation from doing too much in during the day or if we simply want to control it manually.
If the sun is below the horizon and it's during part of the night I am certain my wife and i will be awake, the automation is allowed to execute. I'll refer to this ideal state as "during working hours"
"During working hours":While the automation is allowed to run, it check the stored property if the motion triggered on. If it did, it checks the Motion Gate one more time and then sets the lights to 100%. At the same time (in parallel) it checks to see if the lights are on. If the lights are on, the automation starts the process to "turn off the lights".
"Turn off the lights":This process gets started under 3 circumstances
1. If the motion sensor triggers on during working hours
2. If the motion sensor triggers off during "working hours"
3. If the motion sensor triggers outside "working hours" (this is a fail-safe)
This process will first check to see if lights are on. If this is true then it will start two parallel processes. Both process are debounced nodes that will execute after 10 and 20 mins of NO ACTIVITY. This mean that once the lights turn on or the room registers that there is no motion It will start a 10 minute time and a 20 minute timer. If there is no activity, for 10 minutes the first timer will move on and check to see if ESPresence detects noone in the room. If this true it will check the Motion Gateagain and then set the lights to 40% brightness. After 10 more minutes of inactivity if no motion was detected the last debounce node will move forward and verify with ESPresences that there is noone in the room at which point the lights will turn off.
[{"id":"13d5f5471e376a18","type":"group","z":"f9f7f67eef52780e","name":"Light Motion Detector","style":{"fill":"#ffffff","label":true,"color":"#000000"},"nodes":["58e2b10577702c48","c4337775a4ec7984","075c60db7fc455ac","4c72aed5c391e6ab","55857a0c0f4b4ca8","2a45ec1e0364cab6","65de7a8fbcf27a43","ad242b2cc3562bed","8023f042cba90f49","fee3874fa852554c","f4c0cfa2e9ae7982","6e48265e4906d8a1","ad13c6d18acf0418","1ee6490a78d51a62","590382e0aad03116","cda9ad3343ea331b","9c775bf4c31b1f9c"],"x":74,"y":1919,"w":1132,"h":322},{"id":"0c2e96ea9843cc01","type":"subflow","name":"Is In Room","info":"","category":"","in":[{"x":50,"y":30,"wires":[{"id":"4e669cd8d9bf0706"},{"id":"2ff556df8abe6c2d"}]}],"out":[{"x":620,"y":60,"wires":[{"id":"2d781d7ce351d296","port":0}]},{"x":620,"y":120,"wires":[{"id":"2d781d7ce351d296","port":1}]}],"env":[{"name":"room","type":"str","value":""}],"meta":{},"color":"#DDAA99"},{"id":"2ff556df8abe6c2d","type":"api-current-state","z":"0c2e96ea9843cc01","name":"Michael is in room","server":"228d3d53.df8e02","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.michaelpresence","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":230,"y":60,"wires":[["63a38f118ff0b8d5"]]},{"id":"4e669cd8d9bf0706","type":"api-current-state","z":"0c2e96ea9843cc01","name":"Oriana is in room","server":"228d3d53.df8e02","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.orianapresence","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":210,"y":160,"wires":[["63a38f118ff0b8d5"]]},{"id":"63a38f118ff0b8d5","type":"join","z":"0c2e96ea9843cc01","name":"Combine rooms","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":420,"y":120,"wires":[["2d781d7ce351d296"]]},{"id":"2d781d7ce351d296","type":"function","z":"0c2e96ea9843cc01","name":"is in room","func":"const room = env.get(\"room\")\n\nif (msg.payload.includes(room)){\n return [msg, null]\n}\n\nreturn [null, msg];","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":60,"wires":[[],[]]},{"id":"58e2b10577702c48","type":"api-current-state","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"sun is below the horizon","server":"228d3d53.df8e02","version":3,"outputs":2,"halt_if":"below_horizon","halt_if_type":"str","halt_if_compare":"is","entity_id":"sun.sun","state_type":"str","blockInputOverrides":true,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":350,"y":2080,"wires":[["c4337775a4ec7984"],[]]},{"id":"c4337775a4ec7984","type":"time-range-switch","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"Between 5pm and 12:30pm","lat":"","lon":"","startTime":"17:00","endTime":"00:30","startOffset":0,"endOffset":0,"x":340,"y":2120,"wires":[["ad242b2cc3562bed"],["65de7a8fbcf27a43"]]},{"id":"075c60db7fc455ac","type":"api-call-service","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"light 100%","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"light","service":"turn_on","areaId":[],"deviceId":["841f46e14c4f1b7197b630c64812277f"],"entityId":[],"data":"{\"brightness\": 255}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":710,"y":1960,"wires":[[]]},{"id":"4c72aed5c391e6ab","type":"api-call-service","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"light 40%","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"light","service":"turn_on","areaId":[],"deviceId":["841f46e14c4f1b7197b630c64812277f"],"entityId":[],"data":"{\"brightness\": 100}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":840,"y":2200,"wires":[[]]},{"id":"55857a0c0f4b4ca8","type":"api-call-service","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"light off","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"light","service":"turn_off","areaId":[],"deviceId":["841f46e14c4f1b7197b630c64812277f"],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1120,"y":2100,"wires":[[]]},{"id":"2a45ec1e0364cab6","type":"function","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"preserve motion data","func":"msg.motion = msg.payload\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":2000,"wires":[["6e48265e4906d8a1"]]},{"id":"65de7a8fbcf27a43","type":"switch","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"is motion state off?","property":"motion","propertyType":"msg","rules":[{"t":"eq","v":"off","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":590,"y":2140,"wires":[["f4c0cfa2e9ae7982"]]},{"id":"ad242b2cc3562bed","type":"switch","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"Is motion state on?","property":"motion","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":650,"y":2040,"wires":[["f4c0cfa2e9ae7982","ad13c6d18acf0418"],["f4c0cfa2e9ae7982"]]},{"id":"8023f042cba90f49","type":"debounce-leading-trailing","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","time":"1200000","debouncetype":"trailing","name":"20 min debounce","x":1090,"y":2020,"wires":[["cda9ad3343ea331b"]]},{"id":"fee3874fa852554c","type":"debounce-leading-trailing","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","time":"600000","debouncetype":"trailing","name":"10 min debounce","x":870,"y":2080,"wires":[["590382e0aad03116"]]},{"id":"f4c0cfa2e9ae7982","type":"api-current-state","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"if light is on","server":"228d3d53.df8e02","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"light.master_bedroom_light","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":850,"y":2040,"wires":[["8023f042cba90f49","fee3874fa852554c"],[]]},{"id":"6e48265e4906d8a1","type":"api-current-state","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"motion gate enabled","server":"228d3d53.df8e02","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.master_motion_switch","state_type":"str","blockInputOverrides":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":360,"y":2040,"wires":[["58e2b10577702c48"],[]]},{"id":"ad13c6d18acf0418","type":"api-current-state","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"motion gate enabled","server":"228d3d53.df8e02","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.master_motion_switch","state_type":"str","blockInputOverrides":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":660,"y":2000,"wires":[["075c60db7fc455ac"],[]]},{"id":"1ee6490a78d51a62","type":"api-current-state","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"motion gate enabled","server":"228d3d53.df8e02","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.master_motion_switch","state_type":"str","blockInputOverrides":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":880,"y":2160,"wires":[["4c72aed5c391e6ab"],[]]},{"id":"590382e0aad03116","type":"subflow:0c2e96ea9843cc01","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"is NOT in room","env":[{"name":"room","value":"master_bedroom","type":"str"}],"x":860,"y":2120,"wires":[[],["1ee6490a78d51a62"]]},{"id":"cda9ad3343ea331b","type":"subflow:0c2e96ea9843cc01","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"is NOT in room","env":[{"name":"room","value":"master_bedroom","type":"str"}],"x":1080,"y":2060,"wires":[[],["55857a0c0f4b4ca8"]]},{"id":"9c775bf4c31b1f9c","type":"server-state-changed","z":"f9f7f67eef52780e","g":"13d5f5471e376a18","name":"","server":"228d3d53.df8e02","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"binary_sensor.master_bedroom","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":280,"y":1960,"wires":[["2a45ec1e0364cab6"],["2a45ec1e0364cab6"]]},{"id":"228d3d53.df8e02","type":"server","name":"Home Assistant","addon":true}]
Where am I
This simple automation takes advantage of ESPresence awareness of tracked devices to let you know know which room it is in. This requires a helper switch which could be synced to Google Home allowing you to even ask google to activate this automation. This automation does require a a subflow called "Where is person". This subflow is responsible for reading searching for the specific presence device and returning a message stating where the device is located. Something to note: The ESPresence devices have a consistent Entity naming schema. "sensor.<firstname>presence". This format makes it easier to make the automations reusable for different people. You don't need to follow this format but simply keep it in mind when modifying the automation.
[{"id":"ea1fb700993e29de","type":"group","z":"f9f7f67eef52780e","name":"RESPONSE EVENT: Where am I?","style":{"stroke":"#6f2fa0","fill":"#dbcbe7","label":true,"color":"#000000"},"nodes":["e5dd399b22436605","2cca03a381cd823c","20b83cca716f37bf","7b3ffdd0e58e7c1b","457ac0ddba31c625"],"x":74,"y":2079,"w":712,"h":142},{"id":"656499388a4aa37d","type":"subflow","name":"Telegram Facade","info":"","category":"","in":[{"x":80,"y":40,"wires":[{"id":"44693c7b4594740b"}]}],"out":[{"x":440,"y":160,"wires":[{"id":"c3da1d823169d296","port":0}]}],"env":[{"name":"Method","type":"str","value":"sendMessage","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"Send Message"},"v":"sendMessage"},{"l":{"en-US":"Edit Message"},"v":"editMessage"},{"l":{"en-US":"Typing Status"},"v":"typing"}]}}},{"name":"Message key","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"Use message key as prompt","type":"bool","value":"false","ui":{"type":"checkbox"}},{"name":"Inline_Keyboard key","type":"str","value":"","ui":{"type":"input","opts":{"types":["str","json"]}}},{"name":"Use inline_keyboard as value","type":"bool","value":"false","ui":{"type":"checkbox"}},{"name":"Keyboard key","type":"str","value":""},{"name":"Use keyboard key as value","type":"bool","value":"false","ui":{"type":"checkbox"}}],"meta":{},"color":"#DDAA99"},{"id":"c71f58691e6b25ac","type":"function","z":"656499388a4aa37d","name":"Normalize Data","func":"const useMessageKeyAsPrompt = env.get(\"Use message key as prompt\");\nconst useKeyboardKeyAsValue = env.get(\"Use keyboard key as value\");\nconst useInlineKeyboardKeyAsValue = env.get(\"Use inline_keyboard as value\");\nlet message = sugar.Object.get(msg, env.get(\"Message key\"))\nlet inline_keyboard = sugar.Object.get(msg, env.get(\"Inline_Keyboard key\")) || []\nlet keyboard = sugar.Object.get(msg, env.get(\"Keyboard key\")) || []\nconst payload = {\n method: env.get(\"Method\"),\n body: { \n chat_id: Number(global.get(\"CHAT_ID\")),\n }\n \n}\nlet reply_markup = {}\n\nif (useMessageKeyAsPrompt) {\n message = env.get(\"Message key\")\n}\n\nif (useKeyboardKeyAsValue) {\n keyboard = env.get(\"Keyboard key\") || []\n}\n\nif (useInlineKeyboardKeyAsValue) {\n inline_keyboard = env.get(\"Inline_Keyboard key\") || []\n}\nif(inline_keyboard.length){\n inline_keyboard = createReplyKeyboard(inline_keyboard)\n reply_markup = {\n keyboard:[],\n inline_keyboard: inline_keyboard\n }\n}\n\nif (keyboard.length) {\n keyboard = createReplyKeyboard(keyboard)\n reply_markup = {\n one_time_keyboard: true,\n resize_keyboard: true,\n keyboard: keyboard,\n }\n}\n\n\n\n\nif ([\"sendMessage\", \"editMessage\"].includes(env.get(\"Method\"))) {\n payload.body.text = message;\n payload.body.parse_mode = \"html\",\n payload.body.reply_markup = reply_markup\n}else{\n payload.body.action = env.get(\"Method\");\n payload.method = \"sendChatAction\"\n} \n\nif (env.get(\"Method\") === \"editMessage\") {\n payload.body.message_id = global.get(\"message_id\");\n}\n\nmsg.data = payload\n\nreturn msg;\n\n\nfunction createReplyKeyboard(buttons = []){\n const keyboard = []\n \n buttons.forEach(button => {\n if(typeof button === \"string\"){\n const [text, callback_data] = button.split(\":\")\n\n keyboard.push([{ text, callback_data }])\n }else if(Array.isArray(button)){\n keyboard.push(button.map(item => {\n const [text, callback_data] = item.split(\":\")\n\n return { text, callback_data }\n }))\n }\n })\n\n return keyboard\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"sugar","module":"sugar"}],"x":260,"y":80,"wires":[["43c30b643c3df338"]]},{"id":"c3da1d823169d296","type":"change","z":"656499388a4aa37d","name":"Clean up","rules":[{"t":"set","p":"payload","pt":"msg","to":"cache","tot":"msg","dc":true},{"t":"delete","p":"cache","pt":"msg"},{"t":"delete","p":"data","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":240,"y":160,"wires":[[]]},{"id":"44693c7b4594740b","type":"change","z":"656499388a4aa37d","name":"Cache Payload","rules":[{"t":"set","p":"cache","pt":"msg","to":"payload","tot":"msg","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":260,"y":40,"wires":[["c71f58691e6b25ac"]]},{"id":"43c30b643c3df338","type":"ha-api","z":"656499388a4aa37d","name":"Send Thinking Status","server":"228d3d53.df8e02","version":1,"debugenabled":false,"protocol":"http","method":"post","path":"https://api.telegram.org/bot{{global.TELEGRAM}}/{{data.method}}","data":"msg.data.body","dataType":"jsonata","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":280,"y":120,"wires":[["c3da1d823169d296"]]},{"id":"d2b7014aea25fdce","type":"subflow","name":"Context","info":"## What is this?\nContext will store the given information into\nthe Global Context Store. This means that \ninformation store here is accessible to ANY\nautomation. The Context node is meant to \nallow Home Assistant to \"Remember\" information\nfor a short period of time to help enrich\nuser experience. A typical example would be\nsaving a state before making a change.\n\n## How does it work\n**Key**\nThis is the property name you want to store you info\nunder.\n\n**Value Property**\nThis is the propery path in the msg object\nwhere the data you want to store is kept.\nConsider the following msg object:\n```\n{\n payload:{\n event:{\n data:[\"hello\", \"world\"]\n foo: \"bar\"\n }\n }\n}\n```\nLets say you wanted to store the array at\nthe data property. In the *Value Property* \nyou would put `payload.event.data`\n\n**Treat above as value instead**\nThis will treat the information in the \n*Value Property* as data instead of a path to\ndata. Using the previous example, if\n*Treat above as value instead* was checked\nthis node would instead store the string\n`\"payload.event.data\"`\n\n**Action**\n- Find: Will return the value stored at *key*.\nThis will ignore all the other properties\n- Save: Store the data in/at *Value Property*\nunder the specified *key*. Remember, data\nstore will last about 2 minutes and\nwill be purged\n- Clear: Removes the information at the \nspecified *key*","category":"","in":[{"x":50,"y":30,"wires":[{"id":"ab2a8446077104f6"}]}],"out":[{"x":890,"y":200,"wires":[{"id":"a0c4df469ff886c1","port":0},{"id":"05925a150b917b69","port":0},{"id":"2200500ce117fc7b","port":0}]},{"x":910,"y":300,"wires":[{"id":"b42235ce3c3e7a5e","port":0}]}],"env":[{"name":"key","type":"str","value":"","ui":{"type":"input","opts":{"types":["str","env"]}}},{"name":"value property","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"Treat above as value instead","type":"bool","value":"false","ui":{"type":"checkbox"}},{"name":"action","type":"str","value":"Find","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"Find"},"v":"get"},{"l":{"en-US":"Save"},"v":"set"},{"l":{"en-US":"Clear"},"v":"clear"}]}}}],"meta":{},"color":"#FFF0F0","outputLabels":["contextValue","auto-delete context"],"icon":"node-red/leveldb.png"},{"id":"6127dcb508a96713","type":"switch","z":"d2b7014aea25fdce","name":"depending on the action","property":"action","propertyType":"env","rules":[{"t":"eq","v":"get","vt":"str"},{"t":"eq","v":"set","vt":"str"},{"t":"eq","v":"clear","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":170,"y":200,"wires":[["05925a150b917b69"],["2200500ce117fc7b","b8ba3280ce516350"],["a0c4df469ff886c1"]]},{"id":"b8ba3280ce516350","type":"debounce-leading-trailing","z":"d2b7014aea25fdce","time":"120000","debouncetype":"trailing","name":"Debounce 2 mins","x":470,"y":300,"wires":[["b42235ce3c3e7a5e"]]},{"id":"a0c4df469ff886c1","type":"function","z":"d2b7014aea25fdce","name":"Clear Context","func":"const key = flow.get(\"key\")\nconst _context = global.get(\"context\")\n\ndelete _context[key];\nmsg.contextValue = undefined\nglobal.set(\"context\", _context)\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":240,"wires":[[]]},{"id":"b42235ce3c3e7a5e","type":"function","z":"d2b7014aea25fdce","name":"Delete Context","func":"const key = flow.get(\"key\")\nconst _context = global.get(\"context\")\nconst specificContext = _context[key]\nlet minsAgo = 0;\n\nif (specificContext){\n minsAgo = sugar.Date.minutesAgo(new Date(specificContext.timestamp))\n}\n\nif(minsAgo >= 2){\n _context[key] = undefined\n}\n\nglobal.set(\"context\", _context)\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"sugar","module":"sugar"}],"x":680,"y":300,"wires":[[]]},{"id":"ab2a8446077104f6","type":"function","z":"d2b7014aea25fdce","name":"normalize props","func":"const {key = env.get(\"key\")} = msg\nconst useValuePropertyAsValue = env.get(\"Treat above as value instead\");\n\n// Property key to look at to get the value\nconst valueProp = env.get(\"value property\")\n\n// defaults to the value designated by the value property\nlet primaryValue = sugar.Object.get(msg, valueProp);\n\nif(useValuePropertyAsValue){\n primaryValue = valueProp\n}\n\nflow.set(\"key\", key)\nflow.set(\"value\", primaryValue)\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"sugar","module":"sugar"}],"x":120,"y":100,"wires":[["6127dcb508a96713"]]},{"id":"05925a150b917b69","type":"function","z":"d2b7014aea25fdce","name":"Get context value","func":"const key = flow.get(\"key\")\nconst _context = global.get(\"context\")\n\nmsg.contextValue = _context[key]?.value\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":120,"wires":[[]]},{"id":"2200500ce117fc7b","type":"function","z":"d2b7014aea25fdce","name":"Modify Context","func":"const key = flow.get(\"key\")\nconst value = flow.get(\"value\")\nconst _context = global.get(\"context\")\nconst isValidString = (typeof value === \"string\" && value.length)\nconst isNotUndefined = value !== undefined && value !== null\nconst isValidValue = typeof value === \"string\" ? !!value.length : isNotUndefined\n\n_context[key] = {\n timestamp: Date.now(),\n value\n};\nglobal.set(\"context\", _context)\nmsg.contextValue = value\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":200,"wires":[[]]},{"id":"68740fceb88b6fd9","type":"subflow","name":"announce to person","info":"","category":"","in":[{"x":40,"y":60,"wires":[{"id":"ac7d192c64a6a9e5"}]}],"out":[{"x":1060,"y":400,"wires":[{"id":"159a46c7eb5670e3","port":0},{"id":"e743949c66a83aa9","port":0}]}],"env":[{"name":"message","type":"str","value":"hello world"},{"name":"sms","type":"bool","value":"false","ui":{"label":{"en-US":"When not_home send SMS"},"type":"checkbox"}},{"name":"person","type":"str","value":"sensor.michaelpresence","ui":{"icon":"font-awesome/fa-user","type":"select","opts":{"opts":[{"l":{"en-US":"Michael"},"v":"sensor.michaelpresence"},{"l":{"en-US":"Oriana"},"v":"sensor.orianapresence"},{"l":{"en-US":"All"},"v":""}]}}},{"name":"message key","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"enable ke","type":"bool","value":"false","ui":{"label":{"en-US":"Enable Ke"},"type":"input","opts":{"types":["bool"]}}}],"meta":{},"color":"#C7E9C0","icon":"font-awesome/fa-file-sound-o"},{"id":"0325b8be149c7ea1","type":"api-current-state","z":"68740fceb88b6fd9","name":"find person's location","server":"228d3d53.df8e02","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"{{payload}}","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":200,"y":220,"wires":[["9835016553e3bb32"]]},{"id":"f6913ff8977a0cd2","type":"api-call-service","z":"68740fceb88b6fd9","name":"adjust volume","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"media_player","service":"volume_set","areaId":[],"deviceId":[],"entityId":["media_player.{{location}}_display","media_player.{{location}}_speaker"],"data":"{\"volume_level\": msg.payload}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":180,"y":300,"wires":[["b238b8d30e7df1f6"]]},{"id":"9835016553e3bb32","type":"change","z":"68740fceb88b6fd9","name":"set location value","rules":[{"t":"set","p":"location","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":190,"y":260,"wires":[["1a22277f2b318fc9"]]},{"id":"34122bc126305a97","type":"api-call-service","z":"68740fceb88b6fd9","name":"Announce in location","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"tts","service":"google_translate_say","areaId":[],"deviceId":[],"entityId":[],"data":"{\"entity_id\":[\t \"media_player.\" & msg.location & \"_speaker\",\t \"media_player.\" & msg.location & \"_display\"\t ], \t \"message\": msg.payload}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":200,"y":520,"wires":[["877895f56732aac7","d2d83bbbb0503515"]]},{"id":"aa2e996372ed1781","type":"switch","z":"68740fceb88b6fd9","name":"depending on the location","property":"location","propertyType":"msg","rules":[{"t":"eq","v":"not_home","vt":"str"},{"t":"empty"},{"t":"else"}],"checkall":"false","repair":false,"outputs":3,"x":210,"y":400,"wires":[["0a62f65af8aa52b1"],["0a62f65af8aa52b1"],["a1a553ec989118ea"]]},{"id":"de8e514529f8e48e","type":"api-call-service","z":"68740fceb88b6fd9","name":"Announce everywhere","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"tts","service":"google_translate_say","areaId":[],"deviceId":[],"entityId":["media_player.kitchen_display","media_player.master_bedroom_display","media_player.office_display"],"data":"{ \"message\": msg.payload}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":520,"y":400,"wires":[["621e22f7c7e7ecf6"]]},{"id":"0a62f65af8aa52b1","type":"switch","z":"68740fceb88b6fd9","name":"Should send SMS?","property":"sms","propertyType":"flow","rules":[{"t":"true"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":510,"y":320,"wires":[["f01653a05c5ab4da"],["1bc3e62ed3904b04"]]},{"id":"159a46c7eb5670e3","type":"api-call-service","z":"68740fceb88b6fd9","name":"Send SMS","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"notify","service":"microsoft_live","areaId":[],"deviceId":[],"entityId":[],"data":"{ \"message\": msg.payload}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":770,"y":380,"wires":[[]]},{"id":"1a22277f2b318fc9","type":"api-current-state","z":"68740fceb88b6fd9","name":"Master Volume","server":"228d3d53.df8e02","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_number.master_volume","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":500,"y":260,"wires":[["f6913ff8977a0cd2"]]},{"id":"1930d067a51dab34","type":"ha-wait-until","z":"68740fceb88b6fd9","name":"Wait for google to finish speaking","server":"228d3d53.df8e02","version":2,"outputs":2,"entityId":"media_player.main_speakers","entityIdFilterType":"exact","property":"state","comparator":"is","value":"idle","valueType":"str","timeout":"30","timeoutType":"num","timeoutUnits":"seconds","checkCurrentState":true,"blockInputOverrides":true,"outputProperties":[],"entityLocation":"data","entityLocationType":"none","x":560,"y":480,"wires":[["e743949c66a83aa9"],["e743949c66a83aa9"]]},{"id":"b238b8d30e7df1f6","type":"api-call-service","z":"68740fceb88b6fd9","name":"Save Speaker State","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"scene","service":"create","areaId":[],"deviceId":[],"entityId":[],"data":"{\t \"scene_id\":\"speakers\",\t \"snapshot_entities\":[\t \"media_player.office_display\",\t \"media_player.kitchen_display\",\t \"media_player.master_bedroom\",\t \"media_player.rues_room_speaker\"]\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":200,"y":340,"wires":[["aa2e996372ed1781"]]},{"id":"e743949c66a83aa9","type":"api-call-service","z":"68740fceb88b6fd9","name":"Resume speaker state","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"scene","service":"turn_on","areaId":[],"deviceId":[],"entityId":["scene.speakers"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":860,"y":500,"wires":[[]]},{"id":"987dceac895715fd","type":"ha-wait-until","z":"68740fceb88b6fd9","name":"wait until announcement is done","server":"228d3d53.df8e02","version":2,"outputs":1,"entityId":"{{payload}}","entityIdFilterType":"exact","property":"state","comparator":"is","value":"idle","valueType":"str","timeout":"0","timeoutType":"num","timeoutUnits":"seconds","checkCurrentState":true,"blockInputOverrides":false,"outputProperties":[],"entityLocation":"data","entityLocationType":"none","x":550,"y":520,"wires":[["e743949c66a83aa9"]]},{"id":"e7faa47b75218f88","type":"switch","z":"68740fceb88b6fd9","name":"if Person == all","property":"person","propertyType":"flow","rules":[{"t":"empty"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":180,"y":140,"wires":[["54d411b6bda4ec68"],["376b077c132a2ca2"]]},{"id":"54d411b6bda4ec68","type":"change","z":"68740fceb88b6fd9","name":"set location to empty string","rules":[{"t":"set","p":"location","pt":"msg","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":160,"wires":[["1a22277f2b318fc9"]]},{"id":"a1a553ec989118ea","type":"change","z":"68740fceb88b6fd9","name":"update payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"message","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":180,"y":460,"wires":[["34122bc126305a97"]]},{"id":"badd7e72cc9b5495","type":"function","z":"68740fceb88b6fd9","name":"normalize properties","func":"const {\n sms = env.get(\"sms\"),\n person = env.get(\"person\"),\n volume = env.get(\"volume\"), \n contextValue,\n} = msg;\nconst key = env.get(\"message key\")\nconst message = key ?sugar.Object.get(msg, key) : env.get(\"message\")\n\nflow.set(\"message\", message)\nflow.set(\"sms\", sms)\nflow.set(\"person\", contextValue || person)\nflow.set(\"volume\", volume)\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"sugar","module":"sugar"}],"x":200,"y":100,"wires":[["e7faa47b75218f88"]]},{"id":"ac7d192c64a6a9e5","type":"subflow:d2b7014aea25fdce","z":"68740fceb88b6fd9","name":"get person from context","env":[{"name":"key","value":"person","type":"str"},{"name":"action","value":"get","type":"str"}],"x":210,"y":60,"wires":[["badd7e72cc9b5495"],[]]},{"id":"ca23eee56c418568","type":"subflow:656499388a4aa37d","z":"68740fceb88b6fd9","name":"Send message to telegram","env":[{"name":"Message key","value":"payload","type":"str"}],"x":220,"y":600,"wires":[[]]},{"id":"621e22f7c7e7ecf6","type":"subflow:656499388a4aa37d","z":"68740fceb88b6fd9","name":"Send message to telegram","env":[{"name":"Message key","value":"payload","type":"str"}],"x":540,"y":440,"wires":[["1930d067a51dab34"]]},{"id":"376b077c132a2ca2","type":"change","z":"68740fceb88b6fd9","name":"add person to payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"person","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":200,"y":180,"wires":[["0325b8be149c7ea1"]]},{"id":"f01653a05c5ab4da","type":"change","z":"68740fceb88b6fd9","name":"add message to payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"message","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":810,"y":340,"wires":[["159a46c7eb5670e3"]]},{"id":"1bc3e62ed3904b04","type":"change","z":"68740fceb88b6fd9","name":"add message to payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"message","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":530,"y":360,"wires":[["de8e514529f8e48e"]]},{"id":"877895f56732aac7","type":"change","z":"68740fceb88b6fd9","name":"set entities","rules":[{"t":"set","p":"payload","pt":"msg","to":"\"media_player.\" & msg.location & \"_display\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":580,"wires":[["987dceac895715fd"]]},{"id":"d2d83bbbb0503515","type":"switch","z":"68740fceb88b6fd9","name":"Send to Ke","property":"enable ke","propertyType":"env","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":170,"y":560,"wires":[["ca23eee56c418568"]]},{"id":"06229e8e65556f6e","type":"subflow","name":"where is person","info":"","category":"","in":[{"x":40,"y":80,"wires":[{"id":"37716fc67f113d26"}]}],"out":[{"x":740,"y":140,"wires":[{"id":"8ddd2211e7cbc5dd","port":0}]}],"env":[{"name":"person","type":"str","value":""}],"meta":{},"color":"#A6BBCF","icon":"font-awesome/fa-location-arrow"},{"id":"8ddd2211e7cbc5dd","type":"function","z":"06229e8e65556f6e","name":"create response","func":"const location = Sugar.String.titleize(msg.payload)\n\nmsg.message = `You're currently in the ${location}`\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"Sugar","module":"sugar"}],"x":580,"y":160,"wires":[[]]},{"id":"d260264d5e8f4cf0","type":"api-current-state","z":"06229e8e65556f6e","name":"locate person","server":"228d3d53.df8e02","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.{{person}}presence","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":480,"y":100,"wires":[["8ddd2211e7cbc5dd"]]},{"id":"37716fc67f113d26","type":"switch","z":"06229e8e65556f6e","name":"has dynamic person","property":"person","propertyType":"msg","rules":[{"t":"nempty"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":200,"y":80,"wires":[["d260264d5e8f4cf0"],["6d9e9d52497ec992"]]},{"id":"6d9e9d52497ec992","type":"change","z":"06229e8e65556f6e","name":"","rules":[{"t":"set","p":"person","pt":"msg","to":"person","tot":"env"}],"action":"","property":"","from":"","to":"","reg":false,"x":240,"y":140,"wires":[["d260264d5e8f4cf0"]]},{"id":"e5dd399b22436605","type":"server-state-changed","z":"f9f7f67eef52780e","g":"ea1fb700993e29de","name":"Find my phone enabled","server":"228d3d53.df8e02","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_boolean.find_michael_phone","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"},{"property":"person","propertyType":"msg","value":"michael","valueType":"str"},{"property":"source","propertyType":"msg","value":"smart_device","valueType":"str"}],"x":200,"y":2160,"wires":[["20b83cca716f37bf","2cca03a381cd823c"],[]]},{"id":"2cca03a381cd823c","type":"api-call-service","z":"f9f7f67eef52780e","g":"ea1fb700993e29de","name":"Reset location automation trigger","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"input_boolean","service":"turn_off","areaId":[],"deviceId":[],"entityId":["input_boolean.find_michael_phone"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":500,"y":2180,"wires":[[]]},{"id":"20b83cca716f37bf","type":"subflow:06229e8e65556f6e","z":"f9f7f67eef52780e","g":"ea1fb700993e29de","name":"","x":440,"y":2120,"wires":[["457ac0ddba31c625"]]},{"id":"7b3ffdd0e58e7c1b","type":"comment","z":"f9f7f67eef52780e","g":"ea1fb700993e29de","name":"Why use a switch?","info":"Google will only show toggles and switches\nin it's app. This way we can ask google to\n\"turn on find michaels iphone\" to activate\nthis automation","x":190,"y":2120,"wires":[]},{"id":"457ac0ddba31c625","type":"subflow:68740fceb88b6fd9","z":"f9f7f67eef52780e","g":"ea1fb700993e29de","name":"","env":[{"name":"message","value":"","type":"str"},{"name":"person","value":"sensor.michaelpresence","type":"str"}],"x":660,"y":2120,"wires":[[]]},{"id":"228d3d53.df8e02","type":"server","name":"Home Assistant","addon":true}]
Subflow Automations
A Subflow is a collection of nodes that are combined into a single node. Subflows are used to reduce the complexity of automations and are a great way of encapsulating repeat logic. Below are ESPresence subflows which can be used to augment your existing automations by taking advanage of knowing who is in the room.
Where is Person
You can choose the person you want to track and the node return which room the given person is located
[{"id":"06229e8e65556f6e","type":"subflow","name":"where is person","info":"# Where is person\nThis node will return the location for the\ngiven person. \n\n# Requirements\nMake sure you update this subflow's properties\nwith the name and entities of the people that\nyou want to track. The **location person** node\nwill search for `sensor.{{person}}presence`.\n\nAs a result, you must either update the entities\nwith a similar naming schema or you must update\nthe subflow properties to conform to your specific\nnaming strategy.","category":"","in":[{"x":40,"y":140,"wires":[{"id":"37716fc67f113d26"}]}],"out":[{"x":820,"y":140,"wires":[{"id":"8ddd2211e7cbc5dd","port":0}]}],"env":[{"name":"person","type":"str","value":"michael","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"Michael"},"v":"michael"},{"l":{"en-US":"Oriana"},"v":"oriana"},{"l":{"en-US":"Use msg.person"},"v":""}]}}}],"meta":{},"color":"#A6BBCF","icon":"font-awesome/fa-street-view"},{"id":"8ddd2211e7cbc5dd","type":"function","z":"06229e8e65556f6e","name":"create response","func":"const location = Sugar.String.titleize(msg.payload)\n\nmsg.message = `You're currently in the ${location}`\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"Sugar","module":"sugar"}],"x":700,"y":140,"wires":[[]]},{"id":"d260264d5e8f4cf0","type":"api-current-state","z":"06229e8e65556f6e","name":"locate person","server":"228d3d53.df8e02","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.{{person}}presence","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":500,"y":140,"wires":[["8ddd2211e7cbc5dd"]]},{"id":"37716fc67f113d26","type":"switch","z":"06229e8e65556f6e","name":"has dynamic person","property":"person","propertyType":"msg","rules":[{"t":"nempty"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":200,"y":140,"wires":[["d260264d5e8f4cf0"],["6d9e9d52497ec992"]]},{"id":"6d9e9d52497ec992","type":"change","z":"06229e8e65556f6e","name":"set person from environment","rules":[{"t":"set","p":"person","pt":"msg","to":"person","tot":"env"}],"action":"","property":"","from":"","to":"","reg":false,"x":220,"y":200,"wires":[["d260264d5e8f4cf0"]]},{"id":"228d3d53.df8e02","type":"server","name":"Home Assistant","addon":true},{"id":"c8516277f619e719","type":"subflow:06229e8e65556f6e","z":"ea6d278335cc7c96","name":"","x":140,"y":1100,"wires":[[]]}]
Is In Room
This node informs you if a person is in the specified room.
[{"id":"0c2e96ea9843cc01","type":"subflow","name":"Is In Room","info":"# Is in room\nThis node will let you know who is in a given room.\n\n## Requirements\nThis utilizes sensors that output the location\nof a tracked individual. You will need to update the \nstate nodes in this subflow to match the people your\nsystem can track. Additionally, you must update the Join\nnode (Combine rooms) with the correct number of\npeople you are tracking, otherwise this subflow\nwill return incorrect information.\n\n## Environment Variables\nTo update the locations, you must update the \nEnvironment variables in the subflow's properties.\n","category":"","in":[{"x":60,"y":120,"wires":[{"id":"4e669cd8d9bf0706"},{"id":"2ff556df8abe6c2d"}]}],"out":[{"x":760,"y":80,"wires":[{"id":"2d781d7ce351d296","port":0}]},{"x":770,"y":160,"wires":[{"id":"2d781d7ce351d296","port":1}]}],"env":[{"name":"room","type":"str","value":"office","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"Master Bedroom"},"v":"master_bedroom"},{"l":{"en-US":"Kitchen"},"v":"kitchen"},{"l":{"en-US":"Office"},"v":"office"}]}}}],"meta":{"author":"montaque.developer@gmail.com","keywords":"espresence, location, room","license":"MIT"},"color":"#b8e994","outputLabels":["Is in room","Not in room"],"icon":"font-awesome/fa-street-view"},{"id":"2ff556df8abe6c2d","type":"api-current-state","z":"0c2e96ea9843cc01","name":"Michael is in room","server":"228d3d53.df8e02","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.michaelpresence","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":210,"y":80,"wires":[["63a38f118ff0b8d5"]]},{"id":"4e669cd8d9bf0706","type":"api-current-state","z":"0c2e96ea9843cc01","name":"Oriana is in room","server":"228d3d53.df8e02","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.orianapresence","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":210,"y":160,"wires":[["63a38f118ff0b8d5"]]},{"id":"63a38f118ff0b8d5","type":"join","z":"0c2e96ea9843cc01","name":"Combine rooms","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":420,"y":120,"wires":[["2d781d7ce351d296"]]},{"id":"2d781d7ce351d296","type":"function","z":"0c2e96ea9843cc01","name":"is in room","func":"const room = env.get(\"room\")\n\nif (msg.payload.includes(room)){\n return [msg, null]\n}\n\nreturn [null, msg];","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":120,"wires":[[],[]]},{"id":"228d3d53.df8e02","type":"server","name":"Home Assistant","addon":true},{"id":"59da574538873b57","type":"subflow:0c2e96ea9843cc01","z":"ea6d278335cc7c96","name":"","x":530,"y":1100,"wires":[[],[]]}]
Is Someone Home
This is a generic ESPresence automation that doesn't really care who is home. It only cares that someone is home.
[{"id":"b5861fbfb6495a88","type":"subflow","name":"Is someone home","info":"# Is someone home\nReturns true if at least one tracked person is home\n\n## Requirements\nMake sure to update the state nodes to reference\nthe individuals your system is tracking.","category":"","in":[{"x":40,"y":140,"wires":[{"id":"9a45dc7af0565ed6"}]}],"out":[{"x":1000,"y":120,"wires":[{"id":"f4c9ed7e4eceb8fd","port":0}]},{"x":1010,"y":240,"wires":[{"id":"f4c9ed7e4eceb8fd","port":1},{"id":"f17937f92ab96f9c","port":0}]}],"env":[],"meta":{},"color":"#3FADB5","inputLabels":["any"],"outputLabels":["Is Home","Not Home"],"icon":"font-awesome/fa-location-arrow"},{"id":"76c44136a8519325","type":"api-current-state","z":"b5861fbfb6495a88","name":"If I am home","server":"228d3d53.df8e02","version":3,"outputs":2,"halt_if":"not_home","halt_if_type":"str","halt_if_compare":"is_not","entity_id":"sensor.michaelpresence","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"},{"property":"topic","propertyType":"msg","value":"husband","valueType":"str"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":390,"y":120,"wires":[["a7c7ba05ce2c04ab"],["ff34146f9ca8a27e"]]},{"id":"42c97f9954a97c1a","type":"api-current-state","z":"b5861fbfb6495a88","name":"If wife is home","server":"228d3d53.df8e02","version":3,"outputs":2,"halt_if":"not_home","halt_if_type":"str","halt_if_compare":"is_not","entity_id":"sensor.orianapresence","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"},{"property":"topic","propertyType":"msg","value":"wife","valueType":"str"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":400,"y":180,"wires":[["a7c7ba05ce2c04ab"],["ff34146f9ca8a27e"]]},{"id":"a7c7ba05ce2c04ab","type":"join","z":"b5861fbfb6495a88","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"1","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":590,"y":140,"wires":[["f4c9ed7e4eceb8fd"]]},{"id":"f4c9ed7e4eceb8fd","type":"switch","z":"b5861fbfb6495a88","name":"someone is home","property":"payload","propertyType":"msg","rules":[{"t":"nempty"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":770,"y":140,"wires":[[],[]]},{"id":"9a45dc7af0565ed6","type":"change","z":"b5861fbfb6495a88","name":"Remove Payload","rules":[{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":170,"y":140,"wires":[["76c44136a8519325","42c97f9954a97c1a"]]},{"id":"ff34146f9ca8a27e","type":"join","z":"b5861fbfb6495a88","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"1","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":590,"y":240,"wires":[["f17937f92ab96f9c"]]},{"id":"f17937f92ab96f9c","type":"switch","z":"b5861fbfb6495a88","name":"No one is home","property":"payload.length","propertyType":"msg","rules":[{"t":"eq","v":"2","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":760,"y":240,"wires":[[]]},{"id":"228d3d53.df8e02","type":"server","name":"Home Assistant","addon":true},{"id":"e305f17f12d99ce7","type":"subflow:b5861fbfb6495a88","z":"ea6d278335cc7c96","name":"","x":330,"y":1100,"wires":[[],[]]}]
Announce to Person
This is more of a subflow which can be reused many times depending on the circumstance. Announce to person takes a message and person as an input and will first look for the room the device is located in and then looks for the speakers in the same room. This automation also takes advantage of the particular naming schema where room name is in the name of the speakers. For example: "media_player.<ROOM>.display". This automation has been evolved over time to also include the ability to send SMS to devices and send a copy of message to Ke, the AI chatbot I Created to run my smart home.
[{"id":"656499388a4aa37d","type":"subflow","name":"Telegram Facade","info":"","category":"","in":[{"x":80,"y":40,"wires":[{"id":"44693c7b4594740b"}]}],"out":[{"x":440,"y":160,"wires":[{"id":"c3da1d823169d296","port":0}]}],"env":[{"name":"Method","type":"str","value":"sendMessage","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"Send Message"},"v":"sendMessage"},{"l":{"en-US":"Edit Message"},"v":"editMessage"},{"l":{"en-US":"Typing Status"},"v":"typing"}]}}},{"name":"Message key","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"Use message key as prompt","type":"bool","value":"false","ui":{"type":"checkbox"}},{"name":"Inline_Keyboard key","type":"str","value":"","ui":{"type":"input","opts":{"types":["str","json"]}}},{"name":"Use inline_keyboard as value","type":"bool","value":"false","ui":{"type":"checkbox"}},{"name":"Keyboard key","type":"str","value":""},{"name":"Use keyboard key as value","type":"bool","value":"false","ui":{"type":"checkbox"}}],"meta":{},"color":"#DDAA99"},{"id":"c71f58691e6b25ac","type":"function","z":"656499388a4aa37d","name":"Normalize Data","func":"const useMessageKeyAsPrompt = env.get(\"Use message key as prompt\");\nconst useKeyboardKeyAsValue = env.get(\"Use keyboard key as value\");\nconst useInlineKeyboardKeyAsValue = env.get(\"Use inline_keyboard as value\");\nlet message = sugar.Object.get(msg, env.get(\"Message key\"))\nlet inline_keyboard = sugar.Object.get(msg, env.get(\"Inline_Keyboard key\")) || []\nlet keyboard = sugar.Object.get(msg, env.get(\"Keyboard key\")) || []\nconst payload = {\n method: env.get(\"Method\"),\n body: { \n chat_id: Number(global.get(\"CHAT_ID\")),\n }\n \n}\nlet reply_markup = {}\n\nif (useMessageKeyAsPrompt) {\n message = env.get(\"Message key\")\n}\n\nif (useKeyboardKeyAsValue) {\n keyboard = env.get(\"Keyboard key\") || []\n}\n\nif (useInlineKeyboardKeyAsValue) {\n inline_keyboard = env.get(\"Inline_Keyboard key\") || []\n}\nif(inline_keyboard.length){\n inline_keyboard = createReplyKeyboard(inline_keyboard)\n reply_markup = {\n keyboard:[],\n inline_keyboard: inline_keyboard\n }\n}\n\nif (keyboard.length) {\n keyboard = createReplyKeyboard(keyboard)\n reply_markup = {\n one_time_keyboard: true,\n resize_keyboard: true,\n keyboard: keyboard,\n }\n}\n\n\n\n\nif ([\"sendMessage\", \"editMessage\"].includes(env.get(\"Method\"))) {\n payload.body.text = message;\n payload.body.parse_mode = \"html\",\n payload.body.reply_markup = reply_markup\n}else{\n payload.body.action = env.get(\"Method\");\n payload.method = \"sendChatAction\"\n} \n\nif (env.get(\"Method\") === \"editMessage\") {\n payload.body.message_id = global.get(\"message_id\");\n}\n\nmsg.data = payload\n\nreturn msg;\n\n\nfunction createReplyKeyboard(buttons = []){\n const keyboard = []\n \n buttons.forEach(button => {\n if(typeof button === \"string\"){\n const [text, callback_data] = button.split(\":\")\n\n keyboard.push([{ text, callback_data }])\n }else if(Array.isArray(button)){\n keyboard.push(button.map(item => {\n const [text, callback_data] = item.split(\":\")\n\n return { text, callback_data }\n }))\n }\n })\n\n return keyboard\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"sugar","module":"sugar"}],"x":260,"y":80,"wires":[["43c30b643c3df338"]]},{"id":"c3da1d823169d296","type":"change","z":"656499388a4aa37d","name":"Clean up","rules":[{"t":"set","p":"payload","pt":"msg","to":"cache","tot":"msg","dc":true},{"t":"delete","p":"cache","pt":"msg"},{"t":"delete","p":"data","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":240,"y":160,"wires":[[]]},{"id":"44693c7b4594740b","type":"change","z":"656499388a4aa37d","name":"Cache Payload","rules":[{"t":"set","p":"cache","pt":"msg","to":"payload","tot":"msg","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":260,"y":40,"wires":[["c71f58691e6b25ac"]]},{"id":"43c30b643c3df338","type":"ha-api","z":"656499388a4aa37d","name":"Send Thinking Status","server":"228d3d53.df8e02","version":1,"debugenabled":false,"protocol":"http","method":"post","path":"https://api.telegram.org/bot{{global.TELEGRAM}}/{{data.method}}","data":"msg.data.body","dataType":"jsonata","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":280,"y":120,"wires":[["c3da1d823169d296"]]},{"id":"d2b7014aea25fdce","type":"subflow","name":"Context","info":"## What is this?\nContext will store the given information into\nthe Global Context Store. This means that \ninformation store here is accessible to ANY\nautomation. The Context node is meant to \nallow Home Assistant to \"Remember\" information\nfor a short period of time to help enrich\nuser experience. A typical example would be\nsaving a state before making a change.\n\n## How does it work\n**Key**\nThis is the property name you want to store you info\nunder.\n\n**Value Property**\nThis is the propery path in the msg object\nwhere the data you want to store is kept.\nConsider the following msg object:\n```\n{\n payload:{\n event:{\n data:[\"hello\", \"world\"]\n foo: \"bar\"\n }\n }\n}\n```\nLets say you wanted to store the array at\nthe data property. In the *Value Property* \nyou would put `payload.event.data`\n\n**Treat above as value instead**\nThis will treat the information in the \n*Value Property* as data instead of a path to\ndata. Using the previous example, if\n*Treat above as value instead* was checked\nthis node would instead store the string\n`\"payload.event.data\"`\n\n**Action**\n- Find: Will return the value stored at *key*.\nThis will ignore all the other properties\n- Save: Store the data in/at *Value Property*\nunder the specified *key*. Remember, data\nstore will last about 2 minutes and\nwill be purged\n- Clear: Removes the information at the \nspecified *key*","category":"","in":[{"x":50,"y":30,"wires":[{"id":"ab2a8446077104f6"}]}],"out":[{"x":890,"y":200,"wires":[{"id":"a0c4df469ff886c1","port":0},{"id":"05925a150b917b69","port":0},{"id":"2200500ce117fc7b","port":0}]},{"x":910,"y":300,"wires":[{"id":"b42235ce3c3e7a5e","port":0}]}],"env":[{"name":"key","type":"str","value":"","ui":{"type":"input","opts":{"types":["str","env"]}}},{"name":"value property","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"Treat above as value instead","type":"bool","value":"false","ui":{"type":"checkbox"}},{"name":"action","type":"str","value":"Find","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"Find"},"v":"get"},{"l":{"en-US":"Save"},"v":"set"},{"l":{"en-US":"Clear"},"v":"clear"}]}}}],"meta":{},"color":"#FFF0F0","outputLabels":["contextValue","auto-delete context"],"icon":"node-red/leveldb.png"},{"id":"6127dcb508a96713","type":"switch","z":"d2b7014aea25fdce","name":"depending on the action","property":"action","propertyType":"env","rules":[{"t":"eq","v":"get","vt":"str"},{"t":"eq","v":"set","vt":"str"},{"t":"eq","v":"clear","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":170,"y":200,"wires":[["05925a150b917b69"],["2200500ce117fc7b","b8ba3280ce516350"],["a0c4df469ff886c1"]]},{"id":"b8ba3280ce516350","type":"debounce-leading-trailing","z":"d2b7014aea25fdce","time":"120000","debouncetype":"trailing","name":"Debounce 2 mins","x":470,"y":300,"wires":[["b42235ce3c3e7a5e"]]},{"id":"a0c4df469ff886c1","type":"function","z":"d2b7014aea25fdce","name":"Clear Context","func":"const key = flow.get(\"key\")\nconst _context = global.get(\"context\")\n\ndelete _context[key];\nmsg.contextValue = undefined\nglobal.set(\"context\", _context)\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":240,"wires":[[]]},{"id":"b42235ce3c3e7a5e","type":"function","z":"d2b7014aea25fdce","name":"Delete Context","func":"const key = flow.get(\"key\")\nconst _context = global.get(\"context\")\nconst specificContext = _context[key]\nlet minsAgo = 0;\n\nif (specificContext){\n minsAgo = sugar.Date.minutesAgo(new Date(specificContext.timestamp))\n}\n\nif(minsAgo >= 2){\n _context[key] = undefined\n}\n\nglobal.set(\"context\", _context)\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"sugar","module":"sugar"}],"x":680,"y":300,"wires":[[]]},{"id":"ab2a8446077104f6","type":"function","z":"d2b7014aea25fdce","name":"normalize props","func":"const {key = env.get(\"key\")} = msg\nconst useValuePropertyAsValue = env.get(\"Treat above as value instead\");\n\n// Property key to look at to get the value\nconst valueProp = env.get(\"value property\")\n\n// defaults to the value designated by the value property\nlet primaryValue = sugar.Object.get(msg, valueProp);\n\nif(useValuePropertyAsValue){\n primaryValue = valueProp\n}\n\nflow.set(\"key\", key)\nflow.set(\"value\", primaryValue)\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"sugar","module":"sugar"}],"x":120,"y":100,"wires":[["6127dcb508a96713"]]},{"id":"05925a150b917b69","type":"function","z":"d2b7014aea25fdce","name":"Get context value","func":"const key = flow.get(\"key\")\nconst _context = global.get(\"context\")\n\nmsg.contextValue = _context[key]?.value\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":120,"wires":[[]]},{"id":"2200500ce117fc7b","type":"function","z":"d2b7014aea25fdce","name":"Modify Context","func":"const key = flow.get(\"key\")\nconst value = flow.get(\"value\")\nconst _context = global.get(\"context\")\nconst isValidString = (typeof value === \"string\" && value.length)\nconst isNotUndefined = value !== undefined && value !== null\nconst isValidValue = typeof value === \"string\" ? !!value.length : isNotUndefined\n\n_context[key] = {\n timestamp: Date.now(),\n value\n};\nglobal.set(\"context\", _context)\nmsg.contextValue = value\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":200,"wires":[[]]},{"id":"68740fceb88b6fd9","type":"subflow","name":"announce to person","info":"","category":"","in":[{"x":40,"y":60,"wires":[{"id":"ac7d192c64a6a9e5"}]}],"out":[{"x":1060,"y":400,"wires":[{"id":"159a46c7eb5670e3","port":0},{"id":"e743949c66a83aa9","port":0}]}],"env":[{"name":"message","type":"str","value":"hello world"},{"name":"sms","type":"bool","value":"false","ui":{"label":{"en-US":"When not_home send SMS"},"type":"checkbox"}},{"name":"person","type":"str","value":"sensor.michaelpresence","ui":{"icon":"font-awesome/fa-user","type":"select","opts":{"opts":[{"l":{"en-US":"Michael"},"v":"sensor.michaelpresence"},{"l":{"en-US":"Oriana"},"v":"sensor.orianapresence"},{"l":{"en-US":"All"},"v":""}]}}},{"name":"message key","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"enable ke","type":"bool","value":"false","ui":{"label":{"en-US":"Enable Ke"},"type":"input","opts":{"types":["bool"]}}},{"name":"volume","type":"num","value":".5","ui":{"type":"spinner","opts":{"min":0,"max":1}}}],"meta":{},"color":"#82ccdd","icon":"font-awesome/fa-file-sound-o"},{"id":"0325b8be149c7ea1","type":"api-current-state","z":"68740fceb88b6fd9","name":"find person's location","server":"228d3d53.df8e02","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"{{payload}}","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":200,"y":220,"wires":[["9835016553e3bb32"]]},{"id":"f6913ff8977a0cd2","type":"api-call-service","z":"68740fceb88b6fd9","name":"adjust volume","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"media_player","service":"volume_set","areaId":[],"deviceId":[],"entityId":["media_player.{{location}}_display","media_player.{{location}}_speaker"],"data":"{\"volume_level\": msg.payload}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":180,"y":340,"wires":[["b238b8d30e7df1f6"]]},{"id":"9835016553e3bb32","type":"change","z":"68740fceb88b6fd9","name":"set location value","rules":[{"t":"set","p":"location","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":190,"y":260,"wires":[["1a22277f2b318fc9"]]},{"id":"34122bc126305a97","type":"api-call-service","z":"68740fceb88b6fd9","name":"Announce in location","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"tts","service":"google_translate_say","areaId":[],"deviceId":[],"entityId":[],"data":"{\"entity_id\":[\t \"media_player.\" & msg.location & \"_speaker\",\t \"media_player.\" & msg.location & \"_display\"\t ], \t \"message\": msg.payload}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":200,"y":560,"wires":[["877895f56732aac7","d2d83bbbb0503515"]]},{"id":"aa2e996372ed1781","type":"switch","z":"68740fceb88b6fd9","name":"depending on the location","property":"location","propertyType":"msg","rules":[{"t":"eq","v":"not_home","vt":"str"},{"t":"empty"},{"t":"else"}],"checkall":"false","repair":false,"outputs":3,"x":210,"y":440,"wires":[["0a62f65af8aa52b1"],["0a62f65af8aa52b1"],["a1a553ec989118ea"]]},{"id":"de8e514529f8e48e","type":"api-call-service","z":"68740fceb88b6fd9","name":"Announce everywhere","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"tts","service":"google_translate_say","areaId":[],"deviceId":[],"entityId":["media_player.kitchen_display","media_player.master_bedroom_display","media_player.office_display"],"data":"{ \"message\": msg.payload}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":520,"y":400,"wires":[["621e22f7c7e7ecf6"]]},{"id":"0a62f65af8aa52b1","type":"switch","z":"68740fceb88b6fd9","name":"Should send SMS?","property":"sms","propertyType":"flow","rules":[{"t":"true"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":510,"y":320,"wires":[["f01653a05c5ab4da"],["1bc3e62ed3904b04"]]},{"id":"159a46c7eb5670e3","type":"api-call-service","z":"68740fceb88b6fd9","name":"Send SMS","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"notify","service":"microsoft_live","areaId":[],"deviceId":[],"entityId":[],"data":"{ \"message\": msg.payload}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":770,"y":380,"wires":[[]]},{"id":"1a22277f2b318fc9","type":"api-current-state","z":"68740fceb88b6fd9","name":"Master Volume","server":"228d3d53.df8e02","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_number.master_volume","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":500,"y":260,"wires":[["c1389b989dd2f231"]]},{"id":"1930d067a51dab34","type":"ha-wait-until","z":"68740fceb88b6fd9","name":"Wait for google to finish speaking","server":"228d3d53.df8e02","version":2,"outputs":2,"entityId":"media_player.main_speakers","entityIdFilterType":"exact","property":"state","comparator":"is","value":"idle","valueType":"str","timeout":"30","timeoutType":"num","timeoutUnits":"seconds","checkCurrentState":true,"blockInputOverrides":true,"outputProperties":[],"entityLocation":"data","entityLocationType":"none","x":560,"y":480,"wires":[["e743949c66a83aa9"],["e743949c66a83aa9"]]},{"id":"b238b8d30e7df1f6","type":"api-call-service","z":"68740fceb88b6fd9","name":"Save Speaker State","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"scene","service":"create","areaId":[],"deviceId":[],"entityId":[],"data":"{\t \"scene_id\":\"speakers\",\t \"snapshot_entities\":[\t \"media_player.office_display\",\t \"media_player.kitchen_display\",\t \"media_player.master_bedroom\",\t \"media_player.rues_room_speaker\"]\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":200,"y":380,"wires":[["aa2e996372ed1781"]]},{"id":"e743949c66a83aa9","type":"api-call-service","z":"68740fceb88b6fd9","name":"Resume speaker state","server":"228d3d53.df8e02","version":5,"debugenabled":false,"domain":"scene","service":"turn_on","areaId":[],"deviceId":[],"entityId":["scene.speakers"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":860,"y":500,"wires":[[]]},{"id":"987dceac895715fd","type":"ha-wait-until","z":"68740fceb88b6fd9","name":"wait until announcement is done","server":"228d3d53.df8e02","version":2,"outputs":1,"entityId":"{{payload}}","entityIdFilterType":"exact","property":"state","comparator":"is","value":"idle","valueType":"str","timeout":"0","timeoutType":"num","timeoutUnits":"seconds","checkCurrentState":true,"blockInputOverrides":false,"outputProperties":[],"entityLocation":"data","entityLocationType":"none","x":550,"y":520,"wires":[["e743949c66a83aa9"]]},{"id":"e7faa47b75218f88","type":"switch","z":"68740fceb88b6fd9","name":"if Person == all","property":"person","propertyType":"flow","rules":[{"t":"empty"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":180,"y":140,"wires":[["54d411b6bda4ec68"],["376b077c132a2ca2"]]},{"id":"54d411b6bda4ec68","type":"change","z":"68740fceb88b6fd9","name":"set location to empty string","rules":[{"t":"set","p":"location","pt":"msg","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":160,"wires":[["1a22277f2b318fc9"]]},{"id":"a1a553ec989118ea","type":"change","z":"68740fceb88b6fd9","name":"update payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"message","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":180,"y":500,"wires":[["34122bc126305a97"]]},{"id":"badd7e72cc9b5495","type":"function","z":"68740fceb88b6fd9","name":"normalize properties","func":"const {\n sms = env.get(\"sms\"),\n person = env.get(\"person\"),\n volume = env.get(\"volume\"), \n contextValue,\n} = msg;\nconst key = env.get(\"message key\")\nconst message = key ?sugar.Object.get(msg, key) : env.get(\"message\")\n\nflow.set(\"message\", message)\nflow.set(\"sms\", sms)\nflow.set(\"person\", contextValue || person)\nflow.set(\"volume\", volume)\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"sugar","module":"sugar"}],"x":200,"y":100,"wires":[["e7faa47b75218f88"]]},{"id":"ac7d192c64a6a9e5","type":"subflow:d2b7014aea25fdce","z":"68740fceb88b6fd9","name":"get person from context","env":[{"name":"key","value":"person","type":"str"},{"name":"action","value":"get","type":"str"}],"x":210,"y":60,"wires":[["badd7e72cc9b5495"],[]]},{"id":"ca23eee56c418568","type":"subflow:656499388a4aa37d","z":"68740fceb88b6fd9","name":"Send message to telegram","env":[{"name":"Message key","value":"payload","type":"str"}],"x":220,"y":640,"wires":[[]]},{"id":"621e22f7c7e7ecf6","type":"subflow:656499388a4aa37d","z":"68740fceb88b6fd9","name":"Send message to telegram","env":[{"name":"Message key","value":"payload","type":"str"}],"x":540,"y":440,"wires":[["1930d067a51dab34"]]},{"id":"376b077c132a2ca2","type":"change","z":"68740fceb88b6fd9","name":"add person to payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"person","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":200,"y":180,"wires":[["0325b8be149c7ea1"]]},{"id":"f01653a05c5ab4da","type":"change","z":"68740fceb88b6fd9","name":"add message to payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"message","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":810,"y":340,"wires":[["159a46c7eb5670e3"]]},{"id":"1bc3e62ed3904b04","type":"change","z":"68740fceb88b6fd9","name":"add message to payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"message","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":530,"y":360,"wires":[["de8e514529f8e48e"]]},{"id":"877895f56732aac7","type":"change","z":"68740fceb88b6fd9","name":"set entities","rules":[{"t":"set","p":"payload","pt":"msg","to":"\"media_player.\" & msg.location & \"_display\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":580,"wires":[["987dceac895715fd"]]},{"id":"d2d83bbbb0503515","type":"switch","z":"68740fceb88b6fd9","name":"Send to Ke","property":"enable ke","propertyType":"env","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":170,"y":600,"wires":[["ca23eee56c418568"]]},{"id":"c1389b989dd2f231","type":"function","z":"68740fceb88b6fd9","name":"choose volume","func":"const {payload} = msg\nconst overrideVolume = env.get(\"volume\")\n\nmsg.payload = isNaN(overrideVolume) ? payload : overrideVolume\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":180,"y":300,"wires":[["f6913ff8977a0cd2"]]},{"id":"228d3d53.df8e02","type":"server","name":"Home Assistant","addon":true},{"id":"de4ce1cbc221f3ee","type":"subflow:68740fceb88b6fd9","z":"ea6d278335cc7c96","name":"","x":180,"y":1100,"wires":[[]]}]