# 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 ```python # 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 ```python 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||| 2|version_major|hex2dec||| 2|version_minor|hex2dec||| 2|version_patch|hex2dec||| 22|reserved|skip||| ``` --- ## Lecture cote serveur (exemple Python) ```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 - Les bytes 66-68 sont initialises a 0x00 dans le constructeur SensorPayload (0x00 = aucune erreur/aucun flag). Les bytes 69-71 restent a 0xFF si le fichier VERSION est absent ou malformed. - 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).