update
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
try:
|
||||||
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db")
|
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db")
|
||||||
cursor = conn.cursor()
|
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
|
||||||
|
try:
|
||||||
cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
|
cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
|
||||||
row = cursor.fetchone() # Get the first (and only) row
|
row = cursor.fetchone() # Get the first (and only) row
|
||||||
rtc_time_str = row[1] # '2025-02-07 12:30:45'
|
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
|
||||||
|
try:
|
||||||
cursor.execute("SELECT port, name, coefficient FROM envea_sondes_table WHERE connected = 1")
|
cursor.execute("SELECT port, name, coefficient FROM envea_sondes_table WHERE connected = 1")
|
||||||
connected_envea_sondes = cursor.fetchall() # List of tuples (port, name, coefficient)
|
connected_envea_sondes = cursor.fetchall() # List of tuples (port, name, coefficient)
|
||||||
#print(connected_envea_sondes)
|
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,38 +99,65 @@ 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"\n✗ An 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 (?,?,?,?,?,?,?)'''
|
||||||
@@ -100,12 +166,17 @@ try:
|
|||||||
# 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")
|
||||||
|
|
||||||
@@ -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])})
|
||||||
|
|||||||
Reference in New Issue
Block a user