update
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
0
NPM/firmware_version.py
Normal file → Executable file
2
NPM/get_data_modbus.py
Normal file → Executable file
2
NPM/get_data_modbus.py
Normal file → Executable 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
122
NPM/get_data_modbus_loop.py
Normal 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
0
SARA/SSL/test_22.py
Normal file → Executable file
0
SARA/SSL/test_33.py
Normal file → Executable file
0
SARA/SSL/test_33.py
Normal file → Executable 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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user