- README: ajout section parser Miotiq avec firmware version (bytes 69-71) - error_flags.md: parser mis a jour (version_major/minor/patch + reserved 22) - error_flags.md: correction note init bytes 66-68 a 0x00 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
381 lines
12 KiB
Markdown
Executable File
381 lines
12 KiB
Markdown
Executable File
# nebuleair_pro_4g
|
|
|
|
Based on the Rpi4 or CM4.
|
|
|
|
# Installation
|
|
|
|
# Express
|
|
|
|
You can download the `installation_part1.sh` and run it:
|
|
```
|
|
wget http://gitea.aircarto.fr/PaulVua/nebuleair_pro_4g/raw/branch/main/installation_part1.sh
|
|
chmod +x installation_part1.sh
|
|
sudo ./installation_part1.sh
|
|
```
|
|
|
|
After reboot you can do the same with part 2.
|
|
|
|
```
|
|
wget http://gitea.aircarto.fr/PaulVua/nebuleair_pro_4g/raw/branch/main/installation_part2.sh
|
|
chmod +x installation_part2.sh
|
|
sudo ./installation_part2.sh
|
|
```
|
|
|
|
|
|
## General
|
|
|
|
Line by line installation.
|
|
|
|
```
|
|
sudo apt update
|
|
sudo apt install git gh apache2 sqlite3 php php-sqlite3 python3 python3-pip jq autossh i2c-tools python3-smbus -y
|
|
sudo pip3 install pyserial requests RPi.GPIO adafruit-circuitpython-bme280 crcmod psutil ntplib pytz gpiozero adafruit-circuitpython-ads1x15 numpy nsrt-mk3-dev --break-system-packages
|
|
sudo mkdir -p /var/www/.ssh
|
|
sudo ssh-keygen -t rsa -b 4096 -f /var/www/.ssh/id_rsa -N ""
|
|
sudo ssh-copy-id -i /var/www/.ssh/id_rsa.pub -p 50221 airlab_server1@aircarto.fr
|
|
sudo git clone http://gitea.aircarto.fr/PaulVua/nebuleair_pro_4g.git /var/www/nebuleair_pro_4g
|
|
sudo mkdir /var/www/nebuleair_pro_4g/logs
|
|
sudo touch /var/www/nebuleair_pro_4g/logs/app.log /var/www/nebuleair_pro_4g/logs/loop.log /var/www/nebuleair_pro_4g/wifi_list.csv
|
|
/usr/bin/python3 /var/www/nebuleair_pro_4g/sqlite/create_db.py
|
|
/usr/bin/python3 /var/www/nebuleair_pro_4g/sqlite/set_config.py
|
|
sudo chmod -R 777 /var/www/nebuleair_pro_4g/
|
|
git config --global core.fileMode false
|
|
git -C /var/www/nebuleair_pro_4g config core.fileMode false
|
|
git config --global --add safe.directory /var/www/nebuleair_pro_4g
|
|
sudo crontab /var/www/nebuleair_pro_4g/cron_jobs
|
|
sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/sqlite/create_db.py
|
|
```
|
|
## Apache
|
|
Configuration of Apache to redirect to the html homepage project
|
|
```
|
|
sudo sed -i 's|DocumentRoot /var/www/html|DocumentRoot /var/www/nebuleair_pro_4g|' /etc/apache2/sites-available/000-default.conf
|
|
sudo systemctl reload apache2
|
|
```
|
|
|
|
## Sudo athorization
|
|
To make things simpler we will allow all users to use "nmcli" as sudo without entering password. For that we need to open the sudoers file with `sudo visudo` and add this to the bottom of the file:
|
|
```
|
|
ALL ALL=(ALL) NOPASSWD: /usr/bin/nmcli, /usr/sbin/reboot
|
|
www-data ALL=(ALL) NOPASSWD: /usr/bin/git pull
|
|
www-data ALL=(ALL) NOPASSWD: /usr/bin/ssh
|
|
www-data ALL=(ALL) NOPASSWD: /usr/bin/python3 *
|
|
www-data ALL=(ALL) NOPASSWD: /bin/systemctl *
|
|
www-data ALL=(ALL) NOPASSWD: /usr/bin/pkill
|
|
www-data ALL=(ALL) NOPASSWD: /var/www/nebuleair_pro_4g/*
|
|
```
|
|
## Serial
|
|
|
|
Need to open all the uart port by modifying `sudo nano /boot/firmware/config.txt`
|
|
|
|
```
|
|
enable_uart=1
|
|
dtoverlay=uart0
|
|
dtoverlay=uart1
|
|
dtoverlay=uart2
|
|
dtoverlay=uart3
|
|
dtoverlay=uart4
|
|
dtoverlay=uart5
|
|
```
|
|
And reboot !
|
|
|
|
Then we need to authorize connection over device on `/etc/ttyAMA*`
|
|
```
|
|
sudo chmod 777 /dev/ttyAMA*
|
|
```
|
|
|
|
## 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.
|
|
|
|
### BME280
|
|
|
|
The python script is triggered by the main loop every minutes to get instant temp, hum and press values (no need to have a minute average).
|
|
BME280 address is 0x76.
|
|
|
|
### RTC module (DS3231)
|
|
|
|
|
|
|
|
### Noise sensor
|
|
|
|
As noise varies a lot, we keep the C program running every seconds to create a moving average for the last 60 seconds (we also gather max and min values).
|
|
To keep the script running at boot and stay on we create a systemd service.
|
|
|
|
Nois sensor address is 0x48.
|
|
|
|
Create the service with `sudo nano /etc/systemd/system/sound_meter.service` and add:
|
|
```
|
|
[Unit]
|
|
Description=Sound Meter Service
|
|
After=network.target
|
|
|
|
[Service]
|
|
ExecStart=/var/www/nebuleair_pro_4g/sound_meter/sound_meter_moving_avg
|
|
Restart=always
|
|
User=airlab
|
|
WorkingDirectory=/var/www/nebuleair_pro_4g/sound_meter
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
|
|
Then start the service:
|
|
```
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable sound_meter.service
|
|
|
|
sudo systemctl start sound_meter.service
|
|
```
|
|
|
|
|
|
## SSH Tunneling
|
|
|
|
To have a remote access to the RPI we can start a SSH tunneling at boot with the command:
|
|
```
|
|
ssh -p 50221 -R <device_sshTunelPort>:localhost:22 airlab_server1@aircarto.fr
|
|
```
|
|
|
|
### To make things simpler we need to connect via a ssh key.
|
|
|
|
```
|
|
ssh-keygen -t rsa -b 4096
|
|
```
|
|
|
|
And add the key to the server with `ssh-copy-id -p 50221 airlab_server1@aircarto.fr`
|
|
|
|
|
|
## Crontabs
|
|
|
|
Attention, authorization for uart are reinitialized after reboot. Need to add the command to `sudo crontab -e `
|
|
```
|
|
@reboot chmod 777 /dev/ttyAMA* /dev/i2c-1
|
|
```
|
|
|
|
And start the Hotspot check:
|
|
```
|
|
@reboot /var/www/nebuleair_pro_4g/boot_hotspot.sh >> /var/www/nebuleair_pro_4g/logs/app.log 2>&1
|
|
```
|
|
|
|
And set the base URL for Sara R4 communication:
|
|
```
|
|
@reboot sleep 30 && /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setURL.py ttyAMA2 data.nebuleair.fr >> /var/www/nebuleair_pro_4g/logs/app.log 2>&1
|
|
```
|
|
|
|
|
|
## UDP Payload Miotiq — Structure 100 bytes
|
|
|
|
| Bytes | Taille | Nom | Format | Description |
|
|
|-------|--------|-----|--------|-------------|
|
|
| 0-7 | 8 | device_id | ASCII | Identifiant unique du capteur |
|
|
| 8 | 1 | signal_quality | uint8 | Qualite signal modem (AT+CSQ) |
|
|
| 9 | 1 | protocol_version | uint8 | Version protocole (0x01) |
|
|
| 10-11 | 2 | pm1 | uint16 BE | PM1.0 en ug/m3 (x10) |
|
|
| 12-13 | 2 | pm25 | uint16 BE | PM2.5 en ug/m3 (x10) |
|
|
| 14-15 | 2 | pm10 | uint16 BE | PM10 en ug/m3 (x10) |
|
|
| 16-17 | 2 | temperature | int16 BE | Temperature en C (x100, signe) |
|
|
| 18-19 | 2 | humidity | uint16 BE | Humidite en % (x100) |
|
|
| 20-21 | 2 | pressure | uint16 BE | Pression en hPa |
|
|
| 22-23 | 2 | noise_cur_leq | uint16 BE | Bruit LEQ en dB(A) (x10) |
|
|
| 24-25 | 2 | noise_cur_level | uint16 BE | Bruit instantane en dB(A) (x10) |
|
|
| 26-27 | 2 | noise_max | uint16 BE | Bruit max en dB(A) (x10) |
|
|
| 28-29 | 2 | envea_no2 | uint16 BE | NO2 en ppb |
|
|
| 30-31 | 2 | envea_h2s | uint16 BE | H2S en ppb |
|
|
| 32-33 | 2 | envea_nh3 | uint16 BE | NH3 en ppb |
|
|
| 34-35 | 2 | envea_co | uint16 BE | CO en ppb |
|
|
| 36-37 | 2 | envea_o3 | uint16 BE | O3 en ppb |
|
|
| 38-39 | 2 | npm_ch1 | uint16 BE | NPM canal 1 (5-channel) |
|
|
| 40-41 | 2 | npm_ch2 | uint16 BE | NPM canal 2 (5-channel) |
|
|
| 42-43 | 2 | npm_ch3 | uint16 BE | NPM canal 3 (5-channel) |
|
|
| 44-45 | 2 | npm_ch4 | uint16 BE | NPM canal 4 (5-channel) |
|
|
| 46-47 | 2 | npm_ch5 | uint16 BE | NPM canal 5 (5-channel) |
|
|
| 48-49 | 2 | mppt_temperature | int16 BE | Temperature MPPT en C (x10, signe) |
|
|
| 50-51 | 2 | mppt_humidity | uint16 BE | Humidite MPPT en % (x10) |
|
|
| 52-53 | 2 | battery_voltage | uint16 BE | Tension batterie en V (x100) |
|
|
| 54-55 | 2 | battery_current | int16 BE | Courant batterie en A (x100, signe) |
|
|
| 56-57 | 2 | solar_voltage | uint16 BE | Tension solaire en V (x100) |
|
|
| 58-59 | 2 | solar_power | uint16 BE | Puissance solaire en W |
|
|
| 60-61 | 2 | charger_status | uint16 BE | Status chargeur MPPT |
|
|
| 62-63 | 2 | wind_speed | uint16 BE | Vitesse vent en m/s (x10) |
|
|
| 64-65 | 2 | wind_direction | uint16 BE | Direction vent en degres |
|
|
| 66 | 1 | error_flags | uint8 | Erreurs systeme (voir detail) |
|
|
| 67 | 1 | npm_status | uint8 | Registre status NextPM |
|
|
| 68 | 1 | device_status | uint8 | Etat general du boitier |
|
|
| 69 | 1 | version_major | uint8 | Version firmware major |
|
|
| 70 | 1 | version_minor | uint8 | Version firmware minor |
|
|
| 71 | 1 | version_patch | uint8 | Version firmware patch |
|
|
| 72-99 | 28 | reserved | — | Reserve (initialise a 0xFF) |
|
|
|
|
### Consommation data (UDP Miotiq uniquement)
|
|
|
|
Taille par paquet : 100 bytes payload + 8 bytes UDP header + 20 bytes IP header = **128 bytes**
|
|
|
|
| | Toutes les 60s | Toutes les 10s |
|
|
|---|---|---|
|
|
| Paquets/jour | 1 440 | 8 640 |
|
|
| Par jour | ~180 KB | ~1.08 MB |
|
|
| Par mois | ~5.3 MB | ~32.4 MB |
|
|
| Par an | ~63.6 MB | ~388.8 MB |
|
|
|
|
> Note : ces chiffres ne comptent que l'UDP vers Miotiq. Les envois HTTP (AirCarto) et HTTPS (uSpot) consomment des donnees supplementaires.
|
|
|
|
### Parser Miotiq
|
|
|
|
```
|
|
16|device_id|string|||W
|
|
2|signal_quality|hex2dec|dB||
|
|
2|version|hex2dec|||W
|
|
4|ISO_68|hex2dec|ugm3|x/10|
|
|
4|ISO_39|hex2dec|ugm3|x/10|
|
|
4|ISO_24|hex2dec|ugm3|x/10|
|
|
4|ISO_54|hex2dec|degC|x/100|
|
|
4|ISO_55|hex2dec|%|x/100|
|
|
4|ISO_53|hex2dec|hPa||
|
|
4|noise_cur_leq|hex2dec|dB|x/10|
|
|
4|noise_cur_level|hex2dec|dB|x/10|
|
|
4|max_noise|hex2dec|dB|x/10|
|
|
4|ISO_03|hex2dec|ppb||
|
|
4|ISO_05|hex2dec|ppb||
|
|
4|ISO_21|hex2dec|ppb||
|
|
4|ISO_04|hex2dec|ppb||
|
|
4|ISO_08|hex2dec|ppb||
|
|
4|npm_ch1|hex2dec|count||
|
|
4|npm_ch2|hex2dec|count||
|
|
4|npm_ch3|hex2dec|count||
|
|
4|npm_ch4|hex2dec|count||
|
|
4|npm_ch5|hex2dec|count||
|
|
4|npm_temp|hex2dec|°C|x/10|
|
|
4|npm_humidity|hex2dec|%|x/10|
|
|
4|battery_voltage|hex2dec|V|x/100|
|
|
4|battery_current|hex2dec|A|x/100|
|
|
4|solar_voltage|hex2dec|V|x/100|
|
|
4|solar_power|hex2dec|W||
|
|
4|charger_status|hex2dec|||
|
|
4|wind_speed|hex2dec|m/s|x/10|
|
|
4|wind_direction|hex2dec|degrees||
|
|
2|error_flags|hex2dec|||
|
|
2|npm_status|hex2dec|||
|
|
2|device_status|hex2dec|||
|
|
2|version_major|hex2dec|||
|
|
2|version_minor|hex2dec|||
|
|
2|version_patch|hex2dec|||
|
|
22|reserved|skip|||
|
|
```
|
|
|
|
### Byte 66 — error_flags
|
|
|
|
| Bit | Masque | Description |
|
|
|-----|--------|-------------|
|
|
| 0 | 0x01 | RTC deconnecte |
|
|
| 1 | 0x02 | RTC reset (annee 2000) |
|
|
| 2 | 0x04 | BME280 erreur |
|
|
| 3 | 0x08 | NPM erreur |
|
|
| 4 | 0x10 | Envea erreur |
|
|
| 5 | 0x20 | Bruit erreur |
|
|
| 6 | 0x40 | MPPT erreur |
|
|
| 7 | 0x80 | Vent erreur |
|
|
|
|
### Byte 67 — npm_status
|
|
|
|
| Bit | Masque | Description |
|
|
|-----|--------|-------------|
|
|
| 0 | 0x01 | Sleep mode |
|
|
| 1 | 0x02 | Degraded mode |
|
|
| 2 | 0x04 | Not ready |
|
|
| 3 | 0x08 | Heater error |
|
|
| 4 | 0x10 | THP sensor error |
|
|
| 5 | 0x20 | Fan error |
|
|
| 6 | 0x40 | Memory error |
|
|
| 7 | 0x80 | Laser error |
|
|
|
|
### Byte 68 — device_status
|
|
|
|
| Bit | Masque | Description |
|
|
|-----|--------|-------------|
|
|
| 0 | 0x01 | Modem reboot au cycle precedent |
|
|
| 1 | 0x02 | WiFi connecte |
|
|
| 2 | 0x04 | Hotspot actif |
|
|
| 3 | 0x08 | Pas de fix GPS |
|
|
| 4 | 0x10 | Batterie faible |
|
|
| 5 | 0x20 | Disque plein |
|
|
| 6 | 0x40 | Erreur base SQLite |
|
|
| 7 | 0x80 | Boot recent (uptime < 5 min) |
|
|
|
|
---
|
|
|
|
# Notes
|
|
|
|
## Wifi Hotspot (AP)
|
|
|
|
To connect the device to the internet we need to create a Hotspot using nmcli.
|
|
|
|
Command to create a AP with SSI: nebuleair_pro and PASS: nebuleaircfg:
|
|
|
|
```
|
|
sudo nmcli device wifi hotspot ifname wlan0 ssid nebuleair_pro password nebuleaircfg
|
|
|
|
#we also need to set IP addresses
|
|
sudo nmcli connection modify Hotspot ipv4.addresses 192.168.4.1/24
|
|
sudo nmcli connection modify Hotspot ipv4.method shared
|
|
```
|
|
|
|
This will create a new connection called "Hotspot" using device "wlan0". You can connect to this network
|
|
via wifi and access to the self-hosted webpage on 192.168.4.1 (to get the IP `ip addr show wlan0` or `nmcli device show wlan0`).
|
|
|
|
Only problem is that you cannot perform a wifi scan while wlan0 is in AP mode. So you need to scan the available networks just before creating the Hotspot.
|
|
|
|
Second issue: hotspot need to be lauched at startup only if it cannot connected to the selected wifi network.
|
|
|
|
Wifi connection check, wifi scan and activation of the Hotspot need to be lauched at every startup.
|
|
|
|
This can be doned with script boot_hotspot.sh.
|
|
|
|
```
|
|
@reboot chmod 777 /dev/ttyAMA* /dev/i2c-1
|
|
@reboot /var/www/nebuleair_pro_4g/boot_hotspot.sh
|
|
```
|
|
|
|
## Claude Code
|
|
|
|
Instructions to use claude code on the RPI.
|
|
|
|
### Install NPM
|
|
|
|
```
|
|
sudo apt install -y nodejs npm
|
|
node -v
|
|
npm -v
|
|
```
|
|
|
|
### Install Claude
|
|
|
|
```
|
|
sudo npm install -g @anthropic-ai/claude-code
|
|
```
|
|
|
|
### Run claude
|
|
|
|
```
|
|
claude
|
|
```
|
|
|
|
|