- README: ajout section parser Miotiq avec firmware version (bytes 69-71) - error_flags.md: parser mis a jour (version_major/minor/patch + reserved 22) - error_flags.md: correction note init bytes 66-68 a 0x00 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
323 lines
13 KiB
Markdown
323 lines
13 KiB
Markdown
# 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).
|