update
This commit is contained in:
130
SARA/UDP/sendUDP_message.py
Normal file
130
SARA/UDP/sendUDP_message.py
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
'''
|
||||||
|
____ _ ____ _
|
||||||
|
/ ___| / \ | _ \ / \
|
||||||
|
\___ \ / _ \ | |_) | / _ \
|
||||||
|
___) / ___ \| _ < / ___ \
|
||||||
|
|____/_/ \_\_| \_\/_/ \_\
|
||||||
|
|
||||||
|
Script to set the PDP context for the SARA R5
|
||||||
|
|
||||||
|
|
||||||
|
/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/UDP/sendUDP_message.py
|
||||||
|
|
||||||
|
'''
|
||||||
|
import serial
|
||||||
|
import time
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ser_sara = serial.Serial(
|
||||||
|
port='/dev/ttyAMA2',
|
||||||
|
baudrate=115200, #115200 ou 9600
|
||||||
|
parity=serial.PARITY_NONE, #PARITY_NONE, PARITY_EVEN or PARITY_ODD
|
||||||
|
stopbits=serial.STOPBITS_ONE,
|
||||||
|
bytesize=serial.EIGHTBITS,
|
||||||
|
timeout = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
def read_complete_response(serial_connection, timeout=2, end_of_response_timeout=2, wait_for_lines=None, debug=True):
|
||||||
|
'''
|
||||||
|
Fonction très importante !!!
|
||||||
|
Reads the complete response from a serial connection and waits for specific lines.
|
||||||
|
'''
|
||||||
|
if wait_for_lines is None:
|
||||||
|
wait_for_lines = [] # Default to an empty list if not provided
|
||||||
|
|
||||||
|
response = bytearray()
|
||||||
|
serial_connection.timeout = timeout
|
||||||
|
end_time = time.time() + end_of_response_timeout
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
elapsed_time = time.time() - start_time # Time since function start
|
||||||
|
if serial_connection.in_waiting > 0:
|
||||||
|
data = serial_connection.read(serial_connection.in_waiting)
|
||||||
|
response.extend(data)
|
||||||
|
end_time = time.time() + end_of_response_timeout # Reset timeout on new data
|
||||||
|
|
||||||
|
# Decode and check for any target line
|
||||||
|
decoded_response = response.decode('utf-8', errors='replace')
|
||||||
|
for target_line in wait_for_lines:
|
||||||
|
if target_line in decoded_response:
|
||||||
|
if debug:
|
||||||
|
print(f"[DEBUG] 🔎 Found target line: {target_line} (in {elapsed_time:.2f}s)")
|
||||||
|
return decoded_response # Return response immediately if a target line is found
|
||||||
|
elif time.time() > end_time:
|
||||||
|
if debug:
|
||||||
|
print(f"[DEBUG] Timeout reached. No more data received.")
|
||||||
|
break
|
||||||
|
time.sleep(0.1) # Short sleep to prevent busy waiting
|
||||||
|
|
||||||
|
# Final response and debug output
|
||||||
|
total_elapsed_time = time.time() - start_time
|
||||||
|
if debug:
|
||||||
|
print(f"[DEBUG] ⏱️ elapsed time: {total_elapsed_time:.2f}s. ⏱️")
|
||||||
|
# Check if the elapsed time exceeded 10 seconds
|
||||||
|
if total_elapsed_time > 10 and debug:
|
||||||
|
print(f"[ALERT] 🚨 The operation took too long 🚨")
|
||||||
|
print(f'<span style="color: red;font-weight: bold;">[ALERT] ⚠️{total_elapsed_time:.2f}s⚠️</span>')
|
||||||
|
|
||||||
|
return response.decode('utf-8', errors='replace') # Return the full response if no target line is found
|
||||||
|
|
||||||
|
try:
|
||||||
|
print('Start script')
|
||||||
|
|
||||||
|
# Increase verbosity
|
||||||
|
command = f'AT+CMEE=2\r'
|
||||||
|
ser_sara.write(command.encode('utf-8'))
|
||||||
|
response_SARA_1 = read_complete_response(ser_sara, wait_for_lines=["OK", "ERROR"])
|
||||||
|
print(response_SARA_1, end="")
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
# 1. Create SOCKET
|
||||||
|
print('➡️Create SOCKET')
|
||||||
|
command = f'AT+USOCR=17\r'
|
||||||
|
ser_sara.write(command.encode('utf-8'))
|
||||||
|
response_SARA_1 = read_complete_response(ser_sara, wait_for_lines=["OK", "ERROR"])
|
||||||
|
print(response_SARA_1, end="")
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
# 2. Retreive Socket ID
|
||||||
|
match = re.search(r'\+USOCR:\s*(\d+)', response_SARA_1)
|
||||||
|
if match:
|
||||||
|
socket_id = match.group(1)
|
||||||
|
print(f"Socket ID: {socket_id}")
|
||||||
|
else:
|
||||||
|
print("Failed to extract socket ID")
|
||||||
|
|
||||||
|
|
||||||
|
#3. Connect to UDP server
|
||||||
|
print("Connect to server:")
|
||||||
|
command = f'AT+USOCO={socket_id},"192.168.0.20",4242\r'
|
||||||
|
ser_sara.write(command.encode('utf-8'))
|
||||||
|
response_SARA_2 = read_complete_response(ser_sara, wait_for_lines=["OK", "+CME ERROR", "ERROR"], debug=False)
|
||||||
|
print(response_SARA_2)
|
||||||
|
|
||||||
|
# 4. Write data and send
|
||||||
|
print("Write data:")
|
||||||
|
command = f'AT+USOWR={socket_id},10\r'
|
||||||
|
ser_sara.write(command.encode('utf-8'))
|
||||||
|
response_SARA_2 = read_complete_response(ser_sara, wait_for_lines=["@","OK", "+CME ERROR", "ERROR"], debug=False)
|
||||||
|
print(response_SARA_2)
|
||||||
|
|
||||||
|
ser_sara.write("1234567890".encode())
|
||||||
|
response_SARA_2 = read_complete_response(ser_sara, wait_for_lines=["@","OK", "+CME ERROR", "ERROR"], debug=False)
|
||||||
|
print(response_SARA_2)
|
||||||
|
|
||||||
|
#Close socket
|
||||||
|
print("Close socket:")
|
||||||
|
command = f'AT+USOCL={socket_id}\r'
|
||||||
|
ser_sara.write(command.encode('utf-8'))
|
||||||
|
response_SARA_2 = read_complete_response(ser_sara, wait_for_lines=["OK", "+CME ERROR", "ERROR"], debug=False)
|
||||||
|
print(response_SARA_2)
|
||||||
|
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("An error occurred:", e)
|
||||||
|
traceback.print_exc() # This prints the full traceback
|
||||||
@@ -118,10 +118,25 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" value="" id="check_aircarto" onchange="update_config_sqlite('send_aircarto', this.checked)" disabled>
|
||||||
|
<label class="form-check-label" for="check_aircarto">
|
||||||
|
Send to AirCarto (HTTP)
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-check mb-3">
|
<div class="form-check mb-3">
|
||||||
<input class="form-check-input" type="checkbox" value="" id="check_uSpot" onchange="update_config_sqlite('send_uSpot', this.checked)" disabled>
|
<input class="form-check-input" type="checkbox" value="" id="check_uSpot" onchange="update_config_sqlite('send_uSpot', this.checked)" disabled>
|
||||||
<label class="form-check-label" for="check_uSpot">
|
<label class="form-check-label" for="check_uSpot">
|
||||||
Send to uSpot
|
Send to uSpot (HTTPS)
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" value="" id="check_miotiq" onchange="update_config_sqlite('send_miotiq', this.checked)" disabled>
|
||||||
|
<label class="form-check-label" for="check_miotiq">
|
||||||
|
Send to miotiq (UDP)
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -365,6 +380,9 @@ window.onload = function() {
|
|||||||
const checkbox_nmp5channels = document.getElementById("check_NPM_5channels");
|
const checkbox_nmp5channels = document.getElementById("check_NPM_5channels");
|
||||||
const checkbox_wind = document.getElementById("check_WindMeter");
|
const checkbox_wind = document.getElementById("check_WindMeter");
|
||||||
const checkbox_uSpot = document.getElementById("check_uSpot");
|
const checkbox_uSpot = document.getElementById("check_uSpot");
|
||||||
|
const checkbox_aircarto = document.getElementById("check_aircarto");
|
||||||
|
const checkbox_miotiq = document.getElementById("check_miotiq");
|
||||||
|
|
||||||
const checkbox_bme = document.getElementById("check_bme280");
|
const checkbox_bme = document.getElementById("check_bme280");
|
||||||
const checkbox_envea = document.getElementById("check_envea");
|
const checkbox_envea = document.getElementById("check_envea");
|
||||||
const checkbox_solar = document.getElementById("check_solarBattery");
|
const checkbox_solar = document.getElementById("check_solarBattery");
|
||||||
@@ -378,6 +396,8 @@ window.onload = function() {
|
|||||||
checkbox_noise.checked = response["NOISE"];
|
checkbox_noise.checked = response["NOISE"];
|
||||||
|
|
||||||
checkbox_uSpot.checked = response["send_uSpot"];
|
checkbox_uSpot.checked = response["send_uSpot"];
|
||||||
|
checkbox_aircarto.checked = response["send_aircarto"];
|
||||||
|
checkbox_miotiq.checked = response["send_miotiq"];
|
||||||
|
|
||||||
// If envea is enabled, show the envea sondes container
|
// If envea is enabled, show the envea sondes container
|
||||||
if (response["envea"]) {
|
if (response["envea"]) {
|
||||||
|
|||||||
@@ -57,6 +57,18 @@ CSV PAYLOAD (AirCarto Servers)
|
|||||||
25 -> Wind speed
|
25 -> Wind speed
|
||||||
26 -> Wind direction
|
26 -> Wind direction
|
||||||
|
|
||||||
|
CSV FOR UDP (miotiq)
|
||||||
|
{device_id},{timestamp},{PM1},{PM25},{PM10},{temp},{hum},{press},{avg_noise},{max_noise},{min_noise},{envea_no2},{envea_h2s},{envea_o3},{4g_signal_quality}
|
||||||
|
0 -> device ID
|
||||||
|
1 -> timestamp
|
||||||
|
2 -> PM1
|
||||||
|
3 -> PM2.5
|
||||||
|
4 -> PM10
|
||||||
|
5 -> temp
|
||||||
|
6 -> hum
|
||||||
|
7 -> press
|
||||||
|
|
||||||
|
|
||||||
JSON PAYLOAD (Micro-Spot Servers)
|
JSON PAYLOAD (Micro-Spot Servers)
|
||||||
Same as NebuleAir wifi
|
Same as NebuleAir wifi
|
||||||
Endpoint:
|
Endpoint:
|
||||||
@@ -124,6 +136,8 @@ if uptime_seconds < 120:
|
|||||||
|
|
||||||
#Payload CSV to be sent to data.nebuleair.fr
|
#Payload CSV to be sent to data.nebuleair.fr
|
||||||
payload_csv = [None] * 30
|
payload_csv = [None] * 30
|
||||||
|
#Payload UPD to be sent to miotiq
|
||||||
|
payload_udp = [None] * 30
|
||||||
#Payload JSON to be sent to uSpot
|
#Payload JSON to be sent to uSpot
|
||||||
payload_json = {
|
payload_json = {
|
||||||
"nebuleairid": "XXX",
|
"nebuleairid": "XXX",
|
||||||
@@ -211,8 +225,10 @@ device_longitude_raw = config.get('longitude_raw', 0)
|
|||||||
modem_version=config.get('modem_version', "")
|
modem_version=config.get('modem_version', "")
|
||||||
Sara_baudrate = config.get('SaraR4_baudrate', 115200)
|
Sara_baudrate = config.get('SaraR4_baudrate', 115200)
|
||||||
selected_networkID = int(config.get('SARA_R4_neworkID', 0))
|
selected_networkID = int(config.get('SARA_R4_neworkID', 0))
|
||||||
|
send_miotiq = config.get('send_miotiq', True)
|
||||||
|
send_aircarto = config.get('send_aircarto', True)
|
||||||
send_uSpot = config.get('send_uSpot', False) #envoi sur MicroSpot ()
|
send_uSpot = config.get('send_uSpot', False) #envoi sur MicroSpot ()
|
||||||
npm_5channel = config.get('npm_5channel', False) #5 canaux du NPM
|
npm_5channel = config.get('npm_5channel', False) #5 canaux du NPM
|
||||||
envea_cairsens= config.get('envea', False)
|
envea_cairsens= config.get('envea', False)
|
||||||
wind_meter= config.get('windMeter', False)
|
wind_meter= config.get('windMeter', False)
|
||||||
bme_280_config = config.get('BME280', False)
|
bme_280_config = config.get('BME280', False)
|
||||||
@@ -221,6 +237,7 @@ NOISE_sensor = config.get('NOISE', False)
|
|||||||
|
|
||||||
#update device id in the payload json
|
#update device id in the payload json
|
||||||
payload_json["nebuleairid"] = device_id
|
payload_json["nebuleairid"] = device_id
|
||||||
|
payload_udp[0] = device_id
|
||||||
|
|
||||||
# Skip execution if modem_config_mode is true
|
# Skip execution if modem_config_mode is true
|
||||||
if modem_config_mode:
|
if modem_config_mode:
|
||||||
@@ -648,6 +665,11 @@ try:
|
|||||||
payload_csv[18] = npm_temp
|
payload_csv[18] = npm_temp
|
||||||
payload_csv[19] = npm_hum
|
payload_csv[19] = npm_hum
|
||||||
|
|
||||||
|
#add data to payload UDP
|
||||||
|
payload_udp[2] = PM1
|
||||||
|
payload_udp[3] = PM25
|
||||||
|
payload_udp[4] = PM10
|
||||||
|
|
||||||
#Add data to payload JSON
|
#Add data to payload JSON
|
||||||
payload_json["sensordatavalues"].append({"value_type": "NPM_P0", "value": str(PM1)})
|
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_P1", "value": str(PM10)})
|
||||||
@@ -863,16 +885,91 @@ try:
|
|||||||
print('<p class="text-danger-emphasis">')
|
print('<p class="text-danger-emphasis">')
|
||||||
print(responseReconnect)
|
print(responseReconnect)
|
||||||
print("</p>", end="")
|
print("</p>", end="")
|
||||||
|
|
||||||
print('🛑STOP LOOP🛑')
|
print('🛑STOP LOOP🛑')
|
||||||
print("<hr>")
|
print("<hr>")
|
||||||
|
|
||||||
#on arrete le script pas besoin de continuer
|
#on arrete le script pas besoin de continuer
|
||||||
sys.exit()
|
sys.exit()
|
||||||
else:
|
else:
|
||||||
print("Signal Quality:", signal_quality)
|
print("Signal Quality:", signal_quality)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
____ _____ _ _ ____ _ _ ____ ____
|
||||||
|
/ ___|| ____| \ | | _ \ | | | | _ \| _ \
|
||||||
|
\___ \| _| | \| | | | | | | | | | | | |_) |
|
||||||
|
___) | |___| |\ | |_| | | |_| | |_| | __/
|
||||||
|
|____/|_____|_| \_|____/ \___/|____/|_|
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
if send_miotiq:
|
||||||
|
print('<p class="fw-bold">➡️SEND TO MIOTIQ</p>', end="")
|
||||||
|
|
||||||
|
#create UDP socket (will return socket number) -> 17 is UDP protocol and 6 is TCP protocol
|
||||||
|
# IF ERROR -> need to create the PDP connection
|
||||||
|
print("Create Socket:")
|
||||||
|
command = f'AT+USOCR=17\r'
|
||||||
|
ser_sara.write(command.encode('utf-8'))
|
||||||
|
response_SARA_1 = read_complete_response(ser_sara, wait_for_lines=["OK", "+CME ERROR", "ERROR"], debug=False)
|
||||||
|
print('<p class="text-danger-emphasis">')
|
||||||
|
print(response_SARA_1)
|
||||||
|
print("</p>", end="")
|
||||||
|
|
||||||
|
if "+CME ERROR" in response_SARA_1:
|
||||||
|
print('<span style="color: red;font-weight: bold;">⚠️ATTENTION: need to reset PDP connection⚠️</span>')
|
||||||
|
psd_csd_resets = reset_PSD_CSD_connection()
|
||||||
|
if psd_csd_resets:
|
||||||
|
print("✅PSD CSD connection reset successfully")
|
||||||
|
else:
|
||||||
|
print("⛔There were issues with the modem CSD PSD reinitialize process")
|
||||||
|
|
||||||
|
|
||||||
|
#Retreive Socket ID
|
||||||
|
match = re.search(r'\+USOCR:\s*(\d+)', response_SARA_1)
|
||||||
|
if match:
|
||||||
|
socket_id = match.group(1)
|
||||||
|
print(f"Socket ID: {socket_id}")
|
||||||
|
else:
|
||||||
|
print("Failed to extract socket ID")
|
||||||
|
|
||||||
|
#Connect to UDP server
|
||||||
|
print("Connect to server:")
|
||||||
|
command = f'AT+USOCO={socket_id},"192.168.0.20",4242\r'
|
||||||
|
ser_sara.write(command.encode('utf-8'))
|
||||||
|
response_SARA_2 = read_complete_response(ser_sara, wait_for_lines=["OK", "+CME ERROR", "ERROR"], debug=False)
|
||||||
|
print('<p class="text-danger-emphasis">')
|
||||||
|
print(response_SARA_2)
|
||||||
|
print("</p>", end="")
|
||||||
|
|
||||||
|
#prepare data
|
||||||
|
csv_udp_string = ','.join(str(value) if value is not None else '' for value in payload_udp)
|
||||||
|
size_of_udp_string = len(csv_udp_string)
|
||||||
|
|
||||||
|
# 4. Write data and send
|
||||||
|
print("Write data:")
|
||||||
|
command = f'AT+USOWR={socket_id},{size_of_udp_string}\r'
|
||||||
|
ser_sara.write(command.encode('utf-8'))
|
||||||
|
response_SARA_2 = read_complete_response(ser_sara, wait_for_lines=["@","OK", "+CME ERROR", "ERROR"], debug=False)
|
||||||
|
print(response_SARA_2)
|
||||||
|
|
||||||
|
ser_sara.write(csv_udp_string.encode())
|
||||||
|
response_SARA_2 = read_complete_response(ser_sara, wait_for_lines=["@","OK", "+CME ERROR", "ERROR"], debug=False)
|
||||||
|
print(response_SARA_2)
|
||||||
|
|
||||||
|
|
||||||
|
#Close socket
|
||||||
|
print("Close socket:")
|
||||||
|
command = f'AT+USOCL={socket_id}\r'
|
||||||
|
ser_sara.write(command.encode('utf-8'))
|
||||||
|
response_SARA_2 = read_complete_response(ser_sara, wait_for_lines=["OK", "+CME ERROR", "ERROR"], debug=False)
|
||||||
|
print('<p class="text-danger-emphasis">')
|
||||||
|
print(response_SARA_2)
|
||||||
|
print("</p>", end="")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
____ _____ _ _ ____ _ ___ ____ ____ _ ____ _____ ___
|
____ _____ _ _ ____ _ ___ ____ ____ _ ____ _____ ___
|
||||||
/ ___|| ____| \ | | _ \ / \ |_ _| _ \ / ___| / \ | _ \_ _/ _ \
|
/ ___|| ____| \ | | _ \ / \ |_ _| _ \ / ___| / \ | _ \_ _/ _ \
|
||||||
@@ -882,328 +979,330 @@ try:
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
print('<p class="fw-bold">➡️SEND TO AIRCARTO SERVERS</p>', end="")
|
if send_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_lines=[">"], debug=False)
|
|
||||||
print('<p class="text-danger-emphasis">')
|
|
||||||
print(response_SARA_1)
|
|
||||||
print("</p>", end="")
|
|
||||||
|
|
||||||
time.sleep(1)
|
print('<p class="fw-bold">➡️SEND TO AIRCARTO SERVERS</p>', end="")
|
||||||
|
# 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_lines=[">"], debug=False)
|
||||||
|
print('<p class="text-danger-emphasis">')
|
||||||
|
print(response_SARA_1)
|
||||||
|
print("</p>", end="")
|
||||||
|
|
||||||
#2. Write to shell
|
time.sleep(1)
|
||||||
print("Write data to memory:")
|
|
||||||
ser_sara.write(csv_string.encode())
|
|
||||||
response_SARA_2 = read_complete_response(ser_sara, wait_for_lines=["OK"], debug=False)
|
|
||||||
print(f'<p class="text-danger-emphasis">{response_SARA_2.strip()}</p>', end="")
|
|
||||||
|
|
||||||
#3. Send to endpoint (with device ID)
|
#2. Write to shell
|
||||||
print("Send data (POST REQUEST):")
|
print("Write data to memory:")
|
||||||
command= f'AT+UHTTPC={aircarto_profile_id},4,"/pro_4G/data.php?sensor_id={device_id}&lat={device_latitude_raw}&long={device_longitude_raw}&datetime={influx_timestamp}","aircarto_server_response.txt","sensordata_csv.json",4\r'
|
ser_sara.write(csv_string.encode())
|
||||||
#print("sending:")
|
response_SARA_2 = read_complete_response(ser_sara, wait_for_lines=["OK"], debug=False)
|
||||||
#print('<p class="text-danger-emphasis">')
|
print(f'<p class="text-danger-emphasis">{response_SARA_2.strip()}</p>', end="")
|
||||||
#print(command)
|
|
||||||
#print("</p>", end="")
|
|
||||||
|
|
||||||
ser_sara.write(command.encode('utf-8'))
|
#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}&lat={device_latitude_raw}&long={device_longitude_raw}&datetime={influx_timestamp}","aircarto_server_response.txt","sensordata_csv.json",4\r'
|
||||||
|
#print("sending:")
|
||||||
|
#print('<p class="text-danger-emphasis">')
|
||||||
|
#print(command)
|
||||||
|
#print("</p>", end="")
|
||||||
|
|
||||||
response_SARA_3 = read_complete_response(ser_sara, timeout=5, end_of_response_timeout=120, wait_for_lines=["+UUHTTPCR", "+CME ERROR", "ERROR"], debug=True)
|
ser_sara.write(command.encode('utf-8'))
|
||||||
#print("receiving:")
|
|
||||||
print('<p class="text-danger-emphasis">')
|
|
||||||
print(response_SARA_3)
|
|
||||||
print("</p>", end="")
|
|
||||||
|
|
||||||
# si on recoit la réponse UHTTPCR
|
response_SARA_3 = read_complete_response(ser_sara, timeout=5, end_of_response_timeout=120, wait_for_lines=["+UUHTTPCR", "+CME ERROR", "ERROR"], debug=True)
|
||||||
if "+UUHTTPCR" in response_SARA_3:
|
#print("receiving:")
|
||||||
print("✅ Received +UUHTTPCR response.")
|
print('<p class="text-danger-emphasis">')
|
||||||
|
print(response_SARA_3)
|
||||||
|
print("</p>", end="")
|
||||||
|
|
||||||
# Les types de réponse
|
# si on recoit la réponse UHTTPCR
|
||||||
|
if "+UUHTTPCR" in response_SARA_3:
|
||||||
|
print("✅ Received +UUHTTPCR response.")
|
||||||
|
|
||||||
# 1.La commande n'a pas fonctionné
|
# Les types de réponse
|
||||||
# +CME ERROR: No connection to phone
|
|
||||||
# +CME ERROR: Operation not allowed
|
|
||||||
|
|
||||||
# 2.La commande fonctionne: elle renvoie un code
|
# 1.La commande n'a pas fonctionné
|
||||||
# +UUHTTPCR: <profile_id>,<http_command>,<http_result>
|
# +CME ERROR: No connection to phone
|
||||||
# <http_result>: 1 pour sucess et 0 pour fail
|
# +CME ERROR: Operation not allowed
|
||||||
# +UUHTTPCR: 0,4,1 -> OK ✅
|
|
||||||
# +UUHTTPCR: 0,4,0 -> error ⛔
|
|
||||||
|
|
||||||
# Split response into lines
|
# 2.La commande fonctionne: elle renvoie un code
|
||||||
lines = response_SARA_3.strip().splitlines()
|
# +UUHTTPCR: <profile_id>,<http_command>,<http_result>
|
||||||
|
# <http_result>: 1 pour sucess et 0 pour fail
|
||||||
|
# +UUHTTPCR: 0,4,1 -> OK ✅
|
||||||
|
# +UUHTTPCR: 0,4,0 -> error ⛔
|
||||||
|
|
||||||
# 1.Vérifier si la réponse contient un message d'erreur CME
|
# Split response into lines
|
||||||
if "+CME ERROR" in lines[-1]:
|
lines = response_SARA_3.strip().splitlines()
|
||||||
print("*****")
|
|
||||||
print('<span style="color: red;font-weight: bold;">ATTENTION: CME ERROR</span>')
|
|
||||||
print("error:", lines[-1])
|
|
||||||
print("*****")
|
|
||||||
|
|
||||||
# Gestion de l'erreur spécifique
|
# 1.Vérifier si la réponse contient un message d'erreur CME
|
||||||
if "No connection to phone" in lines[-1]:
|
if "+CME ERROR" 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'
|
|
||||||
#command = f'AT+COPS=0\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 UUHTTPCR
|
|
||||||
# Extract UUHTTPCR response code from the last line
|
|
||||||
|
|
||||||
http_response = lines[-1] # "+UUHTTPCR: 0,4,0"
|
|
||||||
parts = http_response.split(',')
|
|
||||||
|
|
||||||
# 2.1 code 0 (HTTP failed) ⛔⛔⛔
|
|
||||||
# -> GET error code
|
|
||||||
# -> reboot module
|
|
||||||
if len(parts) == 3 and parts[-1] == '0': # The third value indicates success
|
|
||||||
print("*****")
|
print("*****")
|
||||||
print('<span style="color: red;font-weight: bold;">⛔ATTENTION: HTTP operation failed</span>')
|
print('<span style="color: red;font-weight: bold;">ATTENTION: CME ERROR</span>')
|
||||||
|
print("error:", lines[-1])
|
||||||
print("*****")
|
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
|
# Gestion de l'erreur spécifique
|
||||||
print("Getting error code")
|
if "No connection to phone" in lines[-1]:
|
||||||
command = f'AT+UHTTPER={aircarto_profile_id}\r'
|
print("No connection to the phone. Retrying or reset may be required.")
|
||||||
ser_sara.write(command.encode('utf-8'))
|
# Actions spécifiques pour ce type d'erreur (par exemple, réinitialiser ou tenter de reconnecter)
|
||||||
response_SARA_9 = read_complete_response(ser_sara, wait_for_lines=["OK"], debug=False)
|
# need to reconnect to network
|
||||||
print('<p class="text-danger-emphasis">')
|
# and reset HTTP profile (AT+UHTTP=0) -> ne fonctionne pas..
|
||||||
print(response_SARA_9)
|
# tester un reset avec CFUN 15
|
||||||
print("</p>", end="")
|
# 1.Reconnexion au réseau (AT+COPS)
|
||||||
|
|
||||||
# Extract just the error code
|
|
||||||
error_code = extract_error_code(response_SARA_9)
|
|
||||||
|
|
||||||
if error_code is not None:
|
|
||||||
# Display interpretation based on error code
|
|
||||||
if error_code == 0:
|
|
||||||
print('<p class="text-success">No error detected</p>')
|
|
||||||
# INVALID SERVER HOSTNAME
|
|
||||||
elif error_code == 4:
|
|
||||||
print('<p class="text-danger">Error 4: AirCarto - Invalid server Hostname</p>')
|
|
||||||
send_error_notification(device_id, "UHTTPER (error n°4) -> AirCarto Invalid Server Hostname")
|
|
||||||
server_hostname_resets = reset_server_hostname(aircarto_profile_id)
|
|
||||||
if server_hostname_resets:
|
|
||||||
print("✅server hostname reset successfully")
|
|
||||||
else:
|
|
||||||
print("⛔There were issues with the modem server hostname reinitialize process")
|
|
||||||
# SERVER CONNECTION ERROR
|
|
||||||
elif error_code == 11:
|
|
||||||
print('<p class="text-danger">Error 11: Server connection error</p>')
|
|
||||||
hardware_reboot_success = modem_hardware_reboot()
|
|
||||||
if hardware_reboot_success:
|
|
||||||
print("✅Modem successfully rebooted and reinitialized")
|
|
||||||
else:
|
|
||||||
print("⛔There were issues with the modem reboot/reinitialize process")
|
|
||||||
# PSD OR CSD ERROR
|
|
||||||
elif error_code == 22:
|
|
||||||
print('<p class="text-danger">⚠️Error 22: PSD or CSD connection not established (SARA-R5 need to reset PDP conection)⚠️</p>')
|
|
||||||
send_error_notification(device_id, "UHTTPER (error n°22) -> PSD or CSD connection not established")
|
|
||||||
psd_csd_resets = reset_PSD_CSD_connection()
|
|
||||||
if psd_csd_resets:
|
|
||||||
print("✅PSD CSD connection reset successfully")
|
|
||||||
else:
|
|
||||||
print("⛔There were issues with the modem CSD PSD reinitialize process")
|
|
||||||
# CONNECTION TIMED OUT
|
|
||||||
elif error_code == 26:
|
|
||||||
print('<p class="text-danger">Error 26: Connection timed out</p>')
|
|
||||||
send_error_notification(device_id, "UHTTPER (error n°26) -> Connection timed out")
|
|
||||||
# CONNECTION LOST
|
|
||||||
elif error_code == 44:
|
|
||||||
print('<p class="text-danger">Error 44: Connection lost</p>')
|
|
||||||
send_error_notification(device_id, "UHTTPER (error n°44) -> Connection lost")
|
|
||||||
# SECURE SOCKET ERROR
|
|
||||||
elif error_code == 73:
|
|
||||||
print('<p class="text-danger">Error 73: Secure socket connect error</p>')
|
|
||||||
else:
|
|
||||||
print(f'<p class="text-danger">Unknown error code: {error_code}</p>')
|
|
||||||
else:
|
|
||||||
print('<p class="text-danger">Could not extract error code from response</p>')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 2.2 code 1 (✅✅HHTP / UUHTTPCR succeded✅✅)
|
|
||||||
else:
|
|
||||||
print('<span style="font-weight: bold;">✅✅HTTP operation successful.</span>')
|
|
||||||
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:")
|
|
||||||
command = f'AT+URDFILE="aircarto_server_response.txt""\r'
|
|
||||||
ser_sara.write((command + '\r').encode('utf-8'))
|
|
||||||
response_SARA_4 = read_complete_response(ser_sara, wait_for_lines=["OK"], debug=False)
|
|
||||||
print('<p class="text-success">')
|
|
||||||
print(response_SARA_4)
|
|
||||||
print("</p>", end="")
|
|
||||||
|
|
||||||
#Parse the server datetime
|
|
||||||
# Extract just the date from the response
|
|
||||||
date_string = None
|
|
||||||
server_datetime = ""
|
|
||||||
date_start = response_SARA_4.find("Date: ")
|
|
||||||
if date_start != -1:
|
|
||||||
date_end = response_SARA_4.find("\n", date_start)
|
|
||||||
date_string = response_SARA_4[date_start + 6:date_end].strip()
|
|
||||||
print(f'<div class="text-primary">Server date: {date_string}</div>', end="")
|
|
||||||
|
|
||||||
# Optionally convert to datetime object
|
|
||||||
try:
|
|
||||||
from datetime import datetime
|
|
||||||
server_datetime = datetime.strptime(
|
|
||||||
date_string,
|
|
||||||
"%a, %d %b %Y %H:%M:%S %Z"
|
|
||||||
)
|
|
||||||
#print(f'<p class="text-primary">Parsed datetime: {server_datetime}</p>')
|
|
||||||
except Exception as e:
|
|
||||||
print(f'<p class="text-warning">Error parsing date: {e}</p>')
|
|
||||||
|
|
||||||
# Get RTC time from SQLite
|
|
||||||
cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
|
|
||||||
row = cursor.fetchone()
|
|
||||||
rtc_time_str = row[1] # '2025-02-07 12:30:45' or '2000-01-01 00:55:21' or 'not connected'
|
|
||||||
print(f'<div class="text-primary">RTC time: {rtc_time_str}</div>', end="")
|
|
||||||
|
|
||||||
# Compare times if both are available
|
|
||||||
if server_datetime and rtc_time_str != 'not connected':
|
|
||||||
try:
|
|
||||||
# Convert RTC time string to datetime
|
|
||||||
rtc_datetime = datetime.strptime(rtc_time_str, '%Y-%m-%d %H:%M:%S')
|
|
||||||
|
|
||||||
# Calculate time difference in seconds
|
|
||||||
time_diff = abs((server_datetime - rtc_datetime).total_seconds())
|
|
||||||
|
|
||||||
print(f'<div class="text-primary">Time difference: {time_diff:.2f} seconds</div>', end="")
|
|
||||||
|
|
||||||
# Check if difference is more than 60 seconds
|
|
||||||
# and update the RTC clock
|
|
||||||
if time_diff > 60:
|
|
||||||
print(f'<div class="text-warning"><strong>⚠️ RTC time differs from server time by {time_diff:.2f} seconds!</strong></div>', end="")
|
|
||||||
# Format server time for RTC update
|
|
||||||
server_time_formatted = server_datetime.strftime('%Y-%m-%d %H:%M:%S')
|
|
||||||
|
|
||||||
#update RTC module do not wait for answer, non blocking
|
|
||||||
#/usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/set_with_browserTime.py '2024-01-30 12:48:39'
|
|
||||||
# Launch RTC update script as non-blocking subprocess
|
|
||||||
import subprocess
|
|
||||||
update_command = [
|
|
||||||
"/usr/bin/python3",
|
|
||||||
"/var/www/nebuleair_pro_4g/RTC/set_with_browserTime.py",
|
|
||||||
server_time_formatted
|
|
||||||
]
|
|
||||||
|
|
||||||
# Execute the command without waiting for result
|
|
||||||
subprocess.Popen(update_command,
|
|
||||||
stdout=subprocess.DEVNULL,
|
|
||||||
stderr=subprocess.DEVNULL)
|
|
||||||
|
|
||||||
print(f'<div class="text-warning">➡️ Updating RTC with server time: {server_time_formatted}</div>', end="")
|
|
||||||
|
|
||||||
else:
|
|
||||||
print(f'<div class="text-success">✅ RTC time is synchronized with server time (within 60 seconds)</div>')
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f'<p class="text-warning">Error comparing times: {e}</p>')
|
|
||||||
|
|
||||||
|
|
||||||
#Si non ne recoit pas de réponse UHTTPCR
|
|
||||||
#on a peut être une ERROR de type "+CME ERROR: No connection to phone" ou "Operation not allowed" ou "ERROR"
|
|
||||||
else:
|
|
||||||
print('<span style="color: red;font-weight: bold;">No UUHTTPCR response</span>')
|
|
||||||
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()
|
|
||||||
#Vérification de l'erreur
|
|
||||||
print("Getting type of error")
|
|
||||||
# Split the response into lines and search for "+CME ERROR:"
|
|
||||||
lines2 = response_SARA_3.strip().splitlines()
|
|
||||||
for line in lines2:
|
|
||||||
if "+CME ERROR" in line:
|
|
||||||
error_message = line.split("+CME ERROR:")[1].strip()
|
|
||||||
print("*****")
|
|
||||||
print('<span style="color: red;font-weight: bold;">⚠️ATTENTION: CME ERROR⚠️</span>')
|
|
||||||
print(f"Error type: {error_message}")
|
|
||||||
print("*****")
|
|
||||||
# Handle "No connection to phone" error
|
|
||||||
if error_message == "No connection to phone":
|
|
||||||
print('<span style="color: orange;font-weight: bold;">📞Try reconnect to network📞</span>')
|
|
||||||
#IMPORTANT!
|
|
||||||
# Reconnexion au réseau (AT+COPS)
|
|
||||||
command = f'AT+COPS=1,2,{selected_networkID}\r'
|
command = f'AT+COPS=1,2,{selected_networkID}\r'
|
||||||
#command = f'AT+COPS=0\r'
|
#command = f'AT+COPS=0\r'
|
||||||
ser_sara.write(command.encode('utf-8'))
|
ser_sara.write(command.encode('utf-8'))
|
||||||
responseReconnect = read_complete_response(ser_sara, timeout=5, end_of_response_timeout=120, wait_for_lines=["OK", "+CME ERROR"], debug=True)
|
responseReconnect = read_complete_response(ser_sara)
|
||||||
print('<p class="text-danger-emphasis">')
|
print("Response reconnect:")
|
||||||
print(responseReconnect)
|
print(responseReconnect)
|
||||||
print("</p>", end="")
|
print("End response reconnect")
|
||||||
# Handle "Operation not allowed" error
|
|
||||||
if error_message == "Operation not allowed":
|
elif "Operation not allowed" in lines[-1]:
|
||||||
print('<span style="color: orange;font-weight: bold;">❓Try Resetting the HTTP Profile❓</span>')
|
print("Operation not allowed. This may require a different configuration.")
|
||||||
command = f'AT+UHTTP={aircarto_profile_id},1,"data.nebuleair.fr"\r'
|
# 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 UUHTTPCR
|
||||||
|
# Extract UUHTTPCR response code from the last line
|
||||||
|
|
||||||
|
http_response = lines[-1] # "+UUHTTPCR: 0,4,0"
|
||||||
|
parts = http_response.split(',')
|
||||||
|
|
||||||
|
# 2.1 code 0 (HTTP failed) ⛔⛔⛔
|
||||||
|
# -> GET error code
|
||||||
|
# -> reboot module
|
||||||
|
if len(parts) == 3 and parts[-1] == '0': # The third value indicates success
|
||||||
|
print("*****")
|
||||||
|
print('<span style="color: red;font-weight: bold;">⛔ATTENTION: HTTP operation failed</span>')
|
||||||
|
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")
|
||||||
|
command = f'AT+UHTTPER={aircarto_profile_id}\r'
|
||||||
ser_sara.write(command.encode('utf-8'))
|
ser_sara.write(command.encode('utf-8'))
|
||||||
responseResetHTTP_profile = read_complete_response(ser_sara, timeout=5, end_of_response_timeout=5, wait_for_lines=["OK", "+CME ERROR"], debug=True)
|
response_SARA_9 = read_complete_response(ser_sara, wait_for_lines=["OK"], debug=False)
|
||||||
print('<p class="text-danger-emphasis">')
|
print('<p class="text-danger-emphasis">')
|
||||||
print(responseResetHTTP_profile)
|
print(response_SARA_9)
|
||||||
print("</p>", end="")
|
print("</p>", end="")
|
||||||
check_lines = responseResetHTTP_profile.strip().splitlines()
|
|
||||||
for line in check_lines:
|
|
||||||
if "+CME ERROR: Operation not allowed" in line:
|
|
||||||
print('<span style="color: red;font-weight: bold;">⚠️ATTENTION: CME ERROR⚠️</span>')
|
|
||||||
print('<span style="color: orange;font-weight: bold;">❓Try Reboot the module❓</span>')
|
|
||||||
#Software Reboot
|
|
||||||
|
|
||||||
if "ERROR" in line:
|
# Extract just the error code
|
||||||
print("⛔Attention ERROR!⛔")
|
error_code = extract_error_code(response_SARA_9)
|
||||||
#Send notification (WIFI)
|
|
||||||
send_error_notification(device_id, "SARA CME ERROR")
|
|
||||||
|
|
||||||
#Hardware Reboot
|
if error_code is not None:
|
||||||
hardware_reboot_success = modem_hardware_reboot()
|
# Display interpretation based on error code
|
||||||
if hardware_reboot_success:
|
if error_code == 0:
|
||||||
print("✅Modem successfully rebooted and reinitialized")
|
print('<p class="text-success">No error detected</p>')
|
||||||
|
# INVALID SERVER HOSTNAME
|
||||||
|
elif error_code == 4:
|
||||||
|
print('<p class="text-danger">Error 4: AirCarto - Invalid server Hostname</p>')
|
||||||
|
send_error_notification(device_id, "UHTTPER (error n°4) -> AirCarto Invalid Server Hostname")
|
||||||
|
server_hostname_resets = reset_server_hostname(aircarto_profile_id)
|
||||||
|
if server_hostname_resets:
|
||||||
|
print("✅server hostname reset successfully")
|
||||||
|
else:
|
||||||
|
print("⛔There were issues with the modem server hostname reinitialize process")
|
||||||
|
# SERVER CONNECTION ERROR
|
||||||
|
elif error_code == 11:
|
||||||
|
print('<p class="text-danger">Error 11: Server connection error</p>')
|
||||||
|
hardware_reboot_success = modem_hardware_reboot()
|
||||||
|
if hardware_reboot_success:
|
||||||
|
print("✅Modem successfully rebooted and reinitialized")
|
||||||
|
else:
|
||||||
|
print("⛔There were issues with the modem reboot/reinitialize process")
|
||||||
|
# PSD OR CSD ERROR
|
||||||
|
elif error_code == 22:
|
||||||
|
print('<p class="text-danger">⚠️Error 22: PSD or CSD connection not established (SARA-R5 need to reset PDP conection)⚠️</p>')
|
||||||
|
send_error_notification(device_id, "UHTTPER (error n°22) -> PSD or CSD connection not established")
|
||||||
|
psd_csd_resets = reset_PSD_CSD_connection()
|
||||||
|
if psd_csd_resets:
|
||||||
|
print("✅PSD CSD connection reset successfully")
|
||||||
|
else:
|
||||||
|
print("⛔There were issues with the modem CSD PSD reinitialize process")
|
||||||
|
# CONNECTION TIMED OUT
|
||||||
|
elif error_code == 26:
|
||||||
|
print('<p class="text-danger">Error 26: Connection timed out</p>')
|
||||||
|
send_error_notification(device_id, "UHTTPER (error n°26) -> Connection timed out")
|
||||||
|
# CONNECTION LOST
|
||||||
|
elif error_code == 44:
|
||||||
|
print('<p class="text-danger">Error 44: Connection lost</p>')
|
||||||
|
send_error_notification(device_id, "UHTTPER (error n°44) -> Connection lost")
|
||||||
|
# SECURE SOCKET ERROR
|
||||||
|
elif error_code == 73:
|
||||||
|
print('<p class="text-danger">Error 73: Secure socket connect error</p>')
|
||||||
|
else:
|
||||||
|
print(f'<p class="text-danger">Unknown error code: {error_code}</p>')
|
||||||
|
else:
|
||||||
|
print('<p class="text-danger">Could not extract error code from response</p>')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 2.2 code 1 (✅✅HHTP / UUHTTPCR succeded✅✅)
|
||||||
else:
|
else:
|
||||||
print("⛔There were issues with the modem reboot/reinitialize process")
|
print('<span style="font-weight: bold;">✅✅HTTP operation successful.</span>')
|
||||||
|
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:")
|
||||||
|
command = f'AT+URDFILE="aircarto_server_response.txt""\r'
|
||||||
|
ser_sara.write((command + '\r').encode('utf-8'))
|
||||||
|
response_SARA_4 = read_complete_response(ser_sara, wait_for_lines=["OK"], debug=False)
|
||||||
|
print('<p class="text-success">')
|
||||||
|
print(response_SARA_4)
|
||||||
|
print("</p>", end="")
|
||||||
|
|
||||||
|
#Parse the server datetime
|
||||||
|
# Extract just the date from the response
|
||||||
|
date_string = None
|
||||||
|
server_datetime = ""
|
||||||
|
date_start = response_SARA_4.find("Date: ")
|
||||||
|
if date_start != -1:
|
||||||
|
date_end = response_SARA_4.find("\n", date_start)
|
||||||
|
date_string = response_SARA_4[date_start + 6:date_end].strip()
|
||||||
|
print(f'<div class="text-primary">Server date: {date_string}</div>', end="")
|
||||||
|
|
||||||
|
# Optionally convert to datetime object
|
||||||
|
try:
|
||||||
|
from datetime import datetime
|
||||||
|
server_datetime = datetime.strptime(
|
||||||
|
date_string,
|
||||||
|
"%a, %d %b %Y %H:%M:%S %Z"
|
||||||
|
)
|
||||||
|
#print(f'<p class="text-primary">Parsed datetime: {server_datetime}</p>')
|
||||||
|
except Exception as e:
|
||||||
|
print(f'<p class="text-warning">Error parsing date: {e}</p>')
|
||||||
|
|
||||||
|
# Get RTC time from SQLite
|
||||||
|
cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
|
||||||
|
row = cursor.fetchone()
|
||||||
|
rtc_time_str = row[1] # '2025-02-07 12:30:45' or '2000-01-01 00:55:21' or 'not connected'
|
||||||
|
print(f'<div class="text-primary">RTC time: {rtc_time_str}</div>', end="")
|
||||||
|
|
||||||
|
# Compare times if both are available
|
||||||
|
if server_datetime and rtc_time_str != 'not connected':
|
||||||
|
try:
|
||||||
|
# Convert RTC time string to datetime
|
||||||
|
rtc_datetime = datetime.strptime(rtc_time_str, '%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
# Calculate time difference in seconds
|
||||||
|
time_diff = abs((server_datetime - rtc_datetime).total_seconds())
|
||||||
|
|
||||||
|
print(f'<div class="text-primary">Time difference: {time_diff:.2f} seconds</div>', end="")
|
||||||
|
|
||||||
|
# Check if difference is more than 60 seconds
|
||||||
|
# and update the RTC clock
|
||||||
|
if time_diff > 60:
|
||||||
|
print(f'<div class="text-warning"><strong>⚠️ RTC time differs from server time by {time_diff:.2f} seconds!</strong></div>', end="")
|
||||||
|
# Format server time for RTC update
|
||||||
|
server_time_formatted = server_datetime.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
#update RTC module do not wait for answer, non blocking
|
||||||
|
#/usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/set_with_browserTime.py '2024-01-30 12:48:39'
|
||||||
|
# Launch RTC update script as non-blocking subprocess
|
||||||
|
import subprocess
|
||||||
|
update_command = [
|
||||||
|
"/usr/bin/python3",
|
||||||
|
"/var/www/nebuleair_pro_4g/RTC/set_with_browserTime.py",
|
||||||
|
server_time_formatted
|
||||||
|
]
|
||||||
|
|
||||||
|
# Execute the command without waiting for result
|
||||||
|
subprocess.Popen(update_command,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL)
|
||||||
|
|
||||||
|
print(f'<div class="text-warning">➡️ Updating RTC with server time: {server_time_formatted}</div>', end="")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(f'<div class="text-success">✅ RTC time is synchronized with server time (within 60 seconds)</div>')
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f'<p class="text-warning">Error comparing times: {e}</p>')
|
||||||
|
|
||||||
|
|
||||||
#5. empty json
|
#Si non ne recoit pas de réponse UHTTPCR
|
||||||
print("Empty SARA memory:")
|
#on a peut être une ERROR de type "+CME ERROR: No connection to phone" ou "Operation not allowed" ou "ERROR"
|
||||||
command = f'AT+UDELFILE="sensordata_csv.json"\r'
|
else:
|
||||||
ser_sara.write((command + '\r').encode('utf-8'))
|
print('<span style="color: red;font-weight: bold;">No UUHTTPCR response</span>')
|
||||||
response_SARA_5 = read_complete_response(ser_sara, wait_for_lines=["OK","+CME ERROR"], debug=True)
|
print("Blink red LED")
|
||||||
print('<p class="text-danger-emphasis">')
|
# Run LED blinking in a separate thread
|
||||||
print(response_SARA_5)
|
led_thread = Thread(target=blink_led, args=(24, 5, 0.5))
|
||||||
print("</p>", end="")
|
led_thread.start()
|
||||||
|
#Vérification de l'erreur
|
||||||
|
print("Getting type of error")
|
||||||
|
# Split the response into lines and search for "+CME ERROR:"
|
||||||
|
lines2 = response_SARA_3.strip().splitlines()
|
||||||
|
for line in lines2:
|
||||||
|
if "+CME ERROR" in line:
|
||||||
|
error_message = line.split("+CME ERROR:")[1].strip()
|
||||||
|
print("*****")
|
||||||
|
print('<span style="color: red;font-weight: bold;">⚠️ATTENTION: CME ERROR⚠️</span>')
|
||||||
|
print(f"Error type: {error_message}")
|
||||||
|
print("*****")
|
||||||
|
# Handle "No connection to phone" error
|
||||||
|
if error_message == "No connection to phone":
|
||||||
|
print('<span style="color: orange;font-weight: bold;">📞Try reconnect to network📞</span>')
|
||||||
|
#IMPORTANT!
|
||||||
|
# Reconnexion au réseau (AT+COPS)
|
||||||
|
command = f'AT+COPS=1,2,{selected_networkID}\r'
|
||||||
|
#command = f'AT+COPS=0\r'
|
||||||
|
ser_sara.write(command.encode('utf-8'))
|
||||||
|
responseReconnect = read_complete_response(ser_sara, timeout=5, end_of_response_timeout=120, wait_for_lines=["OK", "+CME ERROR"], debug=True)
|
||||||
|
print('<p class="text-danger-emphasis">')
|
||||||
|
print(responseReconnect)
|
||||||
|
print("</p>", end="")
|
||||||
|
# Handle "Operation not allowed" error
|
||||||
|
if error_message == "Operation not allowed":
|
||||||
|
print('<span style="color: orange;font-weight: bold;">❓Try Resetting the HTTP Profile❓</span>')
|
||||||
|
command = f'AT+UHTTP={aircarto_profile_id},1,"data.nebuleair.fr"\r'
|
||||||
|
ser_sara.write(command.encode('utf-8'))
|
||||||
|
responseResetHTTP_profile = read_complete_response(ser_sara, timeout=5, end_of_response_timeout=5, wait_for_lines=["OK", "+CME ERROR"], debug=True)
|
||||||
|
print('<p class="text-danger-emphasis">')
|
||||||
|
print(responseResetHTTP_profile)
|
||||||
|
print("</p>", end="")
|
||||||
|
check_lines = responseResetHTTP_profile.strip().splitlines()
|
||||||
|
for line in check_lines:
|
||||||
|
if "+CME ERROR: Operation not allowed" in line:
|
||||||
|
print('<span style="color: red;font-weight: bold;">⚠️ATTENTION: CME ERROR⚠️</span>')
|
||||||
|
print('<span style="color: orange;font-weight: bold;">❓Try Reboot the module❓</span>')
|
||||||
|
#Software Reboot
|
||||||
|
|
||||||
if "+CME ERROR" in response_SARA_5:
|
if "ERROR" in line:
|
||||||
print("⛔ Attention CME ERROR ⛔")
|
print("⛔Attention ERROR!⛔")
|
||||||
|
#Send notification (WIFI)
|
||||||
|
send_error_notification(device_id, "SARA CME ERROR")
|
||||||
|
|
||||||
|
#Hardware Reboot
|
||||||
|
hardware_reboot_success = modem_hardware_reboot()
|
||||||
|
if hardware_reboot_success:
|
||||||
|
print("✅Modem successfully rebooted and reinitialized")
|
||||||
|
else:
|
||||||
|
print("⛔There were issues with the modem reboot/reinitialize process")
|
||||||
|
|
||||||
|
|
||||||
|
#5. empty json
|
||||||
|
print("Empty SARA memory:")
|
||||||
|
command = f'AT+UDELFILE="sensordata_csv.json"\r'
|
||||||
|
ser_sara.write((command + '\r').encode('utf-8'))
|
||||||
|
response_SARA_5 = read_complete_response(ser_sara, wait_for_lines=["OK","+CME ERROR"], debug=True)
|
||||||
|
print('<p class="text-danger-emphasis">')
|
||||||
|
print(response_SARA_5)
|
||||||
|
print("</p>", end="")
|
||||||
|
|
||||||
|
if "+CME ERROR" in response_SARA_5:
|
||||||
|
print("⛔ Attention CME ERROR ⛔")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,9 @@ config_entries = [
|
|||||||
("SARA_R4_network_status", "connected", "str"),
|
("SARA_R4_network_status", "connected", "str"),
|
||||||
("SARA_R4_neworkID", "20810", "int"),
|
("SARA_R4_neworkID", "20810", "int"),
|
||||||
("WIFI_status", "connected", "str"),
|
("WIFI_status", "connected", "str"),
|
||||||
|
("send_aircarto", "1", "bool"),
|
||||||
("send_uSpot", "0", "bool"),
|
("send_uSpot", "0", "bool"),
|
||||||
|
("send_miotiq", "0", "bool"),
|
||||||
("npm_5channel", "0", "bool"),
|
("npm_5channel", "0", "bool"),
|
||||||
("envea", "0", "bool"),
|
("envea", "0", "bool"),
|
||||||
("windMeter", "0", "bool"),
|
("windMeter", "0", "bool"),
|
||||||
|
|||||||
Reference in New Issue
Block a user