Anyone seeing issues with their alexa routines (applestrudel) within the last hour ~9pm EST?
Alexa appears to be down
That's what I thought but just wanted to make sure it was not something I did.
Split an array of values into individual arrays
I was looking for an easier way to split an array (without having to loop through the arrays and split them in a function node) and discovered the $spread JSONATA function. Worked brilliantly but for some reason, it would not work for a date field returned from a SQL query on a mySQL database. The folks over on the Node-RED community suggested some other solutions, so thought I would share them here in case it helps someone.
[{"id":"337250983f7905d8","type":"inject","z":"9dd3cdef.2f2f38","name":"","props":[{"p":"payload"},{"p":"props","v":"[\"totalHomeuse\",\"gridToHome\",\"solarToHome\",\"batteryToHome\",\"totalSolar\",\"solarToGrid\",\"solarToBattery\",\"day\"]","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":267.6666564941406,"y":147.99989318847656,"wires":[["da751414a159fccd"]]},{"id":"da751414a159fccd","type":"function","z":"9dd3cdef.2f2f38","name":"generate dummy data (ignore me)","func":"\nconst templateRow = {\n totalHomeuse: 67.74,\n gridToHome: 34.62,\n solarToHome: 21.11,\n batteryToHome: 12.01,\n totalSolar: 34.88,\n solarToGrid: 0.05,\n solarToBattery: 13.72,\n day: \"2022-01-17T06:00:00.0002\"\n}\n\nconst data = []\nfor (let index = 0; index < 10; index++) {\n const element = RED.util.cloneMessage(templateRow);\n element.totalHomeuse = randomFloat(60,70)\n element.gridToHome = randomFloat(30,40)\n element.solarToHome = randomFloat(20,30)\n element.batteryToHome = randomFloat(10,20)\n element.totalSolar = randomFloat(30,40)\n element.solarToGrid = randomFloat(0.01,0.99)\n element.solarToBattery = randomFloat(11,14)\n element.day = new Date(Date.now() + ((index+1)*1000*60)).toISOString()\n data.push(element)\n}\nmsg.payload = data;\n\n\nreturn msg;\n\n\n/**\n* @param {number} min\n* @param {number} max\n*/\nfunction randomFloat(min, max) {\n return Math.random() * (max - min) + min;\n};","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":505.6666564941406,"y":147.99989318847656,"wires":[["942662580d53e493","e3e67cb9207e5e23","2f1ca195.87b276","ff10a763.0f6b3","a39977a.9ef3d08"]]},{"id":"942662580d53e493","type":"debug","z":"9dd3cdef.2f2f38","name":"Dummy data","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":546.6666564941406,"y":57.99989318847656,"wires":[]},{"id":"e3e67cb9207e5e23","type":"function","z":"9dd3cdef.2f2f38","name":"toArrays - function","func":"\n//Props can be dynamically sent in via the msg object if required (to make it generic)\n/*const props = [\n \"totalHomeuse\",\n \"gridToHome\",\n \"solarToHome\",\n \"batteryToHome\",\n \"totalSolar\",\n \"solarToGrid\",\n \"solarToBattery\",\n \"day\"\n];\n*/\nconst props = msg.props\n\nmsg.result = toArrays(msg.payload, props)\nreturn msg;\n\n\n\n\n\n/**\n * Convert object properties in `data` to array of values\n * @param {any[]} data - Data to scan\n * @param {string[]} propNames - property names to collect\n*/\nfunction toArrays(data, propNames) {\n const result = {};\n propNames.forEach(p => {\n result[p] = [];\n data.forEach(e => {\n result[p].push(e[p]);\n })\n })\n return result;\n}\n\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":825.6665954589844,"y":221.99987030029297,"wires":[["66081cdb3d263701"]]},{"id":"2f1ca195.87b276","type":"change","z":"9dd3cdef.2f2f38","name":"Split selected values - JSONATA spread","rules":[{"t":"set","p":"totalHomeuse","pt":"msg","to":"$spread(payload.totalHomeuse)","tot":"jsonata"},{"t":"set","p":"dateTime","pt":"msg","to":"$spread(payload.day)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":895.3333435058594,"y":72.99999237060547,"wires":[["e8504ec0.fc0998"]]},{"id":"ff10a763.0f6b3","type":"change","z":"9dd3cdef.2f2f38","name":"Split selected values - JSONATA keys","rules":[{"t":"set","p":"totalHomeuse","pt":"msg","to":"$spread(payload.totalHomeuse)","tot":"jsonata"},{"t":"set","p":"dateTime","pt":"msg","to":"$$payload.day","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":892.6665954589844,"y":147.66663360595703,"wires":[["9e3e4f84.4bbc2"]]},{"id":"a39977a.9ef3d08","type":"change","z":"9dd3cdef.2f2f38","name":"Split all - JSONATA keys","rules":[{"t":"set","p":"payload","pt":"msg","to":"$keys($$.payload).${$:$lookup($$.payload,$)}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":845.6665954589844,"y":298.6666488647461,"wires":[["4ac93c40.a17184"]]},{"id":"66081cdb3d263701","type":"debug","z":"9dd3cdef.2f2f38","name":"Split all - function","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"result","targetType":"msg","statusVal":"payload","statusType":"auto","x":1033.6666564941406,"y":219.99987030029297,"wires":[]},{"id":"e8504ec0.fc0998","type":"debug","z":"9dd3cdef.2f2f38","name":"After selected - spread","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1198.3333435058594,"y":72.99999237060547,"wires":[]},{"id":"9e3e4f84.4bbc2","type":"debug","z":"9dd3cdef.2f2f38","name":"After selected - keys","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1192.6665954589844,"y":147.66661834716797,"wires":[]},{"id":"4ac93c40.a17184","type":"debug","z":"9dd3cdef.2f2f38","name":"Split all - keys","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1079.6665954589844,"y":298.6666488647461,"wires":[]}]
I don't fully understand the Javascript in the function node nor do I understand the JSONATA used to navigate the structure in the split all solution. The other two are much easier to grasp!
JSONATA rocks!!
The date issue sounds weird but is good to know - I'm sure you tried reformatting the incoming field to something else?
It was weird - I'm not sure if it is just the mySQL node or it will have the same issue with other databases. The strange thing is that if I copy the payload and send it via the inject node, it works perfectly. The $$.payload.[..name..] worked for me, so I stopped looking at why $spread was not working. I did create a Github issue for this but the person maintaining that node said this would be unlikely to be fixed since other folks may be relying on the data type of a TIMESTAMP columns.
For anyone interested, node-red 2.2.0 was released a few days ago:
It has some nice enhancements to the editor. I've only been running it for a few hours, and haven't noticed any issues with sequences that use @fblackburn's Hubitat nodes.
@aaiyar, @kuzenkohome - so I realized that my screencap was an older version of the the toggle subflow.. My newer one looks like this... and also I agree with your assessment about having 2 outputs! Sorry for the confusion..
This advanced toggle subflow allows you to define your output via JSON. You can either specify a "command" (see "off") or a set of "commands" defined as an array of objects under "_actions"... For the input you specify which property to check and what the 2 states are - on/off, open/close etc..
In this example turning a light "on" (msg.payload.value = "on") would set level and temp. You can also invert the process as well - which is the default, because, well, you know it's a "toggle" function..
edit: I'm going to tweak the output parameter a little bit - don't like my current format.
So here is the updated Advanced Toggle.. simplified the output - now there are 2 outputs corresponding to the binary events like "on/off" - "output1"/ "output2"
you can define either a single object that will populate the specified property usually "msg.command" + "msg.attributes" (possibly others) or an array of such objects (edit: which will generate a separate message for each element in the array). Note "msg." is implied and not used.
Advanced Toggle V1.21
[{"id":"049dd7eab1551ac1","type":"subflow","name":"AdvancedToggle","info":"","category":"","in":[{"x":60,"y":60,"wires":[{"id":"c11d7711d06a4d51"}]}],"out":[{"x":640,"y":80,"wires":[{"id":"c11d7711d06a4d51","port":0}]}],"env":[{"name":"INPUT","type":"json","value":"{\"payload.value\":\"on/off\"}"},{"name":"OUTPUT1","type":"json","value":"[{\"command\":\"setLevel\",\"arguments\":\"100\"},{\"command\":\"setTemperature\",\"arguments\":\"2800\"}]"},{"name":"OUTPUT2","type":"json","value":"{ \"command\": \"off\" }"},{"name":"INVERT","type":"bool","value":"true"}],"meta":{},"color":"#FDF0C2","icon":"node-red-contrib-sun-position/inputTypeRandomNumber.svg","status":{"x":640,"y":200,"wires":[{"id":"c11d7711d06a4d51","port":0}]}},{"id":"c11d7711d06a4d51","type":"function","z":"049dd7eab1551ac1","name":"Based on Input and \"invert\" convert to Output","func":"\nvar input = env.get(\"INPUT\");\n//var output = env.get(\"OUTPUT\");\nvar output1 = env.get(\"OUTPUT1\");\nvar output2 = env.get(\"OUTPUT2\");\n\nvar output = [];\n\n\nvar invert = env.get(\"INVERT\");\n\n\nvar retMsg;\nvar inputProp = Object.keys(input)[0];\nvar inputTypes = input[inputProp].split(\"/\");\nvar inputVal = getVal(msg,inputProp);\nvar valIndex = inputTypes.findIndex(type => type === inputVal.toString());\nvar val;\nif (valIndex != -1) {\n //retMsg = msg;\n var newIndex = (invert ? (valIndex == 0 ? 1 : 0) : valIndex );\n \n \n if (newIndex == 0) {\n if (Array.isArray(output1)){\n output = output1\n } else {\n output.push(output1);\n }\n } else {\n if (Array.isArray(output2)){\n output = output1\n } else {\n output.push(output2);\n }\n }\n\n var outputActions = output;\n\n for (var i=0;i<outputActions.length;i++) {\n retMsg = {};\n oAction = outputActions[i];\n keys = Object.keys(oAction);\n for (var j=0;j<keys.length;j++) {\n val = oAction[keys[j]];\n setVal(retMsg,keys[j],val);\n }\n //node.warn(retMsg);\n node.send(retMsg);\n }\n \n node.done();\n\n}\n\n//return retMsg;\nreturn;\n\nfunction getVal(obj,propName) {\n\n var retVal;\n var props = propName.split(\".\");\n var name = props[0];\n \n if (props.length > 1) {\n if (obj.hasOwnProperty(name)) {\n props.shift();\n var newProps = props.join(\".\");\n retVal = getVal(obj[name],newProps)\n }\n } else {\n retVal = obj[name];\n }\n \n return retVal;\n\n}\n\n\nfunction setVal(obj,propName,val) {\n var props = propName.split(\".\");\n var name = props[0];\n\n if (props.length > 1) {\n if (!obj.hasOwnProperty(name)) {\n obj[name] = {};\n }\n \n props.shift();\n var newProps = props.join(\".\");\n setVal(obj[name],newProps,val)\n } else {\n obj[name] = val;\n }\n \n return;\n\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":140,"wires":[[]]},{"id":"8718e43bfa9eb921","type":"inject","z":"38a24d1b8c9ddb0f","name":"on","props":[{"p":"payload.value","v":"on","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1510,"y":100,"wires":[["aef00f486d7ace86"]]},{"id":"88b4e89f761f8078","type":"debug","z":"38a24d1b8c9ddb0f","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1950,"y":120,"wires":[]},{"id":"c1d79180d6369b6c","type":"inject","z":"38a24d1b8c9ddb0f","name":"off","props":[{"p":"payload.value","v":"off","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1510,"y":160,"wires":[["aef00f486d7ace86"]]},{"id":"aef00f486d7ace86","type":"subflow:049dd7eab1551ac1","z":"38a24d1b8c9ddb0f","name":"","env":[{"name":"OUTPUT","value":"{\"output1\":[{\"command\":\"setLevel\",\"arguments\":\"100\"},{\"command\":\"setTemperature\",\"arguments\":\"2800\"}],\"output2\":{\"command\":\"off\"}}","type":"json"}],"x":1740,"y":120,"wires":[["88b4e89f761f8078"]]}]
NOTE: of course had small bug with "invert" not inverting, now fixed.
Okay another update, last one - pinky swear...
This adds multiple inputs, basic status and maybe a bug fix or two... also note my previous screen cap mentions "setTemperature" which is wrong wrong wrong - use "setColorTemperature" and yes you can setLevel by passing additional parameters to setColorTemperature but where is the fun in that?
Advanced Toggle V1.3
[{"id":"049dd7eab1551ac1","type":"subflow","name":"AdvancedToggle","info":"","category":"","in":[{"x":60,"y":60,"wires":[{"id":"c11d7711d06a4d51"}]}],"out":[{"x":640,"y":80,"wires":[{"id":"c11d7711d06a4d51","port":0}]}],"env":[{"name":"INPUT","type":"json","value":"{\"payload.value\":\"on/off\"}"},{"name":"OUTPUT1","type":"json","value":"[{\"command\":\"setLevel\",\"arguments\":\"100\"},{\"command\":\"setTemperature\",\"arguments\":\"2800\"}]"},{"name":"OUTPUT2","type":"json","value":"{ \"command\": \"off\" }"},{"name":"INVERT","type":"bool","value":"true"}],"meta":{},"color":"#FDF0C2","icon":"node-red-contrib-sun-position/inputTypeRandomNumber.svg","status":{"x":640,"y":200,"wires":[{"id":"c11d7711d06a4d51","port":1}]}},{"id":"c11d7711d06a4d51","type":"function","z":"049dd7eab1551ac1","name":"Based on Input and \"invert\" convert to Output","func":"\nvar inputParm = env.get(\"INPUT\");\n//var output = env.get(\"OUTPUT\");\nvar output1 = env.get(\"OUTPUT1\");\nvar output2 = env.get(\"OUTPUT2\");\n\nvar input = [];\nvar invert = env.get(\"INVERT\");\nvar retMsg;\n\nif (Array.isArray(inputParm)){\n input = inputParm;\n} else {\n input.push(inputParm);\n}\n\n/*\nvar inputProp = Object.keys(input)[0];\nvar inputTypes = input[inputProp].split(\"/\");\nvar inputVal = getVal(msg,inputProp);\nvar valIndex = inputTypes.findIndex(type => type === inputVal.toString());\n\nvar val;\n\nif (valIndex != -1) {\n*/\n\nfor (var k=0;k<input.length;k++) {\n\n var inputProp = Object.keys(input[k])[0];\n var inputTypes = input[k][inputProp].split(\"/\");\n var inputVal = getVal(msg,inputProp).toString();\n var valIndex = inputTypes.indexOf(inputVal);\n\n var val;\n var output = [];\n \n\n if (valIndex != -1) {\n var newIndex = (invert ? (valIndex == 0 ? 1 : 0) : valIndex );\n \n \n if (newIndex == 0) {\n if (Array.isArray(output1)){\n output = output1\n } else {\n output.push(output1);\n }\n } else {\n if (Array.isArray(output2)){\n output = output2\n } else {\n output.push(output2);\n }\n }\n\n for (var i=0;i<output.length;i++) {\n retMsg = {\"topic\":msg.topic,\"payload\":\"\"};\n var oAction = output[i];\n var actionVal = Object.keys(oAction);\n var keys =[];\n\n if(Array.isArray(actionVal)) {\n keys = actionVal;\n } else {\n keys.push(actionVal);\n }\n //node.warn(\"keys: \" + keys.length);\n for (var j=0;j<keys.length;j++) {\n val = oAction[keys[j]];\n setVal(retMsg,keys[j],val);\n node.send([undefined,{\"payload\":inputTypes[valIndex] + \" => \" + keys[j] + \"/\" + val}]);\n node.done();\n }\n node.send([retMsg,undefined]);\n node.done();\n }\n \n }\n\n}\n\n//return retMsg;\nreturn;\n\nfunction getVal(obj,propName) {\n\n var retVal;\n var props = propName.split(\".\");\n var name = props[0];\n \n if (props.length > 1) {\n if (obj.hasOwnProperty(name)) {\n props.shift();\n var newProps = props.join(\".\");\n retVal = getVal(obj[name],newProps)\n }\n } else {\n retVal = obj[name];\n }\n \n return retVal;\n\n}\n\n\nfunction setVal(obj,propName,val) {\n var props = propName.split(\".\");\n var name = props[0];\n\n if (props.length > 1) {\n if (!obj.hasOwnProperty(name)) {\n obj[name] = {};\n }\n \n props.shift();\n var newProps = props.join(\".\");\n setVal(obj[name],newProps,val)\n } else {\n obj[name] = val;\n }\n \n return;\n\n}\n","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":140,"wires":[[],[]]},{"id":"cf50f7f2ae7a2cb6","type":"subflow:049dd7eab1551ac1","z":"e6807da71ee5477b","name":"","env":[{"name":"INPUT","value":"[{\"payload.value\":\"1/2\"},{\"payload.value\":\"3/4\"}]","type":"json"},{"name":"OUTPUT1","value":"[{\"command\":\"setLevel\",\"arguments\":\"100\"},{\"command\":\"setColorTemperature\",\"arguments\":\"2900\"}]","type":"json"},{"name":"INVERT","value":"false","type":"bool"}],"x":1490,"y":160,"wires":[["688dccfb3250f01f"]]},{"id":"8c6e50277564290c","type":"inject","z":"e6807da71ee5477b","name":"payload.value = 1","props":[{"p":"payload.value","v":"1","vt":"num"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1180,"y":80,"wires":[["cf50f7f2ae7a2cb6"]]},{"id":"fd881a58b0a25f3f","type":"inject","z":"e6807da71ee5477b","name":"payload.value = 2","props":[{"p":"payload.value","v":"2","vt":"num"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1180,"y":120,"wires":[["cf50f7f2ae7a2cb6"]]},{"id":"a2b804cb8750dc53","type":"inject","z":"e6807da71ee5477b","name":"payload.value = 3","props":[{"p":"payload.value","v":"3","vt":"num"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1180,"y":200,"wires":[["cf50f7f2ae7a2cb6"]]},{"id":"09b0f48ac933414e","type":"inject","z":"e6807da71ee5477b","name":"payload.value = 4","props":[{"p":"payload.value","v":"4","vt":"num"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1180,"y":240,"wires":[["cf50f7f2ae7a2cb6"]]},{"id":"688dccfb3250f01f","type":"debug","z":"e6807da71ee5477b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1670,"y":160,"wires":[]}]
So this is an update NOT related to the "Advanced Toggle"... Whilst adding AT to my sequences discovered a bug in my Button Tap subflow which can mess up the "held" action.. fixed and all is well.. Below is an example. For this I have button 3 "held" set to 5 taps.
Button Taps Update of unknown revision..
[{"id":"d0e305e1.7ad558","type":"subflow","name":"Button Taps","info":"","category":"","in":[{"x":50,"y":70,"wires":[{"id":"dceb31cb.fb78f"}]}],"out":[{"x":1230,"y":60,"wires":[{"id":"959b5260.c1c1c","port":0}]},{"x":1230,"y":120,"wires":[{"id":"959b5260.c1c1c","port":1}]},{"x":1220,"y":180,"wires":[{"id":"959b5260.c1c1c","port":2}]},{"x":1230,"y":240,"wires":[{"id":"959b5260.c1c1c","port":3}]}],"env":[{"name":"TIME_LIMIT_MS","type":"num","value":"450"},{"name":"HELD_TAPS","type":"num","value":"0"}],"meta":{"module":"adsavia-button-taps","version":"1.0","license":"GPL-3.0"},"color":"#E2D96E","inputLabels":["Button Press"],"outputLabels":["Single Tap","Double Tap","Triple Tap","Quad+ Tap"],"icon":"node-red-dashboard/ui_button.png","status":{"x":1180,"y":320,"wires":[{"id":"b4ba35d5.020018","port":0}]}},{"id":"959b5260.c1c1c","type":"switch","z":"d0e305e1.7ad558","name":"Single Tap \\n Double Tap \\n Triple Tap \\n Quad+ Tap","property":"count","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"2","vt":"num"},{"t":"eq","v":"3","vt":"str"},{"t":"gte","v":"4","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":950,"y":140,"wires":[[],[],[],[]]},{"id":"b4ba35d5.020018","type":"function","z":"d0e305e1.7ad558","name":"set status payload","func":"\nvar payload = {\n\"fill\": \"green\",\n\"shape\":\"dot\",\n\"text\": (flow.get(\"held\")!==undefined?\"Held/\":\"\") + ( msg.count == 1 ? \"Single\" : (msg.count == 2 ? \"Double\": (msg.count == 3 ? \"Triple\": (msg.count == 4 ? \"Quadruple\": msg.count.toString() )))) + \" Tap\"\n};\n\nflow.set(\"held\",undefined);\n\nmsg.payload = payload;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":970,"y":240,"wires":[[]]},{"id":"dbeab83f.200be8","type":"function","z":"d0e305e1.7ad558","name":"Gnerate \"Held\" Taps","func":"var iterate = env.get(\"HELD_TAPS\");\nfor (var i = 0; i < iterate; i++){\n node.send(msg);\n node.done();\n}\n\nflow.set(\"held\",true);\n\nreturn;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":200,"wires":[["4e584c74.8f1724"]]},{"id":"dceb31cb.fb78f","type":"switch","z":"d0e305e1.7ad558","name":"","property":"payload.name","propertyType":"msg","rules":[{"t":"eq","v":"pushed","vt":"str"},{"t":"eq","v":"doubleTapped","vt":"str"},{"t":"eq","v":"held","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":190,"y":80,"wires":[["4e584c74.8f1724"],["b6af3007.c57de","3eafdc18.33b6e4"],["dbeab83f.200be8"]]},{"id":"b6af3007.c57de","type":"delay","z":"d0e305e1.7ad558","name":"","pauseType":"delay","timeout":"100","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"outputs":1,"x":390,"y":160,"wires":[["4e584c74.8f1724"]]},{"id":"3eafdc18.33b6e4","type":"delay","z":"d0e305e1.7ad558","name":"","pauseType":"delay","timeout":"50","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"outputs":1,"x":390,"y":120,"wires":[["4e584c74.8f1724"]]},{"id":"4b49418ef2d1a440","type":"change","z":"d0e305e1.7ad558","name":"","rules":[{"t":"set","p":"count","pt":"msg","to":"$flowContext(\"held\") ? $env(\"HELD_TAPS\") : count","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":680,"y":140,"wires":[["b4ba35d5.020018","959b5260.c1c1c"]]},{"id":"4e584c74.8f1724","type":"timed-counter","z":"d0e305e1.7ad558","name":"","timelimit":"${TIME_LIMIT_MS}","timeunit":1,"withhold":true,"fixedtimeout":true,"pertopic":false,"x":640,"y":80,"wires":[["4b49418ef2d1a440"]]},{"id":"320f82a042c8d0ac","type":"inject","z":"e6807da71ee5477b","name":"pushed: Button 1","props":[{"p":"payload.value","v":"1","vt":"num"},{"p":"payload.name","v":"pushed","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1320,"y":80,"wires":[["68997bcf.fda874"]]},{"id":"68997bcf.fda874","type":"subflow:d0e305e1.7ad558","z":"e6807da71ee5477b","name":"","env":[{"name":"TIME_LIMIT_MS","value":"600","type":"num"},{"name":"HELD_TAPS","value":"5","type":"num"}],"x":1790,"y":240,"wires":[["cea029c1cf0e527b"],["cea029c1cf0e527b"],["cea029c1cf0e527b"],["cea029c1cf0e527b"]]},{"id":"4272e3f528e50cef","type":"inject","z":"e6807da71ee5477b","name":"doubleTapped: Button 2","props":[{"p":"payload.value","v":"2","vt":"num"},{"p":"payload.name","v":"doubleTapped","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1340,"y":140,"wires":[["68997bcf.fda874"]]},{"id":"a4e3de48fc1a4958","type":"inject","z":"e6807da71ee5477b","name":"pushed: Button 1","props":[{"p":"payload.value","v":"1","vt":"num"},{"p":"payload.name","v":"pushed","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1320,"y":400,"wires":[["387831eff3200d23","2fa651dff3acf9bb","ec54009e600c3a89"]]},{"id":"c46c398899cb4555","type":"inject","z":"e6807da71ee5477b","name":"held: Button 3","props":[{"p":"payload.value","v":"3","vt":"num"},{"p":"payload.name","v":"held","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1310,"y":200,"wires":[["68997bcf.fda874"]]},{"id":"387831eff3200d23","type":"delay","z":"e6807da71ee5477b","name":"","pauseType":"delay","timeout":"100","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1570,"y":360,"wires":[["68997bcf.fda874"]]},{"id":"2fa651dff3acf9bb","type":"delay","z":"e6807da71ee5477b","name":"","pauseType":"delay","timeout":"200","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1570,"y":400,"wires":[["68997bcf.fda874"]]},{"id":"ec54009e600c3a89","type":"delay","z":"e6807da71ee5477b","name":"","pauseType":"delay","timeout":"300","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1570,"y":440,"wires":[["68997bcf.fda874"]]},{"id":"cea029c1cf0e527b","type":"debug","z":"e6807da71ee5477b","name":"Number Of Taps","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"count & \" Tap / Button \" & payload.value","targetType":"jsonata","statusVal":"","statusType":"auto","x":2020,"y":240,"wires":[]},{"id":"8e7008e187d2ae7c","type":"inject","z":"e6807da71ee5477b","name":"pushed: Button 1","props":[{"p":"payload.value","v":"1","vt":"num"},{"p":"payload.name","v":"pushed","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1320,"y":280,"wires":[["a59bb37df1ed0c6b","713799729224c346"]]},{"id":"a59bb37df1ed0c6b","type":"delay","z":"e6807da71ee5477b","name":"","pauseType":"delay","timeout":"100","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1570,"y":260,"wires":[["68997bcf.fda874"]]},{"id":"141b87b130e692ba","type":"inject","z":"e6807da71ee5477b","name":"pushed: Button 1","props":[{"p":"payload.value","v":"1","vt":"num"},{"p":"payload.name","v":"pushed","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1320,"y":540,"wires":[["bb369ec8a67d202e","1d86df1979f825bb","5e7ee91208d956b5","648c5b29defdf580"]]},{"id":"bb369ec8a67d202e","type":"delay","z":"e6807da71ee5477b","name":"","pauseType":"delay","timeout":"100","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1570,"y":500,"wires":[["68997bcf.fda874"]]},{"id":"1d86df1979f825bb","type":"delay","z":"e6807da71ee5477b","name":"","pauseType":"delay","timeout":"200","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1570,"y":540,"wires":[["68997bcf.fda874"]]},{"id":"5e7ee91208d956b5","type":"delay","z":"e6807da71ee5477b","name":"","pauseType":"delay","timeout":"300","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1570,"y":580,"wires":[["68997bcf.fda874"]]},{"id":"648c5b29defdf580","type":"delay","z":"e6807da71ee5477b","name":"","pauseType":"delay","timeout":"400","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1570,"y":620,"wires":[["68997bcf.fda874"]]},{"id":"713799729224c346","type":"delay","z":"e6807da71ee5477b","name":"","pauseType":"delay","timeout":"200","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1570,"y":300,"wires":[["68997bcf.fda874"]]}]
Note: You need to install the node-red-contrib-timed-counter node for this to work.
... and here is an in-production example for thems that are curious how I'm using..
Archiving System-Wide Sensor Data for long term trend analysis:
Here's something I've been enjoying. I slurp up all events from Hubitat and dump them into a metrics table in Postgres. Then a Graphana instance can render dashboards which allow me to scroll back through time, build helpful visualizations, etc.
I used a link-out/in pair between the even receiver and the postgres node because I also manually dispatch events from elsewhere through the same postgres node.
That looks great, thanks for posting! I am always interested in how this kind of data can be used effectively..
We moved last yea, and the home is not at all efficient. Lots of insulation and other upgrades coming, and I would like to be able to prove that it works. The first step in that is visualizing what needs work and collecting data about it!
I haven’t yet found a good source for weather data, so I don’t have reference temperature for outside temperatures during the winter.
It did just occur to me that I can dump my spreadsheet of information about utility bills into this metrics DB too…
Question for anyone using Tasmota based switches with NR & Hubitat. Have some switches using the driver Marcus wrote. But since it is no longer supported I want to try and integrate them through NR.
I am testing a flow but have encountered a race condition where the switch will cycle on/off rapidly for 10-15 seconds then stop and function correctly. I suspect it has to due with timing between the HE status node and the command node. I can't duplicate it but the race happened twice in testing.
Anyone have any insite or a better flow. The flow allows control and maintains status from a HE virtual switch and locally from the switch itself.
Can you split them into 2 sequences maybe? First 3 nodes for the first + Last three nodes for the second. Providing the "wifiplug99" node sends on/off events of course...
I can split them I just don't see what that would accomplish. The wifiplug99 node does send events when the switch changes state either physically or digitally.
I went down the same path, but then decided I didnt need the tasmota switches on Hubitat. All of my logic is now in Node Red. Sorry, I cant be of much help.
Well my thought is if it's a timing thing with the "wifiplug99" then splitting them might smooth things out..