From f2201ba26c4bde05892534b4a6e88e2f33c9e84c Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Sat, 4 Mar 2017 17:12:36 +0200 Subject: [PATCH 1/4] test: add test case for multiple sources/values --- test/data/multiple-values.json | 51 ++++++++++++++++++++++++++++++++++ test/sources.js | 6 ++++ 2 files changed, 57 insertions(+) create mode 100644 test/data/multiple-values.json diff --git a/test/data/multiple-values.json b/test/data/multiple-values.json new file mode 100644 index 000000000..425b2db06 --- /dev/null +++ b/test/data/multiple-values.json @@ -0,0 +1,51 @@ +{ + "vessels": { + "urn:mrn:signalk:uuid:c0d79334-4e25-4245-8892-54e8ccc8021d": { + "uuid": "urn:mrn:signalk:uuid:c0d79334-4e25-4245-8892-54e8ccc8021d", + "navigation": { + "courseOverGroundMagnetic": { + "value": 3.615624078431453, + "$source": "nmea2.II", + "timestamp": "2017-03-04T14:58:48.000Z", + "sentence": "VTG", + "values": { + "nmea1.II": { + "value": 3.6376152270065814, + "sentence": "VTG", + "timestamp": "2017-03-04T14:58:47.000Z" + }, + "nmea2.II": { + "value": 3.615624078431453, + "timestamp": "2017-03-04T14:58:48.000Z", + "sentence": "VTG" + } + } + } + } + } + }, + "self": "urn:mrn:signalk:uuid:c0d79334-4e25-4245-8892-54e8ccc8021d", + "version": "0.1.0", + "sources": { + "nmea1": { + "label": "nmea1", + "type": "NMEA0183", + "II": { + "talker": "II", + "sentences": { + "VTG": "2017-03-04T14:58:47.000Z" + } + } + }, + "nmea2": { + "label": "nmea2", + "type": "NMEA0183", + "II": { + "talker": "II", + "sentences": { + "VTG": "2017-03-04T14:58:48.000Z" + } + } + } + } +} diff --git a/test/sources.js b/test/sources.js index 1d328005e..a8a78cdfc 100644 --- a/test/sources.js +++ b/test/sources.js @@ -141,3 +141,9 @@ describe('Bad sources in delta', function() { }) }); }); + +describe('Multiple sources for the same path:', function() { + it("value + values are valid", function() { + require('./data/multiple-values.json').should.be.validSignalK + }); +}); From 91cd2e97951070439af98dd1fa143ad8ef42d436 Mon Sep 17 00:00:00 2001 From: rob42 Date: Mon, 27 Mar 2017 13:56:53 +1300 Subject: [PATCH 2/4] Made a start on multiple values for a single key --- gitbook-docs/data_model_multiple_values.md | 176 ++++++++++++++------- 1 file changed, 115 insertions(+), 61 deletions(-) diff --git a/gitbook-docs/data_model_multiple_values.md b/gitbook-docs/data_model_multiple_values.md index 866953e8b..2b120531a 100644 --- a/gitbook-docs/data_model_multiple_values.md +++ b/gitbook-docs/data_model_multiple_values.md @@ -26,99 +26,153 @@ It is quite possible for a key value to come from more than one device. eg posit All the incoming values may well be valid in their own context, and it is feasible that all of them may be wanted, for instance, displaying depth under each hull on a catamaran. -Hence discarding or averaging is not a solution, and since signalk is unable to derive the best way to handle multiple values it must always fall to a default action, with human over-ride when needed. +Hence discarding or averaging values is not a solution, we must provide a way to store multiple values for a single measurement. - -*** -The solution presented below has flaws. See https://github.com/SignalK/specification/issues/48 for discussion. -*** - - -In signal K we can leverage the above method and simply store all the devices in the tree under the main item, and have the main items `source` reference the options. Lets consider this for `courseOverGroundTrue` + Lets consider this for `courseOverGroundTrue` If its the first value for the key, it becomes the default value and looks like this: ```json { "vessels": { - "self": { + "urn:mrn:signalk:uuid:c0d79334-4e25-4245-8892-54e8ccc8021d": { + "uuid": "urn:mrn:signalk:uuid:c0d79334-4e25-4245-8892-54e8ccc8021d", "navigation": { - "courseOverGroundTrue": { - "value": 102.29, - "source": "vessels.self.sources.n2k.actisense-115-129026" + "courseOverGroundMagnetic": { + "value": 3.615624078431453, + "$source": "nmea2.II", + "timestamp": "2017-03-04T14:58:48.000Z", + "sentence": "VTG" } - }, - "sources": { - "n2k": { - "actisense-115-129026": { - "value": 102.29, - "bus": "/dev/actisense", - "timestamp": "2014-08-15-16: 00: 01.083", - "src": "115", - "pgn": "129026" - } + } + } + }, + "self": "urn:mrn:signalk:uuid:c0d79334-4e25-4245-8892-54e8ccc8021d", + "version": "0.1.0", + "sources": { + "nmea2": { + "label": "nmea2", + "type": "NMEA0183", + "II": { + "talker": "II", + "sentences": { + "VTG": "2017-03-04T14:58:48.000Z" } } } } } ``` -It has come from device `vessels.self.sources.n2k.actisense-115-129026`, where further details can be found. +It has come from device `sources.nmea2.II`, where further details can be found. -If another value with different source arrives, we add the source with a unique name, so both values are in there - if its our preferred source (from persistent config) we auto-switch to it, otherwise we just record it. It look like this: +If another value with different source arrives, we add the `values` attribute with and values are in there - if its our preferred source (from persistent config) we auto-switch to it, otherwise we just record it. It look like this: ```json { "vessels": { - "self": { + "urn:mrn:signalk:uuid:c0d79334-4e25-4245-8892-54e8ccc8021d": { + "uuid": "urn:mrn:signalk:uuid:c0d79334-4e25-4245-8892-54e8ccc8021d", "navigation": { - "courseOverGroundTrue": { - "timestamp": "2014-08-15-16: 00: 01.083", - "value": 102.29, - "source": "vessels.self.sources.n2k.actisense-115-129026" - } - }, - "sources": { - "n2k": { - "actisense-115-129026": { - "value": 102.29, - "bus": "/dev/actisense", - "timestamp": "2014-08-15-16: 00: 01.083", - "src": "115", - "pgn": "129026" - }, - "actisense-201-130577": { - "value": 102.29, - "bus": "/dev/actisense", - "timestamp": "2014-08-15-16: 00: 00.085", - "src": "201", - "pgn": "130577" + "courseOverGroundMagnetic": { + "value": 3.615624078431453, + "$source": "nmea2.II", + "timestamp": "2017-03-04T14:58:48.000Z", + "sentence": "VTG", + "values": { + "nmea1.II": { + "value": 3.6376152270065814, + "sentence": "VTG", + "timestamp": "2017-03-04T14:58:47.000Z" + }, + "nmea2.II": { + "value": 3.615624078431453, + "sentence": "VTG", + "timestamp": "2017-03-04T14:58:48.000Z" + } } } } } + }, + "self": "urn:mrn:signalk:uuid:c0d79334-4e25-4245-8892-54e8ccc8021d", + "version": "0.1.0", + "sources": { + "nmea1": { + "label": "nmea1", + "type": "NMEA0183", + "II": { + "talker": "II", + "sentences": { + "VTG": "2017-03-04T14:58:47.000Z" + } + } + }, + "nmea2": { + "label": "nmea2", + "type": "NMEA0183", + "II": { + "talker": "II", + "sentences": { + "VTG": "2017-03-04T14:58:48.000Z" + } + } + } } } ``` +###Update messages -### Rules +When a client subscribes to `navigation.courseOverGroundMagnetic`, they recieve _all_ the values held. The update message does not include the `values` path, the case above looks like: -Now simple rules can apply to obtain the default, or any specific value: -* The implementation must ensure that the `key.value` holds an appropriate value. This will be easy if there is only one, and will probably be user configured if more. -* If the `source` value is `string` then it is a reference key to the source object, and can be a relative or absolute signalk key. -* The `source` (as a reference string) also provides a mechanism to handle deprecated keys. -* If the `source` value is a `json object` then it holds meta data on the source of the value. -* Alternate sources must be discovered manually, or by implementation specific meta-data. - -To see all the entries, use the REST api or subscribe to the parent object. A given device may choose to subscribe to a specific entry in the object, allowing multiple displays of the key, or users of the various values. The 'list' verb used in a query message can provide available keys. +``` +{ + "context": "vessels.urn:mrn:signalk:uuid:c0d79334-4e25-4245-8892-54e8ccc8021d", + "updates": [ + { + "source": { + "label": "nmea2", + "type": "NMEA0183", + "II": { + "talker": "II", + "sentences": { + "VTG": "2017-03-04T14:58:48.000Z" + } + } + }, + "timestamp": "2017-03-04T14:58:48.000Z", + "values": [ + { + "path": "navigation.courseOverGroundMagnetic", + "value": 3.615624078431453 + } + ] + }, + { + "source": { + "label": "nmea1", + "type": "NMEA0183", + "II": { + "talker": "II", + "sentences": { + "VTG": "2017-03-04T14:58:47.000Z" + } + } + }, + "timestamp": "2017-03-04T14:58:47.000Z", + "values": [ + { + "path": "navigation.courseOverGroundMagnetic", + "value": 3.6376152270065814 + } + ] + } + ] +} -###Unique names +``` +Individual updates can be distinguished by their source. -The identifier for each device should be unique within the server, and possibly be constructed as follows: +If a client wants only the values of a single source it should subscribe to a path that includes the full path under `values` including the source reference key of the source. The source reference should be enclosed in square brackets: `navigation.speedThroughWater.values[n2kFromFile.43]`. The client can retrieve the relevant data via REST API. - n2k: producerid-sourceid-pgn (producer id from server configuration, others from n2k data) - NOTE: will change, currently under discussion. - nmea0183: producerid-talkerid-sentence (like n2k) - signalk: any valid string matching regex [a-zA-Z0-9-]. eg alphabet, hyphens, and 0 to 9 -(The nmea0183 talker id is not in the schema as I write this, it will be added shortly) From 8f6370c1a9bc0154700f8d547ad547542d108a18 Mon Sep 17 00:00:00 2001 From: rob42 Date: Mon, 27 Mar 2017 14:00:06 +1300 Subject: [PATCH 3/4] Adjusted multiple devices --- gitbook-docs/data_model_multiple_values.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gitbook-docs/data_model_multiple_values.md b/gitbook-docs/data_model_multiple_values.md index 2b120531a..a653f23a3 100644 --- a/gitbook-docs/data_model_multiple_values.md +++ b/gitbook-docs/data_model_multiple_values.md @@ -1,6 +1,7 @@ # Multiple Values for a Key There are two use cases for multiple data: + * Multiple instances of a common device - eg two engines or multiple batteries * Multiple devices providing duplicate data - multiple values for the same Signal K key from different sensors, eg COG from both compass and gps or multiple depth sounders @@ -8,11 +9,10 @@ There are two use cases for multiple data: Some parts of the Signal K schema are **device oriented**. -For example in electrical domain you have the concept of multiple batteries. -Each battery has multiple, common quantities like voltage, current and temperature. -Here we have chosen to organise the Signal K data model hierarchy by instance: multiple batteries are represented as for example `electrical.batteries.starter` and `electrical.batteries.house`. Then underneath that prefix you have the different properties and quantities. +For example in electrical domain you have the concept of multiple batteries. Each battery has multiple, common quantities like voltage, current and temperature. Here we have chosen to organise the Signal K data model hierarchy by instance: multiple batteries are represented as for example `electrical.batteries.starter` and `electrical.batteries.house`. Then underneath that prefix you have the different properties and quantities. + +This organisation allows a user interface to organise the individual readings in meaningful groups and you can query all the values related to that piece of equipment via REST API. -This organisation allows a user interface to organise the individual readings in meaningul groups and you can query all the values related to that piece of equipment via REST API. It maintains the primary requirement that a given data value have a fixed and unique uri, but gives flexibility in the structure and complexities of data. The same device centric organisation is used in `propulsion` subschema, where the most common use case is having dual engine setup with `propulsion.port` and `propulsion.starboard`. From 48351a1eb4c70df67b84d63f531621da3249b8c1 Mon Sep 17 00:00:00 2001 From: rob42 Date: Sun, 16 Apr 2017 10:21:31 +1200 Subject: [PATCH 4/4] Correct update format, and add note on grouping --- gitbook-docs/data_model_multiple_values.md | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/gitbook-docs/data_model_multiple_values.md b/gitbook-docs/data_model_multiple_values.md index a653f23a3..ee02f2092 100644 --- a/gitbook-docs/data_model_multiple_values.md +++ b/gitbook-docs/data_model_multiple_values.md @@ -133,11 +133,7 @@ When a client subscribes to `navigation.courseOverGroundMagnetic`, they recieve "source": { "label": "nmea2", "type": "NMEA0183", - "II": { - "talker": "II", - "sentences": { - "VTG": "2017-03-04T14:58:48.000Z" - } + "talker": "II" } }, "timestamp": "2017-03-04T14:58:48.000Z", @@ -152,11 +148,7 @@ When a client subscribes to `navigation.courseOverGroundMagnetic`, they recieve "source": { "label": "nmea1", "type": "NMEA0183", - "II": { - "talker": "II", - "sentences": { - "VTG": "2017-03-04T14:58:47.000Z" - } + "talker": "II" } }, "timestamp": "2017-03-04T14:58:47.000Z", @@ -175,4 +167,7 @@ Individual updates can be distinguished by their source. If a client wants only the values of a single source it should subscribe to a path that includes the full path under `values` including the source reference key of the source. The source reference should be enclosed in square brackets: `navigation.speedThroughWater.values[n2kFromFile.43]`. The client can retrieve the relevant data via REST API. +**Note:** The exact format of the update message is affected by the subscription policy. A policy of `instant` will result in changes being sent immediately, so typically one item in `values` per update. A policy of `fixed` will result in periodic updates which may contain many items in `values`. + +The update allows grouping `values` by `source`.