For both the groov EPIC power monitoring module (GRV-IVAPM-3
) and groov RIO EMU / Energy Monitoring Unit (GRV-R7-I1VAPM-3
) there are a total of 64 points of power and energy data, where power is measured as instantaneous usage and energy is accumulated over time.
But sometimes the accumulated energy values need to be cleared and reset; maybe at a specific billing period, at the end of the day, or between shifts. This can be done with the “Read and Clear” command in PAC Control – but what if you’re not running a strategy?
The solution is to use a memory mapped endpoint with either OptoMMP or the RESTful API.
This post will focus on how to use these two options with Node-RED, but this method can be applied with C++, Python, or anything that has HTTP request support like CURL or even Postman.
If you want to read more about the Memory Mapped Protocol, the details are covered in the OptoMMP Protocol Guide (form 1465)
Configuring I/O Channels → Reading and Writing Energy Values in GRV-IVAPM-3 & GRV-R7-I1VAPM-3 → Read and Clear Energy Value
The first step is to determine the specific hexadecimal memory address for the channel you want to clear using this formula:
Base address for channel = 0xF01C8000 + <module> * 0x200 + <channel> * 0x8
A quick overview of each value:
0xF01C8000
– The Read and Clear Area starting address, where each channel is 8 bytes, with 64 channels per module.0x200
– The hexadecimal length of one module in bytes. Using a RIO there is only one module with the index of zero, so if you’re using an EMU this can be ignored.
(This value comes from 8 bytes * 64 channels = 512 bytes, and 512 is0x200
in hex.)0x8
– The hexadecimal length of one channel, also in bytes.
This offsets the starting address by the module index then adds the offset of the channel index. Which channel you reset will depend on your application, and you can find a full list of each channel in either your groov Manage I/O menu or the product datasheets; and the channels are the same between both the PM module or RIO EMU. For example “Net Energy” for Phase A is channel 13 on both.
Once you get your address, for example channel 13 on module index 2 is 0xF01C8000 + (2 * 0x200) + (13 * 0x8) = 0xF01C8468
, you just need to read / GET that endpoint using either OptoMMP or the REST API endpoint /api/v1/io/{device}/mmp/address/{address}
.
Here’s what that would look like in Node-RED:
groov-io read node:
HTTP request node:
More details on how to authenticate the HTTP request call can be found in this previous forum post: Authenticating Opto API calls with HTTP request
Also, note that I am using a length of 2 in both cases – this is because the data type is float, and a float is 4 bytes – so getting two floats gets the 8 bytes that make up a single channel. You can also take advantage of this to get and clear multiple consecutive channels at once, if appropriate for your application.
For example to clear the 5 consecutive channels for net energy, positive energy, negative energy, net reactive energy, AND apparent energy with one call, just get a length of 10 and all five channels of accumulated energy will be reset.
Here is an example flow for you to try this out yourself, just remember to put in the MMP endpoint for your specific module / channel and choose your device if using groov-io, or paste in an admin-level API key if using HTTP requests.
[{"id":"77b121fc39325722","type":"inject","z":"996af57394f7db28","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"str","x":270,"y":920,"wires":[["6907acd937ffda87"]]},{"id":"6907acd937ffda87","type":"groov-io-read","z":"996af57394f7db28","device":"","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF01C8468","mmpType":"float","mmpLength":"10","mmpEncoding":"ascii","value":"","valueType":"msg.payload","itemName":"","name":"","x":440,"y":920,"wires":[["53a4fd88adef81b8"]]},{"id":"53a4fd88adef81b8","type":"debug","z":"996af57394f7db28","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":610,"y":920,"wires":[]},{"id":"80d0239e1eb4d49e","type":"inject","z":"996af57394f7db28","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":270,"y":980,"wires":[["1c99653c2d575fd0"]]},{"id":"1c99653c2d575fd0","type":"change","z":"996af57394f7db28","name":"","rules":[{"t":"set","p":"url","pt":"msg","to":"https://<HOSTNAME_OR_IP>/manage/api/v1/io/local/mmp/address/0xF01C8468?type=float&length=2","tot":"str"},{"t":"set","p":"headers","pt":"msg","to":"{\"apiKey\":\"<YOUR_API_KEY>\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":980,"wires":[["49312fcf77b75107"]]},{"id":"49312fcf77b75107","type":"http request","z":"996af57394f7db28","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"7e4813585b6be2bf","persist":false,"proxy":"","authType":"","x":630,"y":980,"wires":[["ebd55fbbc824a85e"]]},{"id":"ebd55fbbc824a85e","type":"debug","z":"996af57394f7db28","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":790,"y":980,"wires":[]},{"id":"7e4813585b6be2bf","type":"tls-config","name":"localhost","cert":"","key":"","ca":"","certname":"","keyname":"","caname":"","servername":"","verifyservercert":false,"alpnprotocol":""}]
If you have any questions, or if you end up using this in one of your applications just drop a line in the thread below, and as always happy coding!