v1.12.0: transmission CO2 S88 dans le payload UDP Miotiq (byte 81)
Débloque le WIP S88->Miotiq. Spec serveur reçue: byte 81-82 = CO2 (ISO_17, uint16 ppm). Source = Senseair S88 (vrai CO2 NDIR). - SensorPayload.set_co2() -> bytes 81-82 (uint16, clamp 0..65535) - lecture data_S88 (derniere ligne) si config S88 active, puis set_co2 - defaut 0xFFFF = capteur absent - canal UDP Miotiq uniquement (CSV/JSON non touches) - error_flags.md: byte-map a jour (81-82 = CO2) CCS811 (TVOC/eCO2) NON transmis: pas encore de champ dans la spec Miotiq. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,20 @@
|
|||||||
{
|
{
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"version": "1.12.0",
|
||||||
|
"date": "2026-06-02",
|
||||||
|
"changes": {
|
||||||
|
"features": [
|
||||||
|
"Transmission du CO2 S88 dans le payload UDP Miotiq (débloque le WIP). Nouvelle méthode SensorPayload.set_co2() -> bytes 81-82 (uint16 ppm, champ ISO_17 de la spec Miotiq). SARA_send_data_v2.py lit data_S88 (dernière ligne) si config S88 active et empaquette le CO2. Défaut 0xFFFF = capteur absent (octets initialisés à 0xFF). Canal UDP Miotiq uniquement (pas CSV/JSON pour l'instant). error_flags.md: cartographie d'octets mise à jour (81-82 = CO2)."
|
||||||
|
],
|
||||||
|
"improvements": [],
|
||||||
|
"fixes": [],
|
||||||
|
"compatibility": [
|
||||||
|
"Source du champ CO2 (ISO_17) = Senseair S88 (vrai CO2 NDIR). Le CCS811 n'alimente PAS ce champ (son eCO2 est dérivé, pas un vrai CO2). Le CCS811 (TVOC + eCO2) n'a pas encore de champ dans la spec serveur Miotiq -> transmission CCS811 toujours en attente d'extension de la spec côté serveur."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notes": "Spec Miotiq reçue: payload 83 octets, byte 81-82 = CO2 ISO_17 uint16 ppm. Packing vérifié (793 -> 0x0319). À faire ensuite pour le CCS811: demander à Miotiq d'ajouter un champ TVOC (code ISO COV) + eCO2."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.11.0",
|
"version": "1.11.0",
|
||||||
"date": "2026-06-02",
|
"date": "2026-06-02",
|
||||||
|
|||||||
@@ -243,9 +243,10 @@ send_uSpot = config.get('send_uSpot', False) #envoi sur M
|
|||||||
npm_5channel = config.get('npm_5channel', False) #5 canaux du NPM
|
npm_5channel = config.get('npm_5channel', False) #5 canaux du NPM
|
||||||
envea_cairsens= config.get('envea', False)
|
envea_cairsens= config.get('envea', False)
|
||||||
wind_meter= config.get('windMeter', False)
|
wind_meter= config.get('windMeter', False)
|
||||||
bme_280_config = config.get('BME280', False)
|
bme_280_config = config.get('BME280', False)
|
||||||
mppt_charger = config.get('MPPT', False)
|
mppt_charger = config.get('MPPT', False)
|
||||||
NOISE_sensor = config.get('NOISE', False)
|
NOISE_sensor = config.get('NOISE', False)
|
||||||
|
s88_sensor = config.get('S88', False)
|
||||||
|
|
||||||
#update device id in the payload json
|
#update device id in the payload json
|
||||||
payload_json["nebuleairid"] = device_id
|
payload_json["nebuleairid"] = device_id
|
||||||
@@ -373,7 +374,14 @@ class SensorPayload:
|
|||||||
self.payload[62:64] = struct.pack('>H', int(speed * 10))
|
self.payload[62:64] = struct.pack('>H', int(speed * 10))
|
||||||
if direction is not None:
|
if direction is not None:
|
||||||
self.payload[64:66] = struct.pack('>H', int(direction))
|
self.payload[64:66] = struct.pack('>H', int(direction))
|
||||||
|
|
||||||
|
def set_co2(self, co2_ppm):
|
||||||
|
"""Set CO2 (bytes 81-82, uint16 ppm) — ISO_17 in the Miotiq spec.
|
||||||
|
Source: Senseair S88 (true NDIR CO2). Default stays 0xFFFF (constructor
|
||||||
|
fills 0xFF) = sensor absent. NOT for CCS811 eCO2 (a derived value)."""
|
||||||
|
if co2_ppm is not None:
|
||||||
|
self.payload[81:83] = struct.pack('>H', max(0, min(int(co2_ppm), 65535)))
|
||||||
|
|
||||||
def set_error_flags(self, flags):
|
def set_error_flags(self, flags):
|
||||||
"""Set system error flags (byte 66)"""
|
"""Set system error flags (byte 66)"""
|
||||||
self.payload[66] = flags & 0xFF
|
self.payload[66] = flags & 0xFF
|
||||||
@@ -1073,7 +1081,19 @@ try:
|
|||||||
payload.set_noise(
|
payload.set_noise(
|
||||||
cur_leq=cur_LEQ, # current LEQ (dBA)
|
cur_leq=cur_LEQ, # current LEQ (dBA)
|
||||||
cur_level=cur_level # current level (dBA)
|
cur_level=cur_level # current level (dBA)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# S88 CO2 sensor (Senseair S88, NDIR) -> byte 81-82 (ISO_17, uint16 ppm)
|
||||||
|
if s88_sensor:
|
||||||
|
print("➡️Getting S88 CO2 value")
|
||||||
|
cursor.execute("SELECT * FROM data_S88 ORDER BY rowid DESC LIMIT 1")
|
||||||
|
last_row = cursor.fetchone()
|
||||||
|
if last_row and last_row[1] is not None:
|
||||||
|
co2_ppm = last_row[1]
|
||||||
|
print(f"CO2 (S88): {co2_ppm} ppm")
|
||||||
|
payload.set_co2(co2_ppm)
|
||||||
|
else:
|
||||||
|
print("No S88 data available in the database.")
|
||||||
|
|
||||||
#print("Verify SARA connection (AT)")
|
#print("Verify SARA connection (AT)")
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ Bytes 69-71 : firmware version (major.minor.patch)
|
|||||||
Bytes 72-75 : latitude (uint32, x/1000000-90)
|
Bytes 72-75 : latitude (uint32, x/1000000-90)
|
||||||
Bytes 76-79 : longitude (uint32, x/1000000-180)
|
Bytes 76-79 : longitude (uint32, x/1000000-180)
|
||||||
Byte 80 : misc (contexte de mesure)
|
Byte 80 : misc (contexte de mesure)
|
||||||
Bytes 81-99 : reserved (initialises a 0xFF)
|
Bytes 81-82 : CO2 (ISO_17, uint16 ppm — Senseair S88, NDIR ; 0xFFFF = absent, 0 = non mesure)
|
||||||
|
Bytes 83-99 : reserved (initialises a 0xFF)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
Reference in New Issue
Block a user