This commit is contained in:
Your Name
2025-02-21 11:02:21 +01:00
parent cf9e373ea8
commit 105e439199
17 changed files with 477 additions and 12 deletions

View File

@@ -39,7 +39,7 @@ import sqlite3
import time import time
# Connect to the SQLite database # Connect to the SQLite database
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
cursor = conn.cursor() cursor = conn.cursor()
def load_config(config_file): def load_config(config_file):
@@ -52,7 +52,7 @@ def load_config(config_file):
return {} return {}
# Load the configuration data # Load the configuration data
config_file = '/var/www/nebuleair_pro_4g/config.json' config_file = '/var/www/moduleair_pro_4g/config.json'
config = load_config(config_file) config = load_config(config_file)
npm_solo_port = config.get('NPM_solo_port', '') #port du NPM solo npm_solo_port = config.get('NPM_solo_port', '') #port du NPM solo

View File

@@ -12,7 +12,7 @@ git config --global user.email "paulvuarambon@gmail.com"
git config --global user.name "PaulVua" git config --global user.name "PaulVua"
sudo gh repo clone aircarto/moduleair_pro_4g /var/www/moduleair_pro_4g sudo gh repo clone aircarto/moduleair_pro_4g /var/www/moduleair_pro_4g
sudo mkdir /var/www/moduleair_pro_4g/logs sudo mkdir /var/www/moduleair_pro_4g/logs
sudo touch /var/www/moduleair_pro_4g/logs/app.log /var/www/moduleair_pro_4g/logs/loop.log matrix/input_NPM.txt matrix/input_MHZ16.txt sudo touch /var/www/moduleair_pro_4g/logs/app.log /var/www/moduleair_pro_4g/logs/loop.log /var/www/moduleair_pro_4g/matrix/input_NPM.txt /var/www/moduleair_pro_4g/matrix/input_MHZ16.txt /var/www/moduleair_pro_4g/wifi_list.csv
sudo cp /var/www/moduleair_pro_4g/config.json.dist /var/www/moduleair_pro_4g/config.json sudo cp /var/www/moduleair_pro_4g/config.json.dist /var/www/moduleair_pro_4g/config.json
sudo chmod -R 777 /var/www/moduleair_pro_4g/ sudo chmod -R 777 /var/www/moduleair_pro_4g/
``` ```
@@ -53,6 +53,25 @@ www-data ALL=(ALL) NOPASSWD: /usr/bin/ssh
www-data ALL=(ALL) NOPASSWD: /usr/bin/python3 * www-data ALL=(ALL) NOPASSWD: /usr/bin/python3 *
``` ```
## I2C
Decibel meter, BME280 and the RTC module (DS3231) is connected via I2C.
Need to activate by modifying `sudo nano /boot/firmware/config.txt`
```
dtparam=i2c_arm=on
```
And authorize access to `/dev/i2c-1`.
```
sudo chmod 777 /dev/i2c-1
```
Attention: sometimes activation with config.txt do not work, you need to activate i2c with `sudo raspi-config` and go to "Interface" -> I2C -> enable.
It is possible to manage raspi-config only with cli: `sudo raspi-config nonint do_i2c 0`
I2C addresses: use `sudo i2cdetect -y 1` to check the connected devices
## Matrix LED ## Matrix LED
### Library ### Library

77
RTC/read.py Executable file
View File

@@ -0,0 +1,77 @@
'''
____ _____ ____
| _ \_ _/ ___|
| |_) || || |
| _ < | || |___
|_| \_\|_| \____|
Script to read time from RTC module
I2C connection
Address 0x68
/usr/bin/python3 /var/www/moduleair_pro_4g/RTC/read.py
'''
import smbus2
import time
import json
from datetime import datetime
# 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))
if __name__ == "__main__":
main()

90
RTC/save_to_db.py Executable file
View File

@@ -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/moduleair_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/moduleair_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()

97
RTC/set_with_NTP.py Executable file
View File

@@ -0,0 +1,97 @@
"""
Script to set the RTC using an NTP server.
RPI needs to be connected to the internet (WIFI).
Requires ntplib and pytz:
sudo pip3 install ntplib pytz --break-system-packages
/usr/bin/python3 /var/www/moduleair_pro_4g/RTC/set_with_NTP.py
"""
import smbus2
import time
from datetime import datetime
import ntplib
import pytz # For timezone handling
# DS3231 I2C address
DS3231_ADDR = 0x68
# Registers for DS3231
REG_TIME = 0x00
def bcd_to_dec(bcd):
"""Convert BCD to decimal."""
return (bcd // 16 * 10) + (bcd % 16)
def dec_to_bcd(dec):
"""Convert decimal to BCD."""
return (dec // 10 * 16) + (dec % 10)
def set_time(bus, year, month, day, hour, minute, second):
"""Set the RTC time."""
# Convert the time to BCD format
second_bcd = dec_to_bcd(second)
minute_bcd = dec_to_bcd(minute)
hour_bcd = dec_to_bcd(hour)
day_bcd = dec_to_bcd(day)
month_bcd = dec_to_bcd(month)
year_bcd = dec_to_bcd(year - 2000) # DS3231 uses year from 2000
# Write time to DS3231
bus.write_i2c_block_data(DS3231_ADDR, REG_TIME, [
second_bcd,
minute_bcd,
hour_bcd,
0x01, # Day of the week (1=Monday, etc.)
day_bcd,
month_bcd,
year_bcd
])
def read_time(bus):
"""Read the RTC time."""
data = bus.read_i2c_block_data(DS3231_ADDR, REG_TIME, 7)
second = bcd_to_dec(data[0] & 0x7F)
minute = bcd_to_dec(data[1])
hour = 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 (year, month, day, hour, minute, second)
def get_internet_time():
"""Get the current time from an NTP server."""
ntp_client = ntplib.NTPClient()
response = ntp_client.request('pool.ntp.org')
utc_time = datetime.utcfromtimestamp(response.tx_time)
return utc_time
def main():
bus = smbus2.SMBus(1)
# Get the current time from the RTC
year, month, day, hours, minutes, seconds = read_time(bus)
rtc_time = datetime(year, month, day, hours, minutes, seconds)
# Get current UTC time from an NTP server
try:
internet_utc_time = get_internet_time()
print(f"Time from Internet (UTC) : {internet_utc_time.strftime('%Y-%m-%d %H:%M:%S')}")
except Exception as e:
print(f"Error retrieving time from the internet: {e}")
return
# Print current RTC time
print(f"Actual RTC Time : {rtc_time.strftime('%Y-%m-%d %H:%M:%S')}")
# Set the RTC to UTC time
set_time(bus, internet_utc_time.year, internet_utc_time.month, internet_utc_time.day,
internet_utc_time.hour, internet_utc_time.minute, internet_utc_time.second)
# Read and print the new time from RTC
year, month, day, hour, minute, second = read_time(bus)
rtc_time_new = datetime(year, month, day, hour, minute, second)
print(f"New RTC Time (UTC) : {rtc_time_new.strftime('%Y-%m-%d %H:%M:%S')}")
if __name__ == "__main__":
main()

47
RTC/set_with_browserTime.py Executable file
View File

@@ -0,0 +1,47 @@
"""
Script to set the RTC using the browser time.
/usr/bin/python3 /var/www/moduleair_pro_4g/RTC/set_with_browserTime.py '2024-01-30 12:48:39'
"""
import sys
from datetime import datetime
import smbus2
# DS3231 I2C address
DS3231_ADDR = 0x68
REG_TIME = 0x00
def dec_to_bcd(dec):
"""Convert decimal to BCD."""
return (dec // 10 * 16) + (dec % 10)
def set_rtc(bus, year, month, day, hour, minute, second):
"""Set the RTC time."""
second_bcd = dec_to_bcd(second)
minute_bcd = dec_to_bcd(minute)
hour_bcd = dec_to_bcd(hour)
day_bcd = dec_to_bcd(day)
month_bcd = dec_to_bcd(month)
year_bcd = dec_to_bcd(year - 2000) # RTC stores years since 2000
bus.write_i2c_block_data(DS3231_ADDR, REG_TIME, [
second_bcd, minute_bcd, hour_bcd, 0x01, day_bcd, month_bcd, year_bcd
])
def main():
if len(sys.argv) != 2:
print("Usage: python3 set_rtc.py 'YYYY-MM-DD HH:MM:SS'")
sys.exit(1)
rtc_time_str = sys.argv[1]
rtc_time = datetime.strptime(rtc_time_str, '%Y-%m-%d %H:%M:%S')
bus = smbus2.SMBus(1)
set_rtc(bus, rtc_time.year, rtc_time.month, rtc_time.day,
rtc_time.hour, rtc_time.minute, rtc_time.second)
print(f"RTC updated to: {rtc_time}")
if __name__ == "__main__":
main()

95
boot_hotspot.sh Executable file
View File

@@ -0,0 +1,95 @@
#!/bin/bash
# Script to check if wifi is connected and start hotspot if not
# will also retreive unique RPi ID and store it to deviceID.txt
# Script launched by cron job
# @reboot /var/www/moduleair_pro_4g/boot_hotspot.sh >> /var/www/moduleair_pro_4g/logs/app.log 2>&1
OUTPUT_FILE="/var/www/moduleair_pro_4g/wifi_list.csv"
JSON_FILE="/var/www/moduleair_pro_4g/config.json"
echo "-------------------"
echo "-------------------"
echo "NebuleAir pro started at $(date)"
# Blink GPIO 23 and 24 five times
for i in {1..5}; do
# Turn GPIO 23 and 24 ON
gpioset gpiochip0 23=1 24=1
#echo "LEDs ON"
sleep 1
# Turn GPIO 23 and 24 OFF
gpioset gpiochip0 23=0 24=0
#echo "LEDs OFF"
sleep 1
done
echo "getting SARA R4 serial number"
# Get the last 8 characters of the serial number and write to text file
serial_number=$(cat /proc/cpuinfo | grep Serial | awk '{print substr($3, length($3) - 7)}')
# Define the JSON file path
# Use jq to update the "deviceID" in the JSON file
jq --arg serial_number "$serial_number" '.deviceID = $serial_number' "$JSON_FILE" > temp.json && mv temp.json "$JSON_FILE"
echo "id: $serial_number"
#get the SSH port for tunneling
SSH_TUNNEL_PORT=$(jq -r '.sshTunnel_port' "$JSON_FILE")
#need to wait for the network manager to be ready
sleep 20
# Get the connection state of wlan0
STATE=$(nmcli -g GENERAL.STATE device show wlan0)
# Check if the state is 'disconnected'
if [ "$STATE" == "30 (disconnected)" ]; then
echo "wlan0 is disconnected."
echo "need to perform a wifi scan"
# Perform a wifi scan and save its output to a csv file
# nmcli device wifi list
nmcli -f SSID,SIGNAL,SECURITY device wifi list | awk 'BEGIN { OFS=","; print "SSID,SIGNAL,SECURITY" } NR>1 { print $1,$2,$3 }' > "$OUTPUT_FILE"
# Start the hotspot
echo "Starting hotspot..."
sudo nmcli device wifi hotspot ifname wlan0 ssid nebuleair_pro password nebuleaircfg
# Update JSON to reflect hotspot mode
jq --arg status "hotspot" '.WIFI_status = $status' "$JSON_FILE" > temp.json && mv temp.json "$JSON_FILE"
else
echo "Success: wlan0 is connected!"
CONN_SSID=$(nmcli -g GENERAL.CONNECTION device show wlan0)
echo "Connection: $CONN_SSID"
#update config JSON file
jq --arg status "connected" '.WIFI_status = $status' "$JSON_FILE" > temp.json && mv temp.json "$JSON_FILE"
sudo chmod 777 "$JSON_FILE"
# Lancer le tunnel SSH
echo "Démarrage du tunnel SSH sur le port $SSH_TUNNEL_PORT..."
# Start the SSH agent if it's not already running
eval "$(ssh-agent -s)"
# Add your SSH private key
ssh-add /home/airlab/.ssh/id_rsa
#connections details
REMOTE_USER="airlab_server1" # Remplacez par votre nom d'utilisateur distant
REMOTE_SERVER="aircarto.fr" # Remplacez par l'adresse de votre serveur
LOCAL_PORT=22 # Port local à rediriger
MONITOR_PORT=0 # Désactive la surveillance de connexion autossh
#autossh -M "$MONITOR_PORT" -f -N -R "$SSH_TUNNEL_PORT:localhost:$LOCAL_PORT" "$REMOTE_USER@$REMOTE_SERVER" -p 50221
# ssh -f -N -R 52221:localhost:22 -p 50221 airlab_server1@aircarto.fr
ssh -i /var/www/.ssh/id_rsa -f -N -R "$SSH_TUNNEL_PORT:localhost:$LOCAL_PORT" -p 50221 -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_SERVER"
#Check if the tunnel was created successfully
if [ $? -eq 0 ]; then
echo "Tunnel started successfully!"
else
echo "Error: Unable to start the tunnel!"
exit 1
fi
fi
echo "-------------------"

32
connexion.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/bash
#script started by the user via the web interface
#$1 and $2 are SSID and Password (arguments passed via the php script launcher.php)
echo "-------"
echo "Start connexion shell script at $(date)"
#disable hotspot
echo "Disable Hotspot:"
sudo nmcli connection down Hotspot
sleep 10
echo "Start connection with:"
echo "SSID: $1"
echo "Password: $2"
sudo nmcli device wifi connect "$1" password "$2"
#check if connection is successfull
if [ $? -eq 0 ]; then
echo "Connection to $1 is successfull"
else
echo "Connection to $1 failed"
echo "Restarting hotspot..."
#enable hotspot
sudo nmcli connection up Hotspot
fi
echo "End connexion shell script"
echo "-------"

View File

@@ -1,4 +1,11 @@
@reboot chmod 777 /dev/ttyAMA* /dev/i2c-1 @reboot chmod 777 /dev/ttyAMA* /dev/i2c-1
@reboot /var/www/moduleair_pro_4g/boot_hotspot.sh >> /var/www/moduleair_pro_4g/logs/app.log 2>&1
@reboot sleep 30 && /usr/bin/python3 /var/www/moduleair_pro_4g/SARA/sara_setURL.py ttyAMA2 data.moduleair.fr 0 >> /var/www/moduleair_pro_4g/logs/app.log 2>&1
@reboot /var/www/moduleair_pro_4g/run_every_10_seconds.sh @reboot /var/www/moduleair_pro_4g/run_every_10_seconds.sh
0 0 * * * > /var/www/moduleair_pro_4g/logs/master.log

0
html/assets/img/logoModuleAirColor_long.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 233 KiB

After

Width:  |  Height:  |  Size: 233 KiB

View File

@@ -402,7 +402,7 @@ if ($type == "wifi_connect") {
$script_path = '/var/www/moduleair_pro_4g/connexion.sh'; $script_path = '/var/www/moduleair_pro_4g/connexion.sh';
$log_file = '/var/www/moduleair_pro_4g/logs/app.log'; $log_file = '/var/www/moduleair_pro_4g/logs/app.log';
shell_exec("$script_path $SSID $PASS >> $log_file 2>&1 &"); shell_exec("$script_path $SSID $PASS >> $log_file 2>&1 &"); #on passe ici en argument le nom du réseau WIFI et le Password
#$output = shell_exec('sudo nmcli connection down Hotspot'); #$output = shell_exec('sudo nmcli connection down Hotspot');
#$output2 = shell_exec('sudo nmcli device wifi connect "AirLab" password "123plouf"'); #$output2 = shell_exec('sudo nmcli device wifi connect "AirLab" password "123plouf"');

View File

@@ -13,20 +13,21 @@ Attention:
First time: need to create the service file First time: need to create the service file
-->sudo nano /etc/systemd/system/master_nebuleair.service -->
sudo nano /etc/systemd/system/master_nebuleair.service
<--
⬇️ ⬇️
[Unit] [Unit]
Description=Master manager for the Python loop scripts Description=Master manager for the Python loop scripts
After=network.target After=network.target
[Service] [Service]
ExecStart=/usr/bin/python3 /var/www/nebuleair_pro_4g/master.py ExecStart=/usr/bin/python3 /var/www/moduleair_pro_4g/master.py
Restart=always Restart=always
User=root User=root
WorkingDirectory=/var/www/nebuleair_pro_4g WorkingDirectory=/var/www/moduleair_pro_4g
StandardOutput=append:/var/www/nebuleair_pro_4g/logs/master.log StandardOutput=append:/var/www/moduleair_pro_4g/logs/master.log
StandardError=append:/var/www/nebuleair_pro_4g/logs/master_errors.log StandardError=append:/var/www/moduleair_pro_4g/logs/master_errors.log
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
@@ -56,8 +57,8 @@ import json
import os import os
# Base directory where scripts are stored # Base directory where scripts are stored
SCRIPT_DIR = "/var/www/nebuleair_pro_4g/" SCRIPT_DIR = "/var/www/moduleair_pro_4g/"
CONFIG_FILE = "/var/www/nebuleair_pro_4g/config.json" CONFIG_FILE = "/var/www/moduleair_pro_4g/config.json"
def load_config(): def load_config():
"""Load the configuration file to determine which scripts to run.""" """Load the configuration file to determine which scripts to run."""

0
sqlite/create_db.py Normal file → Executable file
View File

0
sqlite/flush_old_data.py Normal file → Executable file
View File

0
sqlite/read.py Normal file → Executable file
View File

0
sqlite/read_select_date.py Normal file → Executable file
View File

0
sqlite/write.py Normal file → Executable file
View File