Allsky quep
-
quep
- Messages : 243
- Inscription : 22 mai 2020, 22:55
- Localisation : Rennes
Allsky quep
Beaucoup de tâtonnement et de recherche, notamment pour la partie script.
Je ne traiterais pas de l'installation du logiciel allsky, les documentations disponibles sont très bien faites sur le site.
Matériel
- Raspberry pi 4 - 4Go
- Hat POE
- Raspberry HQ imx477
- Fisheye 1.55mm
- Boitier étanche 260x160
- Connecteur RJ étanche
- Connecteur d'alimentation étanche
- Fond de boitier 250x150
- Dôme plexi
- Relais 12v
- Résistance chaufante 12v
- Protection capteur exterieur
- Capteurs BME280 3.3v et 5v pour différencier l'adresse
- Adaptateur SATA
- SSD 250Go
- Lot d'entretoise M2.5
- Câbles Dupont
-
quep
- Messages : 243
- Inscription : 22 mai 2020, 22:55
- Localisation : Rennes
Allsky quep
Deux logiciels m’intéressait pour mon modèle mais j'ai choisi le logiciel Allsky, de Thomas Jacquin par rapport à indi-allsky, je préfère l'interface utilisateur.
Les deux logiciels sont activement développés.
En plus du logiciel de base il existe des modules à installer, suivant les capteurs que l'on souhaite utiliser et les fonctionnalités recherchées.
J'ai choisi d'installer trois capteurs, deux BME280 pour la température intérieure et extérieure, ainsi qu'un capteur IR pour déterminer la couverture nuageuse. Ce dernier n'est pas encore en fonctionnement, la calibration n'est pas évidente donc je ne le traiterais pas ici.
Je souhaitais en plus de la surveillance du ciel, pouvoir avoir des représentations graphiques du fonctionnement du raspberry et des capteurs. J'ai choisi Influxdb/ comme gestionnaire de base de données et Grafana comme plateforme de visualisation. Ce n'est pas particulièrement utile donc parfaitement indispensable
Présentation du fonctionnement et script
Le raspberry est alimenté via POE par un câble téléphonique 12 paires de 30m (8 paires utilisées pour le RJ) avec un switch POE au bout.
La résistance chauffante est alimentée en 12v par un autre câble téléphonique 8 paires de 30m (4 paires utilisées, 2+ et 2-) avec un transformateur au bout. Elle est asservie par le relais installé, suivant la température captée par le capteur extérieur.
Un des modules ajouté dans le logiciel modifie la position (haute ou basse, 0v ou 5v) d'un des GPIO (le 4) pour déclencher le relais 12v.
Les trois capteurs sont connectés au bus I2C sur les GPIO du raspberry.
- 1 BME280 en 3,3v
- 1 BME280 en 5v
- 1 MLX90614 en 5V
L’intérêt d'avoir les deux capteurs alimentés différemment est de pouvoir différencier leurs adresses sur le bus I2C. Un prendra la valeur 0x76 et l'autre 0x77.
-
quep
- Messages : 243
- Inscription : 22 mai 2020, 22:55
- Localisation : Rennes
Allsky quep
Version de Raspbian : Bookworm
Installation du SSD en 64 bits sans interface utilisateur avec l'utilitaire raspberry pi imager.
Configuration, lors de la préparation avec le logiciel, d'un utilisateur avec mot de passe et activation du ssh pour une gestion à distance.
Il est également possible de modifier le nom du raspberry pi pour la connexion en ssh.
Dans mon cas, après l'allumage du RPI, l'adresse est restée en http://raspberrypi.local
L'adresse changera à l'installation de la partie allsky, en http://allsky.loca
Le script qui me permet de récupérer les différentes données capteurs a été réalisé par ChatGPT, en python. Mes maigres connaissances en programmation ont permis quelques débogages mais l'essentiel a été réalisé par l'IA.
Les données collectées sont enregistrées dans un fichier JSON local. L’emplacement de l’enregistrement est fait dans un dossier particulier du logiciel car cela permet de récupérer les données de mon script, pour les afficher sur la surcouche de l’image du ciel.
Le script est lancé à intervalle régulier par un cron.
Le cron lance le script allsky.sh toutes les 3 minutes, pour créer l'environnement python et lancer le script allsky.py dans cet environnement. A la fin de l'exécution du script allsky.py, allsky.sh désactive l'environnement.
Installation des paquets Influxdb, Grafana et création des scripts
Installation des paquets :
# Mise à jour et installation des paquets nécessaires
Code : Tout sélectionner
sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get install -y curl wget gnupg i2c-tools python3-smbus python3-pip git virtualenv python3-virtualenvCode : Tout sélectionner
sudo raspi-config nonint do_wifi_country FRCode : Tout sélectionner
sudo raspi-config nonint do_change_timezone Europe/ParisCode : Tout sélectionner
sudo raspi-config nonint do_i2c 0Code : Tout sélectionner
curl -LO https://download.influxdata.com/influxdb/releases/influxdb2_2.7.6-1_arm64.deb
sudo dpkg -i influxdb2_2.7.6-1_arm64.deb
Code : Tout sélectionner
wget https://download.influxdata.com/influxdb/releases/influxdb2-client-2.7.5-linux-arm64.tar.gz
tar xvzf ./influxdb2-client-2.7.5-linux-arm64.tar.gz
sudo cp ./influx /usr/local/bin/Code : Tout sélectionner
rm influxdb2_2.7.6-1_arm64.deb
rm influxdb2-client-2.7.5-linux-arm64.tar.gz
rm README.md
rm LICENSECode : Tout sélectionner
sudo mkdir -p /etc/apt/keyrings/
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.listCode : Tout sélectionner
sudo apt-get update
sudo apt-get install -y grafanaCode : Tout sélectionner
sudo /bin/systemctl enable grafana-server
sudo /bin/systemctl start grafana-server
Code : Tout sélectionner
mkdir -p /home/quep/script
cd /home/quep/script
nano allsky.pyCode : Tout sélectionner
import smbus2
import bme280
import json
import os
import datetime
import psutil
from influxdb_client import InfluxDBClient, Point, WriteOptions
from influxdb_client.client.write_api import SYNCHRONOUS
import RPi.GPIO as GPIO
import re
# Define the I2C bus number
bus_number = 1
# Define the addresses of the two sensors
sensor1_address = 0x77
sensor2_address = 0x76
# Initialize the I2C bus
bus = smbus2.SMBus(bus_number)
# Read data from the first sensor
calibration_params = bme280.load_calibration_params(bus, sensor1_address)
data1 = bme280.sample(bus, sensor1_address, calibration_params)
temperature1 = round(data1.temperature, 2)
pressure1 = round(data1.pressure, 2)
# Read data from the second sensor
calibration_params = bme280.load_calibration_params(bus, sensor2_address)
data2 = bme280.sample(bus, sensor2_address, calibration_params)
temperature2 = round(data2.temperature, 2)
pressure2 = round(data2.pressure, 2)
# Read disk usage
disk_usage = psutil.disk_usage("/")
total_size = round(disk_usage.total / (1024 ** 3), 2) # Convert to GB
used_space = round(disk_usage.used / (1024 ** 3), 2) # Convert to GB
free_space = round(disk_usage.free / (1024 ** 3), 2) # Convert to GB
# Read network I/O counters
net_io = psutil.net_io_counters()
download = net_io.bytes_recv
upload = net_io.bytes_sent
# Convert bytes to MB and round to integer
download_mb = int(download / (1024 ** 2)) # Convert to MB and cast to integer
upload_mb = int(upload / (1024 ** 2)) # Convert to MB and cast to integer
# Read CPU temperature
cpu_temp = psutil.sensors_temperatures().get('cpu_thermal')[0].current
# Read system uptime
uptime_seconds = int((datetime.datetime.now() - datetime.datetime.fromtimestamp(psutil.boot_time())).total_seconds())
uptime_hours = uptime_seconds // 3600
uptime_minutes = (uptime_seconds % 3600) // 60
uptime_days = uptime_seconds // 86400 # Corrected this line (1 day = 86400 seconds)
uptime_years = uptime_days // 365 # Approximation (1 year = 365 days)
# Define the dictionary to store the sensor data
sensor_data = {
'measurement': 'allsky',
'tags': {},
'fields': {
'AS_TEMPEXT': temperature1,
'AS_PRESSEXT': pressure1,
'AS_TEMPINT': temperature2,
'AS_PRESSINT': pressure2,
'AS_CPUTEMP': cpu_temp,
'AS_TOTALSIZE': total_size,
'AS_USEDSPACE': used_space,
'AS_FREESPACE': free_space,
'AS_CPUUSAGE': psutil.cpu_percent(interval=1),
'AS_RAMUSAGE': psutil.virtual_memory().percent,
'AS_UPTIME_HOURS': uptime_hours,
'AS_UPTIME_MINUTES': uptime_minutes,
'AS_DOWNLOAD': download_mb,
'AS_UPLOAD': upload_mb,
'AS_UPTIME_YEARS': uptime_years,
'AS_UPTIME_DAYS': uptime_days
}
}
# Load dew control data from allskydew.json
allskydew_path = '/home/quep/allsky/config/overlay/extra/allskydew.json'
if os.path.exists(allskydew_path):
with open(allskydew_path, 'r') as dew_file:
dew_data = json.load(dew_file)
sensor_data['fields']['AS_DEWCONTROLDEW'] = float(dew_data['AS_DEWCONTROLDEW'])
sensor_data['fields']['AS_DEWCONTROLHEATER'] = dew_data['AS_DEWCONTROLHEATER']
# Configure the InfluxDB connection
influxdb_url = 'http://localhost:8086'
influxdb_token = 'XXXXXXXXXX'
influxdb_org = 'XXXXXXXXX'
influxdb_bucket = 'XXXXXXXXX'
# Create the InfluxDB client
client = InfluxDBClient(url=influxdb_url, token=influxdb_token, org=influxdb_org)
# Write the data to InfluxDB
write_api = client.write_api(write_options=SYNCHRONOUS)
point = Point(sensor_data['measurement']).tag("location", "allsky")
for key, value in sensor_data['fields'].items():
point.field(key, value)
write_api.write(bucket=influxdb_bucket, org=influxdb_org, record=point)
# Define the directory path
directory_path = os.path.expanduser('/home/quep/allsky/config/overlay/extra/')
# Create the directory if it does not exist
os.makedirs(directory_path, exist_ok=True)
# Save the sensor data to a JSON file
file_path = os.path.join(directory_path, 'allsky_quep.json')
with open(file_path, 'w') as file:
json.dump(sensor_data['fields'], file, indent=4)
print(f"Sensor data saved to {file_path}")
Code : Tout sélectionner
(crontab -l 2>/dev/null; echo "*/3 * * * * /home/quep/script/allsky.sh") | crontab -Code : Tout sélectionner
crontab -eCode : Tout sélectionner
/3 * * * * /home/quep/script/allsky.sh# création de l'environnement venv
# remonter à la racine de l'utilisateur
Code : Tout sélectionner
cdCode : Tout sélectionner
python3 -m venv script/#Activation de l'environnement dans le dossier
Code : Tout sélectionner
. /home/quep/script/bin/activateCode : Tout sélectionner
pip install rpi.bme280 influxdb-client psutil adafruit-circuitpython-bme280 adafruit-circuitpython-mlx90614 smbus2Code : Tout sélectionner
deactivateCode : Tout sélectionner
nano /home/quep/script/allsky.shCode : Tout sélectionner
#!/bin/bash
# Activate the virtual environment
. /home/quep/script/bin/activate
# Change directory to the script location
cd /home/quep/script
# Run the Python script
python3 allsky.py
# Deactivate the virtual environment
deactivate
Code : Tout sélectionner
chmod +x /home/quep/script/allsky.shCode : Tout sélectionner
sudo apt install -y samba samba-common-binCode : Tout sélectionner
CONFIG_BLOCK="[allsky]
path = /home/quep
writeable = yes
browseable = yes
public = no
"
Code : Tout sélectionner
echo "$CONFIG_BLOCK" | sudo tee -a /etc/samba/smb.conf > /dev/nullCode : Tout sélectionner
sudo systemctl restart smbdCode : Tout sélectionner
git clone --recursive https://github.com/AllskyTeam/allsky.git#Téléchargement de allsky modules
Code : Tout sélectionner
git clone https://github.com/AllskyTeam/allsky-modules.git-
quep
- Messages : 243
- Inscription : 22 mai 2020, 22:55
- Localisation : Rennes
Allsky quep
InfluxDB
Un module InfluxDB est installable via les modules mais je n'ai pas réussi à le faire fonctionner. Je passe donc par le script précédent pour récupérer les données.
Un petit redémarrage et ensuite connexion à l'adresse http://localhost:8086 qui correspond à InfluxDB.
Il faut configurer le nom du compte et mot de passe, le nom de l'organisation et le nom du bucket à créer. (Il est possible de créer celui-ci par la suite)
A la fin de cette étape il faut absolument récupérer le Token d'influxDB.
Il servira à faire accepter la connexion à Influx des autres entités.
Je modifie ensuite les valeurs dans mon script :
# Configure the InfluxDB connection
influxdb_url = 'http://localhost:8086'
influxdb_token = 'token_influx'
influxdb_org = 'nom_org'
influxdb_bucket = 'nom_bucket'
Pour mon cas cela ressemble à ça:
# Configure the InfluxDB connection
influxdb_url = 'http://localhost:8086'
influxdb_token = 'TOKEN'
influxdb_org = 'quep'
influxdb_bucket = 'allsky'
Grafana
Se connecter à l'adresse http://localhost:3000 et procéder à la configuration du mot de passe et du nom d'utilisateur.
Dans l'interface de Grafana, se rendre dans l'onglet "Connections - Data sources" et cliquer sur "add new data source".
Choisir Influx comme base de données et remplir les champs comme suit:
Query : Flux
URL : http://localhost:8086
Auth : Basic Auth
InfluxDB Details : Nom de l'organisation, votre token précedemment récupéré, Default Bucket (mettre le nom de votre bucket)
Lorsque tout est rempli il faut cliquer sur "Save and test", si un encart vert indiquant que la source est trouvée c'est que la configuration est correcte.
Il faut ensuite se rendre dans le menu Dashboard afin d'en créer un nouveau. C'est dans celui-ci que l'on pourra ajouter des visualisations.
-
quep
- Messages : 243
- Inscription : 22 mai 2020, 22:55
- Localisation : Rennes
Allsky quep
Je me suis encore appuyé sur ChatGPT pour la création des requêtes. Charge à moi d'insérer celles-ci dans les visualisations et de tâtonner pour trouver une visualisation qui fonctionne avec la requête.
En pièce-jointe, le json de mon dashboard, permettant une création sans trop de problèmes. La visualisation de eth0 ne fonctionne pas, il vaudra mieux la supprimer.
Pour créer une visualisation il faut éditer le Dashboard --> "Add vizualisation". Dans le champ Influxdb recopier les requêtes et adapter la visualisation à droite de la fenêtre (Gauge, Stat, Histogram...) suivant la façon dont vous souhaiter visualiser les données.
Quelques requêtes Influx:
----------------------------------------------------------------
Température CPU - Utilisation du CPU et de la RAM
from(bucket: "allsky")
|> range(start: -24h)
|> filter(fn: (r) => r._measurement == "allsky" and (r._field == "AS_CPUTEMP" or r._field == "AS_RAMUSAGE" or r._field == "AS_CPUUSAGE"))
|> group(columns: ["_measurement"])
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
|> drop(columns: ["_start", "_stop"])
---------------------------------------------------------------
Températures capteurs
from(bucket: "allsky")
|> range(start: -1h)
|> filter(fn: (r) => r._measurement == "allsky" and (r._field == "AS_TEMPINT" or r._field == "AS_TEMPEXT"))
|> group(columns: ["_measurement"])
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
|> drop(columns: ["_start", "_stop"])
-----------------------------------------------------------------
Hygro intérieure et extérieure
from(bucket: "allsky")
|> range(start: -1h)
|> filter(fn: (r) => r._measurement == "allsky" and (r._field == "AS_HUMIDINT" or r._field == "AS_HUMIDEXT"))
|> group(columns: ["_measurement"])
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
|> drop(columns: ["_start", "_stop"])
------------------------------------------------------------------
Résistante chauffante
from(bucket: "allsky")
|> range(start: -24h)
|> filter(fn: (r) => r._measurement == "allsky" and r._field == "AS_DEWHEATER")
|> last()
choisir stat, text mode Value, unit -> string, value mapping pour les couleurs
-------------------------------------------------------------------
Temps depuis le démarrage de la allsky
from(bucket: "allsky")
|> range(start: -1h)
|> filter(fn: (r) => r._measurement == "allsky" and
(r._field == "AS_UPTIME_HOURS" or
r._field == "AS_UPTIME_MINUTES" or
r._field == "AS_UPTIME_DAYS" or
r._field == "AS_UPTIME_YEARS"))
|> last()
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
|> map(fn: (r) => ({
r with
uptime: (if r.AS_UPTIME_YEARS > 0 then string(v: r.AS_UPTIME_YEARS) + "y " else "") +
(if r.AS_UPTIME_DAYS > 0 then string(v: r.AS_UPTIME_DAYS) + "d " else "") +
string(v: r.AS_UPTIME_HOURS) + "h " +
string(v: r.AS_UPTIME_MINUTES) + "m"
}))
|> keep(columns: ["_time", "uptime"])
choisir une visualisation en stat.
-------------------------------------------------------------------
Je l'ajoute quand même si jamais un bienfaiteur maitrise les requêtes Influx
Dowload et Upload
from(bucket: "allsky")
|> range(start: -1h) // Adjust time range as needed
|> filter(fn: (r) => r._measurement == "allsky" and (r._field == "AS_DOWNLOAD" or r._field == "AS_UPLOAD"))
|> group(columns: ["_measurement"]) // Group by measurement
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
|> drop(columns: ["_start", "_stop"])
--------------------------------------------------------------------
Espace disque
from(bucket: "allsky")
|> range(start: -24h)
|> filter(fn: (r) => r._measurement == "allsky" and (r._field == "AS_USEDSPACE"))
|> aggregateWindow(every: 1m, fn: mean, createEmpty: false)
|> yield(name: "mean")
En cas de questions ou commentaires, je suis dispo
- fcouma
- Messages : 3420
- Inscription : 07 févr. 2021, 19:27
- Localisation : 85
Allsky quep
C'est bien plus propre à l'intérieur que la mienne
J'ai honte, mais elle fonctionne bien quand même
-
SBRCoach
- Messages : 2487
- Inscription : 16 nov. 2020, 21:04
- Localisation : Aisne
-
quep
- Messages : 243
- Inscription : 22 mai 2020, 22:55
- Localisation : Rennes
Allsky quep
Je suis plutôt bordélique d’habitude mais là, pour une fois, je voulais faire un truc lisible et reproductible.
-
SBRCoach
- Messages : 2487
- Inscription : 16 nov. 2020, 21:04
- Localisation : Aisne
-
quep
- Messages : 243
- Inscription : 22 mai 2020, 22:55
- Localisation : Rennes