RIO to USB data logging

A) Is it possible and
B) Is there a “how to” somewhere?

I am looking at using the RIO EMU to monitor and log power data as a stand-alone unit. Can I use a thumb drive as a data-store to increase the storage capacity/data trends? I assume Node-Red???

Thank you!

Yes, Yes and Yes.
Just a bit slammed but your right.
We can do it.
We described it.
Yes, via Node-RED.

On pins and needles waiting for the link. :wink:

First result in Google.

I honestly did search here on the opto site and didn’t find anything (maybe I’m just blind and can’t read :man_shrugging:). It certainly helps when you know what terms to search for.

That’s true. Sorry I was in such a rush yesterday.

Depending on what you are looking to log analog values out of the EMU, then you can simply use a write node that points to the USB stick.

You should keep in mind pausing the logging when the stick is unmounted. There is an API call to unmount the stick and you should have the user do that when they want the data. (ie, take one stick out and plug in the next sort of thing). ie, you should not just jerk the stick out.
I think that’s about the biggest thing to keep in mind as you develop your solution… there will be some user interface required which can be done via the Node-RED dashboard if you like.

If you need a hand to flesh any of this logger out, just ask. Terry and I have both done a bit around it.

I finally got around to this. Here’s my starting point:

[
    {
        "id": "00d6db422d0210d3",
        "type": "tab",
        "label": "Phase A",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "21bfe22916dd246d",
        "type": "inject",
        "z": "00d6db422d0210d3",
        "name": "",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "1",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 110,
        "y": 260,
        "wires": [
            [
                "2671615dc599a099",
                "a0c0acdc395c52b2",
                "5102b38812ddb616",
                "c1196323a7277dbd",
                "4821646f570cc36e",
                "f1b18003614a577b",
                "adf9285e6ed56a69"
            ]
        ]
    },
    {
        "id": "c45224d718b59e08",
        "type": "debug",
        "z": "00d6db422d0210d3",
        "name": "PHASE A",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 580,
        "y": 80,
        "wires": []
    },
    {
        "id": "2671615dc599a099",
        "type": "groov-io-read",
        "z": "00d6db422d0210d3",
        "device": "bb3ded0f0b40af19",
        "dataType": "channel-analog",
        "moduleIndex": "0",
        "channelIndex": "0",
        "mmpAddress": "0xF0D81000",
        "mmpType": "int32",
        "mmpLength": "1",
        "mmpEncoding": "ascii",
        "value": "",
        "valueType": "msg.payload",
        "itemName": "",
        "name": "Phase A Voltage",
        "x": 320,
        "y": 80,
        "wires": [
            [
                "c45224d718b59e08",
                "e972eedb202fa4d9"
            ]
        ]
    },
    {
        "id": "a0c0acdc395c52b2",
        "type": "groov-io-read",
        "z": "00d6db422d0210d3",
        "device": "bb3ded0f0b40af19",
        "dataType": "channel-analog",
        "moduleIndex": "0",
        "channelIndex": "1",
        "mmpAddress": "0xF0D81000",
        "mmpType": "int32",
        "mmpLength": "1",
        "mmpEncoding": "ascii",
        "value": "",
        "valueType": "msg.payload",
        "itemName": "",
        "name": "Phase A Current",
        "x": 320,
        "y": 120,
        "wires": [
            [
                "c45224d718b59e08",
                "e972eedb202fa4d9"
            ]
        ]
    },
    {
        "id": "5102b38812ddb616",
        "type": "groov-io-read",
        "z": "00d6db422d0210d3",
        "device": "bb3ded0f0b40af19",
        "dataType": "channel-analog",
        "moduleIndex": "0",
        "channelIndex": "8",
        "mmpAddress": "0xF0D81000",
        "mmpType": "int32",
        "mmpLength": "1",
        "mmpEncoding": "ascii",
        "value": "",
        "valueType": "msg.payload",
        "itemName": "",
        "name": "Phase A Frequency",
        "x": 330,
        "y": 280,
        "wires": [
            [
                "c45224d718b59e08",
                "e972eedb202fa4d9"
            ]
        ]
    },
    {
        "id": "f1b18003614a577b",
        "type": "groov-io-read",
        "z": "00d6db422d0210d3",
        "device": "bb3ded0f0b40af19",
        "dataType": "channel-analog",
        "moduleIndex": "0",
        "channelIndex": "7",
        "mmpAddress": "0xF0D81000",
        "mmpType": "int32",
        "mmpLength": "1",
        "mmpEncoding": "ascii",
        "value": "",
        "valueType": "msg.payload",
        "itemName": "",
        "name": "Phase A Peak Current",
        "x": 340,
        "y": 240,
        "wires": [
            [
                "c45224d718b59e08",
                "e972eedb202fa4d9"
            ]
        ]
    },
    {
        "id": "4821646f570cc36e",
        "type": "groov-io-read",
        "z": "00d6db422d0210d3",
        "device": "bb3ded0f0b40af19",
        "dataType": "channel-analog",
        "moduleIndex": "0",
        "channelIndex": "6",
        "mmpAddress": "0xF0D81000",
        "mmpType": "int32",
        "mmpLength": "1",
        "mmpEncoding": "ascii",
        "value": "",
        "valueType": "msg.payload",
        "itemName": "",
        "name": "Phase A Peak Voltage",
        "x": 340,
        "y": 200,
        "wires": [
            [
                "c45224d718b59e08",
                "e972eedb202fa4d9"
            ]
        ]
    },
    {
        "id": "c1196323a7277dbd",
        "type": "groov-io-read",
        "z": "00d6db422d0210d3",
        "device": "bb3ded0f0b40af19",
        "dataType": "channel-analog",
        "moduleIndex": "0",
        "channelIndex": "5",
        "mmpAddress": "0xF0D81000",
        "mmpType": "int32",
        "mmpLength": "1",
        "mmpEncoding": "ascii",
        "value": "",
        "valueType": "msg.payload",
        "itemName": "",
        "name": "Phase A PowerFactor",
        "x": 340,
        "y": 160,
        "wires": [
            [
                "c45224d718b59e08",
                "e972eedb202fa4d9"
            ]
        ]
    },
    {
        "id": "adf9285e6ed56a69",
        "type": "groov-io-read",
        "z": "00d6db422d0210d3",
        "device": "bb3ded0f0b40af19",
        "dataType": "channel-analog",
        "moduleIndex": "0",
        "channelIndex": "9",
        "mmpAddress": "0xF0D81000",
        "mmpType": "int32",
        "mmpLength": "1",
        "mmpEncoding": "ascii",
        "value": "",
        "valueType": "msg.payload",
        "itemName": "",
        "name": "Phase A Pwr@Fund.Freq",
        "x": 350,
        "y": 320,
        "wires": [
            [
                "c45224d718b59e08",
                "e972eedb202fa4d9"
            ]
        ]
    },
    {
        "id": "224e8ecf7984e59b",
        "type": "file",
        "z": "00d6db422d0210d3",
        "name": "Phase A",
        "filename": "/run/media/sda2/PhaseA.csv",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "false",
        "encoding": "none",
        "x": 1040,
        "y": 140,
        "wires": [
            []
        ]
    },
    {
        "id": "611515608b6d4b4c",
        "type": "csv",
        "z": "00d6db422d0210d3",
        "name": "",
        "sep": ",",
        "hdrin": true,
        "hdrout": "once",
        "multi": "mult",
        "ret": "\\r\\n",
        "temp": "Voltage, Current, Power Factor, Peak Voltage, Peak Current, Frequency, Pwr@Freq",
        "skip": "0",
        "strings": true,
        "include_empty_strings": "",
        "include_null_values": "",
        "x": 830,
        "y": 140,
        "wires": [
            [
                "25938cad784dd6c2",
                "224e8ecf7984e59b"
            ]
        ]
    },
    {
        "id": "e972eedb202fa4d9",
        "type": "join",
        "z": "00d6db422d0210d3",
        "name": "",
        "mode": "custom",
        "build": "array",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": false,
        "timeout": "",
        "count": "7",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "",
        "reduceFixup": "",
        "x": 630,
        "y": 140,
        "wires": [
            [
                "099294c8f9d4e4b2",
                "611515608b6d4b4c"
            ]
        ]
    },
    {
        "id": "099294c8f9d4e4b2",
        "type": "debug",
        "z": "00d6db422d0210d3",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 830,
        "y": 80,
        "wires": []
    },
    {
        "id": "25938cad784dd6c2",
        "type": "debug",
        "z": "00d6db422d0210d3",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1010,
        "y": 80,
        "wires": []
    },
    {
        "id": "bb3ded0f0b40af19",
        "type": "groov-io-device",
        "address": "localhost",
        "msgQueueFullBehavior": "DROP_OLD"
    }
]
[power to csv flows.zip|attachment](upload://r9752sig2mySoAgczYIuxxpDrWA.zip) (1.4 KB)

The problem I am having is the values are occasionally getting out of sync so the csv file values are not always placed in the correct columns. Where can I fix this/make it better? Also, how can I add a date/timestamp column?

Thank you!

Also,
Is there a way to read all of the RIO (GRV-R7-I1VAPM-3) i/o channels (64 total) as an array and use that to spit out a csv file?

This is totally normal behavior, Node-RED is built to handle messages asynchronously by default — they have a blog that goes into much more detail about that if you’re interested: Making flows asynchronous by default : Node-RED

The main takeaway is that I find it’s better to avoid the “get everything individually and combine” approach, and instead build up a message with values one at a time.
You can inject msg.payload as an empty array and fill each element one at a time, ending in a complete array in the exact same order every single time and avoid the join node entirely.


There are a few ways to tackle this, but the first thing that comes to mind would be to use the Manage REST API in a HTTP request node. The endpoint to hit would be: https://hostname/manage/api/v1/io/local/modules/0/analog/values?channels=64

Does that do the trick for your application?

EDIT: The response is an array, but you will need to do a little bit of massaging to extract just the values and drop the quality error. The easiest way would be a little function node loop.

Can you expand on this? Thank you!

Each groov-io read node has Value field that can be set to msg.___
So as you go through the chain of nodes save to msg.payload[0], the next to msg.payload[1], then msg.payload[2], and so on…

At the end your msg.payload is an array with each element holding the read values in the same order that they’re wired in. To start it off with an empty array set the interval inject node to send msg.payload with the JSON value “[]” for an empty array.

1 Like

Thank you! That was what I was needing.