Secure SCS317 / Horstmann C-Stat 17 zwave Thermostat functions

These flows allow control and monitoring of the Secure SCS317, also known as Horstmann C-Stat 17 zwave 7day thermostat. It's likely that they'll also work on the 1 day version of the thermostat as well.

Calls for functions are made using REST-like http-gets, data is returned using MQTT.

Functions included:

  1. Holiday mode on/off for 7 days
  2. Calculate end date of holiday mode
  3. Monitor setpoint from node-red
  4. Change setpoint from node-red (until next scheduled thermostat change)

You can work out if a change in the thermostat setpoint is pending by comparing the contents of the MQTT topics "/home/zwave/{thermostatNode}/thermostat_setpoint_change_pending" and "/home/zwave/{thermostatNode}/current_setpoint"

[{"id":"ab3f2f9f.b989f","type":"comment","z":"74066dce.c8160c","name":"How to setup Thermostat Zwave Notes","info":"The thermostat used is a Secure SCS317, also known as Horstmann C-Stat 17.\n\nBefore anything else, you’ll need to get the thermostat regularly waking up.\nTo do this, shut down Node-Red and open up Open Zwave Control Panel.\nOn Thermostat and set it to listen (somewhere in the settings/zwave menu) then,\nwith OZWCP set it every 300 seconds, or so, your choice, there is a battery use\ncost here though. Save the zwave settings in OZWCP and copy the zwcfg???.xml\nfile from the OZWCP directory to the openzwave-shared directory, so that these\nsettings will be picked up by Node-Red.\n\nNB: My thermostat is node17, hence references to that node all over the place.\n\nThe programming is a bit sloppy in places, but essentially works ok, I will update\nthe code to be rather better as and when I've got time.","x":250,"y":2620,"wires":[]},{"id":"b6a40276.0a016","type":"zwave-out","z":"74066dce.c8160c","name":"/dev/zwave output","controller":"15a41f3c.b5fba9","x":810,"y":2720,"wires":[]},{"id":"7f373c91.be60b4","type":"http response","z":"74066dce.c8160c","name":"Response page","x":800,"y":2820,"wires":[]},{"id":"7781c73.4ce57b8","type":"template","z":"74066dce.c8160c","name":"Acknowledge Success","field":"payload","template":"<html>\n<head>\n<meta HTTP-EQUIV=\"REFRESH\" content=\"0; url=http://frinkhub01.frinkiac7.net/\">\n</head>\n<body>\n<p> Switching has been switched, reloading page...</p>\n</body>\n</html>\n\n{{*/Code can go here, I think/*}}","x":440,"y":2820,"wires":[["7f373c91.be60b4"]]},{"id":"51d193b2.50c148","type":"http in","z":"74066dce.c8160c","name":"Binary Switch setValue","url":"/setValueBinary.html","method":"get","swaggerDoc":"","x":200,"y":2720,"wires":[["7781c73.4ce57b8","3efa30fa.24bc78","feb893db.579ea"]]},{"id":"e5f25d34.08394","type":"debug","z":"74066dce.c8160c","name":"","active":true,"console":"false","complete":"false","x":790,"y":2780,"wires":[]},{"id":"f0299393.532dd","type":"comment","z":"74066dce.c8160c","name":"Switch on and off zwave binary switches from REST calls","info":"Thermostat holiday mode is just switched using the standard binary switch setValue.\nWhen switched on, it will go on for 7 days, unless siwtched off manually or over zwave.","x":310,"y":2680,"wires":[]},{"id":"3efa30fa.24bc78","type":"function","z":"74066dce.c8160c","name":"Format Message for Z Wave","func":"\n// Make the string variables supplied form the source into Integers\nvar nodeid = parseInt(msg.payload.nodeid);\nif (msg.payload.value==\"true\"){\n    var value=true;\n    } else {\n    var value=false;\n    }\n\n\n// Build these into a message with the name setValue.\nvar returnMsg={topic: \"setValue\", payload: {nodeid: nodeid, value: value}};\nreturn returnMsg;\n\n","outputs":1,"noerr":0,"x":460,"y":2720,"wires":[["b6a40276.0a016","e5f25d34.08394"]]},{"id":"feb893db.579ea","type":"debug","z":"74066dce.c8160c","name":"","active":false,"console":"false","complete":"false","x":410,"y":2860,"wires":[]},{"id":"46cfecac.e2d088","type":"comment","z":"74066dce.c8160c","name":"Holiday Mode Date Off Calculation","info":"","x":240,"y":2920,"wires":[]},{"id":"8e60ed9e.6138b8","type":"zwave-in","z":"74066dce.c8160c","name":"Zwave In","controller":"15a41f3c.b5fba9","x":160,"y":2960,"wires":[["5270430d.92c8c4"]]},{"id":"5270430d.92c8c4","type":"function","z":"74066dce.c8160c","name":"Strip Out Node 17 on/off","func":"if (msg.payload.cmdclass==\"37\" && msg.payload.nodeid==\"17\"){\n  if(msg.payload.currState==msg.payload.oldState){\n      // System remains the same\n      var returnMsg2={topic: \"/home/zwave/node8/holiday_mode_off\", payload:\"No update\"};\n  }\n  else if(msg.payload.currState===true && msg.payload.oldState===false){\n      // Holiday Mode turns on\n      \n      var offDate=new Date();\n      offDate.setDate(offDate.getDate()+7);\n      var offDateString=offDate.toString();\n      var offDateSplit=offDateString.split(\" \").slice(0,4).join(\" \");\n      var returnMsg={topic: \"/home/zwave/node17/holiday_mode_off\", payload:offDateSplit};\n  }\n  else if(msg.payload.currState===false && msg.payload.oldState===true){\n      // Holiday Mode turns off\n      var returnMsg={topic: \"/home/zwave/node17/holiday_mode_off\", payload:\"Off\"};\n  }\n}\n\nif (returnMsg!==null) {\n    return [returnMsg,null];\n    } else if (returnMsg2!==null){\n    return [null,returnMsg2];\n    } else {\n    return [null,null];\n    }","outputs":"2","noerr":0,"x":430,"y":2960,"wires":[["4e49d576.69785c","6b44f8a9.51fa38","233f6b54.df8e74"],["4e49d576.69785c"]]},{"id":"4e49d576.69785c","type":"debug","z":"74066dce.c8160c","name":"","active":true,"console":"false","complete":"false","x":710,"y":3020,"wires":[]},{"id":"42bfa404.edfa3c","type":"inject","z":"74066dce.c8160c","name":"true - true (steady state)","topic":"/node8","payload":"true-true","payloadType":"str","repeat":"","crontab":"","once":false,"x":202,"y":3021,"wires":[["2fe0c94d.796a3a"]]},{"id":"2fe0c94d.796a3a","type":"function","z":"74066dce.c8160c","name":"Simulate Status","func":"\nif (msg.payload==\"true-true\") {var returnMsg={topic:'Hello', payload:{nodeid:'17', cmdclass:'37', currState:true, oldState:true}};}\nif (msg.payload==\"true-false\") {var returnMsg={topic:'Hello', payload:{nodeid:'17', cmdclass:'37', currState:true, oldState:false}};}\nif (msg.payload==\"false-true\") {var returnMsg={topic:'Hello', payload:{nodeid:'17', cmdclass:'37', currState:false, oldState:true}};}\n\n\nreturn returnMsg;","outputs":1,"noerr":0,"x":460,"y":3020,"wires":[["5270430d.92c8c4","4e49d576.69785c"]]},{"id":"d0e9e9e4.20f188","type":"inject","z":"74066dce.c8160c","name":"true - false (going on)","topic":"/node8","payload":"true-false","payloadType":"str","repeat":"","crontab":"","once":false,"x":200,"y":3060,"wires":[["2fe0c94d.796a3a"]]},{"id":"cc5d9617.8dec78","type":"inject","z":"74066dce.c8160c","name":"false - true (going off)","topic":"/node8","payload":"false-true","payloadType":"str","repeat":"","crontab":"","once":false,"x":200,"y":3100,"wires":[["2fe0c94d.796a3a"]]},{"id":"6b44f8a9.51fa38","type":"mqtt out","z":"74066dce.c8160c","name":"/home/zwave/node17/holiday_mode_off","topic":"/home/zwave/node17/holiday_mode_off","qos":"","retain":"true","broker":"8552f64b.80b9c","x":810,"y":2960,"wires":[]},{"id":"57239f5.d28ca2","type":"comment","z":"74066dce.c8160c","name":"Obtain Thermostat Setpoint","info":"Every 30 seconds copy the global variable\nwhich contains the setpoint to mqtt.\n\nnb: this only works if the thermostat is in\n\"heating 1\" mode, ie: not \"away heating\", or\nholiday mode. Extra logic will be required to\nsupport these modes.","x":220,"y":3180,"wires":[]},{"id":"a5cb3484.3885c8","type":"inject","z":"74066dce.c8160c","name":"Trigger","topic":"Trigger","payload":"","payloadType":"date","repeat":"60","crontab":"","once":true,"x":160,"y":3220,"wires":[["75a02776.292f8c"]]},{"id":"75a02776.292f8c","type":"function","z":"74066dce.c8160c","name":"Obtain setpoiont from global var","func":"//Assuming thermostat is node 17\nvar thermostatNode=17;\n\nvar openzwaveNodes = global.get(\"openzwaveNodes\");\nvar valueResult = openzwaveNodes[thermostatNode].classes[67][1][1].value;     \n\nvar returnMsg={\"topic\": \"/home/zwave/node\"+thermostatNode+\"/current_setpoint\", \"payload\": valueResult};\n\n//update pending code to go here!\n\nreturn returnMsg;\n","outputs":1,"noerr":0,"x":450,"y":3220,"wires":[["632cf173.ffbcf4","5440ab67.59045"]]},{"id":"632cf173.ffbcf4","type":"mqtt out","z":"74066dce.c8160c","name":"/home/zwave/{thermostatNode}/current_setpoint","topic":"","qos":"","retain":"true","broker":"8552f64b.80b9c","x":820,"y":3220,"wires":[]},{"id":"5440ab67.59045","type":"debug","z":"74066dce.c8160c","name":"","active":false,"console":"false","complete":"false","x":710,"y":3280,"wires":[]},{"id":"9c6422f.1a60fe","type":"inject","z":"74066dce.c8160c","name":"Poll Thermostat Setpoint","topic":"enablePoll","payload":"[17,67]","payloadType":"json","repeat":"","crontab":"","once":true,"x":210,"y":3380,"wires":[["34b8c849.a5d7b4"]]},{"id":"7de67ca2.fd1234","type":"comment","z":"74066dce.c8160c","name":"Poll thermostat setpoint (fire at startup)","info":"","x":250,"y":3340,"wires":[]},{"id":"34b8c849.a5d7b4","type":"delay","z":"74066dce.c8160c","name":"Delay for 2 mins to allow zwave initialisation","pauseType":"delay","timeout":"2","timeoutUnits":"minutes","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":550,"y":3380,"wires":[["a79ab6f7.fdbe38","994c1a10.c08f18"]]},{"id":"a79ab6f7.fdbe38","type":"zwave-out","z":"74066dce.c8160c","name":"/dev/zwave","controller":"15a41f3c.b5fba9","x":950,"y":3380,"wires":[]},{"id":"233f6b54.df8e74","type":"function","z":"74066dce.c8160c","name":"Clear change pending","func":"var returnMsg = {topic: '/home/zwave/node17/holiday_mode_change_pending', payload: 'false'};\nreturn returnMsg;","outputs":1,"noerr":0,"x":740,"y":3080,"wires":[["32d7c652.a0ac0e"]]},{"id":"32d7c652.a0ac0e","type":"mqtt out","z":"74066dce.c8160c","name":"/home/zwave/node17/holiday_mode_change_pending","topic":"","qos":"","retain":"true","broker":"8552f64b.80b9c","x":1060,"y":3080,"wires":[]},{"id":"994c1a10.c08f18","type":"debug","z":"74066dce.c8160c","name":"","active":false,"console":"false","complete":"true","x":930,"y":3440,"wires":[]},{"id":"35490751.5b2248","type":"mqtt out","z":"74066dce.c8160c","name":"/home/zwave/node17/thermostat_setpoint_change_pending","topic":"","qos":"","retain":"true","broker":"8552f64b.80b9c","x":940,"y":3640,"wires":[]},{"id":"42ddf9b3.e8ea74","type":"zwave-out","z":"74066dce.c8160c","name":"/dev/zwave output","controller":"15a41f3c.b5fba9","x":810,"y":3540,"wires":[]},{"id":"aa7e1e84.64594","type":"http response","z":"74066dce.c8160c","name":"Response page","x":800,"y":3720,"wires":[]},{"id":"e980a741.554248","type":"template","z":"74066dce.c8160c","name":"Acknowledge Success","field":"payload","fieldType":"msg","syntax":"mustache","template":"<html>\n<head>\n<meta HTTP-EQUIV=\"REFRESH\" content=\"0; url=http://frinkhub01.frinkiac7.net/\">\n</head>\n<body>\n<p> Thermostat change has been queued, reloading page...</p>\n</body>\n</html>\n\n{{*/Code can go here, I think/*}}","x":480,"y":3720,"wires":[["aa7e1e84.64594"]]},{"id":"4b2d4daa.9297d","type":"http in","z":"74066dce.c8160c","name":"Thermostat set value","url":"/setThermostat.html","method":"get","swaggerDoc":"","x":200,"y":3540,"wires":[["e980a741.554248","11b4607.c8e9b6","a6c1a4ce.575858"]]},{"id":"bf4b709e.35fed","type":"debug","z":"74066dce.c8160c","name":"","active":true,"console":"false","complete":"true","x":770,"y":3600,"wires":[]},{"id":"8d9046ab.5f791","type":"comment","z":"74066dce.c8160c","name":"Set Thermostat from REST calls","info":"","x":230,"y":3500,"wires":[]},{"id":"a6c1a4ce.575858","type":"function","z":"74066dce.c8160c","name":"Format Message for Z Wave","func":"\n// Make the string variables supplied form the source into Integers\nvar thermostatNodeId = \"17\";\nvar thermostatValue = msg.payload.value;\nvar mqttTopic = \"/home/zwave/node17/thermostat_setpoint_change_pending\";\n\n\n// Build these into a message with the name setValue.\nvar returnMsg={topic:\"setValue\", payload:{\"nodeid\": thermostatNodeId, \"cmdclass\": 67, \"instance\": 1, \"cmdidx\": 1, \"value\":msg.payload.value}};\nvar returnMQTTMsg={topic:mqttTopic, payload:msg.payload.value};\n\nreturn [returnMsg,returnMQTTMsg];\n\n","outputs":"2","noerr":0,"x":500,"y":3540,"wires":[["bf4b709e.35fed","42ddf9b3.e8ea74"],["35490751.5b2248","bf4b709e.35fed"]]},{"id":"11b4607.c8e9b6","type":"debug","z":"74066dce.c8160c","name":"","active":false,"console":"false","complete":"true","x":430,"y":3760,"wires":[]},{"id":"15a41f3c.b5fba9","type":"zwave-controller","z":"","port":"/dev/zwave","driverattempts":"3","pollinterval":"10000","allowunreadyupdates":false},{"id":"8552f64b.80b9c","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","tls":null,"clientid":"","usetls":false,"compatmode":true,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"0","willRetain":null,"willPayload":"","birthTopic":"","birthQos":"0","birthRetain":null,"birthPayload":""}]

Flow Info

Created 8 years, 2 months ago
Rating: not yet rated

Owner

Actions

Rate:

Node Types

Core
  • comment (x6)
  • debug (x7)
  • delay (x1)
  • function (x6)
  • http in (x2)
  • http response (x2)
  • inject (x5)
  • mqtt out (x4)
  • mqtt-broker (x1)
  • template (x2)
Other
  • zwave-controller (x1)
  • zwave-in (x1)
  • zwave-out (x3)

Tags

  • zwave
  • scs317
  • secure
  • horstmann
  • thermostat
  • c-stat
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option