From a411f92ce5f0af923f7b52b5c7cfc734ce7e2010 Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Sun, 24 Oct 2021 16:04:55 +1030 Subject: [PATCH 01/15] Course API proposal --- apis/course/README.md | 325 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 apis/course/README.md diff --git a/apis/course/README.md b/apis/course/README.md new file mode 100644 index 00000000..1837d3f9 --- /dev/null +++ b/apis/course/README.md @@ -0,0 +1,325 @@ +# Feature: Course API + +## Description: + +Define an API for Signal K client applications to be able to set a destination or navigate a route that provides the following methods: + +- Set a position (lat, lon) as a destination +- Select a waypoint (from `/resources/waypoints`) as a destination +- Activate a route (from `/resources/routes`) +- Select the point within the route to be the current destination +- Clear / cancel the course +- Query the current course details. + +The methods described above will set values in the relevant Signal K paths under both `navigation.courseGreatCircle` and `navigation.courseRhumbline` to enable a course computer to generate additional navigation information (XTE, DTG, etc) as well as facilitate display on a chart plotter. + +--- + +### Why an API: +Currently Signal K makes available paths to store navigation data but it is largely left up to implementors of client applications to determine how they are used. + +This is can cause interoperability issues and inconsistency in application (e.g. calculations in `signalk-derived-data` plugin will use a mixture of paths `navigation.courseGreatCircle` and `navigation.courseRhumbline`) so depending on an individual implementation results may vary. + +--- + +### 1. Signal K Paths in Scope: + +The following paths are relative to `/signalk/v1/api/vessels/self`. + +The Signal K specification contains a `navigation.course` schema definition which is applied to both the `navigation/courseGreatCircle` and `navigation/courseRhumbline` paths. + +The following attributes in both these paths are in scope for management by this API. + +``` +activeRoute/href +activeRoute/startTime +``` + +``` +nextPoint/value/href +nextPoint/value/type +nextPoint/position +``` + +``` +previousPoint/value/href +previousPoint/value/type +previousPoint/position +``` + +Additionally it will provide a path to query the current course information. + +``` +navigation/course +``` + +--- + +### 2. How In Scope paths are used: + +While the intended use of the `in scope` Signal K paths are defined in the specification, the use of these paths in practise determines the success of an implementation. + +_Following is the proposed operation of the course API for each of the proposed methods:_ + +__a. Set a position (lat, lon) as a destination.__ + +--- +To facilitate a "navigate to here" operation: +- The client will `PUT` or `POST` the following to the `/navigation/course/destination` path: +```JSON +{ + "value": { + "position": {"latitude": -28.5,"longitude":138.5}, + "type": "Location" + } +} +``` +where: +- `position`: The destination lat, lon (as per Signal K schema) +- `type` (optional): A string describing the destination (as per Signal K schema). + +This will result in the following path values: +```JSON +{ + "activeRoute": { + "href": null, + "startTime": null + }, + "nextPoint": { + "href": null, + "type": "Location", + "position": { + "latitude": -28.5, + "longitude":138.5 + } + }, + "previousPoint": { + "href": null, + "type": null, + "position": { + "latitude": latitude of vessel at time of destination being set, + "longitude": longitude of vessel at time of destination being set + } + } +} +``` + +__b. Set a Waypoint as a destination.__ + +--- +To facilitate a "navigate to selected waypoint" operation: +- The client will `PUT` or `POST` the following to the `/navigation/course/destination` path: +```JSON +{ + "value": { + "href": "/resources/waypoints/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab" + } +} +``` +where: +- `href`: The path to the target waypoint in `/resources/waypoints/`. + +This will result in the following path values: +```JSON +{ + "activeRoute": { + "href": null, + "startTime": null + }, + "nextPoint": { + "href": "/resources/waypoints/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "type": "Waypoint", + "position": { + "latitude": latitude of waypoint, + "longitude": longitude of waypoint + } + }, + "previousPoint": { + "href": null, + "type": null, + "position": { + "latitude": latitude of vessel at time of destination being set, + "longitude": longitude of vessel at time of destination being set + } + } +} +``` + +__c. Clear / Cancel a destination or Activated Route.__ + +--- +To facilitate a "navigate to selected waypoint" operation the client will send a `DELETE` request to either of the the following paths: +- `/navigation/course/destination` +- `/navigation/course/activeRoute` + +This will result in the following path values: +```JSON +{ + "activeRoute": { + "href": null, + "startTime": null + }, + "nextPoint": { + "href": null, + "type": null, + "position": null + }, + "previousPoint": { + "href": null, + "type": null, + "position": null + } +} +``` + +__d. Activate a Route to follow.__ + +--- +To facilitate a "Activate Route" operation: +- The client will `PUT` or `POST` the following to the `/navigation/course/activeRoute` path: +```JSON +{ + "value": { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "pointIndex": 1, + "reverse": false + } +} +``` +where: +- `href`: The path to the target route in `/resources/routes/`. +- `pointIndex` (optional): Zero based index of the point within the route to use as the initial destination (defaults to 0 if not supplied or if value is larger than index of last point in the route). +- `reverse` (optional): If `true` performs operations on route points in reverse (defaults to false). + +This will result in the following path values: +```JSON +{ + "activeRoute": { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "startTime": Time at which route was activated (as per Signal K schema) + }, + "nextPoint": { + "href": null, + "type": "RoutePoint", + "position": { + "latitude": latitude of second point in route, + "longitude": longitude of second point in route + } + }, + "previousPoint": { + "href": null, + "type": null, + "position": { + "latitude": latitude of vessel at time of destination being set, + "longitude": longitude of vessel at time of destination being set + } + } +} +``` + +__d. Select point in the active Route as destination.__ + +--- +To facilitate a "Previous / Next point" operation: +- The client will `PUT` or `POST` the following to the `/navigation/course/activeRoute/nextPoint` path: + +Option 1: +```JSON +{ + "value": { + "pointIndex": 3 + } +} +``` +where: +- `pointIndex`: Zero based index of the point within the route to use as the initial destination (if value is larger than index of last point in the route then destination is not changed). + +Option 2: +```JSON +{ + "value": { + "increment": -1 + } +} +``` +where: +- `increment`: Is either `1` (next point) or `-1` (previous point). + +This will result in the following path values: +```JSON +{ + "activeRoute": { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "startTime": Time at which route was activated (as per Signal K schema) + }, + "nextPoint": { + "href": null, + "type": "RoutePoint", + "position": { + "latitude": latitude of previous point in route, + "longitude": longitude of previous point in route + } + }, + "previousPoint": { + "href": null, + "type": null, + "position": { + "latitude": latitude of vessel at time of destination being set, + "longitude": longitude of vessel at time of destination being set + } + } +} +``` + +__e. Query current course details.__ + +--- +To facilitate a "Previous / Next point" operation: +- The client will make a `GET` request to the `/navigation/course` path and a response of the following format, detailing the course values, will be returned. + +Example: +```JSON +{ + "activeRoute": { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "startTime": "2021-10-23T05:17:20.065Z", + "pointIndex": 2 + }, + "nextPoint": { + "href": null, + "type": "RoutePoint", + "position": { + "latitude":-29.5, + "longitude":137.5 + } + }, + "previousPoint": { + "href": null, + "type": null, + "position": { + "latitude":-29.05, + "longitude":137.75 + } + } +} +``` + +### Use of `previousPoint`. +--- +To facilitate course calculations such as XTE where the source position is required, the `previousPoint.position` attribute is __always__ set to the location of the vessel each time the destination position is set / changed. + +It is set to `null` when the destination has been cleared. + +--- + +## Enabling other navigation equipment (e.g. autopilot) operation. + +This API seeks to define and manage the use of specific `course` paths within the Signal K schema to provide consistency and confidence in the values they contain. + +Maintianing quality data in these paths enables operation of other navigation equipment such as: +- Course computers +- Auto-pilots +by providing a source of data that can be trusted for use in calculating navigation information for steering a course. + +The paths within the Signal K schema pertaining to other navigation operations will be maintained by the relevant equipment or Signal K API . + From 9c4caf5468c20adb1723fbba094396c7ef6622d5 Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Sun, 24 Oct 2021 16:28:26 +1030 Subject: [PATCH 02/15] add openApi definition --- apis/course/README.md | 2 +- apis/course/openApi.json | 401 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 402 insertions(+), 1 deletion(-) create mode 100644 apis/course/openApi.json diff --git a/apis/course/README.md b/apis/course/README.md index 1837d3f9..dbb55647 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -189,7 +189,7 @@ To facilitate a "Activate Route" operation: where: - `href`: The path to the target route in `/resources/routes/`. - `pointIndex` (optional): Zero based index of the point within the route to use as the initial destination (defaults to 0 if not supplied or if value is larger than index of last point in the route). -- `reverse` (optional): If `true` performs operations on route points in reverse (defaults to false). +- `reverse` (optional): If `true` performs operations on route points in reverse order (defaults to false). This will result in the following path values: ```JSON diff --git a/apis/course/openApi.json b/apis/course/openApi.json new file mode 100644 index 00000000..4e40bccf --- /dev/null +++ b/apis/course/openApi.json @@ -0,0 +1,401 @@ +{ + "openapi": "3.0.2", + "info": { + "version": "0.0.1", + "title": "Signal K Course API" + }, + + "tags": [ + { + "name": "activeRoute", + "description": "Route operations" + }, + { + "name": "destination", + "description": "Destination operations" + } + ], + + "components": { }, + + "paths": { + + "/vessels/self/navigation/course/": { + "get": { + "tags": ["course"], + "summary": "Get course information", + "responses": { + "default": { + "description": "Course data", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "activeRoute": { + "type": "object", + "properties": { + "href": { + "type": "string", + "example": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdb69" + }, + "startTime": { + "type": "string", + "example": "2021-10-23T05:17:20.065Z" + }, + "pointIndex": { + "type": "number", + "format": "int64", + "example": 2 + } + } + }, + "nextPoint": { + "type": "object", + "properties": { + "href": { + "type": "string", + "example": "/resources/waypoints/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab" + }, + "type": { + "type": "string", + "example": "RoutePoint" + }, + "position": { + "type": "object", + "properties": { + "latitude": { + "type": "number", + "format": "float" + }, + "longitude": { + "type": "number", + "format": "float" + } + }, + "example": {"latitude":-29.5,"longitude":137.5} + } + } + }, + "previousPoint": { + "type": "object", + "properties": { + "href": { + "type": "string", + "example": null + }, + "type": { + "type": "string", + "example": "Location" + }, + "position": { + "type": "object", + "properties": { + "latitude": { + "type": "number", + "format": "float" + }, + "longitude": { + "type": "number", + "format": "float" + } + }, + "example": {"longitude":29.821001582434413,"latitude":70.7014589462524} + } + } + } + } + } + } + } + } + } + } + }, + + "/vessels/self/navigation/course/destination/": { + "put": { + "tags": ["destination"], + "summary": "Set destination", + "description": "Set destination path from supplied details", + "requestBody": { + "description": "Destination details", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "object", + "properties": { + "position": { + "type": "object", + "description": "Destination position", + "required": [ + "latitude", + "longitude" + ], + "properties": { + "latitude": { + "type": "number", + "format": "float" + }, + "longitude": { + "type": "number", + "format": "float" + } + }, + "example": {"latitude":-29.5,"longitude":137.5} + }, + "href": { + "type": "string", + "description": "A reference (URL) to an object (under /resources) this point is related to", + "example": "/resources/waypoints/urn:mrn:signalk:uuid:3dd34dcc-36bf-4d61-ba80-233799b25672" + }, + "type": { + "type": "string", + "description": "Type of point", + "example": "POI" + } + } + } + } + } + } + } + } + }, + "post": { + "tags": ["destination"], + "summary": "Set destination", + "description": "Set destination path from supplied details", + "requestBody": { + "description": "Destination details", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "object", + "properties": { + "position": { + "type": "object", + "description": "Destination position", + "required": [ + "latitude", + "longitude" + ], + "properties": { + "latitude": { + "type": "number", + "format": "float" + }, + "longitude": { + "type": "number", + "format": "float" + } + }, + "example": {"latitude":-29.5,"longitude":137.5} + }, + "href": { + "type": "string", + "description": "A reference (URL) to an object (under /resources) this point is related to", + "example": "/resources/waypoints/urn:mrn:signalk:uuid:3dd34dcc-36bf-4d61-ba80-233799b25672" + }, + "type": { + "type": "string", + "description": "Type of point", + "example": "POI" + } + } + } + } + } + } + } + } + }, + "delete": { + "tags": ["destination"], + "summary": "Clear destination", + "description": "Sets activeRoute, nextPoint & previousPoint values to null" + } + }, + + "/vessels/self/navigation/course/activeRoute/": { + "put": { + "tags": ["activeRoute"], + "summary": "Set active route", + "description": "Sets activeRoute path and sets nextPoint to first point in the route", + "requestBody": { + "description": "Active route details", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "object", + "properties": { + "href": { + "type": "string", + "description": "Path to route resource", + "example": "/resources/routes/urn:mrn:signalk:uuid:3dd34dcc-36bf-4d61-ba80-233799b25672" + }, + "pointIndex": { + "type": "number", + "format": "int64", + "description": "Zero based index of route point to use as destination", + "default": 0, + "minimum": 0, + "example": 2 + }, + "reverse": { + "type": "boolean", + "default": false, + "description": "If true performs operations on route points in reverse order", + "example": 2 + } + } + } + } + } + } + } + } + }, + "post": { + "tags": ["activeRoute"], + "summary": "Set active route", + "description": "Sets activeRoute path and sets nextPoint to first point in the route", + "requestBody": { + "description": "Active route details", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "object", + "properties": { + "href": { + "type": "string", + "description": "Path to route resource", + "example": "/resources/routes/urn:mrn:signalk:uuid:3dd34dcc-36bf-4d61-ba80-233799b25672" + }, + "pointIndex": { + "type": "number", + "format": "int64", + "description": "Zero based index of route point to use as destination", + "default": 0, + "minimum": 0, + "example": 2 + }, + "reverse": { + "type": "boolean", + "default": false, + "description": "If true performs operations on route points in reverse order", + "example": 2 + } + } + } + } + } + } + } + } + }, + "delete": { + "tags": ["activeRoute"], + "summary": "Clear active route", + "description": "Sets activeRoute, nextPoint & previousPoint values to null" + } + }, + + "/vessels/self/navigation/course/activeRoute/nextPoint": { + "post": { + "tags": ["activeRoute/nextPoint"], + "summary": "Set point in route as destination", + "description": "Sets the specified point in the route as destination", + "requestBody": { + "description": "Next point details", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "object", + "properties": { + "pointIndex": { + "type": "number", + "description": "Index of point in route to use as destination", + "minimum": 0, + "example": 2 + }, + "increment": { + "type": "number", + "description": "increment (1) / decrement (-1) index of point in route to use as destination", + "enum": [-1,1], + "example": 2 + } + } + } + + } + } + } + } + } + }, + "put": { + "tags": ["activeRoute/nextPoint"], + "summary": "Set point in route as destination", + "description": "Sets the specified point in the route as destination", + "requestBody": { + "description": "Next point details", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "object", + "properties": { + "pointIndex": { + "type": "number", + "description": "Index of point in route to use as destination", + "minimum": 0, + "example": 2 + }, + "increment": { + "type": "number", + "description": "increment (1) / decrement (-1) index of point in route to use as destination", + "enum": [-1,1], + "example": 2 + } + } + } + } + } + } + } + } + } + } + + } + +} + + + + + \ No newline at end of file From 8a904057a4581662d25ebee31381db0a9de44596 Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Wed, 27 Oct 2021 14:02:32 +1030 Subject: [PATCH 03/15] Add Deltas section. --- apis/course/README.md | 75 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/apis/course/README.md b/apis/course/README.md index dbb55647..8e8e8a32 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -274,7 +274,7 @@ This will result in the following path values: __e. Query current course details.__ --- -To facilitate a "Previous / Next point" operation: +To facilitate a "get current course" operation: - The client will make a `GET` request to the `/navigation/course` path and a response of the following format, detailing the course values, will be returned. Example: @@ -323,3 +323,76 @@ by providing a source of data that can be trusted for use in calculating navigat The paths within the Signal K schema pertaining to other navigation operations will be maintained by the relevant equipment or Signal K API . +--- + +## Signal K stream Deltas. + +The use of the API endpoints outlined above will trigger delta messages to be sent for related Signal K paths (in-scope paths) where: +- Values have changed +- Periodically for all paths that have a current value. + +The absence of a delta for a specific Signal K path indicates that the path has never had a value assigned to it. + +Where a delta value is `null`, this indicates that a previous value is no longer valid (i.e. there is a provider for this path but there is no current value). + +_Delta messages for in-scope paths:_ +```JSON +[ + { + "path": "navigation.courseGreatCircle.activeRoute.href", + "value": reference to route resource, + "context": "vessels.self", + "source": source of value + }, + { + "path": "navigation.courseGreatCircle.activeRoute.startTime", + "value": Time at which route was activated (as per Signal K schema), + "context": "vessels.self", + "source": source of value + }, + { + "path": "navigation.courseGreatCircle.nextPoint.position", + "value": { + "latitude": number, + "longitude": number + }, + "context": "vessels.self", + "source": source of value + }, + { + "path": "navigation.courseGreatCircle.nextPoint.value.href", + "value": reference to waypoint resource, + "context": "vessels.self", + "source": source of value + }, + { + "path": "navigation.courseGreatCircle.nextPoint.value.type", + "value": string, + "context": "vessels.self", + "source": source of value + }, + { + "path": "navigation.courseGreatCircle.previousPoint.position", + "value": { + "latitude": number, + "longitude": number + }, + "context": "vessels.self", + "source": source of value + }, + { + "path": "navigation.courseGreatCircle.previousPoint.value.href", + "value": reference to waypoint resource, + "context": "vessels.self", + "source": source of value + }, + { + "path": "navigation.courseGreatCircle.previousPoint.value.type", + "value": string, + "context": "vessels.self", + "source": source of value + } +] +``` + + From f01d3f8bbe4653b255ed82eb8f32f06ea322055b Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Wed, 27 Oct 2021 14:18:02 +1030 Subject: [PATCH 04/15] Added source attribute to API requests --- apis/course/README.md | 22 ++++++++++--- apis/course/openApi.json | 67 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/apis/course/README.md b/apis/course/README.md index 8e8e8a32..ed6d3c80 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -71,7 +71,8 @@ To facilitate a "navigate to here" operation: "value": { "position": {"latitude": -28.5,"longitude":138.5}, "type": "Location" - } + }, + "source": Source making the change. } ``` where: @@ -113,7 +114,8 @@ To facilitate a "navigate to selected waypoint" operation: { "value": { "href": "/resources/waypoints/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab" - } + }, + "source": Source making the change. } ``` where: @@ -152,6 +154,13 @@ To facilitate a "navigate to selected waypoint" operation the client will send a - `/navigation/course/destination` - `/navigation/course/activeRoute` +```JSON +{ + "value": null, + "source": Source making the change. +} +``` + This will result in the following path values: ```JSON { @@ -183,7 +192,8 @@ To facilitate a "Activate Route" operation: "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", "pointIndex": 1, "reverse": false - } + }, + "source": Source making the change. } ``` where: @@ -228,7 +238,8 @@ Option 1: { "value": { "pointIndex": 3 - } + }, + "source": Source making the change. } ``` where: @@ -239,7 +250,8 @@ Option 2: { "value": { "increment": -1 - } + }, + "source": Source making the change. } ``` where: diff --git a/apis/course/openApi.json b/apis/course/openApi.json index 4e40bccf..a443a311 100644 --- a/apis/course/openApi.json +++ b/apis/course/openApi.json @@ -159,6 +159,9 @@ "example": "POI" } } + }, + "source": { + "type": "string" } } } @@ -211,6 +214,9 @@ "example": "POI" } } + }, + "source": { + "type": "string" } } } @@ -221,7 +227,27 @@ "delete": { "tags": ["destination"], "summary": "Clear destination", - "description": "Sets activeRoute, nextPoint & previousPoint values to null" + "description": "Sets activeRoute, nextPoint & previousPoint values to null", + "requestBody": { + "description": "Delete payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "object", + "enum": [null] + }, + "source": { + "type": "string" + } + } + } + } + } + } } }, @@ -261,7 +287,10 @@ "example": 2 } } - } + }, + "source": { + "type": "string" + } } } } @@ -303,7 +332,10 @@ "example": 2 } } - } + }, + "source": { + "type": "string" + } } } } @@ -313,7 +345,27 @@ "delete": { "tags": ["activeRoute"], "summary": "Clear active route", - "description": "Sets activeRoute, nextPoint & previousPoint values to null" + "description": "Sets activeRoute, nextPoint & previousPoint values to null", + "requestBody": { + "description": "Delete payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "object", + "enum": [null] + }, + "source": { + "type": "string" + } + } + } + } + } + } } }, @@ -346,8 +398,10 @@ "example": 2 } } + }, + "source": { + "type": "string" } - } } } @@ -382,6 +436,9 @@ "example": 2 } } + }, + "source": { + "type": "string" } } } From 92ac45a1f73197e0aa1bd89f84828ece1e834b37 Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Wed, 27 Oct 2021 15:26:27 +1030 Subject: [PATCH 05/15] create separate setPoint API --- apis/course/README.md | 40 ++++++++++-- apis/course/openApi.json | 127 +++++++++++++++++++++++++++++++-------- 2 files changed, 138 insertions(+), 29 deletions(-) diff --git a/apis/course/README.md b/apis/course/README.md index ed6d3c80..7fd255ef 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -230,10 +230,10 @@ This will result in the following path values: __d. Select point in the active Route as destination.__ --- -To facilitate a "Previous / Next point" operation: +To facilitate a "go to point in route" operation: - The client will `PUT` or `POST` the following to the `/navigation/course/activeRoute/nextPoint` path: -Option 1: +_Example:_ ```JSON { "value": { @@ -245,7 +245,39 @@ Option 1: where: - `pointIndex`: Zero based index of the point within the route to use as the initial destination (if value is larger than index of last point in the route then destination is not changed). -Option 2: +This will result in the following path values: +```JSON +{ + "activeRoute": { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "startTime": Time at which route was activated (as per Signal K schema) + }, + "nextPoint": { + "href": null, + "type": "RoutePoint", + "position": { + "latitude": latitude of previous point in route, + "longitude": longitude of previous point in route + } + }, + "previousPoint": { + "href": null, + "type": null, + "position": { + "latitude": latitude of vessel at time of destination being set, + "longitude": longitude of vessel at time of destination being set + } + } +} +``` + +__e. Increment / decrement point in the active Route as destination.__ + +--- +To facilitate a "Previous / Next point" operation: +- The client will `PUT` or `POST` the following to the `/navigation/course/activeRoute/nextPoint` path: + +_Example:__ ```JSON { "value": { @@ -283,7 +315,7 @@ This will result in the following path values: } ``` -__e. Query current course details.__ +__f. Query current course details.__ --- To facilitate a "get current course" operation: diff --git a/apis/course/openApi.json b/apis/course/openApi.json index a443a311..898857ce 100644 --- a/apis/course/openApi.json +++ b/apis/course/openApi.json @@ -125,6 +125,7 @@ "application/json": { "schema": { "type": "object", + "required": ["value"], "properties": { "value": { "type": "object", @@ -161,7 +162,8 @@ } }, "source": { - "type": "string" + "type": "string", + "example": "freeboard-sk" } } } @@ -180,6 +182,7 @@ "application/json": { "schema": { "type": "object", + "required": ["value"], "properties": { "value": { "type": "object", @@ -216,7 +219,8 @@ } }, "source": { - "type": "string" + "type": "string", + "example": "freeboard-sk" } } } @@ -235,13 +239,15 @@ "application/json": { "schema": { "type": "object", + "required": ["value"], "properties": { "value": { "type": "object", - "enum": [null] + "default": null }, "source": { - "type": "string" + "type": "string", + "example": "freeboard-sk" } } } @@ -263,6 +269,7 @@ "application/json": { "schema": { "type": "object", + "required": ["value"], "properties": { "value": { "type": "object", @@ -289,7 +296,8 @@ } }, "source": { - "type": "string" + "type": "string", + "example": "freeboard-sk" } } } @@ -308,6 +316,7 @@ "application/json": { "schema": { "type": "object", + "required": ["value"], "properties": { "value": { "type": "object", @@ -334,7 +343,8 @@ } }, "source": { - "type": "string" + "type": "string", + "example": "freeboard-sk" } } } @@ -353,13 +363,15 @@ "application/json": { "schema": { "type": "object", + "required": ["value"], "properties": { "value": { "type": "object", - "enum": [null] + "default": null }, "source": { - "type": "string" + "type": "string", + "example": "freeboard-sk" } } } @@ -372,35 +384,32 @@ "/vessels/self/navigation/course/activeRoute/nextPoint": { "post": { "tags": ["activeRoute/nextPoint"], - "summary": "Set point in route as destination", - "description": "Sets the specified point in the route as destination", + "summary": "Increment / decrement point in route as destination", + "description": "Increment / decrement point in the route as destination", "requestBody": { - "description": "Next point details", + "description": "Increment / decrement", "required": true, "content": { "application/json": { "schema": { "type": "object", + "required": ["value"], "properties": { "value": { "type": "object", + "required": ["increment"], "properties": { - "pointIndex": { - "type": "number", - "description": "Index of point in route to use as destination", - "minimum": 0, - "example": 2 - }, "increment": { "type": "number", "description": "increment (1) / decrement (-1) index of point in route to use as destination", "enum": [-1,1], - "example": 2 + "example": -1 } } }, "source": { - "type": "string" + "type": "string", + "example": "freeboard-sk" } } } @@ -410,15 +419,54 @@ }, "put": { "tags": ["activeRoute/nextPoint"], + "summary": "Increment / decrement point in route as destination", + "description": "Increment / decrement point in the route as destination", + "requestBody": { + "description": "Increment / decrement", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "required": ["increment"], + "properties": { + "increment": { + "type": "number", + "description": "increment (1) / decrement (-1) index of point in route to use as destination", + "enum": [-1,1], + "example": -1 + } + } + }, + "source": { + "type": "string", + "example": "freeboard-sk" + } + } + } + } + } + } + } + }, + + "/vessels/self/navigation/course/activeRoute/setPoint": { + "post": { + "tags": ["activeRoute/setPoint"], "summary": "Set point in route as destination", "description": "Sets the specified point in the route as destination", "requestBody": { - "description": "Next point details", + "description": "Next point index", "required": true, "content": { "application/json": { "schema": { "type": "object", + "required": ["value"], "properties": { "value": { "type": "object", @@ -428,17 +476,46 @@ "description": "Index of point in route to use as destination", "minimum": 0, "example": 2 - }, - "increment": { + } + } + }, + "source": { + "type": "string", + "example": "freeboard-sk" + } + } + } + } + } + } + }, + "put": { + "tags": ["activeRoute/setPoint"], + "summary": "Set point in route as destination", + "description": "Sets the specified point in the route as destination", + "requestBody": { + "description": "Next point index", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "properties": { + "pointIndex": { "type": "number", - "description": "increment (1) / decrement (-1) index of point in route to use as destination", - "enum": [-1,1], + "description": "Index of point in route to use as destination", + "minimum": 0, "example": 2 } } }, "source": { - "type": "string" + "type": "string", + "example": "freeboard-sk" } } } From d2bc0516a2a9922756d9594664acd235ff3d4b53 Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Thu, 28 Oct 2021 11:52:13 +1030 Subject: [PATCH 06/15] Add `restart` api endpoint --- apis/course/README.md | 72 ++++++++++++++++++++++++++++++++++------ apis/course/openApi.json | 57 +++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 11 deletions(-) diff --git a/apis/course/README.md b/apis/course/README.md index 7fd255ef..5cdb031a 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -190,7 +190,7 @@ To facilitate a "Activate Route" operation: { "value": { "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", - "pointIndex": 1, + "pointIndex": 0, "reverse": false }, "source": Source making the change. @@ -220,8 +220,8 @@ This will result in the following path values: "href": null, "type": null, "position": { - "latitude": latitude of vessel at time of destination being set, - "longitude": longitude of vessel at time of destination being set + "latitude": latitude of: vessel (if pointIndex=0) or point at poiintIndex-1, + "longitude": longitude of: vessel (if pointIndex=0) or point at poiintIndex-1 } } } @@ -264,8 +264,8 @@ This will result in the following path values: "href": null, "type": null, "position": { - "latitude": latitude of vessel at time of destination being set, - "longitude": longitude of vessel at time of destination being set + "latitude": latitude of: vessel (if pointIndex=0) or point at poiintIndex-1, + "longitude": longitude of: vessel (if pointIndex=0) or point at poiintIndex-1 } } } @@ -308,14 +308,54 @@ This will result in the following path values: "href": null, "type": null, "position": { - "latitude": latitude of vessel at time of destination being set, - "longitude": longitude of vessel at time of destination being set + "latitude": latitude of: vessel (if pointIndex=0) or point at poiintIndex-1, + "longitude": longitude of: vessel (if pointIndex=0) or point at poiintIndex-1 } } } ``` -__f. Query current course details.__ +__f. Restart course calculations.__ + +--- +To facilitate a `restart` of course calculations from the current vessel location": +- The client will `PUT` or `POST` the following to the `/navigation/course/restart` path: + +_Example:__ +```JSON +{ + "value": null, + "source": Source making the change. +} +``` + +This will result in the following path values: +```JSON +{ + "activeRoute": { + "href": unchanged, + "startTime": unchanged + }, + "nextPoint": { + "href": unchanged, + "type": unchanged, + "position": { + "latitude": unchanged, + "longitude": unchanged + } + }, + "previousPoint": { + "href": null, + "type": null, + "position": { + "latitude": latitude of vessel, + "longitude": longitude of vessel + } + } +} +``` + +__g. Query current course details.__ --- To facilitate a "get current course" operation: @@ -327,7 +367,8 @@ Example: "activeRoute": { "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", "startTime": "2021-10-23T05:17:20.065Z", - "pointIndex": 2 + "pointIndex": 2, + "reverse": false }, "nextPoint": { "href": null, @@ -350,9 +391,18 @@ Example: ### Use of `previousPoint`. --- -To facilitate course calculations such as XTE where the source position is required, the `previousPoint.position` attribute is __always__ set to the location of the vessel each time the destination position is set / changed. +To facilitate course calculations such as XTE where the source position is required, the `previousPoint.position` attribute is set as follows: +- __Set position as destination__: Set to the location of the vessel. +- __Set waypoint as destination__: Set to the location of the vessel. +- __Activate a route__: + + 1. If `pointIndex` is `0` (point at start of the route) then `previousPoint.position` is set to location of the vessel. + + 2. If `pointIndex` is not `0` then `previousPoint.position` is set to the position of the point at `pointIndex-1`. + +- __Restart__: Set to the location of the vessel. -It is set to `null` when the destination has been cleared. +- __Clear/Cancel destination__: Set to `null`. --- diff --git a/apis/course/openApi.json b/apis/course/openApi.json index 898857ce..f7c2d388 100644 --- a/apis/course/openApi.json +++ b/apis/course/openApi.json @@ -257,6 +257,63 @@ } }, + "/vessels/self/navigation/course/reset": { + "put": { + "tags": ["course"], + "summary": "Restart course calculations", + "description": "Sets previousPoint value to current vessel location", + "requestBody": { + "description": "Restart payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "default": null + }, + "source": { + "type": "string", + "example": "freeboard-sk" + } + } + } + } + } + } + }, + "post": { + "tags": ["course"], + "summary": "Restart course calculations", + "description": "Sets previousPoint value to current vessel location", + "requestBody": { + "description": "Restart payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "default": null + }, + "source": { + "type": "string", + "example": "freeboard-sk" + } + } + } + } + } + } + } + }, + "/vessels/self/navigation/course/activeRoute/": { "put": { "tags": ["activeRoute"], From 4c19fdb653875850fa6939da242ab81da445a0f5 Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Thu, 28 Oct 2021 17:20:18 +1030 Subject: [PATCH 07/15] add arrivalCircle API --- apis/course/README.md | 101 ++++++++++++++++++++++++++++++++------- apis/course/openApi.json | 89 ++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 18 deletions(-) diff --git a/apis/course/README.md b/apis/course/README.md index 5cdb031a..de7a2dd2 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -70,7 +70,8 @@ To facilitate a "navigate to here" operation: { "value": { "position": {"latitude": -28.5,"longitude":138.5}, - "type": "Location" + "type": "Location", + "arrivalCircle": 500 }, "source": Source making the change. } @@ -78,13 +79,15 @@ To facilitate a "navigate to here" operation: where: - `position`: The destination lat, lon (as per Signal K schema) - `type` (optional): A string describing the destination (as per Signal K schema). +- `arrivalCircle`: radius of circle centered at destination indicating arrival. This will result in the following path values: ```JSON { "activeRoute": { "href": null, - "startTime": null + "startTime": null, + "pointIndex": null }, "nextPoint": { "href": null, @@ -92,7 +95,8 @@ This will result in the following path values: "position": { "latitude": -28.5, "longitude":138.5 - } + }, + "arrivalCircle": radius in meters }, "previousPoint": { "href": null, @@ -113,20 +117,23 @@ To facilitate a "navigate to selected waypoint" operation: ```JSON { "value": { - "href": "/resources/waypoints/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab" + "href": "/resources/waypoints/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "arrivalCircle": 500 }, "source": Source making the change. } ``` where: - `href`: The path to the target waypoint in `/resources/waypoints/`. +- `arrivalCircle`: radius of circle centered at destination indicating arrival. This will result in the following path values: ```JSON { "activeRoute": { "href": null, - "startTime": null + "startTime": null, + "pointIndex": null }, "nextPoint": { "href": "/resources/waypoints/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", @@ -134,7 +141,8 @@ This will result in the following path values: "position": { "latitude": latitude of waypoint, "longitude": longitude of waypoint - } + }, + "arrivalCircle": radius in meters }, "previousPoint": { "href": null, @@ -166,12 +174,14 @@ This will result in the following path values: { "activeRoute": { "href": null, - "startTime": null + "startTime": null, + "pointIndex": null }, "nextPoint": { "href": null, "type": null, - "position": null + "position": null, + "arrivalCircle": radius in meters }, "previousPoint": { "href": null, @@ -191,7 +201,8 @@ To facilitate a "Activate Route" operation: "value": { "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", "pointIndex": 0, - "reverse": false + "reverse": false, + "arrivalCircle": 500 }, "source": Source making the change. } @@ -200,13 +211,15 @@ where: - `href`: The path to the target route in `/resources/routes/`. - `pointIndex` (optional): Zero based index of the point within the route to use as the initial destination (defaults to 0 if not supplied or if value is larger than index of last point in the route). - `reverse` (optional): If `true` performs operations on route points in reverse order (defaults to false). +- `arrivalCircle`: radius of circle centered at destination indicating arrival. This will result in the following path values: ```JSON { "activeRoute": { "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", - "startTime": Time at which route was activated (as per Signal K schema) + "startTime": Time at which route was activated (as per Signal K schema), + "pointIndex": defaults to 0 }, "nextPoint": { "href": null, @@ -214,7 +227,8 @@ This will result in the following path values: "position": { "latitude": latitude of second point in route, "longitude": longitude of second point in route - } + }, + "arrivalCircle": radius in meters }, "previousPoint": { "href": null, @@ -250,7 +264,8 @@ This will result in the following path values: { "activeRoute": { "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", - "startTime": Time at which route was activated (as per Signal K schema) + "startTime": Time at which route was activated (as per Signal K schema), + "pointIndex": index of route point used as destination }, "nextPoint": { "href": null, @@ -258,7 +273,8 @@ This will result in the following path values: "position": { "latitude": latitude of previous point in route, "longitude": longitude of previous point in route - } + }, + "arrivalCircle": radius in meters }, "previousPoint": { "href": null, @@ -294,7 +310,8 @@ This will result in the following path values: { "activeRoute": { "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", - "startTime": Time at which route was activated (as per Signal K schema) + "startTime": Time at which route was activated (as per Signal K schema), + "pointIndex": index of route point used as destination }, "nextPoint": { "href": null, @@ -302,7 +319,8 @@ This will result in the following path values: "position": { "latitude": latitude of previous point in route, "longitude": longitude of previous point in route - } + }, + "arrivalCircle": radius in meters }, "previousPoint": { "href": null, @@ -334,7 +352,8 @@ This will result in the following path values: { "activeRoute": { "href": unchanged, - "startTime": unchanged + "startTime": unchanged, + "pointIndex": unchanged }, "nextPoint": { "href": unchanged, @@ -342,7 +361,52 @@ This will result in the following path values: "position": { "latitude": unchanged, "longitude": unchanged + }, + "arrivalCircle": radius in meters + }, + "previousPoint": { + "href": null, + "type": null, + "position": { + "latitude": latitude of vessel, + "longitude": longitude of vessel } + } +} +``` + +__g. Set arrival circle.__ + +--- +To facilitate the setting of the radius of a circle centered at destination indicating arrival. +- The client will `PUT` or `POST` the following to the `/navigation/course/arrivalCircle` path: + +_Example:__ +```JSON +{ + "value": { + "radius": 500 + }, + "source": Source making the change. +} +``` + +This will result in the following path values: +```JSON +{ + "activeRoute": { + "href": unchanged, + "startTime": unchanged, + "pointIndex": unchanged + }, + "nextPoint": { + "href": unchanged, + "type": unchanged, + "position": { + "latitude": unchanged, + "longitude": unchanged + }, + "arrivalCircle": radius in meters }, "previousPoint": { "href": null, @@ -355,7 +419,7 @@ This will result in the following path values: } ``` -__g. Query current course details.__ +__h. Query current course details.__ --- To facilitate a "get current course" operation: @@ -368,7 +432,8 @@ Example: "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", "startTime": "2021-10-23T05:17:20.065Z", "pointIndex": 2, - "reverse": false + "reverse": false, + "pointIndex": 2 }, "nextPoint": { "href": null, diff --git a/apis/course/openApi.json b/apis/course/openApi.json index f7c2d388..1f189618 100644 --- a/apis/course/openApi.json +++ b/apis/course/openApi.json @@ -158,6 +158,11 @@ "type": "string", "description": "Type of point", "example": "POI" + }, + "arrivalCircle": { + "type": "number", + "format": "float", + "example": 500 } } }, @@ -215,6 +220,11 @@ "type": "string", "description": "Type of point", "example": "POI" + }, + "arrivalCircle": { + "type": "number", + "format": "float", + "example": 500 } } }, @@ -314,6 +324,75 @@ } }, + "/vessels/self/navigation/course/arrivalCircle": { + "put": { + "tags": ["course"], + "summary": "Set arrival circle radius (m)", + "description": "Sets an arrival circle radius (in meters)", + "requestBody": { + "description": "Arrival circle payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "properties": { + "radius": { + "type": "number", + "format": "float", + "example": 500 + } + } + }, + "source": { + "type": "string", + "example": "freeboard-sk" + } + } + } + } + } + } + }, + "post": { + "tags": ["course"], + "summary": "Set arrival circle radius (m)", + "description": "Sets an arrival circle radius (in meters)", + "requestBody": { + "description": "Arrival circle payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "object", + "properties": { + "radius": { + "type": "number", + "format": "float", + "example": 500 + } + } + }, + "source": { + "type": "string", + "example": "freeboard-sk" + } + } + } + } + } + } + } + }, + "/vessels/self/navigation/course/activeRoute/": { "put": { "tags": ["activeRoute"], @@ -349,6 +428,11 @@ "default": false, "description": "If true performs operations on route points in reverse order", "example": 2 + }, + "arrivalCircle": { + "type": "number", + "format": "float", + "example": 500 } } }, @@ -396,6 +480,11 @@ "default": false, "description": "If true performs operations on route points in reverse order", "example": 2 + }, + "arrivalCircle": { + "type": "number", + "format": "float", + "example": 500 } } }, From 0fd49ee22cb5cf85b07ce89f22ffa1ac3928cfa9 Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Sat, 30 Oct 2021 16:50:21 +1030 Subject: [PATCH 08/15] Remove POST operations --- apis/course/README.md | 357 +++++++++++++++++++++------------------ apis/course/openApi.json | 283 +++---------------------------- 2 files changed, 210 insertions(+), 430 deletions(-) diff --git a/apis/course/README.md b/apis/course/README.md index de7a2dd2..ec7d43f6 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -5,9 +5,11 @@ Define an API for Signal K client applications to be able to set a destination or navigate a route that provides the following methods: - Set a position (lat, lon) as a destination -- Select a waypoint (from `/resources/waypoints`) as a destination -- Activate a route (from `/resources/routes`) +- Reference a waypoint from `/resources/waypoints` as a destination +- Activate a route by supplying a reference from `/resources/routes` +- Specify to follow route points in reverse order - Select the point within the route to be the current destination +- Increment / decrement the point in the route to be the current destination. - Clear / cancel the course - Query the current course details. @@ -20,52 +22,82 @@ Currently Signal K makes available paths to store navigation data but it is larg This is can cause interoperability issues and inconsistency in application (e.g. calculations in `signalk-derived-data` plugin will use a mixture of paths `navigation.courseGreatCircle` and `navigation.courseRhumbline`) so depending on an individual implementation results may vary. +Defining and implementing an API will provide reliability in how the values in these paths are populated ensuring confidence in the source data used in course calculations. + --- -### 1. Signal K Paths in Scope: +### __1. Signal K Paths in Scope:__ -The following paths are relative to `/signalk/v1/api/vessels/self`. +_Note: All paths outlined below are relative to `/signalk/v1/api/vessels/self`._ The Signal K specification contains a `navigation.course` schema definition which is applied to both the `navigation/courseGreatCircle` and `navigation/courseRhumbline` paths. -The following attributes in both these paths are in scope for management by this API. +The following properties under both these paths are in scope for management by this API: ``` -activeRoute/href -activeRoute/startTime -``` +activeRoute.href +activeRoute.startTime -``` -nextPoint/value/href -nextPoint/value/type -nextPoint/position -``` +nextPoint.value.href +nextPoint.value.type +nextPoint.position -``` -previousPoint/value/href -previousPoint/value/type -previousPoint/position +previousPoint.value.href +previousPoint.value.type +previousPoint.position ``` -Additionally it will provide a path to query the current course information. +This API will provide endpoints under the path `navigation/course` in order to set a course as well as query the current course information. -``` -navigation/course -``` +### 1.1 Enabling other navigation equipment (e.g. autopilot) operation. +--- +By clearly defining and managing the use of specific `course` paths within the Signal K schema, this will ensure consistency in the values they contain and engender confidence in their use. + +Maintianing quality data in these paths enables the reliable operation of other navigation equipment such as: +- Course computers +- Auto-pilots + +by providing a trusted source of data for use in calculating navigation information for steering a course. + +The paths within the Signal K schema pertaining to other navigation operations will be maintained by the relevant equipment or Signal K API. + +--- + +### __2.API Operation:__ +While the intended use of the `in scope` Signal K paths are defined in the specification, the actual use of these paths in practise determines the success of an implementation. + +### 2.1 Use of `previousPoint`. --- +To facilitate course calculations such as XTE where the source position is required, the `previousPoint.position` attribute will be set as follows: +- __When a position (lat, lon) is supplied as a destination__: Set the value of `previousPoint.position` to the location of the vessel. +- __When a reference to a waypoint resource is supplied as a destination__: Set the value of `previousPoint.position` to the location of the vessel. +- __When a reference to a route resource is is supplied__: + + 1. If the supplied route `pointIndex` is `0` (point at start of the route) then set the value of `previousPoint.position` to the location of the vessel. + + 2. If the supplied route `pointIndex` is not `0` then set the value of`previousPoint.position` to that of the preceding point in the route. + +- __When a "Course Restart" is requested__: Set the value of `previousPoint.position` to the location of the vessel. + +- __When a destination or active route is "Cancelled"__: then set the value of`previousPoint.position` to `null`. -### 2. How In Scope paths are used: +--- -While the intended use of the `in scope` Signal K paths are defined in the specification, the use of these paths in practise determines the success of an implementation. +### __3.API Methods:__ -_Following is the proposed operation of the course API for each of the proposed methods:_ +The following endpoints under the path `navigation/course` make up the Course API. -__a. Set a position (lat, lon) as a destination.__ +### 3.1 Set a position (lat, lon) as a destination --- -To facilitate a "navigate to here" operation: -- The client will `PUT` or `POST` the following to the `/navigation/course/destination` path: +__Use case:__ Provide _"navigate to here"_ operation. + +__Action:__ `PUT` + +__Path:__ `/navigation/course/destination` + +__Request body:__ ```JSON { "value": { @@ -79,24 +111,23 @@ To facilitate a "navigate to here" operation: where: - `position`: The destination lat, lon (as per Signal K schema) - `type` (optional): A string describing the destination (as per Signal K schema). -- `arrivalCircle`: radius of circle centered at destination indicating arrival. +- `arrivalCircle`(optional): Radius of circle centered at destination indicating arrival. -This will result in the following path values: +This will result in the following Signal K path values being set: ```JSON { "activeRoute": { "href": null, - "startTime": null, - "pointIndex": null + "startTime": null }, "nextPoint": { "href": null, - "type": "Location", + "type": null if type not supplied, "position": { - "latitude": -28.5, - "longitude":138.5 + "latitude": supplied latitude, + "longitude": supplied longitude }, - "arrivalCircle": radius in meters + "arrivalCircle": unchanged if value not suplied }, "previousPoint": { "href": null, @@ -109,11 +140,15 @@ This will result in the following path values: } ``` -__b. Set a Waypoint as a destination.__ - +### 3.2 Set a Waypoint as a destination --- -To facilitate a "navigate to selected waypoint" operation: -- The client will `PUT` or `POST` the following to the `/navigation/course/destination` path: +__Use case:__ Provide _"navigate to selected waypoint resource"_ operation. + +__Action:__ `PUT` + +__Path:__ `/navigation/course/destination` + +__Request body:__ ```JSON { "value": { @@ -125,24 +160,23 @@ To facilitate a "navigate to selected waypoint" operation: ``` where: - `href`: The path to the target waypoint in `/resources/waypoints/`. -- `arrivalCircle`: radius of circle centered at destination indicating arrival. +- `arrivalCircle` (optional): Radius of circle centered at destination indicating arrival. -This will result in the following path values: +This will result in the following Signal K path values being set: ```JSON { "activeRoute": { "href": null, - "startTime": null, - "pointIndex": null + "startTime": null }, "nextPoint": { - "href": "/resources/waypoints/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", - "type": "Waypoint", + "href": supplied href, + "type": null if type not supplied, "position": { - "latitude": latitude of waypoint, - "longitude": longitude of waypoint + "latitude": latitude of referenced waypoint, + "longitude": longitude of referenced waypoint }, - "arrivalCircle": radius in meters + "arrivalCircle": unchanged if value not supplied }, "previousPoint": { "href": null, @@ -155,12 +189,15 @@ This will result in the following path values: } ``` -__c. Clear / Cancel a destination or Activated Route.__ - +### 3.3 Clear / Cancel a destination or Activated Route. --- -To facilitate a "navigate to selected waypoint" operation the client will send a `DELETE` request to either of the the following paths: -- `/navigation/course/destination` -- `/navigation/course/activeRoute` +__Use case:__ Provide _"stop navigating to destination"_ or _"deactivate as route"_ operation. + +__Action:__ `DELETE` + +__Path:__ `/navigation/course/destination` or `/navigation/course/activeRoute` + +__Request body:__ ```JSON { @@ -169,19 +206,18 @@ To facilitate a "navigate to selected waypoint" operation the client will send a } ``` -This will result in the following path values: +This will result in the following Signal K path values being set: ```JSON { "activeRoute": { "href": null, - "startTime": null, - "pointIndex": null + "startTime": null }, "nextPoint": { "href": null, "type": null, "position": null, - "arrivalCircle": radius in meters + "arrivalCircle": unchanged }, "previousPoint": { "href": null, @@ -191,11 +227,16 @@ This will result in the following path values: } ``` -__d. Activate a Route to follow.__ - +### 3.4 Activate a Route to follow. --- -To facilitate a "Activate Route" operation: -- The client will `PUT` or `POST` the following to the `/navigation/course/activeRoute` path: + +__Use case:__ Provide _"activate / follow a route"_ operation. + +__Action:__ `PUT` + +__Path:__ `/navigation/course/activeRoute` + +__Request body:__ ```JSON { "value": { @@ -211,43 +252,44 @@ where: - `href`: The path to the target route in `/resources/routes/`. - `pointIndex` (optional): Zero based index of the point within the route to use as the initial destination (defaults to 0 if not supplied or if value is larger than index of last point in the route). - `reverse` (optional): If `true` performs operations on route points in reverse order (defaults to false). -- `arrivalCircle`: radius of circle centered at destination indicating arrival. +- `arrivalCircle` (optional): Radius of circle centered at destination indicating arrival. -This will result in the following path values: +This will result in the following Signal K path values being set: ```JSON { "activeRoute": { - "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", - "startTime": Time at which route was activated (as per Signal K schema), - "pointIndex": defaults to 0 + "href": supplied href, + "startTime": Time at which route was activated (as per Signal K schema) }, "nextPoint": { "href": null, - "type": "RoutePoint", + "type": null if value not supplied, "position": { - "latitude": latitude of second point in route, - "longitude": longitude of second point in route + "latitude": latitude of route point at supplied index, + "longitude": longitude of route point at supplied index }, - "arrivalCircle": radius in meters + "arrivalCircle": unchanged if value not supplied }, "previousPoint": { "href": null, "type": null, "position": { - "latitude": latitude of: vessel (if pointIndex=0) or point at poiintIndex-1, - "longitude": longitude of: vessel (if pointIndex=0) or point at poiintIndex-1 + "latitude": latitude of: vessel if supplied pointIndex=0 or point at poiintIndex-1, + "longitude": longitude of: vessel if supplied pointIndex=0 or point at poiintIndex-1 } } } ``` -__d. Select point in the active Route as destination.__ - +### 3.5 Select point in the active Route as destination. --- -To facilitate a "go to point in route" operation: -- The client will `PUT` or `POST` the following to the `/navigation/course/activeRoute/nextPoint` path: +__Use case:__ Provide _"go to point in route"_ operation. + +__Action:__ `PUT` -_Example:_ +__Path:__ `/navigation/course/activeRoute/setPoint` + +__Request body:__ ```JSON { "value": { @@ -259,41 +301,42 @@ _Example:_ where: - `pointIndex`: Zero based index of the point within the route to use as the initial destination (if value is larger than index of last point in the route then destination is not changed). -This will result in the following path values: +This will result in the following Signal K path values being set: ```JSON { "activeRoute": { - "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", - "startTime": Time at which route was activated (as per Signal K schema), - "pointIndex": index of route point used as destination + "href": unchanged, + "startTime": unchanged }, "nextPoint": { - "href": null, - "type": "RoutePoint", + "href": unchanged, + "type": unchanged, "position": { - "latitude": latitude of previous point in route, - "longitude": longitude of previous point in route + "latitude": latitude of route point at supplied index, + "longitude": longitude of route point at supplied index }, - "arrivalCircle": radius in meters + "arrivalCircle": unchanged }, "previousPoint": { - "href": null, - "type": null, + "href": unchanged, + "type": unchanged, "position": { - "latitude": latitude of: vessel (if pointIndex=0) or point at poiintIndex-1, - "longitude": longitude of: vessel (if pointIndex=0) or point at poiintIndex-1 + "latitude": latitude of: vessel if pointIndex=0 or route point at poiintIndex-1, + "longitude": longitude of: vessel if pointIndex=0 or route point at poiintIndex-1 } } } ``` -__e. Increment / decrement point in the active Route as destination.__ - +### 3.6 Increment / decrement point in the active Route as destination. --- -To facilitate a "Previous / Next point" operation: -- The client will `PUT` or `POST` the following to the `/navigation/course/activeRoute/nextPoint` path: +__Use case:__ Provide _"previous / next point"_ operation. + +__Action:__ `PUT` + +__Path:__ `/navigation/course/activeRoute/nextPoint` -_Example:__ +__Request body:__ ```JSON { "value": { @@ -305,26 +348,25 @@ _Example:__ where: - `increment`: Is either `1` (next point) or `-1` (previous point). -This will result in the following path values: +This will result in the following Signal K path values being set: ```JSON { "activeRoute": { - "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", - "startTime": Time at which route was activated (as per Signal K schema), - "pointIndex": index of route point used as destination + "href": unchanged, + "startTime": unchanged }, "nextPoint": { - "href": null, - "type": "RoutePoint", + "href": unchanged, + "type": unchanged, "position": { - "latitude": latitude of previous point in route, - "longitude": longitude of previous point in route + "latitude": latitude of previous (if -1 supplied) or next (if 1 supplied) route point, + "longitude": longitude of previous (if -1 supplied) or next (if 1 supplied) route point }, - "arrivalCircle": radius in meters + "arrivalCircle": unchanged }, "previousPoint": { - "href": null, - "type": null, + "href": unchanged, + "type": unchanged, "position": { "latitude": latitude of: vessel (if pointIndex=0) or point at poiintIndex-1, "longitude": longitude of: vessel (if pointIndex=0) or point at poiintIndex-1 @@ -333,27 +375,27 @@ This will result in the following path values: } ``` -__f. Restart course calculations.__ - +### 3.7 Restart course calculations. --- -To facilitate a `restart` of course calculations from the current vessel location": -- The client will `PUT` or `POST` the following to the `/navigation/course/restart` path: +__Use case:__ Provide _"restart XTE"_ operation. -_Example:__ +__Action:__ `PUT` + +__Path:__ `/navigation/course/activeRoute/restart` + +__Request body:__ ```JSON { "value": null, "source": Source making the change. } ``` - -This will result in the following path values: +This will result in the following Signal K path values being set: ```JSON { "activeRoute": { "href": unchanged, - "startTime": unchanged, - "pointIndex": unchanged + "startTime": unchanged }, "nextPoint": { "href": unchanged, @@ -362,11 +404,11 @@ This will result in the following path values: "latitude": unchanged, "longitude": unchanged }, - "arrivalCircle": radius in meters + "arrivalCircle": unchanged }, "previousPoint": { - "href": null, - "type": null, + "href": unchanged, + "type": unchanged, "position": { "latitude": latitude of vessel, "longitude": longitude of vessel @@ -375,13 +417,15 @@ This will result in the following path values: } ``` -__g. Set arrival circle.__ - +### 3.8 Set arrival circle. --- -To facilitate the setting of the radius of a circle centered at destination indicating arrival. -- The client will `PUT` or `POST` the following to the `/navigation/course/arrivalCircle` path: +__Use case:__ Provide ability to set the radius of a circle centered at destination indicating arrival. + +__Action:__ `PUT` -_Example:__ +__Path:__ `/navigation/course/arrivalCircle` + +__Request body:__ ```JSON { "value": { @@ -390,14 +434,15 @@ _Example:__ "source": Source making the change. } ``` +where: +- `radius`: Is the radius of the circle in meters. -This will result in the following path values: +This will result in the following Signal K path values being set: ```JSON { "activeRoute": { "href": unchanged, - "startTime": unchanged, - "pointIndex": unchanged + "startTime": unchanged }, "nextPoint": { "href": unchanged, @@ -406,26 +451,28 @@ This will result in the following path values: "latitude": unchanged, "longitude": unchanged }, - "arrivalCircle": radius in meters + "arrivalCircle": supplied value }, "previousPoint": { - "href": null, - "type": null, + "href": unchanged, + "type": unchanged, "position": { - "latitude": latitude of vessel, - "longitude": longitude of vessel + "latitude": unchanged, + "longitude": unchanged } } } ``` -__h. Query current course details.__ - +### 3.9 Query current course details. --- -To facilitate a "get current course" operation: -- The client will make a `GET` request to the `/navigation/course` path and a response of the following format, detailing the course values, will be returned. +__Use case:__ Provide "get current course", "get course details" operation. -Example: +__Action:__ `GET` + +__Path:__ `/navigation/course` + +__Response:__ JSON formatted object containing the current course details as per the following example: ```JSON { "activeRoute": { @@ -454,47 +501,19 @@ Example: } ``` -### Use of `previousPoint`. ---- -To facilitate course calculations such as XTE where the source position is required, the `previousPoint.position` attribute is set as follows: -- __Set position as destination__: Set to the location of the vessel. -- __Set waypoint as destination__: Set to the location of the vessel. -- __Activate a route__: - - 1. If `pointIndex` is `0` (point at start of the route) then `previousPoint.position` is set to location of the vessel. - - 2. If `pointIndex` is not `0` then `previousPoint.position` is set to the position of the point at `pointIndex-1`. - -- __Restart__: Set to the location of the vessel. - -- __Clear/Cancel destination__: Set to `null`. - ---- - -## Enabling other navigation equipment (e.g. autopilot) operation. - -This API seeks to define and manage the use of specific `course` paths within the Signal K schema to provide consistency and confidence in the values they contain. - -Maintianing quality data in these paths enables operation of other navigation equipment such as: -- Course computers -- Auto-pilots -by providing a source of data that can be trusted for use in calculating navigation information for steering a course. - -The paths within the Signal K schema pertaining to other navigation operations will be maintained by the relevant equipment or Signal K API . - --- -## Signal K stream Deltas. +### __4. Signal K Stream Deltas__ -The use of the API endpoints outlined above will trigger delta messages to be sent for related Signal K paths (in-scope paths) where: +The implementation of the Course API requires that the relevant delta messages are sent for the in-scope Signal K paths when: - Values have changed -- Periodically for all paths that have a current value. +- Periodically e.g. every 30 seconds). The absence of a delta for a specific Signal K path indicates that the path has never had a value assigned to it. -Where a delta value is `null`, this indicates that a previous value is no longer valid (i.e. there is a provider for this path but there is no current value). +Where a delta value is `null`, this indicates that a previous value is no longer valid (i.e. there is a provider for this path but there is no current value available). -_Delta messages for in-scope paths:_ +Delta messages for in-scope paths are as follows: ```JSON [ { diff --git a/apis/course/openApi.json b/apis/course/openApi.json index 1f189618..eab4f82c 100644 --- a/apis/course/openApi.json +++ b/apis/course/openApi.json @@ -47,6 +47,10 @@ "type": "number", "format": "int64", "example": 2 + }, + "reverse": { + "type": "boolean", + "default": false } } }, @@ -113,13 +117,13 @@ } }, - "/vessels/self/navigation/course/destination/": { + "/vessels/self/navigation/course/restart": { "put": { - "tags": ["destination"], - "summary": "Set destination", - "description": "Set destination path from supplied details", + "tags": ["course"], + "summary": "Restart course calculations", + "description": "Sets previousPoint value to current vessel location", "requestBody": { - "description": "Destination details", + "description": "Restart payload", "required": true, "content": { "application/json": { @@ -129,55 +133,23 @@ "properties": { "value": { "type": "object", - "properties": { - "position": { - "type": "object", - "description": "Destination position", - "required": [ - "latitude", - "longitude" - ], - "properties": { - "latitude": { - "type": "number", - "format": "float" - }, - "longitude": { - "type": "number", - "format": "float" - } - }, - "example": {"latitude":-29.5,"longitude":137.5} - }, - "href": { - "type": "string", - "description": "A reference (URL) to an object (under /resources) this point is related to", - "example": "/resources/waypoints/urn:mrn:signalk:uuid:3dd34dcc-36bf-4d61-ba80-233799b25672" - }, - "type": { - "type": "string", - "description": "Type of point", - "example": "POI" - }, - "arrivalCircle": { - "type": "number", - "format": "float", - "example": 500 - } - } + "default": null }, "source": { "type": "string", "example": "freeboard-sk" - } + } } } } } } - }, - "post": { - "tags": ["destination"], + } + }, + + "/vessels/self/navigation/course/destination/": { + "put": { + "tags": ["course/destination"], "summary": "Set destination", "description": "Set destination path from supplied details", "requestBody": { @@ -239,7 +211,7 @@ } }, "delete": { - "tags": ["destination"], + "tags": ["course/destination"], "summary": "Clear destination", "description": "Sets activeRoute, nextPoint & previousPoint values to null", "requestBody": { @@ -267,63 +239,6 @@ } }, - "/vessels/self/navigation/course/reset": { - "put": { - "tags": ["course"], - "summary": "Restart course calculations", - "description": "Sets previousPoint value to current vessel location", - "requestBody": { - "description": "Restart payload", - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["value"], - "properties": { - "value": { - "type": "object", - "default": null - }, - "source": { - "type": "string", - "example": "freeboard-sk" - } - } - } - } - } - } - }, - "post": { - "tags": ["course"], - "summary": "Restart course calculations", - "description": "Sets previousPoint value to current vessel location", - "requestBody": { - "description": "Restart payload", - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["value"], - "properties": { - "value": { - "type": "object", - "default": null - }, - "source": { - "type": "string", - "example": "freeboard-sk" - } - } - } - } - } - } - } - }, - "/vessels/self/navigation/course/arrivalCircle": { "put": { "tags": ["course"], @@ -357,97 +272,12 @@ } } } - }, - "post": { - "tags": ["course"], - "summary": "Set arrival circle radius (m)", - "description": "Sets an arrival circle radius (in meters)", - "requestBody": { - "description": "Arrival circle payload", - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["value"], - "properties": { - "value": { - "type": "object", - "properties": { - "radius": { - "type": "number", - "format": "float", - "example": 500 - } - } - }, - "source": { - "type": "string", - "example": "freeboard-sk" - } - } - } - } - } - } } }, "/vessels/self/navigation/course/activeRoute/": { "put": { - "tags": ["activeRoute"], - "summary": "Set active route", - "description": "Sets activeRoute path and sets nextPoint to first point in the route", - "requestBody": { - "description": "Active route details", - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["value"], - "properties": { - "value": { - "type": "object", - "properties": { - "href": { - "type": "string", - "description": "Path to route resource", - "example": "/resources/routes/urn:mrn:signalk:uuid:3dd34dcc-36bf-4d61-ba80-233799b25672" - }, - "pointIndex": { - "type": "number", - "format": "int64", - "description": "Zero based index of route point to use as destination", - "default": 0, - "minimum": 0, - "example": 2 - }, - "reverse": { - "type": "boolean", - "default": false, - "description": "If true performs operations on route points in reverse order", - "example": 2 - }, - "arrivalCircle": { - "type": "number", - "format": "float", - "example": 500 - } - } - }, - "source": { - "type": "string", - "example": "freeboard-sk" - } - } - } - } - } - } - }, - "post": { - "tags": ["activeRoute"], + "tags": ["course/activeRoute"], "summary": "Set active route", "description": "Sets activeRoute path and sets nextPoint to first point in the route", "requestBody": { @@ -499,7 +329,7 @@ } }, "delete": { - "tags": ["activeRoute"], + "tags": ["course/activeRoute"], "summary": "Clear active route", "description": "Sets activeRoute, nextPoint & previousPoint values to null", "requestBody": { @@ -528,43 +358,8 @@ }, "/vessels/self/navigation/course/activeRoute/nextPoint": { - "post": { - "tags": ["activeRoute/nextPoint"], - "summary": "Increment / decrement point in route as destination", - "description": "Increment / decrement point in the route as destination", - "requestBody": { - "description": "Increment / decrement", - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["value"], - "properties": { - "value": { - "type": "object", - "required": ["increment"], - "properties": { - "increment": { - "type": "number", - "description": "increment (1) / decrement (-1) index of point in route to use as destination", - "enum": [-1,1], - "example": -1 - } - } - }, - "source": { - "type": "string", - "example": "freeboard-sk" - } - } - } - } - } - } - }, "put": { - "tags": ["activeRoute/nextPoint"], + "tags": ["course/activeRoute"], "summary": "Increment / decrement point in route as destination", "description": "Increment / decrement point in the route as destination", "requestBody": { @@ -601,42 +396,8 @@ }, "/vessels/self/navigation/course/activeRoute/setPoint": { - "post": { - "tags": ["activeRoute/setPoint"], - "summary": "Set point in route as destination", - "description": "Sets the specified point in the route as destination", - "requestBody": { - "description": "Next point index", - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["value"], - "properties": { - "value": { - "type": "object", - "properties": { - "pointIndex": { - "type": "number", - "description": "Index of point in route to use as destination", - "minimum": 0, - "example": 2 - } - } - }, - "source": { - "type": "string", - "example": "freeboard-sk" - } - } - } - } - } - } - }, "put": { - "tags": ["activeRoute/setPoint"], + "tags": ["course/activeRoute"], "summary": "Set point in route as destination", "description": "Sets the specified point in the route as destination", "requestBody": { From 4c47a69805371e59a43c799d5e0cc8d54b664bd6 Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Fri, 5 Nov 2021 16:23:32 +1030 Subject: [PATCH 09/15] remove trailing / --- apis/course/openApi.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apis/course/openApi.json b/apis/course/openApi.json index eab4f82c..97ca8d5d 100644 --- a/apis/course/openApi.json +++ b/apis/course/openApi.json @@ -275,7 +275,7 @@ } }, - "/vessels/self/navigation/course/activeRoute/": { + "/vessels/self/navigation/course/activeRoute": { "put": { "tags": ["course/activeRoute"], "summary": "Set active route", From a7b77fd20e715fd7250e201bab5fa261540d68e5 Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Fri, 5 Nov 2021 16:39:43 +1030 Subject: [PATCH 10/15] rename setPoint to pointIndex --- apis/course/README.md | 8 +++----- apis/course/openApi.json | 15 +++++---------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/apis/course/README.md b/apis/course/README.md index ec7d43f6..8cb3cc63 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -287,19 +287,17 @@ __Use case:__ Provide _"go to point in route"_ operation. __Action:__ `PUT` -__Path:__ `/navigation/course/activeRoute/setPoint` +__Path:__ `/navigation/course/activeRoute/pointIndex` __Request body:__ ```JSON { - "value": { - "pointIndex": 3 - }, + "value": 3, "source": Source making the change. } ``` where: -- `pointIndex`: Zero based index of the point within the route to use as the initial destination (if value is larger than index of last point in the route then destination is not changed). +- `value`: Zero based index of the point within the route to use as the initial destination (if value is larger than index of last point in the route then destination is not changed). This will result in the following Signal K path values being set: ```JSON diff --git a/apis/course/openApi.json b/apis/course/openApi.json index 97ca8d5d..36ec3704 100644 --- a/apis/course/openApi.json +++ b/apis/course/openApi.json @@ -395,7 +395,7 @@ } }, - "/vessels/self/navigation/course/activeRoute/setPoint": { + "/vessels/self/navigation/course/activeRoute/pointIndex": { "put": { "tags": ["course/activeRoute"], "summary": "Set point in route as destination", @@ -410,15 +410,10 @@ "required": ["value"], "properties": { "value": { - "type": "object", - "properties": { - "pointIndex": { - "type": "number", - "description": "Index of point in route to use as destination", - "minimum": 0, - "example": 2 - } - } + "type": "number", + "description": "Index of point in route to use as destination", + "minimum": 0, + "example": 2 }, "source": { "type": "string", From fd792d45ee02e131a3eeabccefc6628a408a3359 Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Fri, 5 Nov 2021 17:15:41 +1030 Subject: [PATCH 11/15] address comments. --- apis/course/README.md | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/apis/course/README.md b/apis/course/README.md index 8cb3cc63..fa58da90 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -2,28 +2,36 @@ ## Description: -Define an API for Signal K client applications to be able to set a destination or navigate a route that provides the following methods: +Define an API for Signal K client applications that provides methods to set a destination or navigate a route. -- Set a position (lat, lon) as a destination -- Reference a waypoint from `/resources/waypoints` as a destination -- Activate a route by supplying a reference from `/resources/routes` -- Specify to follow route points in reverse order -- Select the point within the route to be the current destination -- Increment / decrement the point in the route to be the current destination. -- Clear / cancel the course -- Query the current course details. +These methods manage the setting of values in the relevant Signal K paths under both `navigation.courseGreatCircle` and `navigation.courseRhumbline` to enable a course computer to generate additional navigation information (XTE, DTG, etc) as well as facilitate display on a chart plotter. + +The API will facilitate operations such as: +- Setting a position (lat, lon) as a destination +- Referencing a waypoint from `/resources/waypoints` as a destination +- Activating a route by supplying a reference to an entry under `/resources/routes` +- Specify to follow route points in reverse order, etc. -The methods described above will set values in the relevant Signal K paths under both `navigation.courseGreatCircle` and `navigation.courseRhumbline` to enable a course computer to generate additional navigation information (XTE, DTG, etc) as well as facilitate display on a chart plotter. --- -### Why an API: +### Motivation: Currently Signal K makes available paths to store navigation data but it is largely left up to implementors of client applications to determine how they are used. This is can cause interoperability issues and inconsistency in application (e.g. calculations in `signalk-derived-data` plugin will use a mixture of paths `navigation.courseGreatCircle` and `navigation.courseRhumbline`) so depending on an individual implementation results may vary. Defining and implementing an API will provide reliability in how the values in these paths are populated ensuring confidence in the source data used in course calculations. +By clearly defining and managing the use of specific `course` paths within the Signal K schema, this will ensure consistency in the values they contain and engender confidence in their use. + +Maintaining quality data in these paths enables the reliable operation of other navigation equipment such as: +- Course computers +- Auto-pilots + +by providing a trusted source of data for use in calculating navigation information for steering a course. + +The paths within the Signal K schema pertaining to other navigation operations will be maintained by the relevant equipment or Signal K API. + --- ### __1. Signal K Paths in Scope:__ @@ -49,17 +57,6 @@ previousPoint.position This API will provide endpoints under the path `navigation/course` in order to set a course as well as query the current course information. -### 1.1 Enabling other navigation equipment (e.g. autopilot) operation. ---- -By clearly defining and managing the use of specific `course` paths within the Signal K schema, this will ensure consistency in the values they contain and engender confidence in their use. - -Maintianing quality data in these paths enables the reliable operation of other navigation equipment such as: -- Course computers -- Auto-pilots - -by providing a trusted source of data for use in calculating navigation information for steering a course. - -The paths within the Signal K schema pertaining to other navigation operations will be maintained by the relevant equipment or Signal K API. --- @@ -69,7 +66,7 @@ While the intended use of the `in scope` Signal K paths are defined in the speci ### 2.1 Use of `previousPoint`. --- -To facilitate course calculations such as XTE where the source position is required, the `previousPoint.position` attribute will be set as follows: +To facilitate course calculations such as XTE where the source position is required, the `previousPoint.position` attribute will be set (at the time the destination is set) as follows: - __When a position (lat, lon) is supplied as a destination__: Set the value of `previousPoint.position` to the location of the vessel. - __When a reference to a waypoint resource is supplied as a destination__: Set the value of `previousPoint.position` to the location of the vessel. - __When a reference to a route resource is is supplied__: From 837aecd3093a14d0331924a8e9e82551064487da Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Mon, 8 Nov 2021 13:22:51 +1030 Subject: [PATCH 12/15] Re-format README.md as per other spec docs. --- apis/course/README.md | 651 ++++++++++++++++++--------------------- apis/course/openApi.json | 38 +-- 2 files changed, 305 insertions(+), 384 deletions(-) diff --git a/apis/course/README.md b/apis/course/README.md index fa58da90..80e0286e 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -1,481 +1,419 @@ -# Feature: Course API +# Course API -## Description: +The Course API provides methods to facilitate setting a destination and navigating a route for use by Signal K client applications. -Define an API for Signal K client applications that provides methods to set a destination or navigate a route. +These methods manage the setting of values in the relevant Signal K paths under both `navigation.courseGreatCircle` and `navigation.courseRhumbline` to enable the generation of additional navigation information (XTE, DTG, etc) by a course computer as well as facilitate display on a chart plotter. -These methods manage the setting of values in the relevant Signal K paths under both `navigation.courseGreatCircle` and `navigation.courseRhumbline` to enable a course computer to generate additional navigation information (XTE, DTG, etc) as well as facilitate display on a chart plotter. +The API will facilitate operations such as setting a position (lat, lon) as a destination, referencing a waypoint from `/resources/waypoints` as a destination, activating a route by supplying a reference to an entry under `/resources/routes`, etc. -The API will facilitate operations such as: -- Setting a position (lat, lon) as a destination -- Referencing a waypoint from `/resources/waypoints` as a destination -- Activating a route by supplying a reference to an entry under `/resources/routes` -- Specify to follow route points in reverse order, etc. +In this way a known, consistant method is used to maintain quality data in these paths enabling the reliable operation of other navigation equipment such as `course computers` and `auto-pilots`. ---- - -### Motivation: -Currently Signal K makes available paths to store navigation data but it is largely left up to implementors of client applications to determine how they are used. -This is can cause interoperability issues and inconsistency in application (e.g. calculations in `signalk-derived-data` plugin will use a mixture of paths `navigation.courseGreatCircle` and `navigation.courseRhumbline`) so depending on an individual implementation results may vary. +## Expected implementation behaviour -Defining and implementing an API will provide reliability in how the values in these paths are populated ensuring confidence in the source data used in course calculations. +The server will provide API endpoints under the path `navigation/course` to facilitate setting a course as well as querying the current course information. -By clearly defining and managing the use of specific `course` paths within the Signal K schema, this will ensure consistency in the values they contain and engender confidence in their use. +The API methods will maintain the following paths under`/signalk/v1/api/vessels/self/navigation`: -Maintaining quality data in these paths enables the reliable operation of other navigation equipment such as: -- Course computers -- Auto-pilots - -by providing a trusted source of data for use in calculating navigation information for steering a course. +``` +courseGreatCircle.activeRoute.href +courseGreatCircle.activeRoute.startTime +courseGreatCircle.nextPoint.value.href +courseGreatCircle.nextPoint.value.type +courseGreatCircle.nextPoint.position +courseGreatCircle.nextPoint.arrivalCircle +courseGreatCircle.previousPoint.value.href +courseGreatCircle.previousPoint.value.type +courseGreatCircle.previousPoint.position + +courseRhumbline.activeRoute.href +courseRhumbline.activeRoute.startTime +courseRhumbline.nextPoint.value.href +courseRhumbline.nextPoint.value.type +courseRhumbline.nextPoint.position +courseRhumbline.nextPoint.arrivalCircle +courseRhumbline.previousPoint.value.href +courseRhumbline.previousPoint.value.type +courseRhumbline.previousPoint.position +``` -The paths within the Signal K schema pertaining to other navigation operations will be maintained by the relevant equipment or Signal K API. +### Use of `previousPoint.position`: +To facilitate course calculations the `previousPoint.position` attribute will be set as follows at the time the destination is set / changed: ---- +- __When a position (lat, lon) or reference to a waypoint resource is supplied as a destination__: The value of `previousPoint.position` will be set to the current location of the vessel. -### __1. Signal K Paths in Scope:__ +- __When a route is activated by supplying a reference to a route resource__: -_Note: All paths outlined below are relative to `/signalk/v1/api/vessels/self`._ + 1. If the point at start of the route is the current destination then the value of `previousPoint.position` will be set to the current location of the vessel. -The Signal K specification contains a `navigation.course` schema definition which is applied to both the `navigation/courseGreatCircle` and `navigation/courseRhumbline` paths. + 2. If any other point in the route is the current destination then the value of `previousPoint.position` will be set to the position of of the preceding point in the route. -The following properties under both these paths are in scope for management by this API: +- __When a "Course Restart" is requested__: The value of `previousPoint.position` will be set to the current location of the vessel. -``` -activeRoute.href -activeRoute.startTime +- __When a destination or active route is "Cancelled"__: The value of`previousPoint.position` will be set to `null`. -nextPoint.value.href -nextPoint.value.type -nextPoint.position -previousPoint.value.href -previousPoint.value.type -previousPoint.position -``` +### Use of `pointIndex`: -This API will provide endpoints under the path `navigation/course` in order to set a course as well as query the current course information. +The API uses the parameter `pointIndex` to specify a point within a route. +`pointIndex` is a zero-based index which represents the position of a point, within an array of route points, relative to the start of the journey. ---- +So setting `pointIndex`= 0 references the first point in the journey relative to the direction the route is being navigated. (i.e. forward or reverse). -### __2.API Operation:__ +Calling `nextPoint` API method with an increment value of 1 increments the value of `pointIndex` i.e. 0->1, 1->2, etc. -While the intended use of the `in scope` Signal K paths are defined in the specification, the actual use of these paths in practise determines the success of an implementation. +Calling `nextPoint` API method with an increment value of -1 increments the value of `pointIndex` i.e. 4->3, 3->2, etc. -### 2.1 Use of `previousPoint`. ---- -To facilitate course calculations such as XTE where the source position is required, the `previousPoint.position` attribute will be set (at the time the destination is set) as follows: -- __When a position (lat, lon) is supplied as a destination__: Set the value of `previousPoint.position` to the location of the vessel. -- __When a reference to a waypoint resource is supplied as a destination__: Set the value of `previousPoint.position` to the location of the vessel. -- __When a reference to a route resource is is supplied__: +So for example consider a route with 4 points: +``` +{latitude: 65.4, longitude: 7.8} +{latitude: 65.4, longitude: 7.8} +{latitude: 65.4, longitude: 7.8} +{latitude: 65.4, longitude: 7.8} +``` +_Following a route in `forward mode`:_ - 1. If the supplied route `pointIndex` is `0` (point at start of the route) then set the value of `previousPoint.position` to the location of the vessel. +``` +{latitude: 65.4, longitude: 7.8} <= pointIndex=0 +{latitude: 65.4, longitude: 7.8} <= pointIndex=1 +{latitude: 65.4, longitude: 7.8} <= pointIndex=2 +{latitude: 65.4, longitude: 7.8} <= pointIndex=3 +``` - 2. If the supplied route `pointIndex` is not `0` then set the value of`previousPoint.position` to that of the preceding point in the route. +_Following a route in `reverse mode`:_ -- __When a "Course Restart" is requested__: Set the value of `previousPoint.position` to the location of the vessel. +``` +{latitude: 65.4, longitude: 7.8} <= pointIndex=3 +{latitude: 65.4, longitude: 7.8} <= pointIndex=2 +{latitude: 65.4, longitude: 7.8} <= pointIndex=1 +{latitude: 65.4, longitude: 7.8} <= pointIndex=0 +``` -- __When a destination or active route is "Cancelled"__: then set the value of`previousPoint.position` to `null`. +This method of implementation means the client application does not have to manage route point sequencing and that a `pointIndex` of: +- __0__: Always references the point at the start of a journey +- __number of route points -1__: Always references the point at the end of a journey. --- -### __3.API Methods:__ +## API Operations: -The following endpoints under the path `navigation/course` make up the Course API. +The Course API will enable the following operations by providing endpoints under the path `navigation/course`: +_Note: API details can be found in the OpenApi document_ -### 3.1 Set a position (lat, lon) as a destination --- -__Use case:__ Provide _"navigate to here"_ operation. +### 1. Set destination by providing a position (lat, lon) or reference to a waypoint resource -__Action:__ `PUT` -__Path:__ `/navigation/course/destination` - -__Request body:__ +_Example: Set destination position_ ```JSON -{ +PUT /navigation/course/destination { "value": { - "position": {"latitude": -28.5,"longitude":138.5}, - "type": "Location", - "arrivalCircle": 500 - }, - "source": Source making the change. + "position": {"latitude": -28.5,"longitude":138.5} + } } ``` -where: -- `position`: The destination lat, lon (as per Signal K schema) -- `type` (optional): A string describing the destination (as per Signal K schema). -- `arrivalCircle`(optional): Radius of circle centered at destination indicating arrival. - -This will result in the following Signal K path values being set: -```JSON -{ - "activeRoute": { - "href": null, - "startTime": null - }, - "nextPoint": { - "href": null, - "type": null if type not supplied, - "position": { - "latitude": supplied latitude, - "longitude": supplied longitude - }, - "arrivalCircle": unchanged if value not suplied - }, - "previousPoint": { - "href": null, - "type": null, - "position": { - "latitude": latitude of vessel at time of destination being set, - "longitude": longitude of vessel at time of destination being set - } +Resulting Signal K paths would be: +``` +"nextPoint": { + "position": { + "latitude": -28.5, + "longitude": 138.5 + } +}, +"previousPoint": { + "position": { + "latitude": latitude of vessel at time of destination being set, + "longitude": longitude of vessel at time of destination being set } } ``` -### 3.2 Set a Waypoint as a destination ---- -__Use case:__ Provide _"navigate to selected waypoint resource"_ operation. - -__Action:__ `PUT` - -__Path:__ `/navigation/course/destination` - -__Request body:__ +_Example: Set referenced waypoint position as destination_ ```JSON -{ +PUT /navigation/course/destination { "value": { - "href": "/resources/waypoints/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", - "arrivalCircle": 500 - }, - "source": Source making the change. + "href": "/resources/waypoints/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab" + } } ``` -where: -- `href`: The path to the target waypoint in `/resources/waypoints/`. -- `arrivalCircle` (optional): Radius of circle centered at destination indicating arrival. -This will result in the following Signal K path values being set: -```JSON -{ - "activeRoute": { - "href": null, - "startTime": null - }, - "nextPoint": { - "href": supplied href, - "type": null if type not supplied, - "position": { - "latitude": latitude of referenced waypoint, - "longitude": longitude of referenced waypoint - }, - "arrivalCircle": unchanged if value not supplied - }, - "previousPoint": { - "href": null, - "type": null, - "position": { - "latitude": latitude of vessel at time of destination being set, - "longitude": longitude of vessel at time of destination being set - } +Resulting Signal K paths would be: +``` +"nextPoint": { + "position": { + "latitude": referenced waypoint latitude, + "longitude": referenced waypoint longitude + } +}, +"previousPoint": { + "position": { + "latitude": latitude of vessel at time of destination being set, + "longitude": longitude of vessel at time of destination being set } } ``` -### 3.3 Clear / Cancel a destination or Activated Route. --- -__Use case:__ Provide _"stop navigating to destination"_ or _"deactivate as route"_ operation. +### 2. Clear current destination / active route -__Action:__ `DELETE` +_Example: Clear destination_ +```JSON +PUT /navigation/course/destination { + "value": null +} +``` -__Path:__ `/navigation/course/destination` or `/navigation/course/activeRoute` +Resulting Signal K paths would be: +``` +"nextPoint": { + "position":null +}, +"previousPoint": { + "position": null +} +``` -__Request body:__ +_Example: Clear active route_ ```JSON -{ - "value": null, - "source": Source making the change. +PUT /navigation/course/activeRoute { + "value": null } ``` -This will result in the following Signal K path values being set: -```JSON -{ - "activeRoute": { - "href": null, - "startTime": null - }, - "nextPoint": { - "href": null, - "type": null, - "position": null, - "arrivalCircle": unchanged - }, - "previousPoint": { - "href": null, - "type": null, - "position": null - } +Resulting Signal K paths would be: +``` +"nextPoint": { + "position":null +}, +"previousPoint": { + "position": null +}, +"activeRoute": { + "href": null, + "startTime": null } ``` -### 3.4 Activate a Route to follow. --- +### 3. Activate a Route to follow -__Use case:__ Provide _"activate / follow a route"_ operation. - -__Action:__ `PUT` - -__Path:__ `/navigation/course/activeRoute` +_Example: Activate a route_ +```JSON +PUT /navigation/course/activeRoute { + "value": { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab" + } +} +``` +Resulting Signal K paths would be: +``` +"activeRoute": { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "startTime": 2021-11-08T01:39:55.296Z +}, +"nextPoint": { + "position": { + "latitude": latitude of route point at pointIndex 0 (route point #1), + "longitude": longitude of route point at pointIndex 0 (route point #1) + } +}, +"previousPoint": { + "position": { + "latitude": latitude of vessel at time of destination being set, + "longitude": longitude of vessel at time of destination being set + } +} +``` -__Request body:__ +_Example: Activate a route (consisting of 8 points) in reverse mode_ ```JSON -{ +PUT /navigation/course/activeRoute { "value": { "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", - "pointIndex": 0, - "reverse": false, - "arrivalCircle": 500 - }, - "source": Source making the change. + "reverse": true + } } ``` -where: -- `href`: The path to the target route in `/resources/routes/`. -- `pointIndex` (optional): Zero based index of the point within the route to use as the initial destination (defaults to 0 if not supplied or if value is larger than index of last point in the route). -- `reverse` (optional): If `true` performs operations on route points in reverse order (defaults to false). -- `arrivalCircle` (optional): Radius of circle centered at destination indicating arrival. -This will result in the following Signal K path values being set: -```JSON -{ - "activeRoute": { - "href": supplied href, - "startTime": Time at which route was activated (as per Signal K schema) - }, - "nextPoint": { - "href": null, - "type": null if value not supplied, - "position": { - "latitude": latitude of route point at supplied index, - "longitude": longitude of route point at supplied index - }, - "arrivalCircle": unchanged if value not supplied - }, - "previousPoint": { - "href": null, - "type": null, - "position": { - "latitude": latitude of: vessel if supplied pointIndex=0 or point at poiintIndex-1, - "longitude": longitude of: vessel if supplied pointIndex=0 or point at poiintIndex-1 - } +Resulting Signal K paths would be: +``` +"activeRoute": { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "startTime": 2021-11-08T01:39:55.296Z +}, +"nextPoint": { + "position": { + "latitude": latitude of route point at pointIndex 0 (route point #8), + "longitude": longitude of route point at pointIndex 0 (route point #8) + } +}, +"previousPoint": { + "position": { + "latitude": latitude of vessel at time of destination being set, + "longitude": longitude of vessel at time of destination being set } } ``` -### 3.5 Select point in the active Route as destination. +_Example: Activate a route and set destination to third point in route_ +```JSON +PUT /navigation/course/activeRoute { + "value": { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "pointIndex": 2 + } +} +``` +Resulting Signal K paths would be: +``` +"activeRoute": { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "startTime": 2021-11-08T01:39:55.296Z +}, +"nextPoint": { + "position": { + "latitude": latitude of route point at pointIndex 2 (route point #3), + "longitude": longitude of route point at pointIndex 2 (route point #3) + } +}, +"previousPoint": { + "position": { + "latitude": latitude of route point at pointIndex 1 (route point #2), + "longitude": longitude of route point at pointIndex 1 (route point #2) + } +} +``` --- -__Use case:__ Provide _"go to point in route"_ operation. +### 4. Select the point within the route to use destination. -__Action:__ `PUT` - -__Path:__ `/navigation/course/activeRoute/pointIndex` - -__Request body:__ +_Example: Set the 4th point in the journey as destination_ ```JSON -{ - "value": 3, - "source": Source making the change. +PUT /navigation/course/activeRoute/pointIndex { + "value": 3 } ``` -where: -- `value`: Zero based index of the point within the route to use as the initial destination (if value is larger than index of last point in the route then destination is not changed). +where `value` is the zero-based index of the point within the journey to use as the initial destination (see `Use of pointIndex` above). -This will result in the following Signal K path values being set: -```JSON -{ - "activeRoute": { - "href": unchanged, - "startTime": unchanged - }, - "nextPoint": { - "href": unchanged, - "type": unchanged, - "position": { - "latitude": latitude of route point at supplied index, - "longitude": longitude of route point at supplied index - }, - "arrivalCircle": unchanged - }, - "previousPoint": { - "href": unchanged, - "type": unchanged, - "position": { - "latitude": latitude of: vessel if pointIndex=0 or route point at poiintIndex-1, - "longitude": longitude of: vessel if pointIndex=0 or route point at poiintIndex-1 - } +Resulting Signal K paths would be: +``` +"nextPoint": { + "position": { + "latitude": latitude of route point at pointIndex 3, + "longitude": longitude of route point at pointIndex 3 + } +}, +"previousPoint": { + "position": { + "latitude": latitude of route point at pointIndex 2, + "longitude": longitude of route point at pointIndex 2 } } ``` -### 3.6 Increment / decrement point in the active Route as destination. --- -__Use case:__ Provide _"previous / next point"_ operation. +### 5. Set previous / next point. -__Action:__ `PUT` +_Example: Set the next point in the route as destination_ +```JSON +PUT /navigation/course/activeRoute/nextPoint { + "value": 1 +} +``` -__Path:__ `/navigation/course/activeRoute/nextPoint` +Resulting Signal K paths would be: +``` +"nextPoint": { + "position": { + "latitude": latitude of route point at pointIndex +1, + "longitude": longitude of route point at pointIndex +1 + } +}, +"previousPoint": { + "position": { + "latitude": latitude of route point at pointIndex, + "longitude": longitude of route point at pointIndex + } +} +``` -__Request body:__ +_Example: Set the previous point in the route as destination_ ```JSON -{ - "value": { - "increment": -1 - }, - "source": Source making the change. +PUT /navigation/course/activeRoute/nextPoint { + "value": -1 } ``` -where: -- `increment`: Is either `1` (next point) or `-1` (previous point). -This will result in the following Signal K path values being set: -```JSON -{ - "activeRoute": { - "href": unchanged, - "startTime": unchanged - }, - "nextPoint": { - "href": unchanged, - "type": unchanged, - "position": { - "latitude": latitude of previous (if -1 supplied) or next (if 1 supplied) route point, - "longitude": longitude of previous (if -1 supplied) or next (if 1 supplied) route point - }, - "arrivalCircle": unchanged - }, - "previousPoint": { - "href": unchanged, - "type": unchanged, - "position": { - "latitude": latitude of: vessel (if pointIndex=0) or point at poiintIndex-1, - "longitude": longitude of: vessel (if pointIndex=0) or point at poiintIndex-1 - } +Resulting Signal K paths would be: +``` +"nextPoint": { + "position": { + "latitude": latitude of route point at pointIndex -1, + "longitude": longitude of route point at pointIndex -1 + } +}, +"previousPoint": { + "position": { + "latitude": latitude of route point at pointIndex -2 or vessel location if new pointIndex=0, + "longitude": longitude of route point at pointIndex -2 or vessel location if new pointIndex=0 } } ``` -### 3.7 Restart course calculations. --- -__Use case:__ Provide _"restart XTE"_ operation. +### 6. Restart course calculations. -__Action:__ `PUT` - -__Path:__ `/navigation/course/activeRoute/restart` - -__Request body:__ +_Example:_ ```JSON -{ - "value": null, - "source": Source making the change. +PUT /navigation/course/activeRoute/restart { + "value": null } ``` -This will result in the following Signal K path values being set: -```JSON -{ - "activeRoute": { - "href": unchanged, - "startTime": unchanged - }, - "nextPoint": { - "href": unchanged, - "type": unchanged, - "position": { - "latitude": unchanged, - "longitude": unchanged - }, - "arrivalCircle": unchanged - }, - "previousPoint": { - "href": unchanged, - "type": unchanged, - "position": { - "latitude": latitude of vessel, - "longitude": longitude of vessel - } +Resulting Signal K paths would be: +``` +"previousPoint": { + "position": { + "latitude": latitude of vessel at time of destination being set, + "longitude": longitude of vessel at time of destination being set } } ``` -### 3.8 Set arrival circle. --- -__Use case:__ Provide ability to set the radius of a circle centered at destination indicating arrival. - -__Action:__ `PUT` - -__Path:__ `/navigation/course/arrivalCircle` +### 7. Set arrival circle. -__Request body:__ +_Example: Set arrival circle to 500m_ ```JSON -{ - "value": { - "radius": 500 - }, - "source": Source making the change. +PUT /navigation/course/arrivalCircle { + "value": 500 } ``` -where: -- `radius`: Is the radius of the circle in meters. -This will result in the following Signal K path values being set: -```JSON -{ - "activeRoute": { - "href": unchanged, - "startTime": unchanged - }, - "nextPoint": { - "href": unchanged, - "type": unchanged, - "position": { - "latitude": unchanged, - "longitude": unchanged - }, - "arrivalCircle": supplied value - }, - "previousPoint": { - "href": unchanged, - "type": unchanged, - "position": { - "latitude": unchanged, - "longitude": unchanged - } - } +Resulting Signal K paths would be: +``` +"nextPoint": { + "arrivaleCircle": 500 } ``` -### 3.9 Query current course details. --- -__Use case:__ Provide "get current course", "get course details" operation. +### 8. Query current course details. -__Action:__ `GET` - -__Path:__ `/navigation/course` +```JSON +GET /navigation/course +``` -__Response:__ JSON formatted object containing the current course details as per the following example: +_Example Response:_ ```JSON { "activeRoute": { "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", "startTime": "2021-10-23T05:17:20.065Z", "pointIndex": 2, - "reverse": false, - "pointIndex": 2 + "reverse": false }, "nextPoint": { "href": null, @@ -483,7 +421,8 @@ __Response:__ JSON formatted object containing the current course details as per "position": { "latitude":-29.5, "longitude":137.5 - } + }, + "arrivalCircle": 500 }, "previousPoint": { "href": null, @@ -498,9 +437,9 @@ __Response:__ JSON formatted object containing the current course details as per --- -### __4. Signal K Stream Deltas__ +## Signal K Stream Deltas -The implementation of the Course API requires that the relevant delta messages are sent for the in-scope Signal K paths when: +The implementation of the Course API requires that the relevant delta messages are sent for the affected Signal K paths when: - Values have changed - Periodically e.g. every 30 seconds). @@ -553,9 +492,15 @@ Delta messages for in-scope paths are as follows: "context": "vessels.self", "source": source of value }, + { + "path": "navigation.courseGreatCircle.nextPoint.arrivalCircle", + "value": string, + "context": "vessels.self", + "source": source of value + }, { "path": "navigation.courseGreatCircle.previousPoint.value.href", - "value": reference to waypoint resource, + "value": number, "context": "vessels.self", "source": source of value }, diff --git a/apis/course/openApi.json b/apis/course/openApi.json index 36ec3704..130ee4cd 100644 --- a/apis/course/openApi.json +++ b/apis/course/openApi.json @@ -4,19 +4,6 @@ "version": "0.0.1", "title": "Signal K Course API" }, - - "tags": [ - { - "name": "activeRoute", - "description": "Route operations" - }, - { - "name": "destination", - "description": "Destination operations" - } - ], - - "components": { }, "paths": { @@ -254,14 +241,9 @@ "required": ["value"], "properties": { "value": { - "type": "object", - "properties": { - "radius": { - "type": "number", - "format": "float", - "example": 500 - } - } + "type": "number", + "format": "float", + "example": 500 }, "source": { "type": "string", @@ -372,16 +354,10 @@ "required": ["value"], "properties": { "value": { - "type": "object", - "required": ["increment"], - "properties": { - "increment": { - "type": "number", - "description": "increment (1) / decrement (-1) index of point in route to use as destination", - "enum": [-1,1], - "example": -1 - } - } + "type": "number", + "description": "increment (1) / decrement (-1) index of point in route to use as destination", + "enum": [-1,1], + "example": -1 }, "source": { "type": "string", From e750f15d4266b999118a040465cb9d6ed142cda4 Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Sun, 2 Jan 2022 14:12:46 +1030 Subject: [PATCH 13/15] Updated examples --- apis/course/README.md | 87 +++++++--------- apis/course/openApi.json | 208 +++++++++++---------------------------- 2 files changed, 91 insertions(+), 204 deletions(-) diff --git a/apis/course/README.md b/apis/course/README.md index 80e0286e..3ad3937b 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -4,12 +4,11 @@ The Course API provides methods to facilitate setting a destination and navigati These methods manage the setting of values in the relevant Signal K paths under both `navigation.courseGreatCircle` and `navigation.courseRhumbline` to enable the generation of additional navigation information (XTE, DTG, etc) by a course computer as well as facilitate display on a chart plotter. -The API will facilitate operations such as setting a position (lat, lon) as a destination, referencing a waypoint from `/resources/waypoints` as a destination, activating a route by supplying a reference to an entry under `/resources/routes`, etc. +The API will facilitate operations such as: setting a position (lat, lon) as a destination, referencing a waypoint from `/resources/waypoints` as a destination, activating a route by supplying a reference to an entry under `/resources/routes`, etc. In this way a known, consistant method is used to maintain quality data in these paths enabling the reliable operation of other navigation equipment such as `course computers` and `auto-pilots`. - ## Expected implementation behaviour The server will provide API endpoints under the path `navigation/course` to facilitate setting a course as well as querying the current course information. @@ -99,24 +98,24 @@ This method of implementation means the client application does not have to mana ## API Operations: -The Course API will enable the following operations by providing endpoints under the path `navigation/course`: +The Course API will enable the following operations by providing endpoints under the path `..../navigation/course`: _Note: API details can be found in the OpenApi document_ +_In the following examples the value `` has been substituted for the full Signal K API path `http://hostname:port/signalk/v1/api/vessels/self` for conciseness._ + --- ### 1. Set destination by providing a position (lat, lon) or reference to a waypoint resource _Example: Set destination position_ ```JSON -PUT /navigation/course/destination { - "value": { - "position": {"latitude": -28.5,"longitude":138.5} - } +HTTP PUT '/navigation/course/destination' { + "position": {"latitude": -28.5,"longitude":138.5} } ``` Resulting Signal K paths would be: -``` +```JSON "nextPoint": { "position": { "latitude": -28.5, @@ -133,15 +132,13 @@ Resulting Signal K paths would be: _Example: Set referenced waypoint position as destination_ ```JSON -PUT /navigation/course/destination { - "value": { - "href": "/resources/waypoints/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab" - } +HTTP PUT '/navigation/course/destination' { + "href": "/resources/waypoints/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab" } ``` Resulting Signal K paths would be: -``` +```JSON "nextPoint": { "position": { "latitude": referenced waypoint latitude, @@ -161,13 +158,11 @@ Resulting Signal K paths would be: _Example: Clear destination_ ```JSON -PUT /navigation/course/destination { - "value": null -} +HTTP DELETE '/navigation/course/destination' ``` Resulting Signal K paths would be: -``` +```JSON "nextPoint": { "position":null }, @@ -179,13 +174,11 @@ Resulting Signal K paths would be: _Example: Clear active route_ ```JSON -PUT /navigation/course/activeRoute { - "value": null -} +HTTP DELETE '/navigation/course/activeRoute' ``` Resulting Signal K paths would be: -``` +```JSON "nextPoint": { "position":null }, @@ -203,14 +196,12 @@ Resulting Signal K paths would be: _Example: Activate a route_ ```JSON -PUT /navigation/course/activeRoute { - "value": { - "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab" - } +HTTP PUT '/navigation/course/activeRoute' { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab" } ``` Resulting Signal K paths would be: -``` +```JSON "activeRoute": { "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", "startTime": 2021-11-08T01:39:55.296Z @@ -231,16 +222,14 @@ Resulting Signal K paths would be: _Example: Activate a route (consisting of 8 points) in reverse mode_ ```JSON -PUT /navigation/course/activeRoute { - "value": { - "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", - "reverse": true - } +HTTP PUT '/navigation/course/activeRoute' { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "reverse": true } ``` Resulting Signal K paths would be: -``` +```JSON "activeRoute": { "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", "startTime": 2021-11-08T01:39:55.296Z @@ -261,15 +250,13 @@ Resulting Signal K paths would be: _Example: Activate a route and set destination to third point in route_ ```JSON -PUT /navigation/course/activeRoute { - "value": { - "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", - "pointIndex": 2 - } +HTTP PUT '/navigation/course/activeRoute' { + "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", + "pointIndex": 2 } ``` Resulting Signal K paths would be: -``` +```JSON "activeRoute": { "href": "/resources/routes/urn:mrn:signalk:uuid:0d95e282-3e1f-4521-8c30-8288addbdbab", "startTime": 2021-11-08T01:39:55.296Z @@ -292,14 +279,14 @@ Resulting Signal K paths would be: _Example: Set the 4th point in the journey as destination_ ```JSON -PUT /navigation/course/activeRoute/pointIndex { +HTTP PUT '/navigation/course/activeRoute/pointIndex' { "value": 3 } ``` where `value` is the zero-based index of the point within the journey to use as the initial destination (see `Use of pointIndex` above). Resulting Signal K paths would be: -``` +```JSON "nextPoint": { "position": { "latitude": latitude of route point at pointIndex 3, @@ -319,13 +306,13 @@ Resulting Signal K paths would be: _Example: Set the next point in the route as destination_ ```JSON -PUT /navigation/course/activeRoute/nextPoint { +HTTP PUT '/navigation/course/activeRoute/nextPoint' { "value": 1 } ``` Resulting Signal K paths would be: -``` +```JSON "nextPoint": { "position": { "latitude": latitude of route point at pointIndex +1, @@ -342,13 +329,13 @@ Resulting Signal K paths would be: _Example: Set the previous point in the route as destination_ ```JSON -PUT /navigation/course/activeRoute/nextPoint { +HTTP PUT '/navigation/course/activeRoute/nextPoint' { "value": -1 } ``` Resulting Signal K paths would be: -``` +```JSON "nextPoint": { "position": { "latitude": latitude of route point at pointIndex -1, @@ -368,12 +355,10 @@ Resulting Signal K paths would be: _Example:_ ```JSON -PUT /navigation/course/activeRoute/restart { - "value": null -} +HTTP PUT '/navigation/course/activeRoute/restart' ``` Resulting Signal K paths would be: -``` +```JSON "previousPoint": { "position": { "latitude": latitude of vessel at time of destination being set, @@ -387,13 +372,13 @@ Resulting Signal K paths would be: _Example: Set arrival circle to 500m_ ```JSON -PUT /navigation/course/arrivalCircle { +HTTP PUT '/navigation/course/arrivalCircle' { "value": 500 } ``` Resulting Signal K paths would be: -``` +```JSON "nextPoint": { "arrivaleCircle": 500 } @@ -403,7 +388,7 @@ Resulting Signal K paths would be: ### 8. Query current course details. ```JSON -GET /navigation/course +HTTP GET '/navigation/course' ``` _Example Response:_ diff --git a/apis/course/openApi.json b/apis/course/openApi.json index 130ee4cd..ef0d480c 100644 --- a/apis/course/openApi.json +++ b/apis/course/openApi.json @@ -1,7 +1,7 @@ { "openapi": "3.0.2", "info": { - "version": "0.0.1", + "version": "1.0.0", "title": "Signal K Course API" }, @@ -108,33 +108,11 @@ "put": { "tags": ["course"], "summary": "Restart course calculations", - "description": "Sets previousPoint value to current vessel location", - "requestBody": { - "description": "Restart payload", - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["value"], - "properties": { - "value": { - "type": "object", - "default": null - }, - "source": { - "type": "string", - "example": "freeboard-sk" - } - } - } - } - } - } + "description": "Sets previousPoint value to current vessel location" } }, - "/vessels/self/navigation/course/destination/": { + "/vessels/self/navigation/course/destination": { "put": { "tags": ["course/destination"], "summary": "Set destination", @@ -146,50 +124,40 @@ "application/json": { "schema": { "type": "object", - "required": ["value"], "properties": { - "value": { + "position": { "type": "object", + "description": "Destination position", + "required": [ + "latitude", + "longitude" + ], "properties": { - "position": { - "type": "object", - "description": "Destination position", - "required": [ - "latitude", - "longitude" - ], - "properties": { - "latitude": { - "type": "number", - "format": "float" - }, - "longitude": { - "type": "number", - "format": "float" - } - }, - "example": {"latitude":-29.5,"longitude":137.5} - }, - "href": { - "type": "string", - "description": "A reference (URL) to an object (under /resources) this point is related to", - "example": "/resources/waypoints/urn:mrn:signalk:uuid:3dd34dcc-36bf-4d61-ba80-233799b25672" - }, - "type": { - "type": "string", - "description": "Type of point", - "example": "POI" + "latitude": { + "type": "number", + "format": "float" }, - "arrivalCircle": { + "longitude": { "type": "number", - "format": "float", - "example": 500 + "format": "float" } - } + }, + "example": {"latitude":-29.5,"longitude":137.5} + }, + "href": { + "type": "string", + "description": "A reference (URL) to an object (under /resources) this point is related to", + "example": "/resources/waypoints/urn:mrn:signalk:uuid:3dd34dcc-36bf-4d61-ba80-233799b25672" }, - "source": { + "type": { "type": "string", - "example": "freeboard-sk" + "description": "Type of point", + "example": "POI" + }, + "arrivalCircle": { + "type": "number", + "format": "float", + "example": 500 } } } @@ -200,29 +168,7 @@ "delete": { "tags": ["course/destination"], "summary": "Clear destination", - "description": "Sets activeRoute, nextPoint & previousPoint values to null", - "requestBody": { - "description": "Delete payload", - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["value"], - "properties": { - "value": { - "type": "object", - "default": null - }, - "source": { - "type": "string", - "example": "freeboard-sk" - } - } - } - } - } - } + "description": "Sets activeRoute, nextPoint & previousPoint values to null" } }, @@ -244,11 +190,7 @@ "type": "number", "format": "float", "example": 500 - }, - "source": { - "type": "string", - "example": "freeboard-sk" - } + } } } } @@ -269,41 +211,31 @@ "application/json": { "schema": { "type": "object", - "required": ["value"], "properties": { - "value": { - "type": "object", - "properties": { - "href": { - "type": "string", - "description": "Path to route resource", - "example": "/resources/routes/urn:mrn:signalk:uuid:3dd34dcc-36bf-4d61-ba80-233799b25672" - }, - "pointIndex": { - "type": "number", - "format": "int64", - "description": "Zero based index of route point to use as destination", - "default": 0, - "minimum": 0, - "example": 2 - }, - "reverse": { - "type": "boolean", - "default": false, - "description": "If true performs operations on route points in reverse order", - "example": 2 - }, - "arrivalCircle": { - "type": "number", - "format": "float", - "example": 500 - } - } - }, - "source": { + "href": { "type": "string", - "example": "freeboard-sk" - } + "description": "Path to route resource", + "example": "/resources/routes/urn:mrn:signalk:uuid:3dd34dcc-36bf-4d61-ba80-233799b25672" + }, + "pointIndex": { + "type": "number", + "format": "int64", + "description": "Zero based index of route point to use as destination", + "default": 0, + "minimum": 0, + "example": 2 + }, + "reverse": { + "type": "boolean", + "default": false, + "description": "If true performs operations on route points in reverse order", + "example": 2 + }, + "arrivalCircle": { + "type": "number", + "format": "float", + "example": 500 + } } } } @@ -313,29 +245,7 @@ "delete": { "tags": ["course/activeRoute"], "summary": "Clear active route", - "description": "Sets activeRoute, nextPoint & previousPoint values to null", - "requestBody": { - "description": "Delete payload", - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["value"], - "properties": { - "value": { - "type": "object", - "default": null - }, - "source": { - "type": "string", - "example": "freeboard-sk" - } - } - } - } - } - } + "description": "Sets activeRoute, nextPoint & previousPoint values to null" } }, @@ -358,10 +268,6 @@ "description": "increment (1) / decrement (-1) index of point in route to use as destination", "enum": [-1,1], "example": -1 - }, - "source": { - "type": "string", - "example": "freeboard-sk" } } } @@ -390,10 +296,6 @@ "description": "Index of point in route to use as destination", "minimum": 0, "example": 2 - }, - "source": { - "type": "string", - "example": "freeboard-sk" } } } From f8a6db3fb158098ab49b0ddea08c4558d3cf1a9f Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Fri, 7 Jan 2022 16:19:01 +1030 Subject: [PATCH 14/15] add pointTotal and refresh() --- apis/course/README.md | 15 +++++++++++++-- apis/course/openApi.json | 13 +++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apis/course/README.md b/apis/course/README.md index 3ad3937b..2ef8e819 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -368,7 +368,18 @@ Resulting Signal K paths would be: ``` --- -### 7. Set arrival circle. +### 7. Refresh data after route points have been modified. + +If the active route has been edited to add, remove or move points then calling this method will ensure that `pointIndex` and `pointTotal` are updated to reflect the position of the current destination within the route and the new number of points in the route. + +_Example:_ +```JSON +HTTP PUT '/navigation/course/activeRoute/refresh' +``` + + +--- +### 8. Set arrival circle. _Example: Set arrival circle to 500m_ ```JSON @@ -385,7 +396,7 @@ Resulting Signal K paths would be: ``` --- -### 8. Query current course details. +### 9. Query current course details. ```JSON HTTP GET '/navigation/course' diff --git a/apis/course/openApi.json b/apis/course/openApi.json index ef0d480c..65822af1 100644 --- a/apis/course/openApi.json +++ b/apis/course/openApi.json @@ -35,6 +35,11 @@ "format": "int64", "example": 2 }, + "pointTotal": { + "type": "number", + "format": "int64", + "example": 9 + }, "reverse": { "type": "boolean", "default": false @@ -303,6 +308,14 @@ } } } + }, + + "/vessels/self/navigation/course/activeRoute/refresh": { + "put": { + "tags": ["course/activeRoute"], + "summary": "Refresh route details.", + "description": "Use after active route is modified to refresh pointIndex and pointsTotal values." + } } } From 330654d9a66b8b29c7fc8cff3bad58f67ec5cc4e Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Sat, 8 Jan 2022 15:41:48 +1030 Subject: [PATCH 15/15] add activeRoute/reverse --- apis/course/README.md | 34 ++++++++++++++++++++++++++++++++-- apis/course/openApi.json | 27 +++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/apis/course/README.md b/apis/course/README.md index 2ef8e819..2716c15c 100644 --- a/apis/course/README.md +++ b/apis/course/README.md @@ -377,9 +377,39 @@ _Example:_ HTTP PUT '/navigation/course/activeRoute/refresh' ``` +--- + +### 8. Reverse route direction. + +Reverse the direction in which to follow the route. You can either: +- Reverse the direction from the current destination point + +OR + +- Reverse the direction and specify the `pointIndex` to use as the current destination. + +_Example: Reverse direction setting the destination to the location at the 3rd point from the end._ +```JSON +HTTP PUT '/navigation/course/activeRoute/reverse' { + "pointIndex": 2 +} +``` + +Resulting Signal K paths would be: +```JSON +"activeRoute": { + "pointIndex": Index of point relative to the direction, + "reverse": Opposite of previous value (e.g. previous value = false, new value = true) +} +``` + +_Example: Reverse direction keeping the current destination._ +```JSON +HTTP PUT '/navigation/course/activeRoute/reverse' +``` --- -### 8. Set arrival circle. +### 9. Set arrival circle. _Example: Set arrival circle to 500m_ ```JSON @@ -396,7 +426,7 @@ Resulting Signal K paths would be: ``` --- -### 9. Query current course details. +### 10. Query current course details. ```JSON HTTP GET '/navigation/course' diff --git a/apis/course/openApi.json b/apis/course/openApi.json index 65822af1..9efca70f 100644 --- a/apis/course/openApi.json +++ b/apis/course/openApi.json @@ -316,6 +316,33 @@ "summary": "Refresh route details.", "description": "Use after active route is modified to refresh pointIndex and pointsTotal values." } + }, + + "/vessels/self/navigation/course/activeRoute/reverse": { + "put": { + "tags": ["course/activeRoute"], + "summary": "Reverse direction of route", + "description": "Reverse direction of route from current point or from supplied pointIndex.", + "requestBody": { + "description": "Reverse route", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "pointIndex": { + "type": "number", + "description": "Index of point in route to use as destination", + "minimum": 0, + "example": 2 + } + } + } + } + } + } + } } }