Skip to content

Commit 381bac9

Browse files
authored
Merge pull request #1472 from kizniche/copilot/add-multi-channel-querying-api
Add Multi-Channel Measurement Querying REST API
2 parents 1b04cc2 + 1a57dca commit 381bac9

File tree

8 files changed

+1707
-3
lines changed

8 files changed

+1707
-3
lines changed

docs/Multi-Channel-API-Architecture.md

Lines changed: 413 additions & 0 deletions
Large diffs are not rendered by default.

docs/Multi-Channel-API-Example.md

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
# Multi-Channel Measurement API
2+
3+
## Overview
4+
5+
The Multi-Channel Measurement API allows you to query measurements from multiple sensor channels in a single HTTP request, reducing network round-trips and improving efficiency when working with multi-channel sensors like BME680, BME688, or Atlas Scientific multi-probes.
6+
7+
## Endpoint
8+
9+
**POST** `/api/measurements/multi`
10+
11+
## Authentication
12+
13+
Requires authentication using API key in the header:
14+
```
15+
Authorization: Bearer YOUR_API_KEY
16+
```
17+
18+
## Request Format
19+
20+
```json
21+
{
22+
"channels": [
23+
{
24+
"unique_id": "sensor_unique_id",
25+
"unit": "unit_name",
26+
"channel": 0,
27+
"measure": "measurement_type"
28+
}
29+
],
30+
"past_seconds": 3600
31+
}
32+
```
33+
34+
### Request Parameters
35+
36+
| Parameter | Type | Required | Description |
37+
|-----------|------|----------|-------------|
38+
| `channels` | array | Yes | List of channel specifications to query |
39+
| `past_seconds` | integer | No | How many seconds in the past to query (default: 3600) |
40+
41+
### Channel Specification
42+
43+
Each channel in the `channels` array must include:
44+
45+
| Field | Type | Required | Description |
46+
|-------|------|----------|-------------|
47+
| `unique_id` | string | Yes | The unique ID of the device |
48+
| `unit` | string | Yes | The unit of the measurement (e.g., 'C', '%', 'hPa') |
49+
| `channel` | integer | Yes | The channel number (0-based) |
50+
| `measure` | string | No | The measurement type (e.g., 'temperature', 'humidity') |
51+
52+
## Response Format
53+
54+
```json
55+
{
56+
"measurements": [
57+
{
58+
"unique_id": "sensor_unique_id",
59+
"unit": "C",
60+
"channel": 0,
61+
"measure": "temperature",
62+
"time": 1703894523.456,
63+
"value": 23.5
64+
},
65+
{
66+
"unique_id": "sensor_unique_id",
67+
"unit": "%",
68+
"channel": 1,
69+
"measure": "humidity",
70+
"time": 1703894523.456,
71+
"value": 65.3
72+
}
73+
]
74+
}
75+
```
76+
77+
## Examples
78+
79+
### Example 1: Query Multiple Channels from a BME680 Sensor
80+
81+
```bash
82+
curl -X POST "https://mycodo.local/api/measurements/multi" \
83+
-H "Authorization: Bearer YOUR_API_KEY" \
84+
-H "Content-Type: application/json" \
85+
-d '{
86+
"channels": [
87+
{
88+
"unique_id": "bme680_sensor_001",
89+
"unit": "C",
90+
"channel": 0,
91+
"measure": "temperature"
92+
},
93+
{
94+
"unique_id": "bme680_sensor_001",
95+
"unit": "%",
96+
"channel": 1,
97+
"measure": "humidity"
98+
},
99+
{
100+
"unique_id": "bme680_sensor_001",
101+
"unit": "hPa",
102+
"channel": 2,
103+
"measure": "pressure"
104+
},
105+
{
106+
"unique_id": "bme680_sensor_001",
107+
"unit": "ohm",
108+
"channel": 3,
109+
"measure": "resistance"
110+
}
111+
],
112+
"past_seconds": 3600
113+
}'
114+
```
115+
116+
### Example 2: Query Different Sensors
117+
118+
```bash
119+
curl -X POST "https://mycodo.local/api/measurements/multi" \
120+
-H "Authorization: Bearer YOUR_API_KEY" \
121+
-H "Content-Type: application/json" \
122+
-d '{
123+
"channels": [
124+
{
125+
"unique_id": "temp_sensor_001",
126+
"unit": "C",
127+
"channel": 0,
128+
"measure": "temperature"
129+
},
130+
{
131+
"unique_id": "humidity_sensor_001",
132+
"unit": "%",
133+
"channel": 0,
134+
"measure": "humidity"
135+
}
136+
],
137+
"past_seconds": 1800
138+
}'
139+
```
140+
141+
### Example 3: Python Client
142+
143+
```python
144+
import requests
145+
146+
API_URL = "https://mycodo.local/api/measurements/multi"
147+
API_KEY = "YOUR_API_KEY"
148+
149+
headers = {
150+
"Authorization": f"Bearer {API_KEY}",
151+
"Content-Type": "application/json"
152+
}
153+
154+
payload = {
155+
"channels": [
156+
{
157+
"unique_id": "bme680_sensor_001",
158+
"unit": "C",
159+
"channel": 0,
160+
"measure": "temperature"
161+
},
162+
{
163+
"unique_id": "bme680_sensor_001",
164+
"unit": "%",
165+
"channel": 1,
166+
"measure": "humidity"
167+
}
168+
],
169+
"past_seconds": 3600
170+
}
171+
172+
response = requests.post(API_URL, json=payload, headers=headers, verify=False)
173+
174+
if response.status_code == 200:
175+
data = response.json()
176+
for measurement in data["measurements"]:
177+
print(f"{measurement['measure']}: {measurement['value']} {measurement['unit']}")
178+
else:
179+
print(f"Error: {response.status_code} - {response.text}")
180+
```
181+
182+
## Error Responses
183+
184+
### 403 Forbidden
185+
User does not have permission to view settings.
186+
187+
### 422 Unprocessable Entity
188+
- Missing or invalid request parameters
189+
- Invalid unit ID
190+
- Invalid channel number (must be >= 0)
191+
- Empty channels list
192+
193+
### 500 Internal Server Error
194+
An exception occurred while processing the request.
195+
196+
## Benefits
197+
198+
1. **Reduced Network Overhead**: Query multiple channels in a single HTTP request instead of multiple requests
199+
2. **Lower Latency**: Single round-trip for all measurements
200+
3. **Power Efficiency**: Particularly beneficial for mobile clients
201+
4. **Synchronized Data**: All measurements are queried in a coordinated manner
202+
203+
## Notes
204+
205+
- The endpoint returns the last measurement for each channel within the specified time window
206+
- If a measurement is not available for a channel, `time` and `value` will be `null`
207+
- The `past_seconds` parameter defaults to 3600 (1 hour) if not specified
208+
- All channels are queried independently, so one failing channel won't affect others
209+
210+
## Future Enhancements
211+
212+
WebSocket support for real-time multi-channel updates is planned for a future release.

0 commit comments

Comments
 (0)