update
This commit is contained in:
172
NPM/old/get_data_modbus_loop.py
Normal file
172
NPM/old/get_data_modbus_loop.py
Normal file
@@ -0,0 +1,172 @@
|
||||
'''
|
||||
Loop to run every minutes
|
||||
|
||||
* * * * * /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_modbus_loop.py ttyAMA5
|
||||
|
||||
saves data (avaerage) to a json file /var/www/nebuleair_pro_4g/NPM/data/data.json
|
||||
saves data (all) to a sqlite database
|
||||
|
||||
first time running the script?
|
||||
sudo mkdir /var/www/nebuleair_pro_4g/NPM/data
|
||||
sudo touch /var/www/nebuleair_pro_4g/NPM/data/data.json
|
||||
'''
|
||||
|
||||
import serial
|
||||
import sys
|
||||
import crcmod
|
||||
import time
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
import smbus2 # For RTC DS3231
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
# 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 SQLite database
|
||||
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db")
|
||||
cursor = conn.cursor()
|
||||
|
||||
# RTC Module (DS3231) Setup
|
||||
RTC_I2C_ADDR = 0x68 # DS3231 I2C Address
|
||||
bus = smbus2.SMBus(1)
|
||||
|
||||
def bcd_to_dec(bcd):
|
||||
return (bcd // 16 * 10) + (bcd % 16)
|
||||
|
||||
def get_rtc_time():
|
||||
"""Reads time from RTC module (DS3231)"""
|
||||
try:
|
||||
data = bus.read_i2c_block_data(RTC_I2C_ADDR, 0x00, 7)
|
||||
seconds = bcd_to_dec(data[0] & 0x7F)
|
||||
minutes = bcd_to_dec(data[1])
|
||||
hours = bcd_to_dec(data[2] & 0x3F)
|
||||
day = bcd_to_dec(data[4])
|
||||
month = bcd_to_dec(data[5])
|
||||
year = bcd_to_dec(data[6]) + 2000
|
||||
return datetime(year, month, day, hours, minutes, seconds).strftime("%Y-%m-%d %H:%M:%S")
|
||||
except Exception as e:
|
||||
print(f"RTC Read Error: {e}")
|
||||
return "N/A"
|
||||
|
||||
# Initialize storage for averaging
|
||||
num_samples = 6
|
||||
channel_sums = [0] * 5 # 5 channels
|
||||
|
||||
#do not start immediately to prevent multiple write/read over NPM serial port
|
||||
time.sleep(3)
|
||||
|
||||
# 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)
|
||||
rtc_timestamp = get_rtc_time()
|
||||
|
||||
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(9)
|
||||
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
|
||||
print(f"Timestamp (RTC): {rtc_timestamp}")
|
||||
for j in range(5):
|
||||
print(f"Channel {j+1}: {channels[j]}")
|
||||
|
||||
|
||||
# Save the individual reading to the database
|
||||
cursor.execute('''
|
||||
INSERT INTO data (timestamp, PM_ch1, PM_ch2, PM_ch3, PM_ch4, PM_ch5)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
''', (rtc_timestamp, channels[0], channels[1], channels[2], channels[3], channels[4]))
|
||||
|
||||
conn.commit()
|
||||
|
||||
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()
|
||||
Reference in New Issue
Block a user