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>
This commit is contained in:
@@ -151,6 +151,16 @@ payload_json = {
|
||||
aircarto_profile_id = 0
|
||||
uSpot_profile_id = 1
|
||||
|
||||
# Error flags constants (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
|
||||
|
||||
# database connection
|
||||
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db")
|
||||
cursor = conn.cursor()
|
||||
@@ -358,6 +368,18 @@ class SensorPayload:
|
||||
if direction is not None:
|
||||
self.payload[64:66] = struct.pack('>H', int(direction))
|
||||
|
||||
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
|
||||
|
||||
def get_bytes(self):
|
||||
"""Get the complete 100-byte payload"""
|
||||
return bytes(self.payload)
|
||||
@@ -1090,6 +1112,14 @@ try:
|
||||
|
||||
'''
|
||||
|
||||
# ---- Build error_flags (byte 66) ----
|
||||
error_flags = 0x00
|
||||
if rtc_status == "disconnected":
|
||||
error_flags |= ERR_RTC_DISCONNECTED
|
||||
if rtc_status == "reset":
|
||||
error_flags |= ERR_RTC_RESET
|
||||
payload.set_error_flags(error_flags)
|
||||
|
||||
if send_miotiq:
|
||||
print('<p class="fw-bold">➡️SEND TO MIOTIQ</p>', end="")
|
||||
|
||||
@@ -1125,9 +1155,20 @@ try:
|
||||
print(response_SARA_1)
|
||||
else:
|
||||
print("⛔There were issues with the modem CSD PSD reinitialize process")
|
||||
print("🔄 PDP reset failed → escalating to hardware reboot")
|
||||
# Clignotement LED rouge en cas d'erreur
|
||||
led_thread = Thread(target=blink_led, args=(24, 5, 0.5))
|
||||
led_thread.start()
|
||||
#Send notification (WIFI)
|
||||
send_error_notification(device_id, "UDP socket creation failed + PDP reset failed -> hardware reboot")
|
||||
#Hardware Reboot
|
||||
hardware_reboot_success = modem_hardware_reboot()
|
||||
if hardware_reboot_success:
|
||||
print("✅Modem successfully rebooted and reinitialized")
|
||||
else:
|
||||
print("⛔There were issues with the modem reboot/reinitialize process")
|
||||
#end loop
|
||||
sys.exit()
|
||||
|
||||
#Retreive Socket ID
|
||||
socket_id = None
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# Error Flags — UDP Payload Miotiq (Bytes 66-67)
|
||||
# Error Flags — UDP Payload Miotiq (Bytes 66-68)
|
||||
|
||||
## Principe
|
||||
|
||||
Les bytes 66 et 67 de la payload UDP (100 bytes) sont utilises comme registres d'erreurs.
|
||||
Chaque bit represente un etat d'erreur independant. Plusieurs erreurs peuvent
|
||||
etre signalees simultanement.
|
||||
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
|
||||
|
||||
@@ -15,7 +16,8 @@ etre signalees simultanement.
|
||||
Bytes 0-65 : donnees capteurs (existant)
|
||||
Byte 66 : error_flags (erreurs systeme)
|
||||
Byte 67 : npm_status (status NextPM)
|
||||
Bytes 68-99 : reserved (initialises a 0xFF)
|
||||
Byte 68 : device_status (etat general du boitier)
|
||||
Bytes 69-99 : reserved (initialises a 0xFF)
|
||||
```
|
||||
|
||||
---
|
||||
@@ -91,6 +93,35 @@ car les deux indiquent un capteur inactif.
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
@@ -112,6 +143,16 @@ 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
|
||||
|
||||
@@ -128,6 +169,27 @@ 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
|
||||
@@ -140,6 +202,10 @@ def set_error_flags(self, flags):
|
||||
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
|
||||
```
|
||||
|
||||
---
|
||||
@@ -180,7 +246,8 @@ def set_npm_status(self, status):
|
||||
4|wind_direction|hex2dec|degrees||
|
||||
2|error_flags|hex2dec|||
|
||||
2|npm_status|hex2dec|||
|
||||
30|reserved|skip|||
|
||||
2|device_status|hex2dec|||
|
||||
28|reserved|skip|||
|
||||
```
|
||||
|
||||
---
|
||||
@@ -212,6 +279,18 @@ 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")
|
||||
@@ -219,6 +298,12 @@ 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")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user