Recently i have changed implementation on Raspberry Pi side. Now it is only using Node-Red dashboard in SignalK server without using Kplex (so, now it is working in Openplotter2 too)
the arduino and node-red code in the testing and debugging state... (just as proof of concept, but working at table perfectly : )
Code:
[
{
"id": "9a419ebb.65893",
"type": "switch",
"z": "ba70a55e.0d29a8",
"name": "Filter XXX to pypilot and another NMEA's to signalk",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "regex",
"v": "^(?=...*XXX)",
"vt": "str",
"case": false
},
{
"t": "regex",
"v": "^\\$",
"vt": "str",
"case": false
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 527,
"y": 388,
"wires": [
[
"195f2de4.b63742"
],
[
"fdd29b96.b7f2a8"
],
[]
],
"inputLabels": [
"Input"
],
"outputLabels": [
"XXX",
"Otherwise",
""
]
},
{
"id": "9f6be0e6.5389b",
"type": "tcp out",
"z": "ba70a55e.0d29a8",
"host": "localhost",
"port": "21311",
"beserver": "client",
"base64": false,
"end": false,
"name": "",
"x": 1184,
"y": 362,
"wires": []
},
{
"id": "195f2de4.b63742",
"type": "function",
"z": "ba70a55e.0d29a8",
"name": "Parse to Pypilot internal Signalk",
"func": "var th = msg.payload.replace(\"\\$APXXX,\",\"\").slice(0, -5).split(\",\");\n\nmsg.payload = '{\\\"name\\\": \\\"'+th[0]+'\\\", \\\"method\\\": \\\"set\\\", \\\"value\\\": '+th[1]+'}\\n'\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 875,
"y": 328,
"wires": [
[
"9f6be0e6.5389b"
]
]
},
{
"id": "ebba1cdb.316b6",
"type": "tcp request",
"z": "ba70a55e.0d29a8",
"server": "localhost",
"port": "21311",
"out": "sit",
"splitc": " ",
"name": "",
"x": 350,
"y": 68,
"wires": [
[
"dcd047b9.925a68"
]
]
},
{
"id": "ebddce32.852eb",
"type": "inject",
"z": "ba70a55e.0d29a8",
"name": "",
"topic": "",
"payload": "[123,34,110,97,109,101,34,58,32,34,105,109,117,46,104,101,97,100,105,110,103,95,108,111,119,112,97,115,115,34,44,32,34,109,101,116,104,111,100,34,58,32,34,103,101,116,34,125,13,10,123,34,110,97,109,101,34,58,32,34,97,112,46,104,101,97,100,105,110,103,95,99,111,109,109,97,110,100,34,44,32,34,109,101,116,104,111,100,34,58,32,34,103,101,116,34,125,13,10,123,34,110,97,109,101,34,58,32,34,97,112,46,101,110,97,98,108,101,100,34,44,32,34,109,101,116,104,111,100,34,58,32,34,103,101,116,34,125,13,10,123,34,110,97,109,101,34,58,32,34,115,101,114,118,111,46,115,116,97,116,101,34,44,32,34,109,101,116,104,111,100,34,58,32,34,103,101,116,34,125,13,10,123,34,110,97,109,101,34,58,32,34,97,112,46,109,111,100,101,34,44,32,34,109,101,116,104,111,100,34,58,32,34,103,101,116,34,125,13,10,123,34,110,97,109,101,34,58,32,34,105,109,117,46,104,101,97,100,105,110,103,95,108,111,119,112,97,115,115,34,44,32,34,109,101,116,104,111,100,34,58,32,34,119,97,116,99,104,34,125,13,10,123,34,110,97,109,101,34,58,32,34,97,112,46,104,101,97,100,105,110,103,95,99,111,109,109,97,110,100,34,44,32,34,109,101,116,104,111,100,34,58,32,34,119,97,116,99,104,34,125,13,10,123,34,110,97,109,101,34,58,32,34,97,112,46,101,110,97,98,108,101,100,34,44,32,34,109,101,116,104,111,100,34,58,32,34,119,97,116,99,104,34,125,13,10,123,34,110,97,109,101,34,58,32,34,115,101,114,118,111,46,115,116,97,116,101,34,44,32,34,109,101,116,104,111,100,34,58,32,34,119,97,116,99,104,34,125,13,10,123,34,110,97,109,101,34,58,32,34,97,112,46,109,111,100,101,34,44,32,34,109,101,116,104,111,100,34,58,32,34,119,97,116,99,104,34,125,13,10]",
"payloadType": "bin",
"repeat": "30",
"crontab": "",
"once": true,
"onceDelay": "1",
"x": 140,
"y": 69,
"wires": [
[
"ebba1cdb.316b6"
]
]
},
{
"id": "dcd047b9.925a68",
"type": "function",
"z": "ba70a55e.0d29a8",
"name": "",
"func": "msg.payload = msg.payload.toString();\nreturn msg;\n",
"outputs": 1,
"noerr": 0,
"x": 533,
"y": 68,
"wires": [
[
"42c84588.bc3fdc"
]
]
},
{
"id": "8075876f.6fb518",
"type": "json",
"z": "ba70a55e.0d29a8",
"name": "",
"property": "payload",
"action": "obj",
"pretty": false,
"x": 1005,
"y": 68,
"wires": [
[
"51e6b603.327568"
]
]
},
{
"id": "d0d13719.18e238",
"type": "change",
"z": "ba70a55e.0d29a8",
"name": "",
"rules": [
{
"t": "change",
"p": "payload",
"pt": "msg",
"from": "name",
"fromt": "str",
"to": "id",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 835,
"y": 68,
"wires": [
[
"8075876f.6fb518"
]
]
},
{
"id": "51e6b603.327568",
"type": "function",
"z": "ba70a55e.0d29a8",
"name": "Form $APDBG NMEA",
"func": "var heading = context.get(\"heading\") || 0; \nvar heading_command = context.get(\"heading_command\") || 0; \nvar ap_enabled = context.get(\"ap_enabled\") || \"\";\nvar ap_mode = context.get(\"ap_mode\") || \"\"; \nvar servo_state = context.get(\"servo_state\") || \"\"; \n\nif (msg.payload.hasOwnProperty(\"imu.heading_lowpass\")) {\n heading = msg.payload[\"imu.heading_lowpass\"].value; \n context.set(\"heading\", heading); \n}\n\nif (msg.payload.hasOwnProperty(\"ap.heading_command\")) {\n heading_command = msg.payload[\"ap.heading_command\"].value; \n context.set(\"heading_command\", heading_command); \n}\n\nif (msg.payload.hasOwnProperty(\"ap.enabled\")) {\n if (msg.payload[\"ap.enabled\"].value===false) ap_enabled=\"False\";\n if (msg.payload[\"ap.enabled\"].value===true) ap_enabled=\"True\"; \n context.set(\"ap_enabled\", ap_enabled); \n}\n\nif (msg.payload.hasOwnProperty(\"ap.mode\")) {\n ap_mode = msg.payload[\"ap.mode\"].value; \n context.set(\"ap_mode\", ap_mode); \n}\n\nif (msg.payload.hasOwnProperty(\"servo.state\")) {\n servo_state = msg.payload[\"servo.state\"].value; \n context.set(\"servo_state\", servo_state); \n}\nvar today = new Date();\n\nfunction addZeroBefore(n) {\n return (n < 10 ? '0' : '') + n;\n}\n\n\n\nmsg.payload=\"$APDBG,\"+Math.trunc(heading)+\",M,\"+ap_enabled+\",\"+heading_command+\",\"+servo_state+\",\"+ap_mode+\",\"+addZeroBefore(today.getHours())+addZeroBefore(today.getMinutes())+\"*00\"+'\\r\\n';\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 1195,
"y": 68,
"wires": [
[
"1cf49820.97cf98"
]
]
},
{
"id": "42c84588.bc3fdc",
"type": "split",
"z": "ba70a55e.0d29a8",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": true,
"addname": "",
"x": 665,
"y": 68,
"wires": [
[
"d0d13719.18e238"
]
]
},
{
"id": "1cf49820.97cf98",
"type": "delay",
"z": "ba70a55e.0d29a8",
"name": "",
"pauseType": "rate",
"timeout": "1",
"timeoutUnits": "seconds",
"rate": "2",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": true,
"x": 581,
"y": 150,
"wires": [
[
"441c49c4.6c2d68"
]
]
},
{
"id": "441c49c4.6c2d68",
"type": "serial out",
"z": "ba70a55e.0d29a8",
"name": "",
"serial": "e7818a0.af4be78",
"x": 885,
"y": 228,
"wires": []
},
{
"id": "b02a0a9a.5d0a18",
"type": "serial in",
"z": "ba70a55e.0d29a8",
"name": "",
"serial": "e7818a0.af4be78",
"x": 169,
"y": 389,
"wires": [
[
"9a419ebb.65893"
]
]
},
{
"id": "58ec5d5a.5bdc04",
"type": "tcp in",
"z": "ba70a55e.0d29a8",
"name": "",
"server": "client",
"host": "localhost",
"port": "10110",
"datamode": "stream",
"datatype": "utf8",
"newline": "\\n",
"topic": "",
"base64": false,
"x": 155,
"y": 228,
"wires": [
[
"27887b9f.7527d4"
]
]
},
{
"id": "27887b9f.7527d4",
"type": "switch",
"z": "ba70a55e.0d29a8",
"name": "Filter RMC NMEA only",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "regex",
"v": "^(?=...*RMC)",
"vt": "str",
"case": false
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 375,
"y": 228,
"wires": [
[
"441c49c4.6c2d68"
],
[]
],
"inputLabels": [
"Input"
],
"outputLabels": [
"OK",
""
]
},
{
"id": "fdd29b96.b7f2a8",
"type": "udp out",
"z": "ba70a55e.0d29a8",
"name": "",
"addr": "localhost",
"iface": "",
"port": "10110",
"ipv": "udp4",
"outport": "",
"base64": false,
"multicast": "false",
"x": 908,
"y": 438,
"wires": []
},
{
"id": "e7818a0.af4be78",
"type": "serial-port",
"z": "",
"serialport": "/dev/ttyUSB1",
"serialbaud": "9600",
"databits": "8",
"parity": "none",
"stopbits": "1",
"newline": "\\n",
"bin": "false",
"out": "char",
"addchar": false
}
]
The principle is to form and send to arduino fake NMEA with information from pypilot and receive fake NMEA from arduino with commands that are passing for pypilot...