WebSocket¶
Connect to /ws/sensors for a live stream of sensor readings. The device currently pushes messages every second.
Data freshness
The default sensor poll interval is 5 seconds, so several WebSocket messages can contain the same sensor reading. The current payload does not include a data timestamp.
Connecting¶
const ws = new WebSocket('ws://sqm-esp32.local/ws/sensors');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('SQM:', data.skyQuality.sqm);
};
ws.onclose = () => {
// reconnect with backoff
};
Message Format¶
{
"lightSensor": {
"lux": 0.0234,
"visible": 123,
"infrared": 45,
"full": 168,
"status": 0
},
"skyQuality": {
"sqm": 21.5,
"nelm": 6.2,
"bortle": 2.0,
"description": "Typical truly dark site"
},
"environment": {
"temperature": 12.4,
"humidity": 72.1,
"pressure": 1013.25,
"dewpoint": 7.8,
"status": 0
},
"irTemperature": {
"objectTemp": -15.2,
"ambientTemp": 12.4,
"status": 0
},
"cloudConditions": {
"temperatureDelta": -27.6,
"correctedDelta": -24.1,
"cloudCoverPercent": 5.0,
"condition": 0,
"description": "Clear",
"humidityUsed": 72.1
},
"gps": {
"hasFix": true,
"satellites": 8,
"latitude": 51.5074,
"longitude": -0.1278,
"altitude": 42.0,
"hdop": 1.2,
"age": 800
},
"rainSensor": {
"isRaining": false,
"acc": 0.000,
"eventAcc": 0.000,
"totalAcc": 12.340,
"rInt": 0.000,
"lensBad": false,
"emSat": false,
"status": 0
}
}
GPS field
gps is only included in the message when a GPS module is connected and initialised.
Rain sensor field
rainSensor is only included when the RG-15 rain sensor is enabled and initialised. Values use the RG-15 configured units; the current payload field names do not include the unit.
status values¶
| Value | Meaning |
|---|---|
0 |
OK |
1 |
Sensor not found |
2 |
Read error |
3 |
Stale data |
Python Example¶
import asyncio
import json
import websockets
async def stream():
async with websockets.connect("ws://sqm-esp32.local/ws/sensors") as ws:
async for message in ws:
data = json.loads(message)
sqm = data["skyQuality"]["sqm"]
bortle = data["skyQuality"]["bortle"]
cloud = data["cloudConditions"]["description"]
print(f"SQM: {sqm:.2f} Bortle: {bortle} Sky: {cloud}")
asyncio.run(stream())
Notes¶
- The server broadcasts to all connected clients simultaneously
- There is no authentication on the WebSocket endpoint
- Broadcasts happen every 1 second regardless of
sensor.readIntervalMs