antipole2 / JavaScript_pi

JavaScript plugin for OpenCPN
GNU General Public License v3.0
2 stars 4 forks source link

Sending Signal K #78

Open antipole2 opened 11 months ago

antipole2 commented 11 months ago

It is desirable that the JavaScript plugin can be used to work with Signal K. Given the close relationship of both Signal K and JavaScript with JSON, this should be relatively easy to do and to use.

I do not have a Signal K set up and am away from my boat for the winter. So I am hoping SKS will work with me to establish this capability.

Sending Signal K messages This should be possible using WriteCommDriver but needs testing by a SignalK user.

antipole2 commented 8 months ago

@barcoMeCasa / Paddy.. please run this script and report output

writeCommDriver not yet implemented. That is what we will be working on but probably not that name. Please run the following script and report output:

handles = OCPNgetActiveDriverHandles();
for (h = 0; h < handles.length; h++){
    attributes = OCPNgetDriverAttributes(handles[h]);
    print(handles[h], "\n\t",attributes, "\n");
    }
boatybits commented 8 months ago

getting an error with that > image

From the diagnostic dump > [dump deleted now seen to compact thread - antipole]

antipole2 commented 8 months ago

@boatybits This is testing v3.0 Beta - not valid for earlier releases. If you want to play, you need the latest beta release from here. User guide here. This is work in progress! This present thread for Sending Signal K. For more general matters, there is a new discussion forum here.

boatybits commented 8 months ago

That's where I got the tarball, think I'm on the latest beta , javascript-v3.0.0-beta-a_msvc-wx32-10-win32.tar.gz I'll try again

edit Not sure what happened there, looks like same file but anyway, reloaded & turned off & on again, now we get >>

image

antipole2 commented 8 months ago

Ready to test sending SignalK.

You will need to download build beta b (or later) from my beta repository. Attached is a starter test script. This

  1. locates the handle for the SignalK port
  2. builds a SignalK object
  3. converts it to JSON
  4. writes it out using a new OCPNpushText(text, handle) API

The object built in my attached script is illustrative only - it presumably does not make SignalK sense. But it illustrates how you could do it. I have not been able to test the new OCPNpushText(text, handle) API for SignalK but if pushing through an NMEA0183 handle, it works correctly and does the same as OCPNpushNMEA0183(text, handle).

When sharing output or scripts, please paste text rather than screen-shotting, unless that is needed to show a particular thing. writeSignalK.js.zip

boatybits commented 8 months ago

plugin updated ok but the script crashes opencpn unless I comment out OCPNpushText(skJson, handle); Don't see anything in opencpn log, it looks the same as it does if booted up but the script not run.

antipole2 commented 8 months ago

plugin updated ok but the script crashes opencpn unless I comment out OCPNpushText(skJson, handle);

Don't see anything in opencpn log, it looks the same as it does if booted up but the script not run.

Can you let me have the crash report, please?

boatybits commented 8 months ago

`<?xml version="1.0" encoding="UTF-8" ?>

77585162-3bc9-4900-8e47-ee6b70ac4ad0 OpenCPN 5.8.0.0 C:\Program Files (x86)\OpenCPN\opencpn.exe Windows 10 Enterprise Build 19045 1 en-gb 2024-01-27T11:52:13Z 0x68040b17 C:\Users\Padz\AppData\Local\opencpn\plugins\JavaScript_pi.dll 0x68010000 0.0.0.0 0 0 2314 572 245508

`

antipole2 commented 8 months ago

Thanks - and your script, please zipped.

boatybits commented 8 months ago

that was using your script from https://github.com/antipole2/JavaScript_pi/files/14076045/writeSignalK.js.zip changing the last line to //OCPNpushText(skJson, handle); the script would run without crashing & gave this output >

{ "self": "123456789", "vessels": { "name": "Titanic", "mmsi": 123456789, "navigation": { "headingTrue": { "value": 23, "source": "self", "timestamp": "2014-03-24T00:15:41Z" }, "headingMagnetic": { "value": 43, "source": "self", "timestamp": "2014-03-24T00:15:41Z" } } } } result: {"self":"123456789","vessels":{"name":"Titanic","mmsi":123456789,"navigation":{"headingTrue":{"value":23,"source":"self","timestamp":"2014-03-24T00:15:41Z"},"headingMagnetic":{"value":43,"source":"self","timestamp":"2014-03-24T00:15:41Z"}}}}

antipole2 commented 8 months ago

@boatybits I know that pushing NMEA0183 data works OK because I can test that. I have now rationalised the push methods so OCPNpushText uses exactly the same code as OCPNpushNMEA0183, apart from the latter adding the checksum. Please try again with new build beta-c.

The SignalK data in my script was illustrative only. I do not know SignalK. Possibly a problem? Please replace with something you know is valid SignalK and appropriate to send.

If it crashes again, please let me have both the script and the crash report.

Thanks for your help with this.

boatybits commented 8 months ago

Hi, must be getting close..still crashing though. Hopefully attached is zipped crashdump folder & script. Same as before, works OK with last line commented out. Output looks OK, not sure how well you know signalk but there's a data fiddler page where you can test data, pasting in the output seems to be fine > image

And maybe this will be useful, I've a linux machine running in the cloud which I loaded signalk onto > Edit - Ooops, not such a good idea to post that publically, did you get the address & password? Nothing important on it so do anything you want & don't worry about breaking it.

sigk.zip

antipole2 commented 8 months ago

Going to need input from others here. To document what I am doing, the crux is the following code:

// handle is the port handle, protocol is the protocol for that handle, data is the data text
    if (protocol == "nmea0183"){
        data = addNMEA0183CheckSum(ctx, data);
        }
    auto payload = make_shared<std::vector<uint8_t>>();
    for (const auto& ch : data) payload->push_back(ch);
    CommDriverResult outcome = WriteCommDriver(handle, payload);

If the protocol for the handle is for an nmea0183 network connection, this works fine and the nmea0183 sentence is received by the other end OK. If attempting to send to a SignalK port, we get a crash as reported above.

TwoCanPlugIn commented 8 months ago

Hi Tony,

Can't say I've had a lot of experience with SignalK, and to be honest, I'm not terribly interested in it.

That being said, I just played with the following code in one of my test plugins, on Windows.

It doesn't work, but it doesn't crash OpenCPN!

CommDriverResult result; wxString message = "{\"updates\":[{\"source\": {\"sentence\":\"HDM\",\"talker\":\"II\",\"type\":\"NMEA0183\"},\"values\": [{\"path\":\"navigation.headingMagnetic\",\"value\":2}]}],\"context\":\"vessels.self\",\"name\":\"Iona\"}"; std::vector<uint8_t>SignalK; for (auto it : message) { SignalK.push_back(it); } auto signalkPointer = std::make_shared<std::vector<uint8_t> >(std::move(SignalK)); result = WriteCommDriver(driverSignalK, signalkPointer);

The return code is 2, which means invalid parameter. I'm pretty sure the driver handle is OK, as I re-use similar code for writing NMEA 2000 stuff.

So I think your crashing of OpenCPN is perhaps a bug in your code ?

Anyway, a few questions arise.

Firstly, does SignalK Server need to be configured for a SignalK incoming data connection, similar to how NMEA 2000 or NMEA 0183 connections are created ? This is different to configuring the SignalK HTTP port, or SignalK over TCP.

Secondly, do you have a JSON SignalK update message that is "known" to update a value in SignalK ?

I can receive SignalK updates from a SignalK Server over TCP (port 8375) using netcat on Linux and a Powershell script on Windows, the obvious test is to use either of these to send an update to SignalK Server. I haven't been able to successfully do that. If that can be proven, the next test is to send it over web sockets, which is the transport that OpenCPN uses.

Thirdly, we both know that GetSignalKPayload was not initially implemented in 5.8.x, who's to say that WriteCommDriver over SignalK has either been implemented or verified to work ?

Regards.

TwoCanPlugIn commented 7 months ago

Hi Tony,

Have done some further testing with some Powershell scripts on Windows, just to verify that it is possible to update values on SignalK Server via web sockets. Now just a matter for you to get the same to work for your Javascript plugin.

This is the uri for my test setup. (I'm not worried about private IP addresses, usernames or passwords)

ws://192.168.43.170:3000/signalk/v1/stream/?subscribe=none

II haven't been able to get this to work with a "working" subscription, eg. subscribe=all or subscribe = {"context":"vessels.self","subscribe":[{"path":"environment."},{"path":"navigation."}]}

It only appears to work with subscribe=none

After connecting to the SignalK Server web socket with no subscription, you receive the server announcement:

{"name":"signalk-server","version":"2.1.0","self":"vessels.urn:mrn:signalk:uuid:1cb1a66a-814c-4478-8b84-701eec9524bb","roles":["master","main"],"timestamp":"2024-02-12T22:11:19.510Z"}

Then send the login request (On Windows I use the guidgen utility to create a valid GUID/UUID)

"{\"requestId\":\"FA1CA3B7-F121-4E5C-99FA-A498BD5CAFEB\",\"login\":{\"username\":\"pi\",\"password\":\"raspberry\"}}";

I don't recall any specific configuration of SignalK Server so I assume security is enabled by default

The successful login response is as follows:

{"requestId":"FA1CA3B7-F121-4E5C-99FA-A498BD5CAFEB","state":"COMPLETED","statusCode":200,"login":{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InBpIiwiaWF0IjoxNzA3Nzc1ODgzLCJleHAiOjE3MDc4NjIyODN9.RoVbGhAQZ5P7lfNIa0dSmQKZGsRa2naeTRjNd8XC-ck"}}

Then send the update message, in this case the value for heading in PGN 127250. I am not sure if any of the other SignalK stuff (label, type, context) or NMEA 2000 stuff (source or deviceInstance) is required.

"{\"updates\":[{\"source\":{\"label\":\"CAN-BUS\",\"type\":\"NMEA2000\",\"pgn\":127250,\"src\":\"2\",\"deviceInstance\":0},\"values\":[{\"path\":\"navigation.headingTrue\",\"value\":2.0}]}],\"context\":\"vessels.self\"}";

The successful update response is then received.

{"requestId":"FA1CA3B7-F121-4E5C-99FA-A498BD5CAFEB","state":"COMPLETED","statusCode":200,"login":{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InBpIiwiaWF0IjoxNzA3Nzc1ODg4LCJleHAiOjE3MDc4NjIyODh9.MAJarWkyAofdZ_-EV7do8Hnb7zUOGNJVaizN0EhqIzc"}}

The attached screenshot shows the updated value in the SignalK Server Data Browser.

I sincerely doubt whether WriteCommDriver for a SignalK connection has ever had a specification written, correctly implemented nor even tested. My gut feel is that when OpenCPN initiates a connection to SignalK Server, it does so with subscribe=all, so I doubt that it is possible to peform a write without doing a subscribe=none, perform the login & update and then doing a subscribe=all

As many of us are discovering, there are many features in OpenCPN that just don't work. I don't understand how the developers can check in a feature without performing a unit test to actually ensure it works as expected. I even doubt whether the SignalK Server discovery (msDNS/Bonjour) actually works (it has never for me),. One day I might just do a network capture to see if anything is even sent or received across the network.

Once you get your plugin and WriteCommDriver working without crashing OpenCPN, feel free to file the bug report.

signalk-update
TwoCanPlugIn commented 4 months ago

I thought I would close the loop on this.

It is possible to update SignalK Server using web sockets from any other application, however at the moment writing to SignalK Server from OpenCPN is not supported. From plugin_api.cpp

if (protocol == "nmea0183") {
....
} else
    return RESULT_COMM_INVALID_PARMS;
}