Name | adar-api JSON |
Version |
1.1.2
JSON |
| download |
home_page | None |
Summary | A reference implementation in python that uses the Sonair ADAR CoAP API. |
upload_time | 2025-08-19 08:47:33 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.10 |
license | None |
keywords |
adar
sonair
ultrasound
adar_api
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# ADAR API Python Package
A Python package for communicating with the ADAR 3D Ultrasonic Sensor via Constrained Application Protocol (CoAP)).
## Overview
This package serves two main purposes:
1. **Easy-to-use Python API**: Provides a simple interface for receiving 3D point cloud data from ADAR sensors, for conversion to other ecosystems like ROS or Foxglove.
2. **Reference Implementation**: Documents the CoAP resources and binary data formats to enable porting to other languages (C, C++, etc.)
## Table of Contents
- [Installation](#installation)
- [Network Requirements](#network-requirements)
- [Quick Start](#quick-start)
- [API Reference](#api-reference) - _For Python developers_
- [Coordinate System](#coordinate-system)
- [Error Handling](#error-handling)
- [Advanced Usage](#advanced-usage)
- [CoAP Resources and Data Formats](#coap-resources-and-data-formats) - _For protocol reference_
## Installation
### Quick Installation
Install the ADAR API package from PyPI:
```bash
pip install adar-api
```
### Recommended: Using a Virtual Environment
For better dependency management, it's recommended to use a virtual environment:
1. **Create a virtual environment:**
```bash
python -m venv .venv
```
2. **Activate the virtual environment:**
**Linux/macOS:**
```bash
source .venv/bin/activate
```
**Windows:**
```cmd
.venv\Scripts\activate
```
3. **Install the package:**
```bash
pip install adar-api
```
**Note:** You need to activate the virtual environment each time you want to use the `pointcloud-publisher` command or the ADAR API in a new terminal session.
## Network Requirements
- **Protocol**: CoAP over UDP (port 5683)
- **Network**: IPv4 connectivity to sensor
- **Firewall**: Ensure UDP port 5683 is accessible
## Quick Start
### Point cloud Publisher
The easiest way to visualize the ADAR point cloud is to use the built-in `pointcloud-publisher`:
```bash
pointcloud-publisher <ADAR_IP_ADDRESS>
```
Example for an ADAR with factory-default IP address:
```bash
pointcloud-publisher 10.20.30.40
```
#### Advanced Usage
Specify a custom Foxglove server host:
This can be useful if you want to publish the pointcloud to a different computer than the one which is running the the pointcloud-publisher script.
```bash
pointcloud-publisher <ADAR_IP_ADDRESS> --foxglove-host <HOST_IP>
```
Example for broadcasting to a specific foxglove host:
This will publish the pointcloud from an ADAR with IP address `10.20.30.40` to a foxglove host running on IP address 127.0.0.2
```bash
pointcloud-publisher 10.20.30.40 --foxglove-host 127.0.0.2
```
**Command Line Options:**
- `ipaddr` (required): IP address of the ADAR device
- `--foxglove-host` (optional): Host IP address for the Foxglove server (default: 127.0.0.1)
#### Visualization with Foxglove Studio
1. **Start the pointcloud publisher** (as shown above)
2. **Open Foxglove Studio**
3. **Connect to the Foxglove server:**
- Go to "Open connection"
- Select "Foxglove WebSocket"
- Enter `ws://127.0.0.1:8765` (or your custom host)
4. **Import layout for ADAR:**
- In the top right pane, select the layout drop-down and click "Import from file..."
- Select the [`foxglove_layout_ADAR.json`](adar_api/examples/foxglove_layout_ADAR.json) file.
- The point cloud should now appear in a 3D view and a 2D top-down view.
### ADAR API
For custom integrations, use the Python API directly:
```python
import asyncio
from adar_api import Adar
from aiocoap import Context
async def main():
# Create CoAP context
ctx = await Context.create_client_context()
# Connect to ADAR sensor
adar = Adar(ctx, ip_address="10.20.30.40")
# Get device information
device_info = await adar.get_device_info()
print(f"Device: {device_info.device_name}")
print(f"Firmware: {device_info.firmware_version}")
# Get single point cloud frame
point_cloud = await adar.get_point_cloud()
print(f"Received {len(point_cloud.points)} points")
# Continuous observation
async for point_cloud in adar.observe_point_cloud():
print(f"Received {len(point_cloud.points)} points")
for point in point_cloud.points:
print(f"Point: x={point.x:.3f}m, y={point.y:.3f}m, z={point.z:.3f}m, "
f"strength={point.strength}, classification={point.classification}")
if __name__ == "__main__":
asyncio.run(main())
```
## API Reference
### Error Handling
The API provides structured exception handling:
```python
from adar_api import CoapException, CoapErrorException
try:
point_cloud = await adar.get_point_cloud()
except CoapErrorException as e:
print(f"CoAP protocol error: {e.response.code}")
except CoapException as e:
print(f"General CoAP error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
```
### Response Code Handling
CoAP errors include response codes that indicate the type of failure or success.
For a complete list of response codes, see [CoAP Response Codes](#coap-response-codes) in the protocol reference.
### Usage Examples
#### Robust Point Cloud Observation
```python
async def robust_observation():
async for point_cloud in adar.observe_point_cloud(keep_running=True):
try:
# Process point cloud
process_points(point_cloud.points)
except Exception as e:
logger.warning(f"Processing error: {e}")
# Continue observation despite processing errors
```
#### Direct CoAP Request
```python
from aiocoap import Message, GET
# Access the underlying CoAP request method
response = await adar.send_request(
Message(code=GET, uri=f"coap://{adar.ip_address}/status/v0")
)
```
#### Network Configuration
```python
# Get current configuration
config = await adar.get_network_config()
print(f"Current DHCP setting: {config.dhcp_enabled}")
# Modify network config
config.dhcp_enabled = True
# Apply modified configuration (device will reboot and might be on a different network than before)
await adar.set_network_config(config)
```
#### Transmission Code Configuration
```python
# Get current transmission code
code_id = await adar.get_transmission_code_id()
print(f"Current transmission code: {code_id}")
# Set transmission code (valid values: 1, 2, 4, 8)
await adar.set_transmission_code_id(4)
```
## CoAP Resources and Data Formats
For developers integrating towards ADAR using other languages, this section documents the CoAP API resources and data formats.
### Resource URI Structure
```
coap://<device_ip>/<resource>/<version>
```
### Resource Reference
| Resource | Method | Description | Response Format |
| ----------------------- | ----------- | ---------------------- | ----------------------------------------------- |
| `/pointcloud/v0` | GET/OBSERVE | 3D point cloud data | [Point Cloud Format](#point-cloud-format) |
| `/status/v0` | GET | Device status | [Device Status Format](#device-status-format) |
| `/device_info/v0` | GET | Device identification | [Device Info Format](#device-info-format) |
| `/network_config/v0` | GET/PUT | Network configuration | [Network Config Format](#network-config-format) |
| `/statistics/v0` | GET | Operational statistics | [Statistics Format](#statistics-format) |
| `/errors/v0` | GET | Device error codes | [Error Format](#error-format) |
| `/transmission_code/v0` | GET/PUT | Transmission code ID | Single byte. Legal values: 1, 2, 4, 8 |
| `/factory_reset/v0` | PUT | Factory reset | Empty payload |
| `/observers/v0` | DELETE | Clear all observers | Empty payload |
### Data Format Specifications (little-endian)
#### Point Cloud Format
Binary payload structure:
| Byte Range | Field | Type | Description |
| ---------- | ------------- | ------------------ | ------------------------------------------------- |
| 0-7 | Timestamp | uint64 | Microseconds since measurement start |
| 8-15 | Device Status | 8 bytes | See [Device Status Format](#device-status-format) |
| 16+ | Point Data | 10 bytes per point | See [Point Format](#point-format) |
_Note: The number of points is determined by parsing 10-byte chunks until the payload ends. The total payload length minus the 16-byte header must be divisible by 10, or the data is considered corrupted._
##### Point Format
| Byte Range | Field | Type | Description |
| ---------- | -------------- | ------ | ------------------------------------------------- |
| 0-1 | X coordinate | int16 | Millimeters, signed |
| 2-3 | Y coordinate | int16 | Millimeters, signed |
| 4-5 | Z coordinate | int16 | Millimeters, signed |
| 6-7 | Strength | uint16 | Signal strength, unsigned |
| 8 | Reserved | uint8 | Ignore |
| 9 | Classification | uint8 | See [Classification Flags](#classification-flags) |
_Note: The Python API converts coordinates from millimeters to meters._
##### Classification Flags
| Bit 7-4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| -------- | ----------------------- | --------------------------- | --------------------------- | ------------------------ |
| Reserved | Point in Exclusion Zone | Point in Outer Warning Zone | Point in Inner Warning Zone | Point in Protective Zone |
#### Device Status Format
8-byte binary structure:
| Byte Range | Field | Type | Description |
| ---------- | ----------------- | ------ | ------------------------------------------------------ |
| 0 | Zone Selected | uint8 | Currently selected zone |
| 1 | Device State | uint8 | See [Device States](#device-states) |
| 2 | Transmission Code | uint8 | Transmission code index (0-3, where code ID = 2^index) |
| 3 | Zone Status | uint8 | See [Zone Status Flags](#zone-status-flags) |
| 4-7 | Device Error | uint32 | Error code, little-endian |
_Note: This format uses a transmission code index (0-3), while the [Transmission Code](#transmission-code-format) resource uses a code ID (1, 2, 4, 8)._
##### Device States
- 1: Init
- 2: SelfTest
- 3: Enabled
- 4: Disabled
- 5: Config
- 6: Error
- 7: Fault
##### Zone Status Flags
| Bit 7-3 | Bit 2 | Bit 1 | Bit 0 |
| -------- | ---------------------------- | ---------------------------- | ------------------------- |
| Reserved | Object in Outer Warning Zone | Object in Inner Warning Zone | Object in Protective Zone |
#### Device Info Format
Variable-length format with [length-prefixed strings](#length-prefixed-string-format):
| Byte Range | Field | Type | Description |
| ------------ | ----------------------- | --------------- | ------------------------------------------------ |
| 0-3 | Serial Number | uint32 | Device serial number, little-endian |
| 4-6 | Hardware Version | 3 Bytes (uint8) | Hardware version bytes (major.minor.patch) |
| 7-10 | Product Number Length | uint32 | Length of product number string, little-endian |
| 11+ | Product Number | UTF-8 string | Product number string |
| Next 4 bytes | Device Name Length | uint32 | Length of device name string, little-endian |
| Next N bytes | Device Name | UTF-8 string | Device name string |
| Next 4 bytes | Firmware Version Length | uint32 | Length of firmware version string, little-endian |
| Next N bytes | Firmware Version | UTF-8 string | Firmware version string |
##### Length-prefixed String Format
- 4 bytes: String length (uint32, little-endian)
- N bytes: UTF-8 string data
#### Network Config Format
212-byte binary structure:
| Byte Range | Field | Type | Description |
| ---------- | ------------------- | ----------------- | -------------------------------------------------------------------- |
| 0-3 | Configuration Flags | uint32 | See [Configuration Flags](#configuration-flags) |
| 4-7 | Static IP Address | 4 Bytes (uint8) | Static IP address bytes |
| 8-11 | Subnet Mask | 4 Bytes (uint8) | Subnet mask bytes |
| 12-15 | Gateway Address | 4 Bytes (uint8) | Gateway IP address bytes |
| 16-19 | Sync Server IP | 4 Bytes (uint8) | Synchronization server IP address |
| 20-83 | Reserved | 64 Bytes (uint8) | Reserved bytes |
| 84-211 | Device Tag | 128 Bytes (uint8) | Reserved for Device Tag. Should be set to existing value or all-zero |
##### Configuration Flags
| Bit 31-3 | Bit 2 | Bit 1 | Bit 0 |
| -------- | ---------------- | ------------ | ------------------------------------ |
| Reserved | Sync server mode | Sync enabled | Static IP enabled (0=DHCP, 1=Static) |
#### Statistics Format
44-byte binary structure:
| Byte Range | Field | Type | Description |
| ---------- | --------------------------------------- | ----------------------------------- | -------------------------------------------- |
| 0-11 | Uptime | [Duration format](#duration-format) | Device uptime |
| 12-19 | Total Number of Pings | uint64 | Total pings count, little-endian |
| 20-27 | Pings with Object in Protective Zone | uint64 | Protective zone detections, little-endian |
| 28-35 | Pings with Object in Inner Warning Zone | uint64 | Inner warning zone detections, little-endian |
| 36-43 | Pings with Object in Outer Warning Zone | uint64 | Outer warning zone detections, little-endian |
##### Duration Format
| Byte Range | Field | Type | Description |
| ---------- | ----------- | ------ | ------------------------------------ |
| 0-7 | Seconds | uint64 | Seconds component, little-endian |
| 8-11 | Nanoseconds | uint32 | Nanoseconds component, little-endian |
#### Error Format
Variable-length format with error bitmask and description strings:
| Byte Range | Field | Type | Description |
| ---------- | ----------------------- | -------- | ----------------------------------------------- |
| 0-3 | Error Bitmask | uint32 | Error bitmask, little-endian |
| 4-7 | Number of Error Strings | uint32 | Count of error strings, little-endian |
| 8+ | Error Strings | Variable | See [Error String Format](#error-string-format) |
##### Error String Format
- 4 bytes: String length (uint32, little-endian)
- N bytes: UTF-8 error description
#### Transmission Code Format
Single byte payload:
| Byte | Field | Type | Description |
| ---- | ------- | ----- | ------------------------------------ |
| 0 | Code ID | uint8 | Transmission code ID (1, 2, 4, or 8) |
_Note: This resource uses the code ID (which is a binary bitmask), while the [Device Status](#device-status-format) uses a transmission code index (0-3) where the code ID is 2^index._
### CoAP Response Codes
When working with ADAR resources, you may encounter these CoAP response codes:
#### Success Responses
- **`2.02 Deleted`** - Resource successfully deleted
- **`2.04 Changed`** - Resource successfully modified (PUT operations)
- **`2.05 Content`** - Resource successfully retrieved (GET operations)
#### Client Error Responses
- **`4.00 Bad Request`** - Malformed request or invalid payload data
- **`4.04 Not Found`** - Resource does not exist (e.g., typos in resource paths like `/pointclouds/v0` instead of `/pointcloud/v0`) or unauthorized access
- **`4.05 Method Not Allowed`** - Invalid HTTP method for the resource (e.g., PUT to a read-only resource)
- **`4.08 Request Entity Incomplete`** - Missing or incomplete payload for operations that require data
- **`4.29 Too Many Requests`** - Observer limit exceeded (max 2 point cloud observers)
#### Server Error Responses
- **`5.01 Not Implemented`** - Resource is deprecated or not supported in the current firmware version
Raw data
{
"_id": null,
"home_page": null,
"name": "adar-api",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "adar, sonair, ultrasound, adar_api",
"author": null,
"author_email": null,
"download_url": null,
"platform": null,
"description": "# ADAR API Python Package\n\nA Python package for communicating with the ADAR 3D Ultrasonic Sensor via Constrained Application Protocol (CoAP)).\n\n## Overview\n\nThis package serves two main purposes:\n\n1. **Easy-to-use Python API**: Provides a simple interface for receiving 3D point cloud data from ADAR sensors, for conversion to other ecosystems like ROS or Foxglove.\n\n2. **Reference Implementation**: Documents the CoAP resources and binary data formats to enable porting to other languages (C, C++, etc.)\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Network Requirements](#network-requirements)\n- [Quick Start](#quick-start)\n- [API Reference](#api-reference) - _For Python developers_\n- [Coordinate System](#coordinate-system)\n- [Error Handling](#error-handling)\n- [Advanced Usage](#advanced-usage)\n- [CoAP Resources and Data Formats](#coap-resources-and-data-formats) - _For protocol reference_\n\n## Installation\n\n### Quick Installation\n\nInstall the ADAR API package from PyPI:\n\n```bash\npip install adar-api\n```\n\n### Recommended: Using a Virtual Environment\n\nFor better dependency management, it's recommended to use a virtual environment:\n\n1. **Create a virtual environment:**\n ```bash\n python -m venv .venv\n ```\n\n2. **Activate the virtual environment:**\n \n **Linux/macOS:**\n ```bash\n source .venv/bin/activate\n ```\n \n **Windows:**\n ```cmd\n .venv\\Scripts\\activate\n ```\n\n3. **Install the package:**\n ```bash\n pip install adar-api\n ```\n\n**Note:** You need to activate the virtual environment each time you want to use the `pointcloud-publisher` command or the ADAR API in a new terminal session.\n\n## Network Requirements\n\n- **Protocol**: CoAP over UDP (port 5683)\n- **Network**: IPv4 connectivity to sensor\n- **Firewall**: Ensure UDP port 5683 is accessible\n\n## Quick Start\n\n### Point cloud Publisher\n\nThe easiest way to visualize the ADAR point cloud is to use the built-in `pointcloud-publisher`:\n\n```bash\npointcloud-publisher <ADAR_IP_ADDRESS>\n```\n\nExample for an ADAR with factory-default IP address:\n```bash\npointcloud-publisher 10.20.30.40\n```\n\n#### Advanced Usage\n\nSpecify a custom Foxglove server host:\nThis can be useful if you want to publish the pointcloud to a different computer than the one which is running the the pointcloud-publisher script.\n\n```bash\npointcloud-publisher <ADAR_IP_ADDRESS> --foxglove-host <HOST_IP>\n```\n\nExample for broadcasting to a specific foxglove host:\nThis will publish the pointcloud from an ADAR with IP address `10.20.30.40` to a foxglove host running on IP address 127.0.0.2\n```bash\npointcloud-publisher 10.20.30.40 --foxglove-host 127.0.0.2\n```\n\n**Command Line Options:**\n- `ipaddr` (required): IP address of the ADAR device\n- `--foxglove-host` (optional): Host IP address for the Foxglove server (default: 127.0.0.1)\n\n#### Visualization with Foxglove Studio\n\n1. **Start the pointcloud publisher** (as shown above)\n2. **Open Foxglove Studio**\n3. **Connect to the Foxglove server:**\n - Go to \"Open connection\" \n - Select \"Foxglove WebSocket\"\n - Enter `ws://127.0.0.1:8765` (or your custom host)\n4. **Import layout for ADAR:**\n - In the top right pane, select the layout drop-down and click \"Import from file...\"\n - Select the [`foxglove_layout_ADAR.json`](adar_api/examples/foxglove_layout_ADAR.json) file.\n - The point cloud should now appear in a 3D view and a 2D top-down view.\n\n### ADAR API\n\nFor custom integrations, use the Python API directly:\n\n```python\nimport asyncio\nfrom adar_api import Adar\nfrom aiocoap import Context\n\nasync def main():\n # Create CoAP context\n ctx = await Context.create_client_context()\n\n # Connect to ADAR sensor\n adar = Adar(ctx, ip_address=\"10.20.30.40\")\n\n # Get device information\n device_info = await adar.get_device_info()\n print(f\"Device: {device_info.device_name}\")\n print(f\"Firmware: {device_info.firmware_version}\")\n\n # Get single point cloud frame\n point_cloud = await adar.get_point_cloud()\n print(f\"Received {len(point_cloud.points)} points\")\n\n # Continuous observation\n async for point_cloud in adar.observe_point_cloud():\n print(f\"Received {len(point_cloud.points)} points\")\n for point in point_cloud.points:\n print(f\"Point: x={point.x:.3f}m, y={point.y:.3f}m, z={point.z:.3f}m, \"\n f\"strength={point.strength}, classification={point.classification}\")\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n## API Reference\n\n### Error Handling\n\nThe API provides structured exception handling:\n\n```python\nfrom adar_api import CoapException, CoapErrorException\n\ntry:\n point_cloud = await adar.get_point_cloud()\nexcept CoapErrorException as e:\n print(f\"CoAP protocol error: {e.response.code}\")\nexcept CoapException as e:\n print(f\"General CoAP error: {e}\")\nexcept Exception as e:\n print(f\"Unexpected error: {e}\")\n```\n\n### Response Code Handling\n\nCoAP errors include response codes that indicate the type of failure or success.\n\nFor a complete list of response codes, see [CoAP Response Codes](#coap-response-codes) in the protocol reference.\n\n### Usage Examples\n\n#### Robust Point Cloud Observation\n\n```python\nasync def robust_observation():\n async for point_cloud in adar.observe_point_cloud(keep_running=True):\n try:\n # Process point cloud\n process_points(point_cloud.points)\n except Exception as e:\n logger.warning(f\"Processing error: {e}\")\n # Continue observation despite processing errors\n```\n\n#### Direct CoAP Request\n\n```python\nfrom aiocoap import Message, GET\n\n# Access the underlying CoAP request method\nresponse = await adar.send_request(\n Message(code=GET, uri=f\"coap://{adar.ip_address}/status/v0\")\n)\n```\n\n#### Network Configuration\n\n```python\n# Get current configuration\nconfig = await adar.get_network_config()\nprint(f\"Current DHCP setting: {config.dhcp_enabled}\")\n\n# Modify network config\nconfig.dhcp_enabled = True\n\n# Apply modified configuration (device will reboot and might be on a different network than before)\nawait adar.set_network_config(config)\n```\n\n#### Transmission Code Configuration\n\n```python\n# Get current transmission code\ncode_id = await adar.get_transmission_code_id()\nprint(f\"Current transmission code: {code_id}\")\n\n# Set transmission code (valid values: 1, 2, 4, 8)\nawait adar.set_transmission_code_id(4)\n```\n\n## CoAP Resources and Data Formats\n\nFor developers integrating towards ADAR using other languages, this section documents the CoAP API resources and data formats.\n\n### Resource URI Structure\n\n```\ncoap://<device_ip>/<resource>/<version>\n```\n\n### Resource Reference\n\n| Resource | Method | Description | Response Format |\n| ----------------------- | ----------- | ---------------------- | ----------------------------------------------- |\n| `/pointcloud/v0` | GET/OBSERVE | 3D point cloud data | [Point Cloud Format](#point-cloud-format) |\n| `/status/v0` | GET | Device status | [Device Status Format](#device-status-format) |\n| `/device_info/v0` | GET | Device identification | [Device Info Format](#device-info-format) |\n| `/network_config/v0` | GET/PUT | Network configuration | [Network Config Format](#network-config-format) |\n| `/statistics/v0` | GET | Operational statistics | [Statistics Format](#statistics-format) |\n| `/errors/v0` | GET | Device error codes | [Error Format](#error-format) |\n| `/transmission_code/v0` | GET/PUT | Transmission code ID | Single byte. Legal values: 1, 2, 4, 8 |\n| `/factory_reset/v0` | PUT | Factory reset | Empty payload |\n| `/observers/v0` | DELETE | Clear all observers | Empty payload |\n\n### Data Format Specifications (little-endian)\n\n#### Point Cloud Format\n\nBinary payload structure:\n\n| Byte Range | Field | Type | Description |\n| ---------- | ------------- | ------------------ | ------------------------------------------------- |\n| 0-7 | Timestamp | uint64 | Microseconds since measurement start |\n| 8-15 | Device Status | 8 bytes | See [Device Status Format](#device-status-format) |\n| 16+ | Point Data | 10 bytes per point | See [Point Format](#point-format) |\n\n_Note: The number of points is determined by parsing 10-byte chunks until the payload ends. The total payload length minus the 16-byte header must be divisible by 10, or the data is considered corrupted._\n\n##### Point Format\n\n| Byte Range | Field | Type | Description |\n| ---------- | -------------- | ------ | ------------------------------------------------- |\n| 0-1 | X coordinate | int16 | Millimeters, signed |\n| 2-3 | Y coordinate | int16 | Millimeters, signed |\n| 4-5 | Z coordinate | int16 | Millimeters, signed |\n| 6-7 | Strength | uint16 | Signal strength, unsigned |\n| 8 | Reserved | uint8 | Ignore |\n| 9 | Classification | uint8 | See [Classification Flags](#classification-flags) |\n\n_Note: The Python API converts coordinates from millimeters to meters._\n\n##### Classification Flags\n\n| Bit 7-4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |\n| -------- | ----------------------- | --------------------------- | --------------------------- | ------------------------ |\n| Reserved | Point in Exclusion Zone | Point in Outer Warning Zone | Point in Inner Warning Zone | Point in Protective Zone |\n\n#### Device Status Format\n\n8-byte binary structure:\n\n| Byte Range | Field | Type | Description |\n| ---------- | ----------------- | ------ | ------------------------------------------------------ |\n| 0 | Zone Selected | uint8 | Currently selected zone |\n| 1 | Device State | uint8 | See [Device States](#device-states) |\n| 2 | Transmission Code | uint8 | Transmission code index (0-3, where code ID = 2^index) |\n| 3 | Zone Status | uint8 | See [Zone Status Flags](#zone-status-flags) |\n| 4-7 | Device Error | uint32 | Error code, little-endian |\n\n_Note: This format uses a transmission code index (0-3), while the [Transmission Code](#transmission-code-format) resource uses a code ID (1, 2, 4, 8)._\n\n##### Device States\n\n- 1: Init\n- 2: SelfTest\n- 3: Enabled\n- 4: Disabled\n- 5: Config\n- 6: Error\n- 7: Fault\n\n##### Zone Status Flags\n\n| Bit 7-3 | Bit 2 | Bit 1 | Bit 0 |\n| -------- | ---------------------------- | ---------------------------- | ------------------------- |\n| Reserved | Object in Outer Warning Zone | Object in Inner Warning Zone | Object in Protective Zone |\n\n#### Device Info Format\n\nVariable-length format with [length-prefixed strings](#length-prefixed-string-format):\n\n| Byte Range | Field | Type | Description |\n| ------------ | ----------------------- | --------------- | ------------------------------------------------ |\n| 0-3 | Serial Number | uint32 | Device serial number, little-endian |\n| 4-6 | Hardware Version | 3 Bytes (uint8) | Hardware version bytes (major.minor.patch) |\n| 7-10 | Product Number Length | uint32 | Length of product number string, little-endian |\n| 11+ | Product Number | UTF-8 string | Product number string |\n| Next 4 bytes | Device Name Length | uint32 | Length of device name string, little-endian |\n| Next N bytes | Device Name | UTF-8 string | Device name string |\n| Next 4 bytes | Firmware Version Length | uint32 | Length of firmware version string, little-endian |\n| Next N bytes | Firmware Version | UTF-8 string | Firmware version string |\n\n##### Length-prefixed String Format\n\n- 4 bytes: String length (uint32, little-endian)\n- N bytes: UTF-8 string data\n\n#### Network Config Format\n\n212-byte binary structure:\n\n| Byte Range | Field | Type | Description |\n| ---------- | ------------------- | ----------------- | -------------------------------------------------------------------- |\n| 0-3 | Configuration Flags | uint32 | See [Configuration Flags](#configuration-flags) |\n| 4-7 | Static IP Address | 4 Bytes (uint8) | Static IP address bytes |\n| 8-11 | Subnet Mask | 4 Bytes (uint8) | Subnet mask bytes |\n| 12-15 | Gateway Address | 4 Bytes (uint8) | Gateway IP address bytes |\n| 16-19 | Sync Server IP | 4 Bytes (uint8) | Synchronization server IP address |\n| 20-83 | Reserved | 64 Bytes (uint8) | Reserved bytes |\n| 84-211 | Device Tag | 128 Bytes (uint8) | Reserved for Device Tag. Should be set to existing value or all-zero |\n\n##### Configuration Flags\n\n| Bit 31-3 | Bit 2 | Bit 1 | Bit 0 |\n| -------- | ---------------- | ------------ | ------------------------------------ |\n| Reserved | Sync server mode | Sync enabled | Static IP enabled (0=DHCP, 1=Static) |\n\n#### Statistics Format\n\n44-byte binary structure:\n\n| Byte Range | Field | Type | Description |\n| ---------- | --------------------------------------- | ----------------------------------- | -------------------------------------------- |\n| 0-11 | Uptime | [Duration format](#duration-format) | Device uptime |\n| 12-19 | Total Number of Pings | uint64 | Total pings count, little-endian |\n| 20-27 | Pings with Object in Protective Zone | uint64 | Protective zone detections, little-endian |\n| 28-35 | Pings with Object in Inner Warning Zone | uint64 | Inner warning zone detections, little-endian |\n| 36-43 | Pings with Object in Outer Warning Zone | uint64 | Outer warning zone detections, little-endian |\n\n##### Duration Format\n\n| Byte Range | Field | Type | Description |\n| ---------- | ----------- | ------ | ------------------------------------ |\n| 0-7 | Seconds | uint64 | Seconds component, little-endian |\n| 8-11 | Nanoseconds | uint32 | Nanoseconds component, little-endian |\n\n#### Error Format\n\nVariable-length format with error bitmask and description strings:\n\n| Byte Range | Field | Type | Description |\n| ---------- | ----------------------- | -------- | ----------------------------------------------- |\n| 0-3 | Error Bitmask | uint32 | Error bitmask, little-endian |\n| 4-7 | Number of Error Strings | uint32 | Count of error strings, little-endian |\n| 8+ | Error Strings | Variable | See [Error String Format](#error-string-format) |\n\n##### Error String Format\n\n- 4 bytes: String length (uint32, little-endian)\n- N bytes: UTF-8 error description\n\n#### Transmission Code Format\n\nSingle byte payload:\n\n| Byte | Field | Type | Description |\n| ---- | ------- | ----- | ------------------------------------ |\n| 0 | Code ID | uint8 | Transmission code ID (1, 2, 4, or 8) |\n\n_Note: This resource uses the code ID (which is a binary bitmask), while the [Device Status](#device-status-format) uses a transmission code index (0-3) where the code ID is 2^index._\n\n### CoAP Response Codes\n\nWhen working with ADAR resources, you may encounter these CoAP response codes:\n\n#### Success Responses\n\n- **`2.02 Deleted`** - Resource successfully deleted\n- **`2.04 Changed`** - Resource successfully modified (PUT operations)\n- **`2.05 Content`** - Resource successfully retrieved (GET operations)\n\n#### Client Error Responses\n\n- **`4.00 Bad Request`** - Malformed request or invalid payload data\n- **`4.04 Not Found`** - Resource does not exist (e.g., typos in resource paths like `/pointclouds/v0` instead of `/pointcloud/v0`) or unauthorized access\n- **`4.05 Method Not Allowed`** - Invalid HTTP method for the resource (e.g., PUT to a read-only resource)\n- **`4.08 Request Entity Incomplete`** - Missing or incomplete payload for operations that require data\n- **`4.29 Too Many Requests`** - Observer limit exceeded (max 2 point cloud observers)\n\n#### Server Error Responses\n\n- **`5.01 Not Implemented`** - Resource is deprecated or not supported in the current firmware version\n\n",
"bugtrack_url": null,
"license": null,
"summary": "A reference implementation in python that uses the Sonair ADAR CoAP API.",
"version": "1.1.2",
"project_urls": {
"Homepage": "https://sonair.com",
"Source": "https://github.com/Sonair-AS/adar_api"
},
"split_keywords": [
"adar",
" sonair",
" ultrasound",
" adar_api"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "8c92f7fd5d772cbf92ac7f4ac09ee6ba3d0bf47a59a220e2418cb87d6dad7846",
"md5": "0f83bce8aa5a0507280213c9028b8f6e",
"sha256": "7f20c1adbfd198e20ea859a2192713485b390bd2cb07daf787d7618bccb07f33"
},
"downloads": -1,
"filename": "adar_api-1.1.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "0f83bce8aa5a0507280213c9028b8f6e",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 25220,
"upload_time": "2025-08-19T08:47:33",
"upload_time_iso_8601": "2025-08-19T08:47:33.846204Z",
"url": "https://files.pythonhosted.org/packages/8c/92/f7fd5d772cbf92ac7f4ac09ee6ba3d0bf47a59a220e2418cb87d6dad7846/adar_api-1.1.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-19 08:47:33",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Sonair-AS",
"github_project": "adar_api",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "adar-api"
}