From d98eb48535e3a1d3dd76ec20a9461ffce1282f0e Mon Sep 17 00:00:00 2001 From: PaulVua Date: Wed, 5 Feb 2025 17:37:27 +0100 Subject: [PATCH] update --- BME280/get_data_v2.py | 43 +++++++++ NPM/get_data_v2.py | 118 +++++++++++------------ html/launcher.php | 2 +- loop/SARA_send_data_v2.py | 190 +++++++++++++++++++++++++++++++++++++- sqlite/read.py | 2 +- 5 files changed, 284 insertions(+), 71 deletions(-) create mode 100644 BME280/get_data_v2.py diff --git a/BME280/get_data_v2.py b/BME280/get_data_v2.py new file mode 100644 index 0000000..33c3331 --- /dev/null +++ b/BME280/get_data_v2.py @@ -0,0 +1,43 @@ +''' + ____ __ __ _____ ____ ___ ___ + | __ )| \/ | ____|___ \( _ ) / _ \ + | _ \| |\/| | _| __) / _ \| | | | + | |_) | | | | |___ / __/ (_) | |_| | + |____/|_| |_|_____|_____\___/ \___/ + +Script to read data from BME280 +Sensor connected to i2c on address 76 (use sudo i2cdetect -y 1 to get the address ) +-> save data to database (table data_BME280 ) +sudo python3 /var/www/nebuleair_pro_4g/BME280/get_data_v2.py + +''' + +import board +import busio +import json + +from adafruit_bme280 import basic as adafruit_bme280 + +# Create I2C bus +i2c = busio.I2C(board.SCL, board.SDA) +bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x76) + +# Configure settings +bme280.sea_level_pressure = 1013.25 # Update this value for your location + +# Read sensor data + +#print(f"Temperature: {bme280.temperature:.2f} °C") +#print(f"Humidity: {bme280.humidity:.2f} %") +#print(f"Pressure: {bme280.pressure:.2f} hPa") +#print(f"Altitude: {bme280.altitude:.2f} m") + +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 +} + + +# Convert to JSON and print +print(json.dumps(sensor_data, indent=4)) \ No newline at end of file diff --git a/NPM/get_data_v2.py b/NPM/get_data_v2.py index ab7321e..577362f 100644 --- a/NPM/get_data_v2.py +++ b/NPM/get_data_v2.py @@ -1,12 +1,12 @@ ''' - ____ _____ _ _ ____ ___ ____ ____ - / ___|| ____| \ | / ___| / _ \| _ \/ ___| - \___ \| _| | \| \___ \| | | | |_) \___ \ - ___) | |___| |\ |___) | |_| | _ < ___) | - |____/|_____|_| \_|____/ \___/|_| \_\____/ - - -Script to get SENSORS values + _ _ ____ __ __ + | \ | | _ \| \/ | + | \| | |_) | |\/| | + | |\ | __/| | | | + |_| \_|_| |_| |_| + +Script to get NPM values +PM and the sensor temp/hum And store them inside sqlite database Uses RTC module for timing /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_v2.py @@ -72,70 +72,58 @@ ser = serial.Serial( #ser.write(b'\x81\x11\x6E') #data10s ser.write(b'\x81\x12\x6D') #data60s -while True: - try: - #print("Start get_data_v2.py script") - byte_data = ser.readline() - #print(byte_data) - stateByte = int.from_bytes(byte_data[2:3], byteorder='big') - Statebits = [int(bit) for bit in bin(stateByte)[2:].zfill(8)] - PM1 = int.from_bytes(byte_data[9:11], byteorder='big')/10 - PM25 = int.from_bytes(byte_data[11:13], byteorder='big')/10 - PM10 = int.from_bytes(byte_data[13:15], byteorder='big')/10 - #print(f"State: {Statebits}") - #print(f"PM1: {PM1}") - #print(f"PM25: {PM25}") - #print(f"PM10: {PM10}") - #create JSON - data = { - 'PM1': PM1, - 'PM25': PM25, - 'PM10': PM10, - 'sleep' : Statebits[0], - 'degradedState' : Statebits[1], - 'notReady' : Statebits[2], - 'heatError' : Statebits[3], - 't_rhError' : Statebits[4], - 'fanError' : Statebits[5], - 'memoryError' : Statebits[6], - 'laserError' : Statebits[7] - } - json_data = json.dumps(data) - #print(json_data) - #GET RTC TIME - # Read RTC time - bus = smbus2.SMBus(1) - # Try to read RTC time - rtc_time = read_time(bus) +#print("Start get_data_v2.py script") +byte_data = ser.readline() +#print(byte_data) +stateByte = int.from_bytes(byte_data[2:3], byteorder='big') +Statebits = [int(bit) for bit in bin(stateByte)[2:].zfill(8)] +PM1 = int.from_bytes(byte_data[9:11], byteorder='big')/10 +PM25 = int.from_bytes(byte_data[11:13], byteorder='big')/10 +PM10 = int.from_bytes(byte_data[13:15], byteorder='big')/10 - 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 +# Write command to retrieve temperature and humidity data +ser.write(b'\x81\x14\x6B') # Temp and humidity command +byte_data_temp_hum = ser.readline() + +# Decode temperature and humidity values +temperature = int.from_bytes(byte_data_temp_hum[3:5], byteorder='big') / 100.0 +humidity = int.from_bytes(byte_data_temp_hum[5:7], byteorder='big') / 100.0 + +#print(f"State: {Statebits}") +#print(f"PM1: {PM1}") +#print(f"PM25: {PM25}") +#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 - #save to sqlite database - cursor.execute(''' - INSERT INTO data (timestamp,PM1, PM25, PM10) VALUES (?,?,?,?)''' - , (rtc_time_str,PM1,PM25,PM10)) +#save to sqlite database +try: + cursor.execute(''' + INSERT INTO data_NPM (timestamp,PM1, PM25, PM10, temp_npm, hum_npm) VALUES (?,?,?,?,?,?)''' + , (rtc_time_str,PM1,PM25,PM10,temperature,humidity )) - # Commit and close the connection - conn.commit() + # Commit and close the connection + conn.commit() - #print("Sensor data saved successfully!") + #print("Sensor data saved successfully!") + +except Exception as e: + print(f"Database error: {e}") - break # Exit loop after successful execution - except KeyboardInterrupt: - print("User interrupt encountered. Exiting...") - time.sleep(3) - exit() - except Exception as e: - print(f"Error: {e}") # Show actual error - time.sleep(3) - exit() conn.close() diff --git a/html/launcher.php b/html/launcher.php index b5b7a04..e698ab6 100755 --- a/html/launcher.php +++ b/html/launcher.php @@ -14,7 +14,7 @@ if ($type == "get_npm_sqlite_data") { $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Fetch the last 30 records - $stmt = $db->query("SELECT timestamp, PM1, PM25, PM10 FROM data ORDER BY timestamp DESC LIMIT 30"); + $stmt = $db->query("SELECT timestamp, PM1, PM25, PM10 FROM data_NPM ORDER BY timestamp DESC LIMIT 30"); $data = $stmt->fetchAll(PDO::FETCH_ASSOC); $reversedData = array_reverse($data); // Reverse the order diff --git a/loop/SARA_send_data_v2.py b/loop/SARA_send_data_v2.py index 8f64685..e7f2e2b 100644 --- a/loop/SARA_send_data_v2.py +++ b/loop/SARA_send_data_v2.py @@ -47,6 +47,8 @@ CSV PAYLOAD (AirCarto Servers) 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) + 18 -> NPM temp inside + 19 -> NPM hum inside JSON PAYLOAD (Micro-Spot Servers) Same as NebuleAir wifi @@ -111,7 +113,7 @@ if uptime_seconds < 120: sys.exit() #Payload CSV to be sent to data.nebuleair.fr -payload_csv = [None] * 20 +payload_csv = [None] * 25 #Payload JSON to be sent to uSpot payload_json = { "nebuleairid": "XXX", @@ -253,15 +255,39 @@ def read_complete_response(serial_connection, timeout=2, end_of_response_timeout return response.decode('utf-8', errors='replace') try: + ''' + _ ___ ___ ____ + | | / _ \ / _ \| _ \ + | | | | | | | | | |_) | + | |__| |_| | |_| | __/ + |_____\___/ \___/|_| + + ''' print('

START LOOP

') print("Getting NPM values") # Retrieve the last sensor readings - cursor.execute("SELECT * FROM data ORDER BY timestamp DESC LIMIT 1") + cursor.execute("SELECT * FROM data_NPM ORDER BY timestamp DESC LIMIT 1") last_row = cursor.fetchone() # Display the result if last_row: - pm1_value = last_row[1] # Adjust the index based on the column order in your table - print("Last available row:", last_row) + print("SQLite DB last available row:", last_row) + PM1 = last_row[1] + PM25 = last_row[2] + PM10 = last_row[3] + npm_temp = last_row[4] + npm_hum = last_row[5] + + #Add data to payload CSV + payload_csv[0] = PM1 + payload_csv[1] = PM25 + payload_csv[2] = PM10 + payload_csv[18] = npm_temp + payload_csv[19] = npm_hum + + #Add data to payload JSON + payload_json["sensordatavalues"].append({"value_type": "NPM_P0", "value": str(PM1)}) + payload_json["sensordatavalues"].append({"value_type": "NPM_P1", "value": str(PM10)}) + payload_json["sensordatavalues"].append({"value_type": "NPM_P2", "value": str(PM25)}) else: print("No data available in the database.") @@ -305,6 +331,162 @@ try: ''' SEND TO AIRCARTO ''' + # Write Data to saraR4 + # 1. Open sensordata_csv.json (with correct data size) + csv_string = ','.join(str(value) if value is not None else '' for value in payload_csv) + size_of_string = len(csv_string) + print("Open JSON:") + command = f'AT+UDWNFILE="sensordata_csv.json",{size_of_string}\r' + ser_sara.write(command.encode('utf-8')) + response_SARA_1 = read_complete_response(ser_sara, wait_for_line=">", debug=False) + print(response_SARA_1) + time.sleep(1) + + #2. Write to shell + print("Write data to memory:") + ser_sara.write(csv_string.encode()) + response_SARA_2 = read_complete_response(ser_sara, wait_for_line="OK", debug=False) + print(response_SARA_2) + + #3. Send to endpoint (with device ID) + print("Send data (POST REQUEST):") + command= f'AT+UHTTPC={aircarto_profile_id},4,"/pro_4G/data.php?sensor_id={device_id}?timestamp=000","server_response.txt","sensordata_csv.json",4\r' + ser_sara.write(command.encode('utf-8')) + + response_SARA_3 = read_complete_response(ser_sara, timeout=5, end_of_response_timeout=120, wait_for_line="+UUHTTPCR") + + print('

') + print(response_SARA_3) + print("

") + + # si on recoit la réponse UHTTPCR + if "+UUHTTPCR" in response_SARA_3: + print("✅ Received +UUHTTPCR response.") + + # Les types de réponse + + # 1.La commande n'a pas fonctionné + # +CME ERROR: No connection to phone + # +CME ERROR: Operation not allowed + + # 2.La commande fonctionne: elle renvoie un code + # +UUHTTPCR: ,, + # : 1 pour sucess et 0 pour fail + # +UUHTTPCR: 0,4,1 -> OK + # +UUHTTPCR: 0,4,0 -> error + + # Split response into lines + lines = response_SARA_3.strip().splitlines() + + # 1.Vérifier si la réponse contient un message d'erreur CME + if "+CME ERROR" in lines[-1]: + print("*****") + print('ATTENTION: CME ERROR') + print("error:", lines[-1]) + print("*****") + #update status + update_json_key(config_file, "SARA_R4_network_status", "disconnected") + + # Gestion de l'erreur spécifique + if "No connection to phone" in lines[-1]: + print("No connection to the phone. Retrying or reset may be required.") + # Actions spécifiques pour ce type d'erreur (par exemple, réinitialiser ou tenter de reconnecter) + # need to reconnect to network + # and reset HTTP profile (AT+UHTTP=0) -> ne fonctionne pas.. + # tester un reset avec CFUN 15 + # 1.Reconnexion au réseau (AT+COPS) + command = f'AT+COPS=1,2,"{selected_networkID}"\r' + ser_sara.write(command.encode('utf-8')) + responseReconnect = read_complete_response(ser_sara) + print("Response reconnect:") + print(responseReconnect) + print("End response reconnect") + + elif "Operation not allowed" in lines[-1]: + print("Operation not allowed. This may require a different configuration.") + # Actions spécifiques pour ce type d'erreur + + # Clignotement LED rouge en cas d'erreur + led_thread = Thread(target=blink_led, args=(24, 5, 0.5)) + led_thread.start() + + else: + # 2.Si la réponse contient une réponse HTTP valide + # Extract HTTP response code from the last line + # ATTENTION: lines[-1] renvoie l'avant dernière ligne et il peut y avoir un soucis avec le OK + # rechercher plutot + http_response = lines[-1] # "+UUHTTPCR: 0,4,0" + parts = http_response.split(',') + + # 2.1 code 0 (HTTP failed) + if len(parts) == 3 and parts[-1] == '0': # The third value indicates success + print("*****") + print('ATTENTION: HTTP operation failed') + update_json_key(config_file, "SARA_R4_network_status", "disconnected") + print("*****") + print("Blink red LED") + # Run LED blinking in a separate thread + led_thread = Thread(target=blink_led, args=(24, 5, 0.5)) + led_thread.start() + + # Get error code + print("Getting error code (11->Server connection error, 73->Secure socket connect error)") + command = f'AT+UHTTPER={aircarto_profile_id}\r' + ser_sara.write(command.encode('utf-8')) + response_SARA_9 = read_complete_response(ser_sara, wait_for_line="OK", debug=False) + print('

') + print(response_SARA_9) + print("

") + + ''' + +UHTTPER: profile_id,error_class,error_code + + error_class + 0 OK, no error + 3 HTTP Protocol error class + 10 Wrong HTTP API USAGE + + error_code (for error_class 3) + 0 No error + 11 Server connection error + 73 Secure socket connect error + ''' + + #Pas forcément un moyen de résoudre le soucis + #print("resetting the URL (domain name):") + #command = f'AT+UHTTP={aircarto_profile_id},1,"{url_nebuleair}"\r' + #ser_sara.write(command.encode('utf-8')) + #response_SARA_31 = read_complete_response(ser_sara) + #print(response_SARA_31) + + # 2.2 code 1 (HHTP succeded) + else: + # Si la commande HTTP a réussi + print('HTTP operation successful.') + update_json_key(config_file, "SARA_R4_network_status", "connected") + print("Blink blue LED") + led_thread = Thread(target=blink_led, args=(23, 5, 0.5)) + led_thread.start() + #4. Read reply from server + print("Reply from server:") + ser_sara.write(b'AT+URDFILE="server_response.txt"\r') + response_SARA_4 = read_complete_response(ser_sara, wait_for_line="OK", debug=False) + print('

') + print(response_SARA_4) + print('

') + else: + print('No UUHTTPCR response') + print("Blink red LED") + # Run LED blinking in a separate thread + led_thread = Thread(target=blink_led, args=(24, 5, 0.5)) + led_thread.start() + + + #5. empty json + print("Empty SARA memory:") + ser_sara.write(b'AT+UDELFILE="sensordata_csv.json"\r') + response_SARA_5 = read_complete_response(ser_sara, wait_for_line="OK", debug=False) + print(response_SARA_5) diff --git a/sqlite/read.py b/sqlite/read.py index 947fe6a..ba8f5ec 100755 --- a/sqlite/read.py +++ b/sqlite/read.py @@ -17,7 +17,7 @@ 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 ORDER BY timestamp DESC LIMIT 10") +cursor.execute("SELECT * FROM data_NPM ORDER BY timestamp DESC LIMIT 10") rows = cursor.fetchall() rows.reverse() # Reverse the order in Python (to get ascending order)