[ { "id": "55318bfc504a4cca", "type": "tab", "label": "CMD CONFIRM", "disabled": false, "info": "" }, { "id": "e188626796d3a7dc", "type": "function", "z": "55318bfc504a4cca", "name": "Filter Intents", "func": "msg.payload = JSON.parse(msg.payload);\nmsg.payload.customData = null;\n\nif( flow.get(\"siteId\") === undefined ){\n node.warn(\"skipping state confirmation, no siteId defined\");\n return null;\n}\n\nmsg.topicorg = msg.topic;\nmsg.topic = \"hermes/intent/\" + msg.payload.intent.intentName; \nsiteIdToKNXNames = global.get(\"siteIdToKNXNames\");\nif(siteIdToKNXNames[msg.payload.id]!==undefined){\n var id = msg.payload.siteId = msg.payload.id; // the id is a siteId, i.e. it is a status check after a command\n}\n//node.warn(\"id \" + id);\n//node.warn(\"NLU direct (chat) - \" + msg.topic);\n\nif(msg.topic.includes(\"ProKNX:deviceStatusCheck\")){\n if(id !== undefined){\n //node.warn(\"ProKNX:deviceStatusCheck with id: \"+id);\n msg.payload = JSON.stringify(msg.payload);\n return [null,msg];\n }\n} else {\n if( msg.topic.toLowerCase().includes(\"lights\") ||\n msg.topic.toLowerCase().includes(\"shutters\") ||\n msg.topic.toLowerCase().includes(\"thermostat\")){\n \n // skip if on-going Super Scene\n var isSuperScene = global.get(\"isSuperScene\");\n if(isSuperScene===undefined || isSuperScene === false){\n if (msg.payload.slots !== undefined){\n if (msg.payload.slots.length > 0) {\n msg.payload = JSON.stringify(msg.payload);\n return [msg, null];\n }\n }\n }\n } else {\n return [null, null];\n }\n}\n", "outputs": 2, "noerr": 0, "initialize": "", "finalize": "", "x": 405, "y": 100, "wires": [ [ "129cea85778e6288" ], [ "a08d616ca1cdb79e", "4d4915aa17a3c53d" ] ], "outputLabels": [ "Send status req. to NLU", "Execute status reuqest" ] }, { "id": "0ebbefd0a0423b15", "type": "mqtt in", "z": "55318bfc504a4cca", "name": "", "topic": "hermes/nlu/intentParsed", "qos": "2", "datatype": "auto", "broker": "93221c155e306ade", "x": 145, "y": 100, "wires": [ [ "8713a7eade297ca7", "7a7054215929473e" ] ] }, { "id": "129cea85778e6288", "type": "delay", "z": "55318bfc504a4cca", "name": "", "pauseType": "delay", "timeout": "5", "timeoutUnits": "seconds", "rate": "1", "nbRateUnits": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "x": 535, "y": 85, "wires": [ [ "ef6373dba36f9101" ] ], "l": false }, { "id": "ef6373dba36f9101", "type": "function", "z": "55318bfc504a4cca", "name": "get state", "func": "let lang = global.get(\"msgLang\");\nlet siteId = flow.get(\"siteId\");\nlet debugMsg = global.get(\"dbgHomeAutomation\");\nif(debugMsg===undefined){\n debugMsg = false;\n}\n\nmsg.payload = JSON.parse(msg.payload);\nif( msg.payload.intent.intentName.toLowerCase().includes(\"status\") || \n msg.payload.intent.intentName.toLowerCase().includes(\"scene\"))\n return;\n\nlet keyword = \"\";\n\nlet deviceCount = 0;\nlet roomCount = 0;\nlet current_device = \"\";\nlet current_room = \"\";\nlet current_cmd = false;\n\nlet found_device = false;\nlet query_device = [];\nlet query_room = [];\nlet roomFound = 0;\nlet itemsCount = 0;\n\nString.prototype.sansAccent = function() {\n try{ \n \tlet accent = [/[\\300-\\306]/g, /[\\340-\\346]/g, // A, a\n \t\t/[\\310-\\313]/g, /[\\350-\\353]/g, // E, e\n \t\t/[\\314-\\317]/g, /[\\354-\\357]/g, // I, i\n \t\t/[\\322-\\330]/g, /[\\362-\\370]/g, // O, o\n \t\t/[\\331-\\334]/g, /[\\371-\\374]/g, // U, u\n \t\t/[\\321]/g, /[\\361]/g, // N, n\n \t\t/[\\307]/g, /[\\347]/g, // C, c\n \t];\n \tlet noaccent = ['A', 'a', 'E', 'e', 'I', 'i', 'O', 'o', 'U', 'u', 'N', 'n', 'C', 'c'];\n \tlet str = this;\n \tfor (let i = 0; i < accent.length; i++) {\n \t\tif (lang === \"de\") {\n \t\t\tstr = str.replace(\"ä\", \"ae\");\n \t\t\tstr = str.replace(\"ü\", \"ue\");\n \t\t\tstr = str.replace(\"ö\", \"oe\");\n \t\t}\n \t\tstr = str.replace(accent[i], noaccent[i]);\n \t}\n \tstr = str.replace(/ /g, \"\");\n \tstr = str.replace(/_/g, \"\");\n \treturn str;\n } catch(e){\n if(debugMsg) node.warn(\"Exception in sansAccent: \" +e);\n return this;\n } \t\n};\n\nfunction findDevice() {\n let deviceList = global.get(\"msgDeviceList\");\n let device;\n\n if (deviceList !== undefined) {\n if (deviceList.length > 0) {\n \n for(let i=0; i> device.zone = \"+ device.zone.toLowerCase().sansAccent() + \" and current_room = \"+ current_room.toLowerCase().sansAccent());\n if (current_room !== undefined && \n device.zone.toLowerCase().sansAccent() === current_room.toLowerCase().sansAccent()) { \n found_device = true;\n } \n }\n\n if (current_room !== undefined && \n device.zone.toLowerCase().sansAccent() === current_room.toLowerCase().sansAccent()) { \n roomFound++;\n }\n }\n \n }\n }\n\n return null;\n}\n\nfor(let i=0; i search in deviceList \n findDevice();\n\n if (query_device[0] === undefined && \n current_device.includes(\"lights\") && current_device.includes(\"licht\") && current_device.includes(\"lumière\") &&\n current_device.includes(\"thermostat\") &&\n current_device.includes(\"shutter\") && current_device.includes(\"rollladen\") && current_device.includes(\"volet\") ||\n current_cmd === true){\n \n if(msg.payload.intent.intentName.toLowerCase().includes(\"lights\")){\n if(lang.toLowerCase().includes(\"en\"))\n query_device[0] = \"lights\";\n else if(lang.toLowerCase().includes(\"de\"))\n query_device[0] = \"licht\";\n else if(lang.toLowerCase().includes(\"fr\"))\n query_device[0] = \"lumière\" ;\n \n itemsCount++;\n } \n if(msg.payload.intent.intentName.toLowerCase().includes(\"thermostat\")){\n query_device[0] = \"thermostat\";\n itemsCount++;\n } \n if(msg.payload.intent.intentName.toLowerCase().includes(\"shutter\")){\n if(lang.toLowerCase().includes(\"en\"))\n query_device[0] = \" shutter\";\n else if(lang.toLowerCase().includes(\"de\"))\n query_device[0] = \" rollladen\";\n else if(lang.toLowerCase().includes(\"fr\"))\n query_device[0] = \"volets\";\n\n itemsCount++;\n }\n } else {\n query_device[0] = current_device;\n itemsCount++;\n }\n\n if (query_room[0] === undefined && current_room === \"\") {\n if(lang.toLowerCase().includes(\"en\"))\n query_room[0] = \"everywhere\";\n else if(lang.toLowerCase().includes(\"de\"))\n query_room[0] = \"überall\";\n else if(lang.toLowerCase().includes(\"fr\"))\n query_room[0] = \"partout\";\n }\n\n //node.warn(\"Items : [\" + query_device[0] + \" - \"+ query_room[0] + \"] and number of specified items = \" + itemsCount);\n\n if (itemsCount >= 1) {\n // At least one device has been found either in the current room or in another room\n \n msg = { payload: {} };\n \n if(lang.toLowerCase().includes(\"en\"))\n msg.payload.input = \"What's the status of \" + query_device[0] + \" in \" + query_room[0];\n else if(lang.toLowerCase().includes(\"de\"))\n msg.payload.input = \"wie ist der status des \" + query_device[0] + \" in \" + query_room[0];\n else if(lang.toLowerCase().includes(\"fr\"))\n msg.payload.input = \"quel est le statut de \" + query_device[0] + \" dans \" + query_room[0];\n\n msg.payload.id = flow.get(\"siteId\");\n \n return msg;\n\n }\n} else {\n // Room has been specified -> check in deviceList\n findDevice();\n \n // Specified device\n if (found_device === true && query_device[0] !== undefined) {\n //node.warn(\"<> Specified device - Items: [\" + query_device[0] + \" - \"+ query_room + \"] and itemsCount = \" + itemsCount);\n \n msg = { payload: {} };\n\n if(lang.toLowerCase().includes(\"en\"))\n msg.payload.input = \"What's the status of \" + keyword;\n else if(lang.toLowerCase().includes(\"de\"))\n msg.payload.input = \"wie ist der status des \" + keyword;\n else if(lang.toLowerCase().includes(\"fr\"))\n msg.payload.input = \"quel est le statut de \" + keyword;\n \n msg.payload.id = flow.get(\"siteId\");\n\n return msg;\n } \n \n // Unspecified device\n if(query_device[0] === undefined){\n \n //node.warn(\"<> Unspecified device - Current room: \"+ current_room + \" and currentDevice = \" + current_device);\n\n if (current_device !== \"\" && \n !current_device.includes(\"lights\") && !current_device.includes(\"licht\") && !current_device.includes(\"lumière\") &&\n !current_device.includes(\"thermostat\") &&\n !current_device.includes(\"shutter\") && !current_device.includes(\"rollladen\") && !current_device.includes(\"volet\")){\n return null; // Device not found\n } else {\n if(msg.payload.intent.intentName.toLowerCase().includes(\"lights\")){\n if(lang.toLowerCase().includes(\"en\"))\n keyword = current_room + \" lights\";\n else if(lang.toLowerCase().includes(\"de\"))\n keyword = \" licht in \" + current_room;\n else if(lang.toLowerCase().includes(\"fr\"))\n keyword = \"lumiere dans \" + current_room;\n } \n if(msg.payload.intent.intentName.toLowerCase().includes(\"thermostat\")){\n keyword = current_room + \" temperature\";\n } \n if(msg.payload.intent.intentName.toLowerCase().includes(\"shutter\")){\n if(lang.toLowerCase().includes(\"en\"))\n keyword = current_room + \" shutter\";\n else if(lang.toLowerCase().includes(\"de\"))\n keyword = \"rollladen in \" + current_room;\n else if(lang.toLowerCase().includes(\"fr\"))\n keyword = \"volet dans \"+ current_room;\n }\n \n msg = { payload: {} };\n \n if(lang.toLowerCase().includes(\"en\"))\n msg.payload.input = \"What's the status of \" + keyword;\n else if(lang.toLowerCase().includes(\"de\"))\n msg.payload.input = \"wie ist der status des \" + keyword;\n else if(lang.toLowerCase().includes(\"fr\"))\n msg.payload.input = \"quel est le statut de \" + keyword;\n \n msg.payload.id = flow.get(\"siteId\");\n \n return msg;\n }\n\n } else {\n return null;\n }\n}", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "x": 640, "y": 85, "wires": [ [ "4c110744aa66a81d", "95ae38320428b941" ] ] }, { "id": "4c110744aa66a81d", "type": "mqtt out", "z": "55318bfc504a4cca", "name": "hermes/nlu/query", "topic": "hermes/nlu/query", "qos": "", "retain": "", "broker": "93221c155e306ade", "x": 815, "y": 85, "wires": [] }, { "id": "2682836340d55815", "type": "comment", "z": "55318bfc504a4cca", "name": "README", "info": "The purpose of this flow is to enable spoken confirmation of the state of devices after a voice command for lights, shutters and heating (LSH).\nThis flow listens to all events from the NLU. If it is a LSH command, it will wait a couple of seconds and then get the state of the device(s).", "x": 100, "y": 45, "wires": [] }, { "id": "a08d616ca1cdb79e", "type": "link out", "z": "55318bfc504a4cca", "name": "HERMES INTENT OUT", "links": [ "1af66df2.44afca", "95b1555a.90392" ], "x": 535, "y": 120, "wires": [] }, { "id": "bcac0457ca3af8fe", "type": "mqtt in", "z": "55318bfc504a4cca", "name": "", "topic": "hermes/intent/+", "qos": "2", "datatype": "auto", "broker": "93221c155e306ade", "x": 115, "y": 155, "wires": [ [ "70c2aa24ae3cef30", "46bafef3ae180df6" ] ] }, { "id": "70c2aa24ae3cef30", "type": "function", "z": "55318bfc504a4cca", "name": "Save current siteId", "func": "msg.payload = JSON.parse(msg.payload);\nif( msg.payload !== undefined && \n msg.payload.siteId !== undefined &&\n msg.payload.siteId !== \"default\"){\n //node.warn(\"save siteId: \"+ msg.payload.siteId);\n flow.set(\"siteId\",msg.payload.siteId);\n return msg;\n}\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "x": 330, "y": 155, "wires": [ [ "f9ec1d12848a199a" ] ] }, { "id": "4f5b4848411d4891", "type": "comment", "z": "55318bfc504a4cca", "name": "Version info", "info": "2022-02-24: \"get state\" node update\n Try to cover all possible cases:\n - Specified room + device\n - Specified room but unspecified device => request state of all lights in the room\n - Specified device but unspecified room => request state of the device in the whole house\n\n2022-01-20: First version", "x": 255, "y": 45, "wires": [] }, { "id": "f9ec1d12848a199a", "type": "delay", "z": "55318bfc504a4cca", "name": "Wait a bit before deleting the siteId", "pauseType": "delay", "timeout": "10", "timeoutUnits": "seconds", "rate": "1", "nbRateUnits": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "x": 475, "y": 155, "wires": [ [ "4d4915aa17a3c53d" ] ], "l": false }, { "id": "4d4915aa17a3c53d", "type": "change", "z": "55318bfc504a4cca", "name": "Forget siteId", "rules": [ { "t": "delete", "p": "siteId", "pt": "flow" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 601, "y": 155, "wires": [ [] ] }, { "id": "8713a7eade297ca7", "type": "delay", "z": "55318bfc504a4cca", "name": "Wait here, the current siteId to be set (below) before continuing", "pauseType": "delay", "timeout": "500", "timeoutUnits": "milliseconds", "rate": "1", "nbRateUnits": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "x": 290, "y": 100, "wires": [ [ "e188626796d3a7dc" ] ], "l": false }, { "id": "6deb01aca2839822", "type": "debug", "z": "55318bfc504a4cca", "name": "hermes/intent/+", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 290, "y": 190, "wires": [], "l": false }, { "id": "b0a20c81acce4d0e", "type": "debug", "z": "55318bfc504a4cca", "name": "hermes/nlu/intentParsed", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 385, "y": 65, "wires": [], "l": false }, { "id": "7a7054215929473e", "type": "json", "z": "55318bfc504a4cca", "name": "", "property": "payload", "action": "", "pretty": false, "x": 340, "y": 65, "wires": [ [ "b0a20c81acce4d0e" ] ], "l": false }, { "id": "46bafef3ae180df6", "type": "json", "z": "55318bfc504a4cca", "name": "", "property": "payload", "action": "", "pretty": false, "x": 245, "y": 190, "wires": [ [ "6deb01aca2839822" ] ], "l": false }, { "id": "95ae38320428b941", "type": "json", "z": "55318bfc504a4cca", "name": "", "property": "payload", "action": "", "pretty": false, "x": 740, "y": 50, "wires": [ [ "54da0f3b59a5984f" ] ], "l": false }, { "id": "54da0f3b59a5984f", "type": "debug", "z": "55318bfc504a4cca", "name": "hermes/nlu/intentParsed", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 785, "y": 50, "wires": [], "l": false }, { "id": "93221c155e306ade", "type": "mqtt-broker", "z": "911701ff.6731e", "name": "-", "broker": "localhost", "port": "1883", "clientid": "", "usetls": false, "compatmode": true, "keepalive": "60", "cleansession": true, "birthTopic": "", "birthQos": "0", "birthPayload": "", "closeTopic": "", "closeQos": "0", "closePayload": "", "willTopic": "", "willQos": "0", "willPayload": "", "info": "-" } ]