Files
nebuleair_pro_4g/loop/error_flags.md
PaulVua 3804a52fda Error flags byte 66: implementation RTC flags + escalade PDP reset → hardware reboot
- Constantes error_flags (byte 66) + methodes SensorPayload
- Construction byte 66 avec flags RTC (disconnected/reset)
- Escalade: si PDP reset echoue apres echec UDP → notification + hardware reboot + exit
- Doc: ajout byte 68 device_status (specification)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 09:58:39 +01:00

13 KiB

Error Flags — UDP Payload Miotiq (Bytes 66-68)

Principe

Les bytes 66, 67 et 68 de la payload UDP (100 bytes) sont utilises comme registres d'erreurs et d'etat. Chaque bit represente un etat independant. Plusieurs flags peuvent etre actifs simultanement.

  • Byte 66 : erreurs systeme (RTC, capteurs)
  • Byte 67 : status NextPM (registre interne du capteur)
  • Byte 68 : status device (etat general du boitier)

Position dans la payload

Bytes 0-65  : donnees capteurs (existant)
Byte  66    : error_flags (erreurs systeme)
Byte  67    : npm_status (status NextPM)
Byte  68    : device_status (etat general du boitier)
Bytes 69-99 : reserved (initialises a 0xFF)

Byte 66 — Error Flags (erreurs systeme)

Chaque bit represente une erreur detectee par le script d'envoi (SARA_send_data_v2.py).

Bit Masque Nom Description Source
0 0x01 RTC_DISCONNECTED Module RTC DS3231 non detecte sur le bus I2C timestamp_table → 'not connected'
1 0x02 RTC_RESET RTC en date par defaut (annee 2000) timestamp_table → annee 2000
2 0x04 BME280_ERROR Capteur BME280 non detecte ou erreur de lecture data_BME280 → valeurs a 0
3 0x08 NPM_ERROR Capteur NextPM non detecte ou erreur communication data_NPM → toutes valeurs a 0
4 0x10 ENVEA_ERROR Capteurs Envea non detectes ou erreur serie data_envea → valeurs a 0
5 0x20 NOISE_ERROR Capteur bruit NSRT MK4 non detecte ou erreur data_noise → valeurs a 0
6 0x40 MPPT_ERROR Chargeur solaire MPPT non detecte ou erreur data_MPPT → valeurs a 0
7 0x80 WIND_ERROR Capteur vent non detecte ou erreur data_windMeter → valeurs a 0

Detection des erreurs

Les scripts de collecte (get_data_modbus_v3.py, get_data_v2.py, etc.) ecrivent des 0 en base SQLite quand un capteur ne repond pas. Le script d'envoi (SARA_send_data_v2.py) lit ces valeurs et peut detecter l'erreur quand toutes les valeurs d'un capteur sont a 0.

Pour le RTC, le champ timestamp_table contient directement 'not connected' ou une date en annee 2000 quand le module est deconnecte ou reinitialise.

Exemples de valeurs

Valeur dec Hex Signification
0 0x00 Aucune erreur
1 0x01 RTC deconnecte
2 0x02 RTC reset (annee 2000)
5 0x05 RTC deconnecte + BME280 erreur
9 0x09 RTC deconnecte + NPM erreur
255 0xFF Toutes les erreurs (cas extreme)

Byte 67 — NPM Status (registre interne NextPM)

Le capteur NextPM possede un registre de status sur 9 bits (registre Modbus). On stocke les 8 bits bas dans le byte 67. Ce registre est lu directement depuis le capteur via Modbus, pas depuis SQLite.

Bit Masque Nom Description Severite
0 0x01 SLEEP_STATE Capteur en veille (commande sleep). Seule la lecture status autorisee Info
1 0x02 DEGRADED_STATE Erreur mineure confirmee. Mesures possibles mais precision reduite Warning
2 0x04 NOT_READY Demarrage en cours (15s apres mise sous tension). Mesures non fiables Info
3 0x08 HEAT_ERROR Humidite relative > 60% pendant > 10 minutes Warning
4 0x10 TRH_ERROR Capteur T/RH interne hors specification Warning
5 0x20 FAN_ERROR Vitesse ventilateur hors plage (tourne encore) Warning
6 0x40 MEMORY_ERROR Acces memoire impossible, fonctions internes limitees Warning
7 0x80 LASER_ERROR Aucune particule detectee pendant > 240s, possible erreur laser Warning

Note : le bit 8 du registre NextPM (DEFAULT_STATE — ventilateur arrete apres 3 tentatives) ne tient pas dans un byte. Si necessaire, il peut etre combine avec le bit 0 (SLEEP_STATE) car les deux indiquent un capteur inactif.

Exemples de valeurs

Valeur dec Hex Signification
0 0x00 Capteur OK, mesures fiables
4 0x04 Demarrage en cours (NOT_READY)
8 0x08 Erreur humidite (HEAT_ERROR)
32 0x20 Erreur ventilateur (FAN_ERROR)
128 0x80 Possible erreur laser (LASER_ERROR)
40 0x28 HEAT_ERROR + FAN_ERROR

Byte 68 — Device Status (etat general du boitier)

Flags d'etat du device, determines par le script d'envoi (SARA_send_data_v2.py). Ces flags donnent du contexte sur l'etat general du boitier pour le diagnostic a distance.

Bit Masque Nom Description Source
0 0x01 SARA_REBOOTED Le modem a ete reboot hardware au cycle precedent flag fichier ou SQLite
1 0x02 WIFI_CONNECTED Le device est connecte en WiFi (atelier/maintenance) nmcli device status
2 0x04 HOTSPOT_ACTIVE Le hotspot WiFi est actif (configuration en cours) nmcli device status
3 0x08 GPS_NO_FIX Pas de position GPS valide config_table latitude/longitude
4 0x10 BATTERY_LOW Tension batterie sous seuil critique data_MPPT → battery_voltage
5 0x20 DISK_FULL Espace disque critique sur la Pi (< 5%) os.statvfs ou shutil.disk_usage
6 0x40 DB_ERROR Erreur d'acces a la base SQLite try/except sur connexion SQLite
7 0x80 BOOT_RECENT Le device a redemarre recemment (uptime < 5 min) /proc/uptime

Exemples de valeurs

Valeur dec Hex Signification
0 0x00 Tout est normal
1 0x01 Modem reboot au cycle precedent
2 0x02 WiFi connecte (probablement en atelier)
6 0x06 WiFi + hotspot actifs (configuration en cours)
128 0x80 Boot recent (uptime < 5 min)
145 0x91 Modem reboot + batterie faible + boot recent

Implementation

Etape 1 : Lire le status NPM depuis le capteur

Le script NPM/get_data_modbus_v3.py doit etre modifie pour :

  1. Lire le registre de status du NextPM (adresse Modbus a determiner)
  2. Stocker le status byte dans une nouvelle colonne SQLite (ex: npm_status dans data_NPM)

Etape 2 : Construire les flags dans SARA_send_data_v2.py

# Constantes error_flags (byte 66)
ERR_RTC_DISCONNECTED = 0x01
ERR_RTC_RESET        = 0x02
ERR_BME280           = 0x04
ERR_NPM              = 0x08
ERR_ENVEA            = 0x10
ERR_NOISE            = 0x20
ERR_MPPT             = 0x40
ERR_WIND             = 0x80

# Constantes device_status (byte 68)
DEV_SARA_REBOOTED    = 0x01
DEV_WIFI_CONNECTED   = 0x02
DEV_HOTSPOT_ACTIVE   = 0x04
DEV_GPS_NO_FIX       = 0x08
DEV_BATTERY_LOW      = 0x10
DEV_DISK_FULL        = 0x20
DEV_DB_ERROR         = 0x40
DEV_BOOT_RECENT      = 0x80

# Construction byte 66
error_flags = 0x00

if rtc_status == "disconnected":
    error_flags |= ERR_RTC_DISCONNECTED
if rtc_status == "reset":
    error_flags |= ERR_RTC_RESET
if PM1 == 0 and PM25 == 0 and PM10 == 0:
    error_flags |= ERR_NPM
# ... autres capteurs

payload.set_error_flags(error_flags)

# Construction byte 67 (lu depuis SQLite, ecrit par get_data_modbus_v3.py)
npm_status = get_npm_status_from_db()  # 0-255
payload.set_npm_status(npm_status)

# Construction byte 68
device_status = 0x00

if sara_was_rebooted():                       # flag fichier persistant
    device_status |= DEV_SARA_REBOOTED
if check_wifi_connected():                    # nmcli device status
    device_status |= DEV_WIFI_CONNECTED
if check_hotspot_active():                    # nmcli device status
    device_status |= DEV_HOTSPOT_ACTIVE
if latitude == 0.0 and longitude == 0.0:      # config_table
    device_status |= DEV_GPS_NO_FIX
if battery_voltage < 11.0:                    # data_MPPT seuil a ajuster
    device_status |= DEV_BATTERY_LOW
if check_disk_usage() > 95:                   # shutil.disk_usage
    device_status |= DEV_DISK_FULL
# DEV_DB_ERROR: set dans le try/except de la connexion SQLite
if get_uptime_seconds() < 300:                # /proc/uptime
    device_status |= DEV_BOOT_RECENT

payload.set_device_status(device_status)

Etape 3 : Ajouter les methodes dans SensorPayload

def set_error_flags(self, flags):
    """Set system error flags (byte 66)"""
    self.payload[66] = flags & 0xFF

def set_npm_status(self, status):
    """Set NextPM status register (byte 67)"""
    self.payload[67] = status & 0xFF

def set_device_status(self, status):
    """Set device status flags (byte 68)"""
    self.payload[68] = status & 0xFF

Parser Miotiq

16|device_id|string|||W
2|signal_quality|hex2dec|dB||
2|version|hex2dec|||W
4|ISO_68|hex2dec|ugm3|x/10|
4|ISO_39|hex2dec|ugm3|x/10|
4|ISO_24|hex2dec|ugm3|x/10|
4|ISO_54|hex2dec|degC|x/100|
4|ISO_55|hex2dec|%|x/100|
4|ISO_53|hex2dec|hPa||
4|noise_cur_leq|hex2dec|dB|x/10|
4|noise_cur_level|hex2dec|dB|x/10|
4|max_noise|hex2dec|dB|x/10|
4|ISO_03|hex2dec|ppb||
4|ISO_05|hex2dec|ppb||
4|ISO_21|hex2dec|ppb||
4|ISO_04|hex2dec|ppb||
4|ISO_08|hex2dec|ppb||
4|npm_ch1|hex2dec|count||
4|npm_ch2|hex2dec|count||
4|npm_ch3|hex2dec|count||
4|npm_ch4|hex2dec|count||
4|npm_ch5|hex2dec|count||
4|npm_temp|hex2dec|°C|x/10|
4|npm_humidity|hex2dec|%|x/10|
4|battery_voltage|hex2dec|V|x/100|
4|battery_current|hex2dec|A|x/100|
4|solar_voltage|hex2dec|V|x/100|
4|solar_power|hex2dec|W||
4|charger_status|hex2dec|||
4|wind_speed|hex2dec|m/s|x/10|
4|wind_direction|hex2dec|degrees||
2|error_flags|hex2dec|||
2|npm_status|hex2dec|||
2|device_status|hex2dec|||
28|reserved|skip|||

Lecture cote serveur (exemple Python)

# Byte 66 — erreurs systeme
error_flags = int(parsed_error_flags)

rtc_disconnected = bool(error_flags & 0x01)
rtc_reset        = bool(error_flags & 0x02)
bme280_error     = bool(error_flags & 0x04)
npm_error        = bool(error_flags & 0x08)
envea_error      = bool(error_flags & 0x10)
noise_error      = bool(error_flags & 0x20)
mppt_error       = bool(error_flags & 0x40)
wind_error       = bool(error_flags & 0x80)

# Byte 67 — status NextPM
npm_status = int(parsed_npm_status)

npm_sleep     = bool(npm_status & 0x01)
npm_degraded  = bool(npm_status & 0x02)
npm_not_ready = bool(npm_status & 0x04)
npm_heat_err  = bool(npm_status & 0x08)
npm_trh_err   = bool(npm_status & 0x10)
npm_fan_err   = bool(npm_status & 0x20)
npm_mem_err   = bool(npm_status & 0x40)
npm_laser_err = bool(npm_status & 0x80)

# Byte 68 — status device
device_status = int(parsed_device_status)

sara_rebooted    = bool(device_status & 0x01)
wifi_connected   = bool(device_status & 0x02)
hotspot_active   = bool(device_status & 0x04)
gps_no_fix       = bool(device_status & 0x08)
battery_low      = bool(device_status & 0x10)
disk_full        = bool(device_status & 0x20)
db_error         = bool(device_status & 0x40)
boot_recent      = bool(device_status & 0x80)

# Alertes
if rtc_disconnected:
    alert("RTC module deconnecte — verifier pile/cables I2C")
if npm_fan_err:
    alert("NextPM: ventilateur hors plage — maintenance requise")
if npm_laser_err:
    alert("NextPM: possible erreur laser — verifier le capteur")
if battery_low:
    alert("Batterie faible — verifier alimentation solaire")
if disk_full:
    alert("Espace disque critique — verifier logs/DB")
if sara_rebooted:
    alert("Modem reboot hardware au cycle precedent — instabilite reseau")

Notes

  • La payload est initialisee a 0xFF (tous bytes a 255). Le script doit explicitement ecrire 0x00 dans les bytes 66-67 quand tout va bien, sinon Miotiq interpretera 255 = toutes les erreurs.
  • Le NPM status n'est pas encore lu par get_data_modbus_v3.py. Il faut d'abord ajouter la lecture du registre de status Modbus et le stocker en SQLite.
  • Les flags du byte 66 sont determines par le script d'envoi en analysant les valeurs lues depuis SQLite (toutes a 0 = capteur en erreur).