Get solar power plant data from SMA Sunny Webbox using RPC API
Description
This flow requests data directly from Sunny Webbox data acquisition unit every 30 seconds (00:00:30, 00:01:00... etc) and then parses the result only if response payload.result has changed or timeout value has reached 1800 seconds.
Returned values are current power [W], daily energy [kWh], total energy [kWh], current mode and error message.
Created and tested with Node-RED 0.16.2 and Node.js 6.10.0 in Windows 10 machine. Connection to Sunny Webbox is established over local area network.
User actions
Change Sunny Webbox IP address (msg.url for HTTP request) to match your Sunny Webbox.
RPC API
SMA Sunny Webbox RPC API: http://files.sma.de/dl/4253/SWebBoxRPC-eng-BUS112713.pdf
[{"id":"c82c82cf.19283","type":"http request","z":"b41f15af.eabd08","name":"make HTTP POST request","method":"POST","ret":"obj","url":"","tls":"","x":796.6000518798828,"y":117.59999084472656,"wires":[["141953eb.2f3e3c","73b171a1.86fc7"]]},{"id":"d33e0fa.2fc7df","type":"function","z":"b41f15af.eabd08","name":"Create GetPlantOverview request","func":"msg.url = \"http://172.16.26.144/rpc\"\nmsg.payload='RPC={\"proc\":\"GetPlantOverview\",\"format\":\"JSON\",\"version\":\"1.0\",\"id\":\"1\"}'\nreturn msg;","outputs":1,"noerr":0,"x":494.6000518798828,"y":117.60003662109375,"wires":[["c82c82cf.19283"]]},{"id":"b40f01a4.070f9","type":"function","z":"b41f15af.eabd08","name":"Parse GetPlantOverview","func":"data = msg.payload\n\nvar tsUTC = flow.get(\"tsUTC\");\nvar tsLocal = flow.get(\"tsLOCAL\");\n\nvar power = 0;\nvar daily = 0;\nvar total = 0;\nvar opstt = \"\";\nvar msgtt = \"\";\n\ntsUTC = flow.get(\"tsUTC\")\nmsg = { \n \"payload\": {\n \"d\": { }, \n \"ts\": tsUTC\n }\n};\n\nmsg.payload.d.power = {};\nmsg.payload.d.power.value = {};\n\nmsg.payload.d.daily_energy = {};\nmsg.payload.d.daily_energy.value = {};\n\nmsg.payload.d.total_energy = {};\nmsg.payload.d.total_energy.value = {};\n\n\npower = parseFloat(data.result.overview[0].value);\ndaily = parseFloat(data.result.overview[1].value);\ntotal = parseFloat(data.result.overview[2].value);\nopstt = data.result.overview[3].value;\nmsgtt = data.result.overview[4].value;\n\nif(msgtt === \"\")\n{\n msgtt = \"-\"; \n}\n\nmsg.payload.d.power.value = power;\nmsg.payload.d.daily_energy.value = daily;\nmsg.payload.d.total_energy.value = total;\n\nnode.status({fill:\"blue\",shape:\"dot\",text:\"Latest update: \"+tsUTC});\n \nreturn msg;","outputs":"1","noerr":0,"x":668.6001129150391,"y":322.59999084472656,"wires":[["445a951a.ad1d3c","333ec82a.d14278"]]},{"id":"445a951a.ad1d3c","type":"debug","z":"b41f15af.eabd08","name":"MQTT payload to Watson IoT","active":true,"console":"false","complete":"payload","x":1005.6001739501953,"y":321.2000274658203,"wires":[]},{"id":"7404fc7.2481204","type":"file","z":"b41f15af.eabd08","name":"Save to log file","filename":"","appendNewline":true,"createDir":true,"overwriteFile":"false","x":1319.5000762939453,"y":355.7999725341797,"wires":[]},{"id":"333ec82a.d14278","type":"function","z":"b41f15af.eabd08","name":"Create filename by year, month and date","func":"function addZero(i) {\n if (i < 10) {\n i = \"0\" + i;\n }\n return i;\n}\n\nmsg.filename = \"\";\n\nvar nowDate = new Date(); \n\nvar year = nowDate.getFullYear();\nvar month = addZero(nowDate.getMonth()+1);\nvar day = addZero(nowDate.getDate());\nvar hh = addZero(nowDate.getHours());\nvar mm = addZero(nowDate.getMinutes());\nvar ss = addZero(nowDate.getSeconds());\n\nvar date = year+'-'+month+'-'+day; \n\nmsg.filename = \"c:\\\\data\\\\\"+year+\"\\\\\"+month+\"\\\\\"+date+\"-\"+\"webbox.json\";\n\nreturn msg;","outputs":1,"noerr":0,"x":1045.500015258789,"y":355.7999725341797,"wires":[["7404fc7.2481204"]]},{"id":"c364c5c5.809158","type":"inject","z":"b41f15af.eabd08","name":"interval 30 s | timeout 1800 s","topic":"","payload":"{\"interval\": 30, \"timeout\":1800}","payloadType":"json","repeat":"1","crontab":"","once":false,"x":165,"y":28.799942016601562,"wires":[["e1cdb574.3aaca8"]]},{"id":"e1cdb574.3aaca8","type":"function","z":"b41f15af.eabd08","name":"release every 30 secs","func":"function addZero(i) {\n if (i < 10) {\n i = \"0\" + i;\n }\n return i;\n}\n\nvar date = new Date();\n\nvar year = date.getFullYear();\nvar month = addZero(date.getMonth()+1);\nvar day = addZero(date.getDate());\nvar hh = addZero(date.getHours());\nvar mm = addZero(date.getMinutes());\nvar ss = addZero(date.getSeconds());\nvar minutes = date.getMinutes();\nvar seconds = date.getSeconds();\n\nvar tsLocal = year + \"-\" +month+ \"-\" + day+\" \" + hh + \":\" + mm+ \":\" + ss;\n\nflow.set(\"timeout\",msg.payload.timeout);\n \ntimeoutCount = flow.get(\"timeoutCount\")||0;\n \nvar interval = msg.payload.interval;\nvar returnValue = false;\n \nmsg.payload.ts = date.toISOString();\nflow.set(\"tsUTC\",msg.payload.ts)\nflow.set(\"tsLOCAL\",tsLocal)\ntimeoutCount++;\nflow.set(\"timeoutCount\",timeoutCount); \n \nvar total = (minutes * 60) + seconds;\n \nvar remainder = total % interval;\n \nif(remainder === 0)\n{\n returnValue = true;\n node.status({fill:\"green\",shape:\"dot\",text:\"total: \"+total +\" | \"+ \"remainder: \"+remainder +\" | \" + \"Interval hit...\"});\n}\nelse\n{\n returnValue = false; \n node.status({fill:\"red\",shape:\"dot\",text:\"total: \"+total +\" | \"+ \"remainder: \"+remainder +\" | \" + \"Waiting...\"});\n}\n\nif(returnValue){ return msg; }","outputs":1,"noerr":0,"x":194,"y":117.79994201660156,"wires":[["d33e0fa.2fc7df"]]},{"id":"141953eb.2f3e3c","type":"function","z":"b41f15af.eabd08","name":"Continue if payload data has changed or timeout hits","func":" var d = context.get(\"d\")||\"\";\n var timeoutCount = flow.get(\"timeoutCount\")||\"\";\n var timeout = flow.get(\"timeout\");\n var returnValue = false;\n var data = JSON.stringify(msg.payload.result); \n \n if(data != d)\n {\n returnValue = true;\n node.status({fill:\"green\",shape:\"dot\",text: \"timeoutCount: \"+timeoutCount +\" / \"+timeout+ \" | \" + \"Payload changed...\"});\n timeoutCount = 0; \n }\n else if(timeoutCount >= timeout)\n {\n returnValue = true;\n node.status({fill:\"green\",shape:\"dot\",text: \"timeoutCount: \"+timeoutCount+\" / \"+timeout+\" | \" + \"Timeout...\"});\n timeoutCount = 0; \n }\n else\n {\n node.status({fill:\"red\",shape:\"dot\",text:\"timeoutCount: \"+timeoutCount +\" / \"+timeout+ \" | \" + \"Payload not changed...\"});\n returnValue = false; \n }\n\n flow.set(\"timeoutCount\",timeoutCount); \n context.set(\"d\",data);\n if(returnValue){ return msg; }","outputs":1,"noerr":0,"x":622.0001068115234,"y":225.7999267578125,"wires":[["b40f01a4.070f9"]]},{"id":"85c91f4f.70f0d","type":"comment","z":"b41f15af.eabd08","name":"Set your Webbox IP address here","info":"","x":496.50001525878906,"y":85.19999694824219,"wires":[]},{"id":"73b171a1.86fc7","type":"debug","z":"b41f15af.eabd08","name":"Original GetPlantOverview response","active":true,"console":"false","complete":"payload","x":1148.1998443603516,"y":117.19999694824219,"wires":[]}]