From 1cb1b05b511a47105984f24acfc33ae355bf3875 Mon Sep 17 00:00:00 2001 From: PaulVua Date: Mon, 10 Feb 2025 10:06:16 +0100 Subject: [PATCH] update --- BME280/get_data_v2.py | 41 +++++++++++++++++--- NPM/get_data_v2.py | 39 +++---------------- README.md | 2 +- RTC/save_to_db.py | 90 +++++++++++++++++++++++++++++++++++++++++++ config.json.dist | 6 +-- html/index.html | 34 +++++++++++----- html/launcher.php | 34 ++++++++-------- master.py | 7 ++-- sqlite/create_db.py | 20 ++++++++-- sqlite/read.py | 4 +- 10 files changed, 200 insertions(+), 77 deletions(-) create mode 100644 RTC/save_to_db.py diff --git a/BME280/get_data_v2.py b/BME280/get_data_v2.py index 33c3331..132bb96 100644 --- a/BME280/get_data_v2.py +++ b/BME280/get_data_v2.py @@ -15,9 +15,13 @@ sudo python3 /var/www/nebuleair_pro_4g/BME280/get_data_v2.py import board import busio import json - +import sqlite3 from adafruit_bme280 import basic as adafruit_bme280 +# Connect to the SQLite database +conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") +cursor = conn.cursor() + # Create I2C bus i2c = busio.I2C(board.SCL, board.SDA) bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x76) @@ -32,12 +36,39 @@ bme280.sea_level_pressure = 1013.25 # Update this value for your location #print(f"Pressure: {bme280.pressure:.2f} hPa") #print(f"Altitude: {bme280.altitude:.2f} m") +temperature = round(bme280.temperature, 2) +humidity = round(bme280.humidity, 2) +pressure = round(bme280.pressure, 2) + sensor_data = { - "temp": round(bme280.temperature, 2), # Temperature in °C - "hum": round(bme280.humidity, 2), # Humidity in % - "press": round(bme280.pressure, 2), # Pressure in hPa + "temp": temperature, # Temperature in °C + "hum": humidity, # Humidity in % + "press": pressure # Pressure in hPa } +#GET RTC TIME from SQlite +cursor.execute("SELECT * FROM timestamp_table LIMIT 1") +row = cursor.fetchone() # Get the first (and only) row +rtc_time_str = row[1] # '2025-02-07 12:30:45' + # Convert to JSON and print -print(json.dumps(sensor_data, indent=4)) \ No newline at end of file +#print(json.dumps(sensor_data, indent=4)) + + +#save to sqlite database +try: + cursor.execute(''' + INSERT INTO data_BME280 (timestamp,temperature, humidity, pressure) VALUES (?,?,?,?)''' + , (rtc_time_str,temperature,humidity,pressure)) + + # Commit and close the connection + conn.commit() + + #print("Sensor data saved successfully!") + +except Exception as e: + print(f"Database error: {e}") + + +conn.close() \ No newline at end of file diff --git a/NPM/get_data_v2.py b/NPM/get_data_v2.py index 577362f..4609ce8 100644 --- a/NPM/get_data_v2.py +++ b/NPM/get_data_v2.py @@ -8,7 +8,7 @@ Script to get NPM values PM and the sensor temp/hum And store them inside sqlite database -Uses RTC module for timing +Uses RTC module for timing (from SQLite db) /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_v2.py ''' @@ -25,27 +25,6 @@ from datetime import datetime conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") cursor = conn.cursor() -#RTC module -DS3231_ADDR = 0x68 -REG_TIME = 0x00 - -def bcd_to_dec(bcd): - return (bcd // 16 * 10) + (bcd % 16) - -def read_time(bus): - """Try to read and decode time from the RTC module (DS3231).""" - try: - data = bus.read_i2c_block_data(DS3231_ADDR, REG_TIME, 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) - except OSError: - return None # RTC module not connected - def load_config(config_file): try: with open(config_file, 'r') as file: @@ -96,19 +75,11 @@ humidity = int.from_bytes(byte_data_temp_hum[5:7], byteorder='big') / 100.0 #print(f"PM10: {PM10}") #print(f"temp: {temperature}") #print(f"hum: {humidity}") -#GET RTC TIME -# Read RTC time -bus = smbus2.SMBus(1) -# Try to read RTC time -rtc_time = read_time(bus) - -if rtc_time: - rtc_time_str = rtc_time.strftime('%Y-%m-%d %H:%M:%S') - #print(rtc_time_str) -else: - print("Error! RTC module not connected") - rtc_time_str = "1970-01-01 00:00:00" # Default fallback time +#GET RTC TIME from SQlite +cursor.execute("SELECT * FROM timestamp_table LIMIT 1") +row = cursor.fetchone() # Get the first (and only) row +rtc_time_str = row[1] # '2025-02-07 12:30:45' #save to sqlite database try: diff --git a/README.md b/README.md index ab69621..8b672c4 100755 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ To make things simpler we will allow all users to use "nmcli" as sudo without en ALL ALL=(ALL) NOPASSWD: /usr/bin/nmcli, /usr/sbin/reboot www-data ALL=(ALL) NOPASSWD: /usr/bin/git pull www-data ALL=(ALL) NOPASSWD: /usr/bin/ssh - +www-data ALL=(ALL) NOPASSWD: /usr/bin/python3 * ``` ## Serial diff --git a/RTC/save_to_db.py b/RTC/save_to_db.py new file mode 100644 index 0000000..77a6968 --- /dev/null +++ b/RTC/save_to_db.py @@ -0,0 +1,90 @@ +''' + ____ _____ ____ + | _ \_ _/ ___| + | |_) || || | + | _ < | || |___ + |_| \_\|_| \____| + +Script to read time from RTC module and save it to DB +I2C connection +Address 0x68 +/usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/save_to_db.py +''' +import smbus2 +import time +import json +from datetime import datetime +import sqlite3 + +# Connect to (or create if not existent) the database +conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") +cursor = conn.cursor() + +# DS3231 I2C address +DS3231_ADDR = 0x68 + +# Registers for DS3231 +REG_TIME = 0x00 + +def bcd_to_dec(bcd): + return (bcd // 16 * 10) + (bcd % 16) + +def read_time(bus): + """Try to read and decode time from the RTC module (DS3231).""" + try: + data = bus.read_i2c_block_data(DS3231_ADDR, REG_TIME, 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) + except OSError: + return None # RTC module not connected + +def main(): + # Read RTC time + bus = smbus2.SMBus(1) + # Try to read RTC time + rtc_time = read_time(bus) + + # Get current system time + system_time = datetime.now() #local + utc_time = datetime.utcnow() #UTC + + # If RTC is not connected, set default message + # Calculate time difference (in seconds) if RTC is connected + if rtc_time: + rtc_time_str = rtc_time.strftime('%Y-%m-%d %H:%M:%S') + time_difference = int((utc_time - rtc_time).total_seconds()) # Convert to int + else: + rtc_time_str = "not connected" + time_difference = "N/A" # Not applicable + + # Print both times + #print(f"RTC module Time: {rtc_time.strftime('%Y-%m-%d %H:%M:%S')}") + #print(f"Sys local Time: {system_time.strftime('%Y-%m-%d %H:%M:%S')}") + #print(f"Sys UTC Time: {utc_time.strftime('%Y-%m-%d %H:%M:%S')}") + + # Create JSON output + time_data = { + "rtc_module_time":rtc_time_str, + "system_local_time": system_time.strftime('%Y-%m-%d %H:%M:%S'), + "system_utc_time": utc_time.strftime('%Y-%m-%d %H:%M:%S'), + "time_difference_seconds": time_difference + } + + #print(json.dumps(time_data, indent=4)) + + cursor.execute("UPDATE timestamp_table SET last_updated = ? WHERE id = 1", (rtc_time_str,)) + + # Commit and close the connection + conn.commit() + conn.close() + + #print("Sensor data saved successfully!") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/config.json.dist b/config.json.dist index 6b32a88..150b131 100755 --- a/config.json.dist +++ b/config.json.dist @@ -2,9 +2,9 @@ "loop_activation": true, "loop_log": true, "boot_log": true, - "NPM/get_data.py": true, - "tests/script2.py": false, - "tests/script3.py": true, + "NPM/get_data_v2.py": true, + "loop/SARA_send_data_v2.py": true, + "RTC/save_to_db.py": true, "deviceID": "XXXX", "deviceName": "NebuleAir-proXXX", "SaraR4_baudrate": 115200, diff --git a/html/index.html b/html/index.html index 581b30d..4637062 100755 --- a/html/index.html +++ b/html/index.html @@ -53,10 +53,21 @@

Votre capteur

Bienvenue sur votre interface de configuration de votre capteur.

+
- -
+ +
+
+
+
Mesures PM
+ +
+
+
+ + +
Linux stats
@@ -69,19 +80,24 @@
- -
+ + +
+ +
+ + +
-
Mesures PM
- +
Mesures Temperature
+
+
- -
@@ -292,7 +308,7 @@ window.onload = function() { } }); - let chart; // Store the Chart.js instance globally + let chart; // Store the Chart.js instance globally function updatePMChart(data) { const labels = data.map(d => d.timestamp); diff --git a/html/launcher.php b/html/launcher.php index 7d07375..b4db751 100755 --- a/html/launcher.php +++ b/html/launcher.php @@ -45,7 +45,7 @@ if ($type == "update_config") { } if ($type == "getModem_busy") { - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/check_running.py'; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/check_running.py'; $output = shell_exec($command); echo $output; } @@ -56,7 +56,7 @@ if ($type == "RTC_time") { } if ($type == "sys_RTC_module_time") { - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/read.py'; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/read.py'; $output = shell_exec($command); echo $output; } @@ -68,7 +68,7 @@ if ($type == "git_pull") { } if ($type == "set_RTC_withNTP") { - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/set_with_NTP.py'; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/set_with_NTP.py'; $output = shell_exec($command); echo $output; } @@ -84,7 +84,7 @@ if ($type == "set_RTC_withBrowser") { $rtc_time = date('Y-m-d H:i:s', strtotime($time)); // Execute Python script to update the RTC - $command = escapeshellcmd("/usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/set_with_browserTime.py '$rtc_time'"); + $command = escapeshellcmd("sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/set_with_browserTime.py '$rtc_time'"); $output = shell_exec($command); if ($output === null) { echo json_encode(['success' => false, 'message' => 'Failed to update RTC']); @@ -177,7 +177,7 @@ if ($type == "reboot") { if ($type == "npm") { $port=$_GET['port']; - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data.py ' . $port; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data.py ' . $port; $output = shell_exec($command); echo $output; } @@ -185,7 +185,7 @@ if ($type == "npm") { if ($type == "envea") { $port=$_GET['port']; $name=$_GET['name']; - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/envea/read_value.py ' . $port; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/envea/read_value.py ' . $port; $output = shell_exec($command); echo $output; } @@ -197,7 +197,7 @@ if ($type == "noise") { } if ($type == "BME280") { - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/BME280/read.py'; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/BME280/read.py'; $output = shell_exec($command); echo $output; } @@ -208,7 +208,7 @@ if ($type == "sara") { $sara_command=$_GET['command']; $sara_command = escapeshellcmd($sara_command); $timeout=$_GET['timeout']; - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara.py ' . $port . ' ' . $sara_command . ' ' . $timeout; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara.py ' . $port . ' ' . $sara_command . ' ' . $timeout; $output = shell_exec($command); echo $output; } @@ -227,7 +227,7 @@ if ($type == "sara_getMQTT_login_logout") { $port=$_GET['port']; $timeout=$_GET['timeout']; $login_logout=$_GET['login_logout']; - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/MQTT/login_logout.py ' . $port . ' ' . $login_logout . ' ' . $timeout; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/MQTT/login_logout.py ' . $port . ' ' . $login_logout . ' ' . $timeout; $output = shell_exec($command); echo $output; } @@ -237,7 +237,7 @@ if ($type == "sara_MQTT_publish") { $port=$_GET['port']; $timeout=$_GET['timeout']; $message=$_GET['message']; - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/MQTT/publish.py ' . $port . ' ' . $message . ' ' . $timeout; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/MQTT/publish.py ' . $port . ' ' . $message . ' ' . $timeout; $output = shell_exec($command); echo $output; } @@ -247,7 +247,7 @@ if ($type == "sara_connectNetwork") { $port=$_GET['port']; $timeout=$_GET['timeout']; $networkID=$_GET['networkID']; - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_connectNetwork.py ' . $port . ' ' . $networkID . ' ' . $timeout; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_connectNetwork.py ' . $port . ' ' . $networkID . ' ' . $timeout; $output = shell_exec($command); echo $output; #save to config.json @@ -283,7 +283,7 @@ if ($type == "sara_setURL") { $port=$_GET['port']; $url=$_GET['url']; $profile_id = 2; - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setURL.py ' . $port . ' ' . $url . ' ' . $profile_id; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setURL.py ' . $port . ' ' . $url . ' ' . $profile_id; $output = shell_exec($command); echo $output; } @@ -293,7 +293,7 @@ if ($type == "sara_APN") { $port=$_GET['port']; $timeout=$_GET['timeout']; $APN_address=$_GET['APN_address']; - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setAPN.py ' . $port . ' ' . $APN_address . ' ' . $timeout; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setAPN.py ' . $port . ' ' . $APN_address . ' ' . $timeout; $output = shell_exec($command); echo $output; } @@ -306,15 +306,15 @@ if ($type == "sara_writeMessage") { $type2=$_GET['type2']; if ($type2 === "write") { - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_writeMessage.py ' . $port . ' ' . $message; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_writeMessage.py ' . $port . ' ' . $message; $output = shell_exec($command); } if ($type2 === "read") { - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_readMessage.py ' . $port . ' ' . $message; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_readMessage.py ' . $port . ' ' . $message; $output = shell_exec($command); } if ($type2 === "erase") { - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_eraseMessage.py ' . $port . ' ' . $message; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_eraseMessage.py ' . $port . ' ' . $message; $output = shell_exec($command); } @@ -327,7 +327,7 @@ if ($type == "sara_sendMessage") { $endpoint=$_GET['endpoint']; $endpoint = escapeshellcmd($endpoint); $profile_id = 2; - $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_sendMessage.py ' . $port . ' ' . $endpoint. ' ' . $profile_id; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_sendMessage.py ' . $port . ' ' . $endpoint. ' ' . $profile_id; $output = shell_exec($command); echo $output; } diff --git a/master.py b/master.py index b965208..805995b 100644 --- a/master.py +++ b/master.py @@ -75,9 +75,10 @@ def run_script(script_name, interval): # Define scripts and their execution intervals (seconds) SCRIPTS = [ - ("NPM/get_data_v2.py", 60), # Get NPM data every 60s - ("loop/SARA_send_data_v2.py", 60), # Runs every 60 seconds - ("tests/script3.py", 10), # Runs every 10 seconds + ("NPM/get_data_v2.py", 60), # Get NPM data every 60s + ("loop/SARA_send_data_v2.py", 60), # Send data every 60 seconds + ("RTC/save_to_db.py", 1), # SAVE RTC time every 1 second + ("BME280/get_data_v2.py", 120) # Get BME280 data every 120 seconds ] # Start threads for enabled scripts diff --git a/sqlite/create_db.py b/sqlite/create_db.py index 01a5c09..8a11d08 100755 --- a/sqlite/create_db.py +++ b/sqlite/create_db.py @@ -15,7 +15,19 @@ import sqlite3 conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") cursor = conn.cursor() -# Create a table 1 +# Create a table timer +cursor.execute(""" +CREATE TABLE IF NOT EXISTS timestamp_table ( + id INTEGER PRIMARY KEY CHECK (id = 1), -- Enforce single row by using fixed ID + last_updated DATETIME NOT NULL +) +""") +cursor.execute(""" + INSERT INTO timestamp_table (id, last_updated) VALUES (1, CURRENT_TIMESTAMP); +""") + + +# Create a table NPM cursor.execute(""" CREATE TABLE IF NOT EXISTS data_NPM ( timestamp TEXT, @@ -27,7 +39,7 @@ CREATE TABLE IF NOT EXISTS data_NPM ( ) """) -# Create a table 2 +# Create a table BME280 cursor.execute(""" CREATE TABLE IF NOT EXISTS data_BME280 ( timestamp TEXT, @@ -37,7 +49,7 @@ CREATE TABLE IF NOT EXISTS data_BME280 ( ) """) -# Create a table 3 +# Create a table cairsens cursor.execute(""" CREATE TABLE IF NOT EXISTS data_envea ( timestamp TEXT, @@ -49,7 +61,7 @@ CREATE TABLE IF NOT EXISTS data_envea ( ) """) -# Create a table 4 +# Create a table NPM_5ch cursor.execute(""" CREATE TABLE IF NOT EXISTS data_NPM_5channels ( timestamp TEXT, diff --git a/sqlite/read.py b/sqlite/read.py index ba8f5ec..94039ce 100755 --- a/sqlite/read.py +++ b/sqlite/read.py @@ -17,7 +17,9 @@ conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") cursor = conn.cursor() # Retrieve the last 10 sensor readings -cursor.execute("SELECT * FROM data_NPM ORDER BY timestamp DESC LIMIT 10") +#cursor.execute("SELECT * FROM data_NPM ORDER BY timestamp DESC LIMIT 10") +cursor.execute("SELECT * FROM data_BME280 ORDER BY timestamp DESC LIMIT 10") +#cursor.execute("SELECT * FROM timestamp_table") rows = cursor.fetchall() rows.reverse() # Reverse the order in Python (to get ascending order)