From c5f0046f128861434f883ffc94e232e6dfc40c38 Mon Sep 17 00:00:00 2001 From: tholok Date: Thu, 6 Nov 2025 09:52:46 +0100 Subject: [PATCH 1/3] sonar: document http & move api section --- .../sonar-3d-15-api-swagger/swagger.json | 390 ++++++++++++++++++ docs/sonar-3d/sonar-3d-15-api.md | 29 +- mkdocs.yml | 2 +- 3 files changed, 410 insertions(+), 11 deletions(-) create mode 100644 docs/sonar-3d/sonar-3d-15-api-swagger/swagger.json diff --git a/docs/sonar-3d/sonar-3d-15-api-swagger/swagger.json b/docs/sonar-3d/sonar-3d-15-api-swagger/swagger.json new file mode 100644 index 0000000..65cd9bc --- /dev/null +++ b/docs/sonar-3d/sonar-3d-15-api-swagger/swagger.json @@ -0,0 +1,390 @@ +{ + "swagger": "2.0", + "info": { + "contact": {} + }, + "paths": { + "/api/v1/integration/about": { + "get": { + "description": "Get system version", + "tags": [ + "about", + "integrationAPI" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/integrationapi.GinSystemVersion" + } + } + } + } + }, + "/api/v1/integration/acoustics/enabled": { + "get": { + "description": "Get whether acoustics is enabled or disabled", + "tags": [ + "acoustics", + "integrationAPI" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "boolean" + } + }, + "204": { + "description": "No Content" + } + } + }, + "post": { + "description": "Enable/disable acoustic imaging", + "tags": [ + "acoustics", + "integrationAPI" + ], + "parameters": [ + { + "description": " ", + "name": "request", + "in": "body", + "required": true, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request" + }, + "408": { + "description": "Request Timeout" + }, + "409": { + "description": "Conflict" + } + } + } + }, + "/api/v1/integration/acoustics/range": { + "get": { + "description": "Get range", + "tags": [ + "acoustics", + "integrationAPI" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/integrationapi.RangeResponse" + } + } + } + }, + "post": { + "description": "Set range", + "tags": [ + "acoustics", + "integrationAPI" + ], + "parameters": [ + { + "description": " ", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/integrationapi.RangeResponse" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request" + }, + "409": { + "description": "Conflict" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/api/v1/integration/acoustics/speed_of_sound": { + "get": { + "description": "Get speed of sound", + "tags": [ + "acoustics", + "integrationAPI" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "number" + } + }, + "204": { + "description": "No Content" + } + } + }, + "post": { + "description": "Set speed of sound", + "tags": [ + "acoustics", + "integrationAPI" + ], + "parameters": [ + { + "description": " ", + "name": "request", + "in": "body", + "required": true, + "schema": { + "type": "number", + "example": 1500 + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request" + }, + "408": { + "description": "Request Timeout" + }, + "409": { + "description": "Conflict" + } + } + } + }, + "/api/v1/integration/status": { + "get": { + "description": "Get the status of the system", + "tags": [ + "status", + "integrationAPI" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/integrationapi.GinStatusResponse" + } + } + } + } + }, + "/api/v1/integration/temperature": { + "get": { + "description": "Get the internal temperature of the Sonar in degrees Celsius", + "tags": [ + "status", + "integrationAPI" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "number" + } + } + } + } + }, + "/api/v1/integration/udp": { + "get": { + "description": "Get the current UDP configuration for how the Sonar outputs data.", + "tags": [ + "integrationAPI" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/integrationapi.GinHandleUdpConfigPayload" + } + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "post": { + "description": "Set UDP configuration for how the Sonar should output data.", + "tags": [ + "integrationAPI" + ], + "parameters": [ + { + "description": " ", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/integrationapi.GinHandleUdpConfigPayload" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request" + }, + "500": { + "description": "Internal Server Error" + } + } + } + } + }, + "definitions": { + "integrationapi.GinHandleUdpConfigPayload": { + "type": "object", + "properties": { + "mode": { + "description": "Must be \"multicast\", \"unicast\" or \"disabled\"\n\nIf mode is \"disabled\", no UDP packets will be sent\n\nIf mode is \"multicast\", UDP packets will be sent on multicast\n\nIf mode is \"unicast\", UDP packets will be sent to the destination\nIP and port", + "type": "string", + "enum": [ + "multicast", + "unicast", + "disabled" + ], + "example": "multicast" + }, + "unicast_destination_ip": { + "description": "The destination IP address if mode is \"unicast\".\nIf mode is \"unicast\", this must be a valid IP address.\nOtherwise, this must be a valid IP adddress or empty string.", + "type": "string", + "example": "192.168.1.100" + }, + "unicast_destination_port": { + "description": "The destination port if mode is \"unicast\".\nIf mode is \"unicast\", this must be a valid port.\nOtherwise, this must be a valid port or 0.", + "type": "integer", + "example": 12345 + } + } + }, + "integrationapi.GinStatusResponse": { + "type": "object", + "properties": { + "api": { + "description": "IntegrationAPI is the status of the UDP IntegrationAPI for external communication", + "allOf": [ + { + "$ref": "#/definitions/integrationapi.GinSystemStatusEntryResponse" + } + ] + }, + "calibration": { + "description": "Calibration is the status of the Sonar calibration", + "allOf": [ + { + "$ref": "#/definitions/integrationapi.GinSystemStatusEntryResponse" + } + ] + }, + "temperature": { + "description": "Temperature is the status of the Sonar temperature", + "allOf": [ + { + "$ref": "#/definitions/integrationapi.GinSystemStatusEntryResponse" + } + ] + } + } + }, + "integrationapi.GinSystemStatusEntryResponse": { + "type": "object", + "properties": { + "id": { + "description": "Unique ID for the status message", + "type": "string", + "example": "api-normal" + }, + "message": { + "description": "Message is a human readable message describing the status", + "type": "string", + "example": "Integration API is operational" + }, + "operational": { + "description": "Operational is true if the system is functional, false if it is not", + "type": "boolean", + "example": true + }, + "severity": { + "description": "Severity is the severity of the status message: info, warning, error", + "type": "string", + "example": "info" + } + } + }, + "integrationapi.GinSystemVersion": { + "type": "object", + "properties": { + "chipid": { + "type": "string", + "example": "0x12345678" + }, + "hardware_revision": { + "type": "integer", + "example": 6 + }, + "is_ready": { + "type": "boolean", + "example": true + }, + "product_id": { + "type": "integer", + "example": 21045 + }, + "product_name": { + "type": "string", + "example": "Sonar 3D-15" + }, + "variant": { + "type": "string" + }, + "version": { + "type": "string", + "example": "1.5.1 (v1.3.0-26-gedccab6.2025-07-11T06:14:03.837365)" + }, + "version_short": { + "type": "string", + "example": "1.5.1" + } + } + }, + "integrationapi.RangeResponse": { + "type": "object", + "properties": { + "max": { + "type": "number", + "example": 15 + }, + "min": { + "type": "number", + "example": 0 + } + } + } + } +} \ No newline at end of file diff --git a/docs/sonar-3d/sonar-3d-15-api.md b/docs/sonar-3d/sonar-3d-15-api.md index 972e3fd..c0b8e5f 100644 --- a/docs/sonar-3d/sonar-3d-15-api.md +++ b/docs/sonar-3d/sonar-3d-15-api.md @@ -1,7 +1,9 @@ # Integration API Sonar 3D-15 ## Introduction -The **Water Linked Sonar 3D-15** provides real-time 3D views of underwater environments using a low-bandwidth **Range Image Protocol (RIP1)**. This protocol efficiently transmits data such as 3D points or grayscale bitmaps over UDP multicast, enabling live visualization, analysis, or archival for later use. +The **Water Linked Sonar 3D-15** provides real-time 3D views of underwater environments using a low-bandwidth **Range Image Protocol (RIP1)**. This protocol efficiently transmits data such as 3D points or grayscale bitmaps over UDP, enabling live visualization, analysis, or archival for later use. + +The Sonar 3D-15 also exposes a HTTP API for configuration and inspection of system state. A Python example implementation of the Sonar API is available on [github](https://github.com/waterlinked/Sonar-3D-15-api-example). @@ -25,12 +27,14 @@ RIP1 is a compact format for range and bitmap images, designed for <10 Mbit ba --- -## Network -By default, the Sonar 3D-15 uses **UDP Multicast** (`224.0.0.96:4747`), so any device on the local network can receive data without knowing the sonar’s IP. +### Network +By default, the Sonar 3D-15 uses **UDP Multicast** (`224.0.0.96:4747`), so any device on the local network can receive RIP1 packets without knowing the sonar’s IP. + +The Sonar can also be configured for UDP unicast, or to disable sending of UDP packets. See HTTP API. --- -## Image Sizes and Update Rates +### Image Sizes and Update Rates | **Mode** | **Resolution (W×H)** | **FOV (H×V)** | **Rate** | |---------------|----------------------|--------------|---------| | Low Frequency | 256 × 64 | 90° × 40° | 5 Hz | @@ -38,21 +42,21 @@ By default, the Sonar 3D-15 uses **UDP Multicast** (`224.0.0.96:4747`), so any d --- -## Message Types +### Message Types RIP1 supports several Protobuf-encoded messages, including: -### `BitmapImageGreyscale8` +#### `BitmapImageGreyscale8` - 8-bit grayscale; each pixel = signal strength or shaded depth. - `type` enum differentiates **signal strength** vs. **shaded**. -### `RangeImage` +#### `RangeImage` - Each pixel represents distance (radius) to the strongest reflection. - `0` = no valid data. - `radius = pixelValue * imagePixelScale`. --- -## Coordinate and Image Conventions +### Coordinate and Image Conventions **Axes** (right-handed): - **x**: forward @@ -91,7 +95,7 @@ z = -radius * sin(pitch); // z is downward --- -## `.proto` File (Excerpt) +### `.proto` File (Excerpt) ```protobuf // Water Linked Sonar 3D-15 protocol syntax = "proto3"; @@ -173,7 +177,12 @@ message RangeImage { - Decoders should ignore unrecognized messages. - Major breaking changes will involve a new protocol identifier. +Refer to the full protocol specification and `.proto` file shown above for more information. + +## HTTP API + +The Sonar 3D-15 exposes a HTTP API for configuration and inspection of system state. The HTTP API is exposed on port 80 and uses paths rooted at `/api/v1/integration/`. JSON is used for request and response bodies. The HTTP API is documented with a [swagger.json](./sonar-3d-15-api-swagger/swagger.json) file. This file can be opened in a compatible viewer such as [this one](https://petstore.swagger.io/?url=https://docs.waterlinked.com/sonar-3d/sonar-3d-15-api/sonar-3d-15-api-swagger/swagger.json). Example code using the HTTP API exists on [github](https://github.com/waterlinked/Sonar-3D-15-api-example). + --- **Thank you for using the Water Linked Sonar 3D-15!** -Refer to the full protocol specification and `.proto` file shown above for more information. diff --git a/mkdocs.yml b/mkdocs.yml index 7e17494..258957b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -40,12 +40,12 @@ nav: - Wiring: sonar-3d/sonar-3d-15-wiring.md - LED: sonar-3d/sonar-3d-15-led.md - GUI: sonar-3d/sonar-3d-15-gui.md + - API: sonar-3d/sonar-3d-15-api.md - Integration: - DeepTrekker Pivot: sonar-3d/sonar-3d-15-deep-trekker-rov.md - Blueye X3: sonar-3d/sonar-3d-15-blueye-rov.md - BlueROV2: sonar-3d/sonar-3d-15-bluerov-integration.md - Chasing M2 PRO MAX: sonar-3d/sonar-3d-15-chasing-rov.md - - API: sonar-3d/sonar-3d-15-api.md - Software Updates: sonar-3d/sonar-3d-15-software-update.md - Settings: sonar-3d/sonar-3d-15-config.md - Networking: sonar-3d/sonar-3d-15-networking.md From 43f2e7efd6934a8ee5c24f81f1b2ad3c549d7fea Mon Sep 17 00:00:00 2001 From: wl-estensd <142801766+wl-estensd@users.noreply.github.com> Date: Thu, 27 Nov 2025 11:07:09 +0100 Subject: [PATCH 2/3] Update sonar-3d-15-bluerov-integration.md Added link to blueOS extension --- docs/sonar-3d/sonar-3d-15-bluerov-integration.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/sonar-3d/sonar-3d-15-bluerov-integration.md b/docs/sonar-3d/sonar-3d-15-bluerov-integration.md index 24d8017..fc4e417 100644 --- a/docs/sonar-3d/sonar-3d-15-bluerov-integration.md +++ b/docs/sonar-3d/sonar-3d-15-bluerov-integration.md @@ -197,6 +197,8 @@ The Sonar 3D-15 will now show a green light, indicating it is powered. ### 2. **Access the Sonar 3D-15 GUI** +We recommend installing the **[Sonar 3D-15 extension](https://github.com/waterlinked/BlueOS-Sonar-Extension)** found in the [BlueOS extension manager](https://www.google.com/search?q=https://blueos.cloud/docs/latest/usage/advanced/%23extensions-manager). If you use the extension, you can skip directly to **Connection Step 3**. Otherwise, follow the procedure below to connect manually. + The Sonar 3D-15 GUI can be accessed by entering the Sonar 3D-15's IP-address into the browser running on the computer connected to the ROV. You have to determine which IP-address has been automatically assigned to the Sonar 3D-15 by the BlueRov2 system. Steps to find it follows below. Once located, entering it in your browser will display a page like the one below — in this example, the Sonar 3D-15 is assigned the IP-address `192.168.2.172`. @@ -310,4 +312,4 @@ When ready, click the ”Enable acoustics” button to initiate the Sonar 3D-15. ![Pixels](../img/sonar3d-integration-bluerov2/cockpit_sonar10.png){width="100%"} -You are now ready to use the Water Linked Sonar 3D-15 with the BlueROV2! \ No newline at end of file +You are now ready to use the Water Linked Sonar 3D-15 with the BlueROV2! From 4c2dec2a74f7a21746206a1d87e5d7bd7906de35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20L=C3=B8kkeborg?= Date: Thu, 27 Nov 2025 13:19:23 +0100 Subject: [PATCH 3/3] Update sonar-3d-15-api.md fix link to swagger.json viewer --- docs/sonar-3d/sonar-3d-15-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sonar-3d/sonar-3d-15-api.md b/docs/sonar-3d/sonar-3d-15-api.md index c0b8e5f..a2c8008 100644 --- a/docs/sonar-3d/sonar-3d-15-api.md +++ b/docs/sonar-3d/sonar-3d-15-api.md @@ -181,7 +181,7 @@ Refer to the full protocol specification and `.proto` file shown above for more ## HTTP API -The Sonar 3D-15 exposes a HTTP API for configuration and inspection of system state. The HTTP API is exposed on port 80 and uses paths rooted at `/api/v1/integration/`. JSON is used for request and response bodies. The HTTP API is documented with a [swagger.json](./sonar-3d-15-api-swagger/swagger.json) file. This file can be opened in a compatible viewer such as [this one](https://petstore.swagger.io/?url=https://docs.waterlinked.com/sonar-3d/sonar-3d-15-api/sonar-3d-15-api-swagger/swagger.json). Example code using the HTTP API exists on [github](https://github.com/waterlinked/Sonar-3D-15-api-example). +The Sonar 3D-15 exposes a HTTP API for configuration and inspection of system state. The HTTP API is exposed on port 80 and uses paths rooted at `/api/v1/integration/`. JSON is used for request and response bodies. The HTTP API is documented with a [swagger.json](./sonar-3d-15-api-swagger/swagger.json) file. This file can be opened in a compatible viewer such as [this one](https://petstore.swagger.io/?url=https://docs.waterlinked.com/sonar-3d/sonar-3d-15-api-swagger/swagger.json). Example code using the HTTP API exists on [github](https://github.com/waterlinked/Sonar-3D-15-api-example). ---