Go SignalK implementation and more.
This implementation consist of several small programs that collect, map, store and publish sensor data from one or more vessels.
GOSK is a set of micro services that collect, map, store, transport and publish data available on a ship. GOSK publishes data in the SignalK Open Marine Data Standard. All data is stored in both a raw format (before any mapping is done) and in a mapped format.
The only role of a collector is to collect raw data from the sensors on board. Collectors are made for specific protocols, e.g. a collector for NMEA0183 over UDP knows how to listen for data and a collector for Modbus over TCP knows how to pull data. Collectors have their individual configuration. Multiple collectors for the same protocol/transport can coexist in a system, e.g. 2 Canbus collectors for a port side and starboard engine.
The only role of a raw store is to store the raw data in a time series database. See below for the storage format.
The only role of a mapper is to translate data from a raw format to a mapped format. Mappers should not be aware of transport protocols, e.g. data coming from NMEA0183 over RS-422 and NMEA0183 over UDP should be handled by the same mapper.
The only role of a mapped store is to store the mapped data in a time series database. See below for the storage format.
Transporters move (subsets) of mapped data from one network to another network. Transporters can be used to send data from the vessel to the cloud. Currently no transporters are implemented.
A publisher can provide the mapped data to other applications in different data formats and transport protocols. Currently a publisher for SignalK REST API and SignalK Streaming API.
For communication between the different micro services NNG is used. The messages are serialized using JSON encoding.
The JSON message contains the following fields:
- collector, identifier for the source of the data;
- timestamp, the time when the data was receive in UTC and RFC3339Nano format;
- uuid, used to link raw and mapped data together;
- value, the actual value in base64 encoded format. This value contains all information needed for the mapper to map the data.
{
"collector": "GPS",
"timestamp": "2022-02-09T16:12:29.481162381Z",
"uuid": "49175a7e-c4cb-455c-ae99-05eca8f7997d",
"value": "JEdQR0xMLDM3MjMuMjQ3NSxOLDEyMTU4LjM0MTYsVywxNjEyMjkuNDg3LEEsQSo0MQ=="
}
The value
is a base 64 encoded string of the NMEA018 sentence $GPGLL,3723.2475,N,12158.3416,W,161229.487,A,A*41
.
{
"collector": "CAT 3512",
"timestamp": "2022-02-09T12:03:57.431272983Z",
"uuid": "c67ae38f-64c6-427d-a91d-282a25623cc2",
"value": "AQAEyOwAAgABjnA="
}
The value
is a base64 encoded string of the following bytes
0x01
The slave id0x00 0x04
The function code0xc8 0xec
The address of the first register0x00 0x02
The number of registers0x00 0x01
The value of the first register0x8e 0x70
The value of the second register
The basis is the Signal K Delta format with some extras. The label
, type
and src
properties in the source
section are used as follows. label
is filled with name
property of the collector config, type
is filled with protocol that is used and src
is filled with the url
property of the collector config. Each individual value
section has an extra property uuid
that is filled with the uuid
of the corresponding raw data.
{
"context": "vessels.urn:mrn:imo:mmsi:234567890",
"updates": [
{
"source": {
"label": "CAT 3512",
"type": "MODBUS",
"src": "tcp://127.0.0.1:5020"
},
"timestamp": "2010-01-07T07:18:44Z",
"values": [
{
"path": "propulsion.0.revolutions",
"value": 16.341667,
"uuid": "05a2ce62-6c52-4ce9-bb4f-07bb47cfa348"
},
{
"path": "propulsion.0.boostPressure",
"value": 45500,
"uuid": "05a2ce62-6c52-4ce9-bb4f-07bb47cfa348"
}
]
}
]
}
PostgreSQL and TimescaleDB are used as a time series database. Two tables are created. One table stores the raw data as received from the different collectors. The other table stores the mapped data as received from the different mappers.
CREATE TABLE "raw_data" (
"time" TIMESTAMPTZ NOT NULL,
"collector" TEXT NOT NULL,
"extra_info" TEXT NOT NULL,
"value" TEXT NOT NULL -- base64 encoded binary data
);
CREATE TABLE "key_value_data" (
"time" TIMESTAMPTZ NOT NULL,
"context" TEXT NULL,
"source" JSON NOT NULL,
"path" TEXT NOT NULL,
"value" JSON NOT NULL
);