Skip to content

Instantly share code, notes, and snippets.

@nygma2004
Created May 11, 2017 07:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nygma2004/75a4715fb6a3595057343a92abc493e4 to your computer and use it in GitHub Desktop.
Save nygma2004/75a4715fb6a3595057343a92abc493e4 to your computer and use it in GitHub Desktop.
SDM120 single phase Modbus RTU energy meter

This flow shows how to set up Eastron SDM120 single phase energy meter under Node-Red. For this I am using node-red-contrib-modbus for the serial modbus communication. There are a few fucntion nodes titled "Diagnostic message*" which is used for my diagnostic process. That process is not included in the flow and I will only post about it the future. So ignore them for the time being, or just implement your own logic for those sections.

I have also posted a relatively long video on setting up the energy meter, changing the modbus settings and detailed explanation how the flow works: https://youtu.be/yBtqKSWDn1Q

[{"id":"b3ae0448.822d08","type":"comment","z":"2934a51a.93393a","name":"SDM120 Energy Meter","info":"","x":141.5,"y":1142,"wires":[]},{"id":"53b4b356.bf124c","type":"modbus-read","z":"2934a51a.93393a","name":"SDM 120 Voltage","showStatusActivities":true,"showErrors":true,"unitid":"30","dataType":"InputRegister","adr":"0","quantity":"2","rate":"5","rateUnit":"s","server":"40f20c7f.13a934","x":113,"y":1235,"wires":[["e4d3fade.1132a8","1b35ee5d.7dd512"],[]]},{"id":"e4d3fade.1132a8","type":"function","z":"2934a51a.93393a","name":"Voltage","func":"var rawData = new ArrayBuffer(4);\nvar intView = new Uint16Array(rawData);\nvar fltView = new Float32Array(rawData);\n\nintView[0] = msg.payload[1]; //low\nintView[1] = msg.payload[0]; //high\n\nmsg.payload = parseFloat(fltView[0].toFixed(1));\nmsg.topic = \"voltage\";\n\nnode.status({fill:\"blue\",shape:\"ring\",text:msg.topic + \":\" + msg.payload}); \n\nreturn msg;","outputs":1,"noerr":0,"x":342,"y":1228,"wires":[["94b7c2b7.b61ae","267d6c75.311c84"]]},{"id":"29fc9cac.869404","type":"modbus-queue-info","z":"2934a51a.93393a","name":"SDM120_queue","unitid":"30","lowLowLevel":"1","lowLevel":75,"highLevel":150,"highHighLevel":300,"server":"40f20c7f.13a934","errorOnHighLevel":false,"x":484.6428527832031,"y":1602.107177734375,"wires":[["759e42e9.23762c"]]},{"id":"27ead677.91de0a","type":"inject","z":"2934a51a.93393a","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":113.64286041259766,"y":1603.1072025299072,"wires":[["1d0b599c.544786"]]},{"id":"1d0b599c.544786","type":"change","z":"2934a51a.93393a","name":"Reset queue","rules":[{"t":"set","p":"resetQueue","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":282.64286041259766,"y":1603.1071891784668,"wires":[["29fc9cac.869404"]]},{"id":"e3643b3e.be3a88","type":"function","z":"2934a51a.93393a","name":"Current","func":"var rawData = new ArrayBuffer(4);\nvar intView = new Uint16Array(rawData);\nvar fltView = new Float32Array(rawData);\n\nintView[0] = msg.payload[1]; //low\nintView[1] = msg.payload[0]; //high\n\nmsg.payload = parseFloat(fltView[0].toFixed(1));\nmsg.topic = \"current\";\n\nnode.status({fill:\"blue\",shape:\"ring\",text:msg.topic + \":\" + msg.payload}); \n\nreturn msg;","outputs":1,"noerr":0,"x":341,"y":1286,"wires":[["fa18b5f3.ba6be8","267d6c75.311c84"]]},{"id":"4dbf9277.487e4c","type":"function","z":"2934a51a.93393a","name":"Power","func":"var rawData = new ArrayBuffer(4);\nvar intView = new Uint16Array(rawData);\nvar fltView = new Float32Array(rawData);\n\nintView[0] = msg.payload[1]; //low\nintView[1] = msg.payload[0]; //high\n\nmsg.payload = parseFloat(fltView[0].toFixed(1));\nmsg.topic = \"power\";\n\nnode.status({fill:\"blue\",shape:\"ring\",text:msg.topic + \":\" + msg.payload}); \n\nreturn msg;","outputs":1,"noerr":0,"x":332,"y":1339,"wires":[["c3697655.758e28","267d6c75.311c84"]]},{"id":"593c6698.c25388","type":"function","z":"2934a51a.93393a","name":"Frequency","func":"var rawData = new ArrayBuffer(4);\nvar intView = new Uint16Array(rawData);\nvar fltView = new Float32Array(rawData);\n\nintView[0] = msg.payload[1]; //low\nintView[1] = msg.payload[0]; //high\n\nmsg.payload = parseFloat(fltView[0].toFixed(1));\nmsg.topic = \"frequency\";\n\nnode.status({fill:\"blue\",shape:\"ring\",text:msg.topic + \":\" + msg.payload}); \n\nreturn msg;","outputs":1,"noerr":0,"x":352,"y":1395,"wires":[["c38e8fed.7fb6a","267d6c75.311c84"]]},{"id":"7df027a2.13a1f8","type":"function","z":"2934a51a.93393a","name":"Energy","func":"var rawData = new ArrayBuffer(4);\nvar intView = new Uint16Array(rawData);\nvar fltView = new Float32Array(rawData);\n\nintView[0] = msg.payload[1]; //low\nintView[1] = msg.payload[0]; //high\n\nmsg.payload = parseFloat(fltView[0].toFixed(2));\nmsg.topic = \"energy\";\n\nnode.status({fill:\"blue\",shape:\"ring\",text:msg.topic + \":\" + msg.payload}); \n\nreturn msg;","outputs":1,"noerr":0,"x":342,"y":1455,"wires":[["d87b3ecd.2dab2","267d6c75.311c84"]]},{"id":"7d42a707.bcd618","type":"modbus-read","z":"2934a51a.93393a","name":"SDM 120 Current","showStatusActivities":true,"showErrors":true,"unitid":"30","dataType":"InputRegister","adr":"6","quantity":"2","rate":"5","rateUnit":"s","server":"40f20c7f.13a934","x":122,"y":1293,"wires":[["e3643b3e.be3a88"],[]]},{"id":"576a7fbe.d0861","type":"modbus-read","z":"2934a51a.93393a","name":"SDM 120 Power","showStatusActivities":true,"showErrors":true,"unitid":"30","dataType":"InputRegister","adr":"12","quantity":"2","rate":"5","rateUnit":"s","server":"40f20c7f.13a934","x":112,"y":1345,"wires":[["4dbf9277.487e4c"],[]]},{"id":"519b5a74.1a7314","type":"modbus-read","z":"2934a51a.93393a","name":"SDM 120 Frequency","showStatusActivities":true,"showErrors":true,"unitid":"30","dataType":"InputRegister","adr":"70","quantity":"2","rate":"5","rateUnit":"s","server":"40f20c7f.13a934","x":132,"y":1401,"wires":[["593c6698.c25388"],[]]},{"id":"b84798db.04be98","type":"modbus-read","z":"2934a51a.93393a","name":"SDM 120 Energy","showStatusActivities":true,"showErrors":true,"unitid":"30","dataType":"InputRegister","adr":"342","quantity":"2","rate":"5","rateUnit":"s","server":"40f20c7f.13a934","x":110,"y":1460,"wires":[["7df027a2.13a1f8","5fe7e9a5.d88c68"],[]]},{"id":"94b7c2b7.b61ae","type":"ui_text","z":"2934a51a.93393a","group":"2c2fdfeb.fe41e","order":0,"width":0,"height":0,"name":"","label":"Voltage","format":"{{msg.payload}} V","layout":"row-spread","x":528,"y":1230,"wires":[]},{"id":"fa18b5f3.ba6be8","type":"ui_text","z":"2934a51a.93393a","group":"2c2fdfeb.fe41e","order":0,"width":0,"height":0,"name":"","label":"Current","format":"{{msg.payload}} A","layout":"row-spread","x":529,"y":1285,"wires":[]},{"id":"c3697655.758e28","type":"ui_text","z":"2934a51a.93393a","group":"2c2fdfeb.fe41e","order":0,"width":0,"height":0,"name":"","label":"Power","format":"{{msg.payload}} W","layout":"row-spread","x":525,"y":1340,"wires":[]},{"id":"c38e8fed.7fb6a","type":"ui_text","z":"2934a51a.93393a","group":"2c2fdfeb.fe41e","order":0,"width":0,"height":0,"name":"","label":"Frequency","format":"{{msg.payload}} Hz","layout":"row-spread","x":545,"y":1396,"wires":[]},{"id":"d87b3ecd.2dab2","type":"ui_text","z":"2934a51a.93393a","group":"2c2fdfeb.fe41e","order":0,"width":0,"height":0,"name":"","label":"Total Energy","format":"{{msg.payload}} kWh","layout":"row-spread","x":547,"y":1456,"wires":[]},{"id":"267d6c75.311c84","type":"function","z":"2934a51a.93393a","name":"Build object","func":"watch_topic = \"energy\";\nvar output = {};\n\ncontext.set(msg.topic,msg.payload);\n\nif (context.get(\"voltage\")!==undefined) {\n output.voltage = context.get(\"voltage\");\n}\nif (context.get(\"current\")!==undefined) {\n output.current = context.get(\"current\");\n}\nif (context.get(\"power\")!==undefined) {\n output.power = context.get(\"power\");\n}\nif (context.get(\"frequency\")!==undefined) {\n output.frequency = context.get(\"frequency\");\n}\nif (context.get(\"energy\")!==undefined) {\n output.energy = context.get(\"energy\");\n}\nmsg.payload = output;\n\nif (msg.topic===watch_topic) {\n msg.topic = \"sdm120\";\n return msg;\n}","outputs":1,"noerr":0,"x":718,"y":1313,"wires":[["6d3190d1.e5037","30d370ab.48c66"]]},{"id":"6d3190d1.e5037","type":"debug","z":"2934a51a.93393a","name":"","active":false,"console":"false","complete":"true","x":882,"y":1313,"wires":[]},{"id":"78d7ebbc.cea674","type":"function","z":"2934a51a.93393a","name":"Diagnostic input message structure","func":"// setting a global flag that the solar system is down\n\nmsg.payload = \"High voltage warning: \" + msg.payload.voltage +\" V\";\nmsg.system = 1; // System id, use 1 for Dummy\n//msg.state = 1; // specify if the message is to change system status\nmsg.severity = 1; // 0: information, 1: warning, 2: error\nmsg.email = false; // if separate email should be sent\n//msg.emailtext = \"Clean up step of the SAIA log backup has failed\";\nreturn msg;","outputs":1,"noerr":0,"x":1433,"y":1201,"wires":[["d9ab022c.d40aa"]]},{"id":"d9ab022c.d40aa","type":"link out","z":"2934a51a.93393a","name":"","links":["13e089a7.73cb46"],"x":1640,"y":1223,"wires":[]},{"id":"44460146.8cda4","type":"switch","z":"2934a51a.93393a","name":"Voltage check","property":"payload.voltage_check","propertyType":"msg","rules":[{"t":"eq","v":"high","vt":"str"},{"t":"eq","v":"low","vt":"str"}],"checkall":"true","outputs":2,"x":1141,"y":1225,"wires":[["78d7ebbc.cea674"],["a194e5c6.7a7eb8"]]},{"id":"a194e5c6.7a7eb8","type":"function","z":"2934a51a.93393a","name":"Diagnostic input message structure","func":"// setting a global flag that the solar system is down\n\nmsg.payload = \"Low voltage warning: \" + msg.payload.voltage +\" V\";\nmsg.system = 1; // System id, use 1 for Dummy\n//msg.state = 1; // specify if the message is to change system status\nmsg.severity = 1; // 0: information, 1: warning, 2: error\nmsg.email = false; // if separate email should be sent\n//msg.emailtext = \"Clean up step of the SAIA log backup has failed\";\nreturn msg;","outputs":1,"noerr":0,"x":1433,"y":1246,"wires":[["d9ab022c.d40aa"]]},{"id":"30d370ab.48c66","type":"function","z":"2934a51a.93393a","name":"Voltage check","func":"var high = 250.0;\nvar low = 220.0;\n\nif (msg.payload.voltage > high) {\n msg.payload.voltage_check = \"high\";\n}\nif (msg.payload.voltage < low) {\n msg.payload.voltage_check = \"low\";\n}\nreturn msg;","outputs":1,"noerr":0,"x":928,"y":1226,"wires":[["44460146.8cda4"]]},{"id":"d01ace0b.7d3d4","type":"function","z":"2934a51a.93393a","name":"reset on HighHigh","func":"if(\"high high level reached\" === msg.state) {\n msg.resetQueue = true;\n return msg;\n}\n","outputs":1,"noerr":0,"x":357.50000762939453,"y":1733.2500247955322,"wires":[["29fc9cac.869404","dc784194.a11f6"]]},{"id":"ec676e18.9bbae","type":"catch","z":"2934a51a.93393a","name":"Catch queue errors","scope":["29fc9cac.869404"],"x":119.50000762939453,"y":1733.2500247955322,"wires":[["d01ace0b.7d3d4"]]},{"id":"284bdf25.d13a9","type":"comment","z":"2934a51a.93393a","name":"Error handling","info":"","x":85.50000762939453,"y":1688.2500247955322,"wires":[]},{"id":"dc784194.a11f6","type":"function","z":"2934a51a.93393a","name":"Diagnostic input message structure","func":"// setting a global flag that the solar system is down\n\nmsg.payload = \"SDM120 modbus queue reached high level, resetting. (\" + msg.state + \")\";\nmsg.system = 4; // System id, use 1 for Dummy\n//msg.state = 1; // specify if the message is to change system status\nmsg.severity = 1; // 0: information, 1: warning, 2: error\nmsg.email = false; // if separate email should be sent\n//msg.emailtext = \"Clean up step of the SAIA log backup has failed\";\nreturn msg;","outputs":1,"noerr":0,"x":657.5000076293945,"y":1732.2500247955322,"wires":[["5c63f003.554"]]},{"id":"5c63f003.554","type":"link out","z":"2934a51a.93393a","name":"","links":["13e089a7.73cb46"],"x":843.5000076293945,"y":1732.2500247955322,"wires":[]},{"id":"e1c40b2e.6b7978","type":"catch","z":"2934a51a.93393a","name":"Modbus read errors","scope":["7d42a707.bcd618","b84798db.04be98","519b5a74.1a7314","576a7fbe.d0861","53b4b356.bf124c","b3ae0448.822d08"],"x":119.50000762939453,"y":1776.2500247955322,"wires":[["c8d0574c.839038"]]},{"id":"c8d0574c.839038","type":"function","z":"2934a51a.93393a","name":"Diagnostic input message structure","func":"// setting a global flag that the solar system is down\n\nmsg.payload = \"SDM120 modbus error: \" + msg.error.message;\nmsg.system = 4; // System id, use 1 for Dummy\n//msg.state = 1; // specify if the message is to change system status\nmsg.severity = 1; // 0: information, 1: warning, 2: error\nmsg.email = false; // if separate email should be sent\n//msg.emailtext = \"Clean up step of the SAIA log backup has failed\";\nreturn msg;","outputs":1,"noerr":0,"x":408.50000762939453,"y":1776.2500247955322,"wires":[["89cc7882.52fb68"]]},{"id":"89cc7882.52fb68","type":"link out","z":"2934a51a.93393a","name":"","links":["13e089a7.73cb46"],"x":594.5000076293945,"y":1776.2500247955322,"wires":[]},{"id":"759e42e9.23762c","type":"debug","z":"2934a51a.93393a","name":"","active":true,"console":"false","complete":"true","x":665.5000076293945,"y":1601.2500247955322,"wires":[]},{"id":"5fe7e9a5.d88c68","type":"function","z":"2934a51a.93393a","name":"Health check","func":"var devicename = \"sdm120\"; // Device name used for context variable\nvar system_id = 4; // System id number for diagnostic update\nvar online_threshold = 10; // Seconds between updates under which the device is considered online\nvar offline_threshold = 30; // Seconds between updates above which the device is considered offline\n\nvar temp = context.get(devicename+\"_update\");\nvar current = new Date();\nmsg.payload = \"No data\";\nmsg.warning = false;\nif (msg.topic!==\"timecheck\") {\n // Do not update the context if it is triggered by the check inject node\n context.set(devicename+\"_update\",current);\n}\nif (temp===undefined) {\n // this will be the case when node-red is booting up or redeployed\n context.set(devicename+\"_update\",current);\n}\n\nif (temp!==undefined) {\n current = current - temp;\n current = Math.floor(current/1000);\n var minute = Math.floor(current/60);\n var hour = Math.floor(minute/60);\n var day = Math.floor(hour/24);\n if (current>24*60*60) {\n msg.payload = \"Last update \" + day + \" days, \" + hour%24 + \" hours, \" + minute%60 + \" minutes, \" + current%60 + \" seconds ago\";\n } else if (current>60*60) {\n msg.payload = \"Last update \" + hour%24 + \" hours, \" + minute%60 + \" minutes, \" + current%60 + \" seconds ago\";\n } else if (current>60) {\n msg.payload = \"Last update \" + minute%60 + \" minutes, \" + current%60 + \" seconds ago\";\n } else {\n msg.payload = \"Last update \" + current%60 + \" seconds ago\";\n }\n\n if (context.get(devicename+\"_state\")!==1) {\n if (current<online_threshold) {\n msg.payload = \"SDM120 is now online\";\n msg.system = system_id; // System id, use 1 for Dummy\n msg.state = 1; // specify if the message is to change system status\n msg.severity = 0; // 0: information, 1: warning, 2: error\n //msg.email = true; // if separate email should be sent\n //msg.emailtext = \"\"; this a long text which goes into the email \n msg.warning = true;\n context.set(devicename+\"_state\",1);\n }\n } else {\n if (current>offline_threshold) {\n msg.payload = \"SDM120 is not transmitting\";\n msg.system = system_id; // System id, use 1 for Dummy\n msg.state = 99; // specify if the message is to change system status\n msg.severity = 2; // 0: information, 1: warning, 2: error\n //msg.email = true; // if separate email should be sent\n //msg.emailtext = \"\"; this a long text which goes into the email \n msg.warning = true;\n context.set(devicename+\"_state\",99);\n }\n }\n \n \n}\n\nnode.status({fill:\"blue\",shape:\"ring\",text:msg.payload});\n\nreturn msg;","outputs":1,"noerr":0,"x":366,"y":1520,"wires":[["e8795434.be1748"]]},{"id":"4646391.9ea9cc8","type":"inject","z":"2934a51a.93393a","name":"Check","topic":"timecheck","payload":"","payloadType":"date","repeat":"1","crontab":"","once":false,"x":150,"y":1532,"wires":[["5fe7e9a5.d88c68"]]},{"id":"e8795434.be1748","type":"switch","z":"2934a51a.93393a","name":"Update diag?","property":"warning","propertyType":"msg","rules":[{"t":"true"}],"checkall":"true","outputs":1,"x":561,"y":1520,"wires":[["ee08c280.18881"]]},{"id":"ee08c280.18881","type":"link out","z":"2934a51a.93393a","name":"","links":["13e089a7.73cb46"],"x":680.3015727996826,"y":1519.571403503418,"wires":[]},{"id":"1b35ee5d.7dd512","type":"debug","z":"2934a51a.93393a","name":"","active":true,"console":"false","complete":"false","x":338,"y":1176,"wires":[]},{"id":"40f20c7f.13a934","type":"modbus-client","z":"","name":"Serial_9600_8_N_1","clienttype":"serial","bufferCommands":true,"stateLogEnabled":false,"tcpHost":"127.0.0.1","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB0","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","unit_id":"","commandDelay":"30","clientTimeout":"2000","reconnectTimeout":"5000"},{"id":"2c2fdfeb.fe41e","type":"ui_group","z":"","name":"SDM120 Energy Meter","tab":"72b1a4dc.4f488c","order":2,"disp":true,"width":"6"},{"id":"72b1a4dc.4f488c","type":"ui_tab","z":"","name":"Modbus","icon":"memory","order":15}]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment