This commit is contained in:
Your Name
2025-07-22 15:36:36 +02:00
parent 4d512685a0
commit 25c5a7a65a
4 changed files with 132 additions and 39 deletions

View File

@@ -1,3 +1,20 @@
"""
_____ _ ___ _______ _
| ____| \ | \ \ / / ____| / \
| _| | \| |\ \ / /| _| / _ \
| |___| |\ | \ V / | |___ / ___ \
|_____|_| \_| \_/ |_____/_/ \_\
Gather data from envea Sensors and store them to the SQlite table
Use the RTC time for the timestamp
This script is run by a service nebuleair-envea-data.service
/usr/bin/python3 /var/www/nebuleair_pro_4g/envea/read_ref_v2.py ttyAMA4
ATTENTION --> read_ref.py fonctionne mieux
"""
import serial import serial
import time import time
import sys import sys

View File

@@ -44,9 +44,9 @@ def read_cairsens(port, baudrate=9600, parity=serial.PARITY_NONE, stopbits=seria
# Lire les données reçues # Lire les données reçues
#data = ser.read_until(b'\n') # Lire jusqu'à la fin de ligne ou un autre délimiteur data = ser.read_until(b'\n') # Lire jusqu'à la fin de ligne ou un autre délimiteur
data = ser.readline() data = ser.readline()
#print(f"Données reçues brutes : {data}") print(f"Données reçues brutes : {data}")
#print(f"Données reçues (utf-8) : {data.decode('utf-8').strip()}") #print(f"Données reçues (utf-8) : {data.decode('utf-8').strip()}")
# Extraire le 20ème octet # Extraire le 20ème octet

View File

@@ -10,7 +10,7 @@ Use the RTC time for the timestamp
This script is run by a service nebuleair-envea-data.service This script is run by a service nebuleair-envea-data.service
/usr/bin/python3 /var/www/nebuleair_pro_4g/envea/read_value_v2.py /usr/bin/python3 /var/www/nebuleair_pro_4g/envea/read_value_v2.py -d
""" """
@@ -20,23 +20,58 @@ import time
import traceback import traceback
import sqlite3 import sqlite3
from datetime import datetime from datetime import datetime
import sys
# Set DEBUG to True to enable debug prints, False to disable
DEBUG = False # Change this to False to disable debug output
# You can also control debug via command line argument
if len(sys.argv) > 1 and sys.argv[1] in ['--debug', '-d']:
DEBUG = True
elif len(sys.argv) > 1 and sys.argv[1] in ['--quiet', '-q']:
DEBUG = False
def debug_print(message):
"""Print debug messages only if DEBUG is True"""
if DEBUG:
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] {message}")
debug_print("=== ENVEA Sensor Reader Started ===")
# Connect to the SQLite database # Connect to the SQLite database
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") try:
cursor = conn.cursor() conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db")
cursor = conn.cursor()
except Exception as e:
debug_print(f"✗ Failed to connect to database: {e}")
sys.exit(1)
#GET RTC TIME from SQlite # GET RTC TIME from SQlite
cursor.execute("SELECT * FROM timestamp_table LIMIT 1") try:
row = cursor.fetchone() # Get the first (and only) row cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
rtc_time_str = row[1] # '2025-02-07 12:30:45' row = cursor.fetchone() # Get the first (and only) row
rtc_time_str = row[1] # '2025-02-07 12:30:45'
except Exception as e:
debug_print(f"✗ Failed to get RTC time: {e}")
rtc_time_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
debug_print(f" Using system time instead: {rtc_time_str}")
# Fetch connected ENVEA sondes from SQLite config table # Fetch connected ENVEA sondes from SQLite config table
cursor.execute("SELECT port, name, coefficient FROM envea_sondes_table WHERE connected = 1") try:
connected_envea_sondes = cursor.fetchall() # List of tuples (port, name, coefficient) cursor.execute("SELECT port, name, coefficient FROM envea_sondes_table WHERE connected = 1")
#print(connected_envea_sondes) connected_envea_sondes = cursor.fetchall() # List of tuples (port, name, coefficient)
debug_print(f"✓ Found {len(connected_envea_sondes)} connected ENVEA sensors")
for port, name, coefficient in connected_envea_sondes:
debug_print(f" - {name}: port={port}, coefficient={coefficient}")
except Exception as e:
debug_print(f"✗ Failed to fetch connected sensors: {e}")
connected_envea_sondes = []
serial_connections = {} serial_connections = {}
if connected_envea_sondes: if connected_envea_sondes:
debug_print("\n--- Opening Serial Connections ---")
for port, name, coefficient in connected_envea_sondes: for port, name, coefficient in connected_envea_sondes:
try: try:
serial_connections[name] = serial.Serial( serial_connections[name] = serial.Serial(
@@ -47,10 +82,14 @@ if connected_envea_sondes:
bytesize=serial.EIGHTBITS, bytesize=serial.EIGHTBITS,
timeout=1 timeout=1
) )
debug_print(f"✓ Opened serial port for {name} on /dev/{port}")
except serial.SerialException as e: except serial.SerialException as e:
print(f"Error opening serial port for {name}: {e}") debug_print(f"Error opening serial port for {name}: {e}")
else:
debug_print("! No connected ENVEA sensors found in configuration")
global data_h2s, data_no2, data_o3 # Initialize sensor data variables
global data_h2s, data_no2, data_o3, data_co, data_nh3, data_so2
data_h2s = 0 data_h2s = 0
data_no2 = 0 data_no2 = 0
data_o3 = 0 data_o3 = 0
@@ -60,52 +99,84 @@ data_so2 = 0
try: try:
if connected_envea_sondes: if connected_envea_sondes:
debug_print("\n--- Reading Sensor Data ---")
for port, name, coefficient in connected_envea_sondes: for port, name, coefficient in connected_envea_sondes:
if name in serial_connections: if name in serial_connections:
serial_connection = serial_connections[name] serial_connection = serial_connections[name]
try: try:
serial_connection.write( debug_print(f"Reading from {name}...")
b"\xFF\x02\x13\x30\x01\x02\x03\x04\x05\x06\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x12\xAF\x88\x03"
) # Send command to sensor
command = b"\xFF\x02\x13\x30\x01\x02\x03\x04\x05\x06\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x12\xAF\x88\x03"
serial_connection.write(command)
debug_print(f" → Sent command: {command.hex()}")
# Read response
data_envea = serial_connection.readline() data_envea = serial_connection.readline()
debug_print(f" ← Received {len(data_envea)} bytes: {data_envea.hex()}")
if len(data_envea) >= 20: if len(data_envea) >= 20:
byte_20 = data_envea[19] * coefficient byte_20 = data_envea[19]
raw_value = byte_20
calculated_value = byte_20 * coefficient
debug_print(f" → Byte 20 value: {raw_value} (0x{raw_value:02X})")
debug_print(f" → Calculated value: {raw_value} × {coefficient} = {calculated_value}")
if name == "h2s": if name == "h2s":
data_h2s = byte_20 data_h2s = calculated_value
elif name == "no2": elif name == "no2":
data_no2 = byte_20 data_no2 = calculated_value
elif name == "o3": elif name == "o3":
data_o3 = byte_20 data_o3 = calculated_value
elif name == "co": elif name == "co":
data_co = byte_20 data_co = calculated_value
elif name == "nh3": elif name == "nh3":
data_nh3 = byte_20 data_nh3 = calculated_value
elif name == "so2": elif name == "so2":
data_so2 = byte_20 data_so2 = calculated_value
debug_print(f"{name.upper()} = {calculated_value}")
else:
debug_print(f" ✗ Response too short (expected ≥20 bytes)")
except serial.SerialException as e: except serial.SerialException as e:
print(f"Error communicating with {name}: {e}") debug_print(f"Error communicating with {name}: {e}")
else:
debug_print(f"! No serial connection available for {name}")
except Exception as e: except Exception as e:
print("An error occurred while gathering data:", e) debug_print(f"\nAn error occurred while gathering data: {e}")
traceback.print_exc() traceback.print_exc()
# Display all collected data
debug_print(f"\n--- Collected Sensor Data ---")
debug_print(f"H2S: {data_h2s} ppb")
debug_print(f"NO2: {data_no2} ppb")
debug_print(f"O3: {data_o3} ppb")
debug_print(f"CO: {data_co} ppb")
debug_print(f"NH3: {data_nh3} ppb")
debug_print(f"SO2: {data_so2} ppb")
#print(f" H2S: {data_h2s}, NO2: {data_no2}, O3: {data_o3}, CO : {data_co}, nh3: {data_nh3}, so2: {data_so2} ") # Save to sqlite database
#save to sqlite database
try: try:
cursor.execute(''' cursor.execute('''
INSERT INTO data_envea (timestamp,h2s, no2, o3, co, nh3, so2) VALUES (?,?,?,?,?,?,?)''' INSERT INTO data_envea (timestamp, h2s, no2, o3, co, nh3, so2) VALUES (?,?,?,?,?,?,?)'''
, (rtc_time_str,data_h2s,data_no2,data_o3,data_co,data_nh3,data_so2)) , (rtc_time_str, data_h2s, data_no2, data_o3, data_co, data_nh3, data_so2))
# Commit and close the connection # Commit and close the connection
conn.commit() conn.commit()
#print("Sensor data saved successfully!")
except Exception as e: except Exception as e:
print(f"Database error: {e}") debug_print(f"Database error: {e}")
traceback.print_exc()
# Close serial connections
if serial_connections:
for name, connection in serial_connections.items():
try:
connection.close()
except:
pass
conn.close() conn.close()
debug_print("\n=== ENVEA Sensor Reader Finished ===\n")

View File

@@ -28,7 +28,7 @@ CSV PAYLOAD (AirCarto Servers)
ATTENTION : do not change order ! ATTENTION : do not change order !
CSV size: 18 CSV size: 18
{PM1},{PM25},{PM10},{temp},{hum},{press},{avg_noise},{max_noise},{min_noise},{envea_no2},{envea_h2s},{envea_o3},{4g_signal_quality} {PM1},{PM25},{PM10},{temp},{hum},{press},{avg_noise},{max_noise},{min_noise},{envea_no2},{envea_h2s},{envea_nh3},{4g_signal_quality}
0 -> PM1 (μg/m3) 0 -> PM1 (μg/m3)
1 -> PM25 (μg/m3) 1 -> PM25 (μg/m3)
2 -> PM10 (μg/m3) 2 -> PM10 (μg/m3)
@@ -56,6 +56,8 @@ CSV PAYLOAD (AirCarto Servers)
24 -> charger_status 24 -> charger_status
25 -> Wind speed 25 -> Wind speed
26 -> Wind direction 26 -> Wind direction
27 -> envea_CO
28 -> envea_O3
CSV FOR UDP (miotiq) CSV FOR UDP (miotiq)
{device_id},{timestamp},{PM1},{PM25},{PM10},{temp},{hum},{press},{avg_noise},{max_noise},{min_noise},{envea_no2},{envea_h2s},{envea_o3},{4g_signal_quality} {device_id},{timestamp},{PM1},{PM25},{PM10},{temp},{hum},{press},{avg_noise},{max_noise},{min_noise},{envea_no2},{envea_h2s},{envea_o3},{4g_signal_quality}
@@ -138,6 +140,7 @@ if uptime_seconds < 120:
payload_csv = [None] * 30 payload_csv = [None] * 30
#Payload UPD to be sent to miotiq #Payload UPD to be sent to miotiq
payload_udp = [None] * 30 payload_udp = [None] * 30
#Payload JSON to be sent to uSpot #Payload JSON to be sent to uSpot
payload_json = { payload_json = {
"nebuleairid": "XXX", "nebuleairid": "XXX",
@@ -743,6 +746,8 @@ try:
payload_csv[9] = averages[0] # envea_no2 payload_csv[9] = averages[0] # envea_no2
payload_csv[10] = averages[1] # envea_h2s payload_csv[10] = averages[1] # envea_h2s
payload_csv[11] = averages[2] # envea_nh3 payload_csv[11] = averages[2] # envea_nh3
payload_csv[27] = averages[3] # envea_CO
payload_csv[28] = averages[4] # envea_O3
#Add data to payload JSON #Add data to payload JSON
payload_json["sensordatavalues"].append({"value_type": "CAIRSENS_NO2", "value": str(averages[0])}) payload_json["sensordatavalues"].append({"value_type": "CAIRSENS_NO2", "value": str(averages[0])})