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:
PaulVua
2026-06-02 16:55:54 +02:00
parent 13c266d694
commit dad953acdc
4 changed files with 41 additions and 5 deletions

View File

@@ -1 +1 @@
1.11.0 1.12.0

View File

@@ -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",

View File

@@ -246,6 +246,7 @@ 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
@@ -374,6 +375,13 @@ class SensorPayload:
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
@@ -1075,6 +1083,18 @@ try:
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)")
# Getting the LTE Signal (AT+CSQ) # Getting the LTE Signal (AT+CSQ)

View File

@@ -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)
``` ```
--- ---