This commit is contained in:
Your Name
2025-01-29 10:04:01 +01:00
parent d095e53cd6
commit 4a5e0b3577
9 changed files with 179 additions and 7 deletions

2
.gitignore vendored
View File

@@ -9,4 +9,6 @@ config.json
sound_meter/moving_avg_minute.txt sound_meter/moving_avg_minute.txt
wifi_list.csv wifi_list.csv
envea/data/*.txt envea/data/*.txt
NPM/data/*.txt
NPM/data/*.json
*.lock *.lock

0
NPM/firmware_version.py Normal file → Executable file
View File

2
NPM/get_data_modbus.py Normal file → Executable file
View File

@@ -14,7 +14,7 @@ Request
\x01 Slave Address (slave device address) \x01 Slave Address (slave device address)
\x03 Function code (read multiple holding registers) \x03 Function code (read multiple holding registers)
\x00\x80 Starting Address (The request starts reading from holding register address 0x80 or 128) \x00\x80 Starting Address (The request starts reading from holding register address 0x80 or 128)
\x00\x0A Quantity of Registers (Requests to read 0x0A or 10 consecutive registers starting from address 50) \x00\x0A Quantity of Registers (Requests to read 0x0A or 10 consecutive registers starting from address 128)
\xE4\x1E Cyclic Redundancy Check (checksum ) \xE4\x1E Cyclic Redundancy Check (checksum )
''' '''

122
NPM/get_data_modbus_loop.py Normal file
View File

@@ -0,0 +1,122 @@
'''
Loop to run every minutes
* * * * * /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_modbus_loop.py
saves data to a json file /var/www/nebuleair_pro_4g/NPM/data/data.json
'''
import serial
import sys
import crcmod
import time
import json
import os
# Ensure a port argument is provided
if len(sys.argv) < 2:
print("Usage: python3 get_data_modbus.py <serial_port>")
sys.exit(1)
port = '/dev/' + sys.argv[1]
# Initialize serial communication
try:
ser = serial.Serial(
port=port,
baudrate=115200,
parity=serial.PARITY_EVEN,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=0.5
)
except Exception as e:
print(f"Error opening serial port {port}: {e}")
sys.exit(1)
# Define Modbus CRC-16 function
crc16 = crcmod.predefined.mkPredefinedCrcFun('modbus')
# Request frame without CRC
data = b'\x01\x03\x00\x80\x00\x0A'
# Calculate CRC
crc = crc16(data)
crc_low = crc & 0xFF
crc_high = (crc >> 8) & 0xFF
# Append CRC to the frame
request = data + bytes([crc_low, crc_high])
# Log request frame
print(f"Request frame: {request.hex()}")
# Initialize storage for averaging
num_samples = 6
channel_sums = [0] * 5 # 5 channels
# Loop 6 times to collect data every 10 seconds
for i in range(num_samples):
print(f"\nIteration {i+1}/{num_samples}")
ser.write(request)
try:
byte_data = ser.readline()
formatted = ''.join(f'\\x{byte:02x}' for byte in byte_data)
print(f"Raw Response: {formatted}")
if len(byte_data) < 23:
print("Incomplete response, skipping this sample.")
time.sleep(10)
continue
# Extract and process the 5 channels
channels = []
for j in range(5):
lsw = int.from_bytes(byte_data[3 + j*4 : 5 + j*4], byteorder='little')
msw = int.from_bytes(byte_data[5 + j*4 : 7 + j*4], byteorder='little')
raw_value = (msw << 16) | lsw
channels.append(raw_value)
# Accumulate sum for each channel
for j in range(5):
channel_sums[j] += channels[j]
# Print collected values
for j in range(5):
print(f"Channel {j+1}: {channels[j]}")
except Exception as e:
print(f"Error reading data: {e}")
# Wait 10 seconds before next reading
time.sleep(10)
# Compute the average values
channel_means = [int(s / num_samples) for s in channel_sums]
# Create JSON structure
data_json = {
"channel_1": channel_means[0],
"channel_2": channel_means[1],
"channel_3": channel_means[2],
"channel_4": channel_means[3],
"channel_5": channel_means[4]
}
# Print final JSON data
print("\nFinal JSON Data (Averaged over 6 readings):")
print(json.dumps(data_json, indent=4))
# Define JSON file path
output_file = "/var/www/nebuleair_pro_4g/NPM/data/data.json"
# Write results to a JSON file
try:
with open(output_file, "w") as f:
json.dump(data_json, f, indent=4)
print(f"\nAveraged JSON data saved to {output_file}")
except Exception as e:
print(f"Error writing to file: {e}")
# Close serial connection
ser.close()

0
SARA/SSL/test_22.py Normal file → Executable file
View File

0
SARA/SSL/test_33.py Normal file → Executable file
View File

View File

@@ -8,6 +8,7 @@
"NextPM_ports": [ "NextPM_ports": [
"ttyAMA5" "ttyAMA5"
], ],
"NextPM_5channels": false,
"i2C_sound": false, "i2C_sound": false,
"i2c_BME": false, "i2c_BME": false,
"sshTunnel_port": 59228, "sshTunnel_port": 59228,

View File

@@ -1,6 +1,8 @@
""" """
Main loop to gather data from envea Sensors Main loop to gather data from envea Sensors
/usr/bin/python3 /var/www/nebuleair_pro_4g/envea/read_value_loop.py /usr/bin/python3 /var/www/nebuleair_pro_4g/envea/read_value_loop.py
Save data to .txt file inside /var/www/nebuleair_pro_4g/envea/data/
""" """
import json import json
import serial import serial

View File

@@ -12,10 +12,11 @@ CSV PAYLOAD (AirCarto Servers)
/pro_4G/data.php?sensor_id={device_id} /pro_4G/data.php?sensor_id={device_id}
ATTENTION : do not change order ! ATTENTION : do not change order !
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_o3},{4g_signal_quality}
0 -> PM1 0 -> PM1 (μg/m3)
1 -> PM25 1 -> PM25 (μg/m3)
2 -> PM10 2 -> PM10 (μg/m3)
3 -> temp 3 -> temp
4 -> hum 4 -> hum
5 -> press 5 -> press
@@ -25,7 +26,12 @@ CSV PAYLOAD (AirCarto Servers)
9 -> envea_no2 9 -> envea_no2
10 -> envea_h2s 10 -> envea_h2s
11 -> envea_o3 11 -> envea_o3
12 -> 4G signal quality 12 -> 4G signal quality,
13 -> PM 0.2μm to 0.5μm quantity (Nb/L)
14 -> PM 0.5μm to 1.0μm quantity (Nb/L)
15 -> PM 1.0μm to 2.5μm quantity (Nb/L)
16 -> PM 2.5μm to 5.0μm quantity (Nb/L)
17 -> PM 5.0μm to 10μm quantity (Nb/L)
JSON PAYLOAD (Micro-Spot Servers) JSON PAYLOAD (Micro-Spot Servers)
Same as NebuleAir wifi Same as NebuleAir wifi
@@ -178,6 +184,7 @@ bme_280_config = config.get('i2c_BME', False) #présence du BME280
i2C_sound_config = config.get('i2C_sound', False) #présence du capteur son i2C_sound_config = config.get('i2C_sound', False) #présence du capteur son
send_aircarto = config.get('send_aircarto', True) #envoi sur AirCarto (data.nebuleair.fr) send_aircarto = config.get('send_aircarto', True) #envoi sur AirCarto (data.nebuleair.fr)
send_uSpot = config.get('send_uSpot', False) #envoi sur MicroSpot () send_uSpot = config.get('send_uSpot', False) #envoi sur MicroSpot ()
npm_5channel = config.get('NextPM_5channels', False) #5 canaux du NPM
envea_sondes = config.get('envea_sondes', []) envea_sondes = config.get('envea_sondes', [])
connected_envea_sondes = [sonde for sonde in envea_sondes if sonde.get('connected', False)] connected_envea_sondes = [sonde for sonde in envea_sondes if sonde.get('connected', False)]
@@ -307,6 +314,44 @@ try:
payload_json["sensordatavalues"].append({"value_type": "BME280_humidity", "value": f"{round(bme280.humidity, 2)}"}) payload_json["sensordatavalues"].append({"value_type": "BME280_humidity", "value": f"{round(bme280.humidity, 2)}"})
payload_json["sensordatavalues"].append({"value_type": "BME280_pressure", "value": f"{round(bme280.pressure, 2)}"}) payload_json["sensordatavalues"].append({"value_type": "BME280_pressure", "value": f"{round(bme280.pressure, 2)}"})
# NPM sur 5 cannaux
if npm_5channel:
print("Getting NPM 5 Channels")
# Define the path to the JSON file
json_file_path_npm = "/var/www/nebuleair_pro_4g/NPM/data/data.json"
# Read the JSON file
try:
with open(json_file_path_npm, "r") as file:
data = json.load(file) # Load JSON into a dictionary
# Extract values
channel_1 = data.get("channel_1", 0)
channel_2 = data.get("channel_2", 0)
channel_3 = data.get("channel_3", 0)
channel_4 = data.get("channel_4", 0)
channel_5 = data.get("channel_5", 0)
# Print extracted values
print(f"Channel 1: {channel_1}")
print(f"Channel 2: {channel_2}")
print(f"Channel 3: {channel_3}")
print(f"Channel 4: {channel_4}")
print(f"Channel 5: {channel_5}")
#add to CSV
payload_csv[13] = channel_1
payload_csv[14] = channel_2
payload_csv[15] = channel_3
payload_csv[16] = channel_4
payload_csv[17] = channel_5
except FileNotFoundError:
print(f"Error: JSON file not found at {json_file_path_npm}")
except json.JSONDecodeError:
print("Error: JSON file is not formatted correctly")
except Exception as e:
print(f"Unexpected error: {e}")
# Sonde Bruit connected # Sonde Bruit connected
if i2C_sound_config: if i2C_sound_config:
@@ -324,7 +369,7 @@ try:
payload_csv[8] = min_noise payload_csv[8] = min_noise
except FileNotFoundError: except FileNotFoundError:
print(f"Error: File {file_path} not found.") print(f"Error: File {file_path_data_noise} not found.")
except ValueError: except ValueError:
print("Error: File content is not valid numbers.") print("Error: File content is not valid numbers.")