adar-api


Nameadar-api JSON
Version 1.1.2 PyPI version JSON
download
home_pageNone
SummaryA reference implementation in python that uses the Sonair ADAR CoAP API.
upload_time2025-08-19 08:47:33
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseNone
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"
}
        
Elapsed time: 1.69567s