diff --git a/boot_hotspot.sh b/boot_hotspot.sh index 8dac2f8..a9a4311 100755 --- a/boot_hotspot.sh +++ b/boot_hotspot.sh @@ -12,6 +12,8 @@ echo "-------------------" echo "NebuleAir pro started at $(date)" +chmod -R 777 /var/www/nebuleair_pro_4g/ + # Blink GPIO 23 and 24 five times for i in {1..5}; do # Turn GPIO 23 and 24 ON diff --git a/cron_jobs b/cron_jobs index 9b0ac33..84a9c4c 100755 --- a/cron_jobs +++ b/cron_jobs @@ -5,3 +5,6 @@ @reboot sleep 30 && /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/reboot/start.py >> /var/www/nebuleair_pro_4g/logs/app.log 2>&1 0 0 * * * > /var/www/nebuleair_pro_4g/logs/master.log +0 0 * * * > /var/www/nebuleair_pro_4g/logs/master_errors.log +0 0 * * * > /var/www/nebuleair_pro_4g/logs/app.log + diff --git a/loop/SARA_send_data_v2.py b/loop/SARA_send_data_v2.py index 8047bdd..e6ae4e5 100755 --- a/loop/SARA_send_data_v2.py +++ b/loop/SARA_send_data_v2.py @@ -304,6 +304,121 @@ def extract_error_code(response): # Return None if we couldn't find the error code return None +def modem_complete_reboot_and_reinitialize(modem_version, aircarto_profile_id): + """ + Performs a complete modem restart sequence: + 1. Reboots the modem using the appropriate command for its version + 2. Waits for the modem to restart + 3. Resets the HTTP profile + 4. For SARA-R5, resets the PDP connection + + Args: + modem_version (str): The modem version, e.g., 'SARA-R500' or 'SARA-R410' + aircarto_profile_id (int): The HTTP profile ID to reset + + Returns: + bool: True if the complete sequence was successful, False otherwise + """ + print('🔄 Complete SARA reboot and reinitialize sequence 🔄') + + # Step 1: Reboot the modem - Integrated modem_software_reboot logic + print('🔄 Software SARA reboot! 🔄') + + # Use different commands based on modem version + if 'R5' in modem_version: # For SARA-R5 series + command = 'AT+CFUN=16\r' # Normal restart for R5 + else: # For SARA-R4 series + command = 'AT+CFUN=15\r' # Factory reset for R4 + + ser_sara.write(command.encode('utf-8')) + response = read_complete_response(ser_sara, wait_for_lines=["OK", "ERROR"], debug=True) + + print('

') + print(response) + print("

", end="") + + # Check if reboot command was acknowledged + reboot_success = response is not None and "OK" in response + if not reboot_success: + print("⚠️ Modem reboot command failed") + return False + + # Step 2: Wait for the modem to restart (adjust time as needed) + print("Waiting for modem to restart...") + time.sleep(15) # 15 seconds should be enough for most modems to restart + + # Step 3: Check if modem is responsive after reboot + print("Checking if modem is responsive...") + ser_sara.write(b'AT\r') + response_check = read_complete_response(ser_sara, wait_for_lines=["OK"], debug=True) + if response_check is None or "OK" not in response_check: + print("⚠️ Modem not responding after reboot") + return False + + print("✅ Modem restarted successfully") + + # Step 4: Reset the HTTP Profile + print('🔧 Resetting the HTTP Profile') + command = f'AT+UHTTP={aircarto_profile_id},1,"data.nebuleair.fr"\r' + ser_sara.write(command.encode('utf-8')) + responseResetHTTP = read_complete_response(ser_sara, timeout=5, end_of_response_timeout=5, + wait_for_lines=["OK", "+CME ERROR"], debug=True) + print('

') + print(responseResetHTTP) + print("

", end="") + + http_reset_success = responseResetHTTP is not None and "OK" in responseResetHTTP + if not http_reset_success: + print("⚠️ HTTP profile reset failed") + # Continue anyway, don't return False here + + # Step 5: For SARA-R5, reset the PDP connection + pdp_reset_success = True + if modem_version == "SARA-R500": + print("⚠️ Need to reset PDP connection for SARA-R500") + + # Activate PDP context 1 + print('➡️ Activate PDP context 1') + command = f'AT+CGACT=1,1\r' + ser_sara.write(command.encode('utf-8')) + response_pdp1 = read_complete_response(ser_sara, wait_for_lines=["OK"]) + print(response_pdp1, end="") + pdp_reset_success = pdp_reset_success and (response_pdp1 is not None and "OK" in response_pdp1) + time.sleep(1) + + # Set the PDP type + print('➡️ Set the PDP type to IPv4 referring to the output of the +CGDCONT read command') + command = f'AT+UPSD=0,0,0\r' + ser_sara.write(command.encode('utf-8')) + response_pdp2 = read_complete_response(ser_sara, wait_for_lines=["OK"]) + print(response_pdp2, end="") + pdp_reset_success = pdp_reset_success and (response_pdp2 is not None and "OK" in response_pdp2) + time.sleep(1) + + # Profile #0 is mapped on CID=1 + print('➡️ Profile #0 is mapped on CID=1.') + command = f'AT+UPSD=0,100,1\r' + ser_sara.write(command.encode('utf-8')) + response_pdp3 = read_complete_response(ser_sara, wait_for_lines=["OK"]) + print(response_pdp3, end="") + pdp_reset_success = pdp_reset_success and (response_pdp3 is not None and "OK" in response_pdp3) + time.sleep(1) + + # Activate the PSD profile + print('➡️ Activate the PSD profile #0: the IPv4 address is already assigned by the network.') + command = f'AT+UPSDA=0,3\r' + ser_sara.write(command.encode('utf-8')) + response_pdp4 = read_complete_response(ser_sara, wait_for_lines=["OK", "+UUPSDA"]) + print(response_pdp4, end="") + pdp_reset_success = pdp_reset_success and (response_pdp4 is not None and ("OK" in response_pdp4 or "+UUPSDA" in response_pdp4)) + time.sleep(1) + + if not pdp_reset_success: + print("⚠️ PDP connection reset had some issues") + + # Return overall success + return http_reset_success and pdp_reset_success + try: ''' _ ___ ___ ____ @@ -479,43 +594,50 @@ try: # Getting the LTE Signal print("➡️Getting LTE signal") ser_sara.write(b'AT+CSQ\r') - response2 = read_complete_response(ser_sara, wait_for_lines=["OK"]) + response2 = read_complete_response(ser_sara, wait_for_lines=["OK", "ERROR", "+CME ERROR"]) + print('

') + print(response2) + print("

", end="") - #Here it's possible that the SARA do not repond at all + + #Here it's possible that the SARA do not repond at all or send a error message #-> TO DO : harware reboot #-> send notification #-> end loop, no need to continue - if response2 is None or response2 == "" or not any(expected in response2 for expected in ["OK", "ERROR", "+", "AT"]): + + #1. No answer at all form SARA + if response2 is None or response2 == "": print("No answer from SARA module") print('🛑STOP LOOP🛑') print("
") # Send notification try: - # Format the URL with the device_id alert_url = f'http://data.nebuleair.fr/pro_4G/alert.php?capteur_id={device_id}&error_type=serial_error' - - # Send POST request with short timeout response = requests.post(alert_url, timeout=3) - if response.status_code == 200: print(f"Alert notification sent successfully") else: print(f"Alert notification failed with status code: {response.status_code}") - except Exception as e: - # Catch any exception and continue print(f"Alert notification failed: {e}") #end loop sys.exit() + #2. si on a une erreur + elif "+CME ERROR" in response2: + print(f"SARA module returned error: {response2}") + print("The CSQ command is not supported by this module or in its current state") + print("⚠️ATTENTION: SARA is connected over serial but CSQ command not supported") + print('🛑STOP LOOP🛑') + #end loop + sys.exit() + else : print("✅SARA is connected over serial") - print('

') - print(response2) - print("

", end="") + match = re.search(r'\+CSQ:\s*(\d+),', response2) if match: signal_quality = int(match.group(1)) @@ -556,22 +678,27 @@ try: 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) + response_SARA_1 = read_complete_response(ser_sara, wait_for_lines=[">"], debug=True) + print('

') print(response_SARA_1) + print("

", end="") + 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_lines=["OK"], debug=False) + response_SARA_2 = read_complete_response(ser_sara, wait_for_lines=["OK"], debug=True) + print('

') print(response_SARA_2) + print("

", end="") #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' ser_sara.write(command.encode('utf-8')) - response_SARA_3 = read_complete_response(ser_sara, timeout=5, end_of_response_timeout=120, wait_for_lines=["+UUHTTPCR", "+CME ERROR"], debug=True) + response_SARA_3 = read_complete_response(ser_sara, timeout=5, end_of_response_timeout=120, wait_for_lines=["+UUHTTPCR", "+CME ERROR", "ERROR"], debug=True) print('

') print(response_SARA_3) @@ -678,64 +805,12 @@ try: print('

Could not extract error code from response

') - #Reboot du SARA R4 - #ATTENTION: sur le SARA R5 la commande renvoie une erreur - print('🔄SARA reboot!🔄') - command = f'AT+CFUN=15\r' - ser_sara.write(command.encode('utf-8')) - response_SARA_9r = read_complete_response(ser_sara, wait_for_lines=["OK"], debug=True) - print('

') - print(response_SARA_9r) - print("

", end="") - - reset_uSpot_url = True - - print("Sleep 10 secs before continuing") - time.sleep(10) - - #reset l'url AirCarto - print('🔧Resetting the HTTP Profile') - command = f'AT+UHTTP={aircarto_profile_id},1,"data.nebuleair.fr"\r' - ser_sara.write(command.encode('utf-8')) - responseResetHTTP2_profile = read_complete_response(ser_sara, timeout=5, end_of_response_timeout=5, wait_for_lines=["OK", "+CME ERROR"], debug=True) - print('

') - print(responseResetHTTP2_profile) - print("

", end="") - - #si on a un sara r5 il faut également reset la connection PDP - if modem_version == "SARA-R500": - print("⚠️Need to reset PDP connection") - # 2. Activate PDP context 1 - print('➡️Activate PDP context 1') - command = f'AT+CGACT=1,1\r' - ser_sara.write(command.encode('utf-8')) - response_SARA_2dpd = read_complete_response(ser_sara, wait_for_lines=["OK"]) - print(response_SARA_2dpd, end="") - time.sleep(1) - - # 2. Set the PDP type - print('➡️Set the PDP type to IPv4 referring to the outputof the +CGDCONT read command') - command = f'AT+UPSD=0,0,0\r' - ser_sara.write(command.encode('utf-8')) - response_SARA_31dpd = read_complete_response(ser_sara, wait_for_lines=["OK"]) - print(response_SARA_31dpd, end="") - time.sleep(1) - - # 2. Profile #0 is mapped on CID=1. - print('➡️Profile #0 is mapped on CID=1.') - command = f'AT+UPSD=0,100,1\r' - ser_sara.write(command.encode('utf-8')) - response_SARA_32dpd = read_complete_response(ser_sara, wait_for_lines=["OK"]) - print(response_SARA_32dpd, end="") - time.sleep(1) - - # 2. Set the PDP type - print('➡️Activate the PSD profile #0: the IPv4 address is already assigned by the network.') - command = f'AT+UPSDA=0,3\r' - ser_sara.write(command.encode('utf-8')) - response_SARA_33dpd = read_complete_response(ser_sara, wait_for_lines=["OK","+UUPSDA"]) - print(response_SARA_33dpd, end="") - time.sleep(1) + #Software Reboot + software_reboot_success = modem_complete_reboot_and_reinitialize(modem_version, aircarto_profile_id) + if software_reboot_success: + print("Modem successfully rebooted and reinitialized") + else: + print("There were issues with the modem reboot/reinitialize process") # 2.2 code 1 (✅✅HHTP / UUHTTPCR succeded✅✅) @@ -867,14 +942,30 @@ try: if "+CME ERROR: Operation not allowed" in line: print('⚠️ATTENTION: CME ERROR⚠️') print('❓Try Reboot the module❓') + #Software Reboot + if "ERROR" in line: + print("⛔Attention ERROR!⛔") + #Software Reboot + software_reboot_success = modem_complete_reboot_and_reinitialize(modem_version, aircarto_profile_id) + if software_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:") ser_sara.write(b'AT+UDELFILE="sensordata_csv.json"\r') - response_SARA_5 = read_complete_response(ser_sara, wait_for_lines=["OK"], debug=False) - print(response_SARA_5) + response_SARA_5 = read_complete_response(ser_sara, wait_for_lines=["OK","+CME ERROR"], debug=True) + print('

') + print(response_SARA_5) + print("

", end="") + + if "+CME ERROR" in response_SARA_5: + print("⛔ Attention CME ERROR ⛔") + + '''