0-10V Output Endnode unexpected answer on Read

I can set voltage on the endnode as expected, using e.g.
0xaa,0x06,0x35,0x0E,0x01,0x01,0x0F,0x61,0x65

Sets channel one voltage to 10v, and responds as expected:
0xaa,0x02,0x0f,0x61,0x1c

However, if I send the command to read channel one:
0xaa,0x04,0x35,0x0e,0x01,0x01,0xf3

I only get back 0x55 as a response… (or, encoded, 0xaa,0x01,0x55,0x00)

Same thing checking channels 2 and 3:
0xaa,0x04,0x35,0x0e,0x02,0x03,0xf6

only returns 0xaa,0x01,0x55,0x00.

Doc used: https://ncd.io/0-10v-output-dac-usb-wireless-endnode/

Edit:
I modified Alpha Station to add a Read State button, and observed the same issue. Using NCDLib.Enterprise.Device.PR53_14.ReadInputs only returns 55.

PR53_14 ReadInputs also has a mandatory “Scale” variable for the 35 0E func, which the docs above do not. Something appears to be wrong here.


ScaleNone

53, 14 ofc being 0x35, 0x0e in hex.

Being able to read state on startup is pretty damn important, so this is extremely breaking.

EEProm read was the only way I could get it to work; docs probably need updating?

Working node-red flow to get current values from a 0-10V endnode:

[{"id":"49309f71.766f6","type":"tab","label":"ASM1-5 0-10V Read","disabled":false,"info":""},{"id":"7937084d.f023b8","type":"ncd-gateway-node","z":"49309f71.766f6","name":"Gateway","connection":"3a674906.5b9e76","unknown_devices":true,"outputs":2,"x":668,"y":108,"wires":[["aaf672d.c4cfc9"],["e7d5726d.b13aa","aaf672d.c4cfc9"]]},{"id":"c8408ef2.58339","type":"function","z":"49309f71.766f6","name":"Read All 0-10V Controllers","func":"msg.payload = {};\nmsg.payload.data = [0xfe,0x34,0x1d,0xb0,0x10];\nmsg.payload.address = \"00:00:00:00:00:00:FF:FF\"; // broadcast\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":382,"y":105,"wires":[["e2971ca2.3e749"]]},{"id":"e7d5726d.b13aa","type":"function","z":"49309f71.766f6","name":"Is Return?","func":"// only continue if this is a 16 bit response\nif (msg.payload.data.length != 19)\n    return null\nif (msg.payload.data[0] != 0xaa || msg.payload.data[1] != 0x10)\n    return null;\n    \n// compose the result msg\nmsg.payload.addr = msg.payload.addr;\nmsg.payload.sensor_data = {};\nmsg.payload.sensor_data.pr53_14_Output_1 = (msg.payload.data[2] * 256) + msg.payload.data[3];\nmsg.payload.sensor_data.pr53_14_Output_2 = (msg.payload.data[4] * 256) + msg.payload.data[5];\nmsg.payload.sensor_data.pr53_14_Output_3 = (msg.payload.data[6] * 256) + msg.payload.data[7];\nmsg.payload.sensor_data.pr53_14_Output_4 = (msg.payload.data[8] * 256) + msg.payload.data[9];\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":709.5,"y":199,"wires":[["aaf672d.c4cfc9"]]},{"id":"aaf672d.c4cfc9","type":"debug","z":"49309f71.766f6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":950.5,"y":202,"wires":[]},{"id":"7d44e897.142798","type":"inject","z":"49309f71.766f6","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":121.5,"y":107,"wires":[["c8408ef2.58339"]]},{"id":"e2971ca2.3e749","type":"function","z":"49309f71.766f6","name":"doNcdEncode","func":"var command = msg.payload.data;\ncommand.unshift(0xAA, command.length);\nvar sum = 0x00;\nfor(i = 0; i < command.length; i++){\n    sum+=command[i];\n}\ncommand.push(sum&0xFF);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":412,"y":204,"wires":[["7937084d.f023b8"]]},{"id":"3a674906.5b9e76","type":"ncd-gateway-config","name":"","comm_type":"serial","ip_address":"","tcp_port":"2101","port":"/dev/ttyS1","baudRate":"115200","pan_id":"7FFF","rssi":false}]

edit: a few improvements to the output if anyone cares:

[{"id":"49309f71.766f6","type":"tab","label":"ASM1-5 0-10V Read","disabled":false,"info":""},{"id":"7937084d.f023b8","type":"ncd-gateway-node","z":"49309f71.766f6","name":"Gateway","connection":"3a674906.5b9e76","unknown_devices":true,"outputs":2,"x":634.0000190734863,"y":106.00000381469727,"wires":[[],["e7d5726d.b13aa"]]},{"id":"c8408ef2.58339","type":"function","z":"49309f71.766f6","name":"Broadcast for 0-10V Controller data","func":"msg.payload = {};\nmsg.payload.data = [0xfe,0x34,0x1d,0xb0,0x10];\nmsg.payload.address = \"00:00:00:00:00:00:FF:FF\"; // broadcast\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":343.00000762939453,"y":107.00000381469727,"wires":[["e2971ca2.3e749"]]},{"id":"e7d5726d.b13aa","type":"function","z":"49309f71.766f6","name":"decodeASM5-1","func":"var getFriendlyFromOutput = function(state) {\n    var percent;\n    if (state == 0)\n        percent = 0;\n    else\n        percent = state * 103.99 / 4095;\n        \n    if (percent > 90) {\n        return \"ON\";\n    } else if (percent < 30) {\n        return \"OFF\";\n    } else {\n        return Math.round(percent) + \"%\";\n    }\n}\n\nvar getPercentFromOutput = function(state) {\n    var percent;\n    if (state == 0)\n        percent = 0;\n    else\n        percent = state * 103.99 / 4095;\n        \n    return Math.round(percent);\n}\n    \n\n// only continue if this is a 16 bit response (fram read)\nif (msg.payload.data.length != 19 ||\n    msg.payload.data[0] != 0xaa || \n    msg.payload.data[1] != 0x10\n)\n    return null;\n    \n// compose the result msg\nmsg.payload.addr = msg.payload.addr;\nmsg.payload.sensor_data = {};\nmsg.payload.sensor_data.pr53_14_Raw_1 = (msg.payload.data[2] * 256) + msg.payload.data[3];\nmsg.payload.sensor_data.pr53_14_Raw_2 = (msg.payload.data[4] * 256) + msg.payload.data[5];\nmsg.payload.sensor_data.pr53_14_Raw_3 = (msg.payload.data[6] * 256) + msg.payload.data[7];\nmsg.payload.sensor_data.pr53_14_Raw_4 = (msg.payload.data[8] * 256) + msg.payload.data[9];\n\nmsg.payload.sensor_data.pr53_14_Voltage_1 = msg.payload.sensor_data.pr53_14_Raw_1 * (10.3992 / 4095);\nmsg.payload.sensor_data.pr53_14_Voltage_2 = msg.payload.sensor_data.pr53_14_Raw_2 * (10.3992 / 4095);\nmsg.payload.sensor_data.pr53_14_Voltage_3 = msg.payload.sensor_data.pr53_14_Raw_3 * (10.3992 / 4095);\nmsg.payload.sensor_data.pr53_14_Voltage_4 = msg.payload.sensor_data.pr53_14_Raw_4 * (10.3992 / 4095);\n\nmsg.payload.sensor_data.pr53_14_Percent_1 = getPercentFromOutput(msg.payload.sensor_data.pr53_14_Raw_1);\nmsg.payload.sensor_data.pr53_14_Percent_2 = getPercentFromOutput(msg.payload.sensor_data.pr53_14_Raw_2);\nmsg.payload.sensor_data.pr53_14_Percent_3 = getPercentFromOutput(msg.payload.sensor_data.pr53_14_Raw_3);\nmsg.payload.sensor_data.pr53_14_Percent_4 = getPercentFromOutput(msg.payload.sensor_data.pr53_14_Raw_4);\n\nmsg.payload.sensor_data.pr53_14_Friendly_1 = getFriendlyFromOutput(msg.payload.sensor_data.pr53_14_Raw_1);\nmsg.payload.sensor_data.pr53_14_Friendly_2 = getFriendlyFromOutput(msg.payload.sensor_data.pr53_14_Raw_2);\nmsg.payload.sensor_data.pr53_14_Friendly_3 = getFriendlyFromOutput(msg.payload.sensor_data.pr53_14_Raw_3);\nmsg.payload.sensor_data.pr53_14_Friendly_4 = getFriendlyFromOutput(msg.payload.sensor_data.pr53_14_Raw_4);\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":651.5000190734863,"y":179.0000057220459,"wires":[["aaf672d.c4cfc9"]]},{"id":"aaf672d.c4cfc9","type":"debug","z":"49309f71.766f6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":867.5000267028809,"y":179.0000057220459,"wires":[]},{"id":"7d44e897.142798","type":"inject","z":"49309f71.766f6","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":121.5,"y":107,"wires":[["c8408ef2.58339"]]},{"id":"e2971ca2.3e749","type":"function","z":"49309f71.766f6","name":"doNcdEncode","func":"var command = msg.payload.data;\ncommand.unshift(0xAA, command.length);\nvar sum = 0x00;\nfor(i = 0; i < command.length; i++){\n    sum+=command[i];\n}\ncommand.push(sum&0xFF);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":400.00001525878906,"y":180.0000057220459,"wires":[["7937084d.f023b8"]]},{"id":"3a674906.5b9e76","type":"ncd-gateway-config","name":"","comm_type":"serial","ip_address":"","tcp_port":"2101","port":"/dev/ttyS1","baudRate":"115200","pan_id":"7FFF","rssi":false}]
1 Like

@jacob @ryan1 can you look into this

Unfortunately I have not worked closely with the API for endNode. @ryan1 or @TravisE_NCD_Technica may have more insight.

HI, the “ReadInputs” function shown is not in use, if you look above the code clipping shown, it has zero references. This means this section of code is not currently in play. The very first thing the ASM1-4/PR54-14 code does (shown in the endNode folder) is read the state of all outputs and update the sliders/data to display output values. All data is permanently stored in FRAM so it is saved even if power is lost. There is a FRAM memory control panel when you first run Alpha Station, it also shows how to read bytes out of the on-board memory. Memory is linear, so you simply pass the function a memory location and it will return the state of outputs. You can read one channel output or all channel outputs if needed. Please use Alpha Station software, examine FRAM memory starting at location 7000. This should point you to the memory location you need to force a read of the current output state. Again, this is done automatically when you load the PR54-14 control panel. Hope this helps.
Ryan

I already found the solution by considering the alpha station code, and made a node-red flow as posted above… But your documentation and library clearly need updating, so someone else doesn’t waste their time. I’ll make a pull request on the library if I get a chance in the next few days.

Edit: I don’t see a repo for alpha station, does NCD keep that internal for a reason?

Working ReadOutputs function for PR53_14 (To replace the broken ReadInputs func):

                Public Shared Function ReadOutputs(ByRef ncdObj As NCDEnterprise.NCDController, StartChannel As Integer, StopChannel As Integer)
                    If StartChannel < 1 Then StartChannel = 1
                    If StartChannel > 4 Then StartChannel = 4
                    If StopChannel < 1 Then StopChannel = 1
                    If StopChannel > 4 Then StopChannel = 4
                    Dim ByteCount As Integer = (StopChannel - StartChannel + 1) * 2
                    ' we only need 8 bytes maximum, but 16 bytes is always returned
                    NCDLib.WriteBytesAPI(ncdObj, True, 254, 52, 29, 176, 16)
                    Dim Result As Byte() = NCDLib.ReadBytesAPI(ncdObj, True, ByteCount)
                    Dim Ret(ByteCount - 1) As Byte
                    Array.Copy(Result, (StartChannel - 1) * 2, Ret, 0, ByteCount)
                    Return Ret
                End Function

And I added a Read State button to frmPR53_14.vb:

    Private Sub ReadState_Click(sender As Object, e As EventArgs) Handles ReadState.Click
        Dim result As Byte() = NCDLib.Enterprise.Device.PR53_14.ReadOutputs(NCDComponent1, 1, 4)
        GetTXRXData()
        DAC1.Value = NCDLib.Safe.Limit_Value(NCDLib.Math.MSBLSB(result(0), result(1)), 0, 4095)
        DAC2.Value = NCDLib.Safe.Limit_Value(NCDLib.Math.MSBLSB(result(2), result(3)), 0, 4095)
        DAC3.Value = NCDLib.Safe.Limit_Value(NCDLib.Math.MSBLSB(result(4), result(5)), 0, 4095)
        DAC4.Value = NCDLib.Safe.Limit_Value(NCDLib.Math.MSBLSB(result(6), result(7)), 0, 4095)
    End Sub

I think this example makes it a lot more clear how to interact with these devices. Docs should be updated too ofc.