Bonus round!
What if you want to reset all the accumulated energy channels?
That’s a total of 21 channels; 5 for each of the three A, B, and C phases, plus another 6 for the three-phase totals… That might sound like a lot of API calls – but it’s really easy to do them all dynamically in just a few seconds using a bit of JavaScript.
I’ll have full flow imports for both RIO EMU and EPIC PM modules below; but here’s the main part of the code:
// List of starting channels and the total length of channels to read & clear
channels = [
[13 , 5], // 13-17 = five channels in phase A
[31 , 5], // 31-35 = five channels in phase B
[49 , 5], // 49-53 = five channels in phase C
[57 , 6]];// 57-62 = six 3-phase totals channels
for(i = 0; i < channels.length; i++) {
// Calculate the address offset based on the starting channel number stored in channels[i][0], convert to hex string
myAddress = (0xF01C8000 + (channels[i][0] * 0x08)).toString(16);
// Determine the URL based on hostname, current address, and length of stored in channels[i][1]
msg.url = "https://" + hostname + "/manage/api/v1/io/local/mmp/address/" + myAddress + "?type=float&length=" + channels[i][1]*2;
// Send this HTTPS request with msg.headers and msg.url for this group of channels
node.send(msg);
}
First I define an array that holds the starting channel number and the number of channels to read & clear. For each of the phases there are five consecutive channels, and six for the totals – but if you want to reset only a particular phase, not reset the totals, or anything else you can just edit or remove the pair of numbers associated with any group of channels as-needed.
Once the channels are set it’s a simple matter of looping through that array and calculating the MMP address for each group and sending out the URL for the RESTful HTTPS request to trigger the read & clear.
Here’s the full flow for a RIO EMU, including an inject node that must provide the hostname and an admin-level API key. I’ve included two for in this example, but make sure you edit it with your info before deploying the flow.
Also, note that this does use the same HTTPS authentication linked in the original post above: Authenticating Opto API calls with HTTP request
[{"id":"f6b548b2a30bde25","type":"function","z":"9e233840361059cc","name":"Clear Energy Totals & Phases","func":"msg.headers = {\"apiKey\":msg.apiKey};\nhostname = msg.hostname;\n\n// List of starting channels and the total length of channels to read & clear\nchannels = [\n [13 , 5], // 13-17 = five channels in phase A\n [31 , 5], // 31-35 = five channels in phase B\n [49 , 5], // 49-53 = five channels in phase C\n [57 , 6]];// 57-62 = six 3-phase totals channels\n\nfor(i = 0; i < channels.length; i++) {\n // Calculate the address offset based on the starting channel number stored in channels[i][0], convert to hex string\n myAddress = (0xF01C8000 + (channels[i][0] * 0x08)).toString(16);\n \n // Uncomment the line below for debugging\n// node.warn(channels[i][0] + \", \" + channels[i][1] + \" = \" + myAddress);\n\n // Determine the URL based on hostname, current address, and length of stored in channels[i][1]\n msg.url = \"https://\" + hostname + \"/manage/api/v1/io/local/mmp/address/\" + myAddress + \"?type=float&length=\" + channels[i][1]*2;\n\n // Send this HTTPS request with msg.headers and msg.url for this group of channels\n node.send(msg);\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":1580,"wires":[["a90893f9c0bdd485"]]},{"id":"5d15ec958b670021","type":"inject","z":"9e233840361059cc","name":"device information","props":[{"p":"hostname","v":"hostname-or-IP","vt":"str"},{"p":"apiKey","v":"zikA9FKdp3FRdBzRyBwkBnqFq5MmyHSH","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":190,"y":1580,"wires":[["f6b548b2a30bde25"]]},{"id":"93881fc5.654f3","type":"inject","z":"9e233840361059cc","name":"second device","props":[{"p":"hostname","v":"another-hostname-or-IP","vt":"str"},{"p":"apiKey","v":"4uwr3Nbx7EKvbSrVLkKoVwaN2APWAQUv","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":170,"y":1620,"wires":[["f6b548b2a30bde25"]]},{"id":"a90893f9c0bdd485","type":"http request","z":"9e233840361059cc","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"7e4813585b6be2bf","persist":false,"proxy":"","authType":"","x":690,"y":1580,"wires":[["7609d29856336696"]]},{"id":"7609d29856336696","type":"debug","z":"9e233840361059cc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":850,"y":1580,"wires":[]},{"id":"7e4813585b6be2bf","type":"tls-config","name":"localhost","cert":"","key":"","ca":"","certname":"","keyname":"","caname":"","servername":"","verifyservercert":false}]
If you’re using an EPIC with one or more power monitoring modules use this alternate flow which also reads in an array of modules (if you just have one module, just have an array with one index in it, for example [3]
for one module installed in the fourth slot).
[{"id":"f6b548b2a30bde25","type":"function","z":"0928763894a95f05","name":"Clear Energy Totals & Phases","func":"msg.headers = {\"apiKey\":msg.apiKey};\nhostname = msg.hostname;\n// modules should be an array of numbers representing one or more module indices that have power monitoring modules installed\n// ex: msg.modules = [4] or = [3, 5, 7, 8]\nmodules = msg.modules;\n\n// List of starting channels and the total length of channels to read & clear\nchannels = [\n [13 , 5], // 13-17 = five channels in phase A\n [31 , 5], // 31-35 = five channels in phase B\n [49 , 5], // 49-53 = five channels in phase C\n [57 , 6]];// 57-62 = six 3-phase totals channels\n\nfor(o = 0; o < modules.length; o++){\n for(i = 0; i < channels.length; i++) {\n // Calculate the address offset based on the module and starting channel number (stored in channels[i][0]) & convert to hex string\n myAddress = (0xF01C8000 + (modules[o] * 0x200) + (channels[i][0] * 0x08)).toString(16);\n \n // Uncomment the line below for debugging\n // node.warn(channels[i][0] + \", \" + channels[i][1] + \" = \" + myAddress);\n \n // Determine the URL based on hostname, current address, and length of stored in channels[i][1]\n msg.url = \"https://\" + hostname + \"/manage/api/v1/io/local/mmp/address/\" + myAddress + \"?type=float&length=\" + channels[i][1]*2;\n \n // Send this HTTPS request with msg.headers and msg.url for this group of channels\n node.send(msg);\n }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":410,"y":120,"wires":[["a90893f9c0bdd485"]]},{"id":"93881fc5.654f3","type":"inject","z":"0928763894a95f05","name":"second device","props":[{"p":"hostname","v":"another-hostname-or-IP","vt":"str"},{"p":"apiKey","v":"4uwr3Nbx7EKvbSrVLkKoVwaN2APWAQUv","vt":"str"},{"p":"modules","v":"[3]","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":130,"y":160,"wires":[["f6b548b2a30bde25"]]},{"id":"5d15ec958b670021","type":"inject","z":"0928763894a95f05","name":"device information","props":[{"p":"hostname","v":"hostname-or-IP","vt":"str"},{"p":"apiKey","v":"zikA9FKdp3FRdBzRyBwkBnqFq5MmyHSH","vt":"str"},{"p":"modules","v":"[3, 5, 7, 9]","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":150,"y":120,"wires":[["f6b548b2a30bde25"]]},{"id":"a90893f9c0bdd485","type":"http request","z":"0928763894a95f05","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"7e4813585b6be2bf","persist":false,"proxy":"","authType":"","credentials":{"user":"","password":""},"x":650,"y":120,"wires":[["7609d29856336696"]]},{"id":"7609d29856336696","type":"debug","z":"0928763894a95f05","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":810,"y":120,"wires":[]},{"id":"7e4813585b6be2bf","type":"tls-config","name":"localhost","cert":"","key":"","ca":"","certname":"","keyname":"","caname":"","servername":"","verifyservercert":false}]