I didn't know about the signalk-autopilot plugin, this saves a lot of time.
What I started doing was creating a NodeRed dashboard with buttons, which when pressed would trigger Marco Bergman's script.
Code:
[{"id":"69638511.9f0fdc","type":"tab","label":"seatalk tiller pilot remote","disabled":false,"info":""},{"id":"cbb1ef69.90424","type":"ui_button","z":"69638511.9f0fdc","name":"","group":"966da9df.2c4648","order":0,"width":0,"height":0,"passthru":true,"label":"AUTO","tooltip":"Enable autopilot","color":"","bgcolor":"","icon":"","payload":"2","payloadType":"num","topic":"","x":470,"y":340,"wires":[["3f72a40.aac515c"]]},{"id":"3f72a40.aac515c","type":"python-function","z":"69638511.9f0fdc","name":"write seatalk","func":"#!/usr/bin/env python\n\nimport RPi.GPIO as GPIO\nimport time\nimport serial\nimport os\n\n# ST2000 remote control with Raspberry Pi 2\n# Marco Bergman 2019\n#\n# +5V (01) ---------------------+\n# |\n# +++\n# 2 x NPN | |\n# 2 x 10k | |\n# +++ c------o SEATALK\n# | | /\n# c-----+----b|<\n# +---+ | / | \\\n# GPIO14 (08) ----+ +--b|< e\n# +---+ | \\ |\n# e |\n# | |\n# GND (03) ---------------+--------------+\n\n# GPIO constants: connect switches to ground on these GPIO pins\n#AU = 24 # Auto GPIO 24 (pin# 18) BROWN\n#M1 = 22 # Minus 1 GPIO 22 (pin# 15) ORANGE\n#M10 = 27 # Minus 10 GPIO 27 (pin# 13) GREEN\n#P10 = 17 # Plus 10 GPIO 17 (pin# 11) BLUE\n#P1 = 18 # Plus 1 GPIO 18 (pin# 12) YELLOW\n#SB = 23 # Standby GPIO 23 (pin# 16) WHITE\nBUZZER = 25 # Buzzer GPIO 25 (pin# 22) WHITE\n\nnode.log(\"test\")\n\nMODE_NORMAL = 1\nMODE_STEER_INTO_WIND = 2\n\ndef write_seatalk (xx, yy):\n# thanks to http://www.thomasknauf.de/seatalk.htm\n with serial.Serial() as ser:\n ser.baudrate = 4800\n ser.port = '/dev/serial0'\n ser.stopbits=serial.STOPBITS_ONE\n ser.bytesize=serial.EIGHTBITS\n\n ser.open()\n ser.parity = serial.PARITY_MARK\n ser.write(b'\\x86')\n ser.parity = serial.PARITY_SPACE\n ser.write(b'\\x11' + chr(int(xx, 16)) + chr(int(yy, 16)))\n ser.close()\n \n \nangle = 0\nprevious_angle = 0\n\ndef send_command(command):\n global angle\n print \"command=\"+str(command)\n\n if command == -10:\n write_seatalk(\"06\", \"F9\")\n if command == -1:\n write_seatalk(\"05\", \"FA\")\n if command == +1:\n write_seatalk(\"07\", \"F8\")\n if command == +10:\n write_seatalk(\"08\", \"F7\")\n angle = angle - command\n\n\ndef steer_to_angle(angle_to_steer_to):\n global angle\n angle = angle_to_steer_to\n\n while angle != 0:\n if angle <= -10:\n send_command(-10)\n if angle > -10 and angle < 0:\n send_command(-1)\n if angle > 0 and angle < 10:\n send_command(+1)\n if angle >= 10:\n send_command(+10)\n\ndef steer_into_wind():\n global previous_angle\n\n try:\n with open('/tmp/AWA', 'r') as myfile:\n line = myfile.read().replace(\"\\n\", \"\")\n awa = int(line)\n except:\n awa = 0\n\n angle=(awa+180) % 360-180\n previous_angle = angle\n node.log(\"awa=\" + str(awa) + \"; angle=\" + str(angle))\n\n steer_to_angle(angle)\n\n\ndef steer_previous_angle():\n global previous_angle\n\n steer_to_angle(-previous_angle)\n \nGPIO.setmode(GPIO.BCM)\n#GPIO.setup(SB, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Stand By: 1\n#GPIO.setup(AU, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Auto: 2\n#GPIO.setup(P1, GPIO.IN, pull_up_down=GPIO.PUD_UP) # +1: 4\n#GPIO.setup(P10, GPIO.IN, pull_up_down=GPIO.PUD_UP) # +10: 8\n#GPIO.setup(M10, GPIO.IN, pull_up_down=GPIO.PUD_UP) # -10: 16\n#GPIO.setup(M1, GPIO.IN, pull_up_down=GPIO.PUD_UP) # -1: 32\nGPIO.setup(BUZZER, GPIO.OUT) \n\n \ndef beep(b):\n if ( b == 1 ):\n GPIO.output(BUZZER, 1)\n time.sleep(0.1)\n GPIO.output(BUZZER, 0)\n if ( b == 2 ):\n GPIO.output(BUZZER, 1)\n time.sleep(0.2)\n GPIO.output(BUZZER, 0)\n if ( b == 3 ):\n beep(1)\n time.sleep(0.1)\n beep(1)\n\n\nbeep(3)\n\nmode=MODE_NORMAL\n\nwhile 1:\n\n\tkey=msg['payload']\n\n\t# Stand by\n\tif (key == 1):\n\t\t\tnode.log(\"Stand by (\" + str(key) + \")\")\n\t\t\tbeep(2)\n\t\t\twrite_seatalk(\"02\", \"FD\")\n\t\t\tmode = MODE_NORMAL\n\t# Auto\n\tif (key == 2 and mode == MODE_NORMAL):\n\t\t\tnode.log(\"Auto (\" + str(key) + \")\")\n\t\t\tbeep(1)\n\t\t\twrite_seatalk(\"01\", \"FE\")\n\t# Auto steer back\n\tif (key == 2 and mode == MODE_STEER_INTO_WIND):\n\t\t\tnode.log(\"Steer previous wind angle\")\n\t\t\tbeep(3)\n\t\t\tsteer_previous_angle()\n\t\t\tmode = MODE_NORMAL\n\n\t# +1\n\tif (key == 4):\n\t\t\tnode.log(\"+1 (\" + str(key) + \")\")\n\t\t\tbeep(1)\n\t\t\twrite_seatalk(\"07\", \"F8\")\n\t# +10\n\tif (key == 8):\n\t\t\tnode.log(\"+10 (\" + str(key) + \")\")\n\t\t\tbeep(2)\n\t\t\twrite_seatalk(\"08\", \"F7\")\n\t# -10\n\tif (key == 16):\n\t\t\tnode.log(\"-10 (\" + str(key) + \")\")\n\t\t\tbeep(2)\n\t\t\twrite_seatalk(\"06\", \"F9\")\n\t# -1\n\tif (key == 32):\n\t\t\tnode.log(\"-1 (\" + str(key) + \")\")\n\t\t\tbeep(1)\n\t\t\twrite_seatalk(\"05\", \"FA\")\n\n\t# Track -10 & +10\n\tif (key == 24):\n\t\t\tnode.log(\"Track (\" + str(key) + \")\")\n\t\t\tbeep(3)\n\t\t\twrite_seatalk(\"28\", \"D7\")\n\t# Tack Port -1 & -10\n\tif (key == 48):\n\t\t\tnode.log(\"Tack Port (\" + str(key) + \")\")\n\t\t\tbeep(3)\n\t\t\twrite_seatalk(\"21\", \"DE\")\n\t# Tack Starboard +1 & +10\n\tif (key == 12):\n\t\t\tnode.log(\"Tack Starboard (\" + str(key) + \")\")\n\t\t\tbeep(3)\n\t\t\twrite_seatalk(\"22\", \"DD\")\n\t# Toggle auto seastate +1 & -1\n\tif (key == 36):\n\t\t\tnode.log(\"Toggle auto seastate (\" + str(key) + \")\")\n\t\t\tbeep(3)\n\t\t\twrite_seatalk(\"20\", \"DF\")\n\n\tif (key == 3 and mode == MODE_NORMAL):\n\t\t\tnode.log(\"Steer into wind\")\n\t\t\tbeep(3)\n\t\t\tsteer_into_wind()\n\t\t\tmode = MODE_STEER_INTO_WIND","outputs":1,"x":640,"y":300,"wires":[[]]},{"id":"55bb2f92.c05b3","type":"ui_button","z":"69638511.9f0fdc","name":"","group":"966da9df.2c4648","order":1,"width":0,"height":0,"passthru":true,"label":"STANDBY","tooltip":"","color":"","bgcolor":"","icon":"","payload":"1","payloadType":"num","topic":"","x":450,"y":260,"wires":[["3f72a40.aac515c"]]},{"id":"63cd06d1.cc5018","type":"inject","z":"69638511.9f0fdc","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":300,"y":260,"wires":[["55bb2f92.c05b3"]]},{"id":"71191e8a.4a8df","type":"inject","z":"69638511.9f0fdc","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":300,"y":340,"wires":[["cbb1ef69.90424"]]},{"id":"966da9df.2c4648","type":"ui_group","z":"","name":"Müdür","tab":"2cac5f75.ceba6","order":1,"disp":true,"width":"6","collapse":true},{"id":"2cac5f75.ceba6","type":"ui_tab","z":"","name":"Monitor","icon":"dashboard","order":1,"disabled":false,"hidden":false}]
Mind you, this is still rough and probably full of bugs while I'm learning to use Python and NodeRed.
I got stuck last night on the fact I had to enable UART first, but openplotter warned me this was going to disable bluetooth (which I'd maybe need later).
I'm using an RPi 4, which should have 6 UARTs, so I need to investigate if I can use one of them without disabling bluetooth, as it's only disable when using UART0 I think.
But as Seatalk is a single-wire system, probably STALK_read.py will pick up the transmitted datagrams again?
With all the bits of info I have now, there must be a way for me to translate NMEA XTE messages, coming from OpenCPN, to Seatalk.