update
This commit is contained in:
@@ -29,7 +29,7 @@ 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 --break-system-packages
|
||||
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
|
||||
|
||||
@@ -111,6 +111,13 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input" type="checkbox" value="" id="check_NOISE" onchange="update_config_sqlite('NOISE', this.checked)">
|
||||
<label class="form-check-label" for="check_NOISE">
|
||||
Send Noise data
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<label class="form-check-label" for="check_uSpot">
|
||||
@@ -361,12 +368,15 @@ window.onload = function() {
|
||||
const checkbox_bme = document.getElementById("check_bme280");
|
||||
const checkbox_envea = document.getElementById("check_envea");
|
||||
const checkbox_solar = document.getElementById("check_solarBattery");
|
||||
const checkbox_noise = document.getElementById("check_NOISE");
|
||||
|
||||
checkbox_bme.checked = response["BME280"];
|
||||
checkbox_envea.checked = response["envea"];
|
||||
checkbox_solar.checked = response["MPPT"];
|
||||
checkbox_nmp5channels.checked = response.npm_5channel;
|
||||
checkbox_wind.checked = response["windMeter"];
|
||||
checkbox_noise.checked = response["NOISE"];
|
||||
|
||||
checkbox_uSpot.checked = response["send_uSpot"];
|
||||
|
||||
// If envea is enabled, show the envea sondes container
|
||||
|
||||
@@ -71,6 +71,8 @@
|
||||
<button class="btn btn-primary" onclick="get_data_sqlite('data_BME280',getSelectedLimit(),false)">Mesures Temp/Hum</button>
|
||||
<button class="btn btn-primary" onclick="get_data_sqlite('data_NPM_5channels',getSelectedLimit(),false)">Mesures PM (5 canaux)</button>
|
||||
<button class="btn btn-primary" onclick="get_data_sqlite('data_envea',getSelectedLimit(),false)">Sonde Cairsens</button>
|
||||
<button class="btn btn-primary" onclick="get_data_sqlite('data_NOISE',getSelectedLimit(),false)">Sonde bruit</button>
|
||||
|
||||
<button class="btn btn-primary" onclick="get_data_sqlite('data_WIND',getSelectedLimit(),false)">Sonde Vent</button>
|
||||
<button class="btn btn-primary" onclick="get_data_sqlite('data_MPPT',getSelectedLimit(),false)">Batterie</button>
|
||||
|
||||
@@ -97,6 +99,8 @@
|
||||
<button class="btn btn-primary" onclick="get_data_sqlite('data_BME280',10,true, getStartDate(), getEndDate())">Mesures Temp/Hum</button>
|
||||
<button class="btn btn-primary" onclick="get_data_sqlite('data_NPM_5channels',10,true, getStartDate(), getEndDate())">Mesures PM (5 canaux)</button>
|
||||
<button class="btn btn-primary" onclick="get_data_sqlite('data_envea',10,true, getStartDate(), getEndDate())">Sonde Cairsens</button>
|
||||
<button class="btn btn-primary" onclick="get_data_sqlite('data_NOISE',10,true, getStartDate(), getEndDate())">Sonde Bruit</button>
|
||||
|
||||
<button class="btn btn-primary" onclick="get_data_sqlite('data_mppt',10,true, getStartDate(), getEndDate())">Batterie</button>
|
||||
|
||||
</table>
|
||||
@@ -291,10 +295,17 @@ function get_data_sqlite(table, limit, download , startDate = "", endDate = "")
|
||||
<th> solar_power</th>
|
||||
<th> charger_status</th>
|
||||
|
||||
`;
|
||||
}else if (table === "data_NOISE") {
|
||||
tableHTML += `
|
||||
<th>Timestamp</th>
|
||||
<th>Curent LEQ</th>
|
||||
<th>DB_A_value</th>
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
tableHTML += `</tr></thead><tbody>`;
|
||||
|
||||
// Loop through rows and create table rows
|
||||
@@ -357,6 +368,12 @@ function get_data_sqlite(table, limit, download , startDate = "", endDate = "")
|
||||
<td>${columns[3]}</td>
|
||||
<td>${columns[4]}</td>
|
||||
<td>${columns[5]}</td>
|
||||
`;
|
||||
}else if (table === "data_NOISE") {
|
||||
tableHTML += `
|
||||
<td>${columns[0]}</td>
|
||||
<td>${columns[1]}</td>
|
||||
<td>${columns[2]}</td>
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1017,6 +1017,10 @@ if ($type == "get_systemd_services") {
|
||||
'description' => 'Tracks solar panel and battery status',
|
||||
'frequency' => 'Every 2 minutes'
|
||||
],
|
||||
'nebuleair-noise-data.timer' => [
|
||||
'description' => 'Get Data from noise sensor',
|
||||
'frequency' => 'Every minute'
|
||||
],
|
||||
'nebuleair-db-cleanup-data.timer' => [
|
||||
'description' => 'Cleans up old data from database',
|
||||
'frequency' => 'Daily'
|
||||
|
||||
@@ -27,7 +27,7 @@ sudo apt update && sudo apt install -y git gh apache2 sqlite3 php php-sqlite3 py
|
||||
|
||||
# Install Python libraries
|
||||
info "Installing Python libraries..."
|
||||
sudo pip3 install pyserial requests RPi.GPIO adafruit-circuitpython-bme280 crcmod psutil gpiozero ntplib pytz --break-system-packages || error "Failed to install Python libraries."
|
||||
sudo pip3 install pyserial requests RPi.GPIO adafruit-circuitpython-bme280 crcmod psutil gpiozero ntplib adafruit-circuitpython-ads1x15 nsrt-mk3-dev pytz --break-system-packages || error "Failed to install Python libraries."
|
||||
|
||||
# Clone the repository (check if it exists first)
|
||||
REPO_DIR="/var/www/nebuleair_pro_4g"
|
||||
|
||||
@@ -1,39 +1,277 @@
|
||||
#!/bin/bash
|
||||
# File: /var/www/nebuleair_pro_4g/services/check_services.sh
|
||||
# Purpose: Check status of all NebuleAir services and logs
|
||||
# Install:
|
||||
# sudo chmod +x /var/www/nebuleair_pro_4g/services/check_services.sh
|
||||
# sudo /var/www/nebuleair_pro_4g/services/check_services.sh
|
||||
# Version with fixed color handling for proper table display
|
||||
|
||||
echo "=== NebuleAir Services Status ==="
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
BOLD='\033[1m'
|
||||
DIM='\033[2m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Service list
|
||||
SERVICES=("npm" "envea" "sara" "bme280" "mppt" "db-cleanup" "noise")
|
||||
|
||||
# Function to print header
|
||||
print_header() {
|
||||
local text="$1"
|
||||
echo ""
|
||||
echo -e "${BLUE}${BOLD}=== $text ===${NC}"
|
||||
echo -e "${BLUE}$(printf '%.0s=' {1..70})${NC}"
|
||||
}
|
||||
|
||||
# Check status of all timers
|
||||
echo "--- TIMER STATUS ---"
|
||||
systemctl list-timers | grep nebuleair
|
||||
# Function to print section
|
||||
print_section() {
|
||||
local text="$1"
|
||||
echo ""
|
||||
echo -e "${CYAN}${BOLD}--- $text ---${NC}"
|
||||
}
|
||||
|
||||
# Check status of all services
|
||||
echo "--- SERVICE STATUS ---"
|
||||
for service in npm envea sara bme280 mppt db-cleanup; do
|
||||
status=$(systemctl is-active nebuleair-$service-data.service)
|
||||
timer_status=$(systemctl is-active nebuleair-$service-data.timer)
|
||||
# Function to print a separator line
|
||||
print_separator() {
|
||||
echo "+--------------------------+-----------+-----------+-------------+-------------+-------------------------+"
|
||||
}
|
||||
|
||||
echo "nebuleair-$service-data: Service=$status, Timer=$timer_status"
|
||||
# Clear screen for clean output
|
||||
clear
|
||||
|
||||
# Main header
|
||||
print_header "NebuleAir Services Status Report"
|
||||
echo -e "Generated on: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
|
||||
# Timer Schedule
|
||||
print_section "Active Timers Schedule"
|
||||
echo ""
|
||||
systemctl list-timers --no-pager | head -n 1
|
||||
systemctl list-timers --no-pager | grep nebuleair || echo "No active nebuleair timers found"
|
||||
|
||||
# Service Status Overview with fixed color handling
|
||||
print_section "Service Status Overview"
|
||||
echo ""
|
||||
print_separator
|
||||
printf "| %-24s | %-9s | %-9s | %-11s | %-11s | %-23s |\n" "Service" "Svc State" "Svc Boot" "Timer State" "Timer Boot" "Health Status"
|
||||
print_separator
|
||||
|
||||
for service in "${SERVICES[@]}"; do
|
||||
# Check the actual service and timer names (with -data suffix)
|
||||
full_service_name="nebuleair-${service}-data"
|
||||
|
||||
# Get raw status values
|
||||
service_status=$(systemctl is-active ${full_service_name}.service 2>/dev/null | tr -d '\n' || echo "not-found")
|
||||
service_enabled=$(systemctl is-enabled ${full_service_name}.service 2>/dev/null | tr -d '\n' || echo "not-found")
|
||||
timer_status=$(systemctl is-active ${full_service_name}.timer 2>/dev/null | tr -d '\n' || echo "not-found")
|
||||
timer_enabled=$(systemctl is-enabled ${full_service_name}.timer 2>/dev/null | tr -d '\n' || echo "not-found")
|
||||
|
||||
# Check if files exist and override if not found
|
||||
if ! systemctl list-unit-files | grep -q "^${full_service_name}.service" &>/dev/null; then
|
||||
service_status="not-found"
|
||||
service_enabled="not-found"
|
||||
fi
|
||||
if ! systemctl list-unit-files | grep -q "^${full_service_name}.timer" &>/dev/null; then
|
||||
timer_status="not-found"
|
||||
timer_enabled="not-found"
|
||||
fi
|
||||
|
||||
# Create display strings without embedded colors for table cells
|
||||
case $service_status in
|
||||
"active") svc_st_display="active"; svc_st_color="${GREEN}" ;;
|
||||
"inactive") svc_st_display="inactive"; svc_st_color="${DIM}" ;;
|
||||
"activating") svc_st_display="starting"; svc_st_color="${YELLOW}" ;;
|
||||
"not-found") svc_st_display="missing"; svc_st_color="${RED}" ;;
|
||||
*) svc_st_display="$service_status"; svc_st_color="${RED}" ;;
|
||||
esac
|
||||
|
||||
case $service_enabled in
|
||||
"enabled"|"static") svc_en_display="enabled"; svc_en_color="${GREEN}" ;;
|
||||
"disabled") svc_en_display="disabled"; svc_en_color="${YELLOW}" ;;
|
||||
"not-found") svc_en_display="missing"; svc_en_color="${RED}" ;;
|
||||
*) svc_en_display="$service_enabled"; svc_en_color="${YELLOW}" ;;
|
||||
esac
|
||||
|
||||
case $timer_status in
|
||||
"active") tim_st_display="active"; tim_st_color="${GREEN}" ;;
|
||||
"inactive") tim_st_display="inactive"; tim_st_color="${RED}" ;;
|
||||
"not-found") tim_st_display="missing"; tim_st_color="${RED}" ;;
|
||||
*) tim_st_display="$timer_status"; tim_st_color="${RED}" ;;
|
||||
esac
|
||||
|
||||
case $timer_enabled in
|
||||
"enabled"|"static") tim_en_display="enabled"; tim_en_color="${GREEN}" ;;
|
||||
"disabled") tim_en_display="disabled"; tim_en_color="${YELLOW}" ;;
|
||||
"not-found") tim_en_display="missing"; tim_en_color="${RED}" ;;
|
||||
*) tim_en_display="$timer_enabled"; tim_en_color="${YELLOW}" ;;
|
||||
esac
|
||||
|
||||
# Determine health status
|
||||
if [[ "$timer_status" == "active" ]]; then
|
||||
if [[ "$timer_enabled" == "enabled" || "$timer_enabled" == "static" ]]; then
|
||||
health_display="✓ OK"
|
||||
health_color="${GREEN}"
|
||||
else
|
||||
health_display="⚠ Boot disabled"
|
||||
health_color="${YELLOW}"
|
||||
fi
|
||||
elif [[ "$timer_status" == "inactive" ]]; then
|
||||
health_display="✗ Timer stopped"
|
||||
health_color="${RED}"
|
||||
else
|
||||
health_display="✗ Timer missing"
|
||||
health_color="${RED}"
|
||||
fi
|
||||
|
||||
# Print row with colors applied outside of printf formatting
|
||||
printf "| %-24s | " "$full_service_name"
|
||||
printf "${svc_st_color}%-9s${NC} | " "$svc_st_display"
|
||||
printf "${svc_en_color}%-9s${NC} | " "$svc_en_display"
|
||||
printf "${tim_st_color}%-11s${NC} | " "$tim_st_display"
|
||||
printf "${tim_en_color}%-11s${NC} | " "$tim_en_display"
|
||||
printf "${health_color}%-23s${NC} |\n" "$health_display"
|
||||
done
|
||||
echo ""
|
||||
print_separator
|
||||
|
||||
# Show recent logs for each service
|
||||
echo "--- RECENT LOGS (last 5 entries per service) ---"
|
||||
for service in npm envea sara bme280 mppt db-cleanup; do
|
||||
echo "[$service service logs]"
|
||||
journalctl -u nebuleair-$service-data.service -n 5 --no-pager
|
||||
# Understanding the table
|
||||
echo ""
|
||||
echo -e "${DIM}Note: For timer-based services, it's normal for the service to be 'inactive' and 'disabled'.${NC}"
|
||||
echo -e "${DIM} What matters is that the timer is 'active' and 'enabled'.${NC}"
|
||||
|
||||
# Configuration Issues
|
||||
print_section "Configuration Issues"
|
||||
echo ""
|
||||
issues_found=false
|
||||
|
||||
for service in "${SERVICES[@]}"; do
|
||||
full_service_name="nebuleair-${service}-data"
|
||||
|
||||
timer_status=$(systemctl is-active ${full_service_name}.timer 2>/dev/null | tr -d '\n' || echo "not-found")
|
||||
timer_enabled=$(systemctl is-enabled ${full_service_name}.timer 2>/dev/null | tr -d '\n' || echo "not-found")
|
||||
|
||||
# Check if timer exists
|
||||
if ! systemctl list-unit-files | grep -q "^${full_service_name}.timer" &>/dev/null; then
|
||||
timer_status="not-found"
|
||||
timer_enabled="not-found"
|
||||
fi
|
||||
|
||||
if [[ "$timer_status" != "active" || ("$timer_enabled" != "enabled" && "$timer_enabled" != "static") ]]; then
|
||||
issues_found=true
|
||||
echo -e " ${RED}•${NC} ${BOLD}$full_service_name${NC}"
|
||||
if [[ "$timer_status" == "not-found" ]]; then
|
||||
echo -e " ${RED}→${NC} Timer unit file is missing"
|
||||
elif [[ "$timer_status" != "active" ]]; then
|
||||
echo -e " ${RED}→${NC} Timer is not running (status: $timer_status)"
|
||||
fi
|
||||
if [[ "$timer_enabled" == "not-found" ]]; then
|
||||
echo -e " ${RED}→${NC} Timer unit file is missing"
|
||||
elif [[ "$timer_enabled" != "enabled" && "$timer_enabled" != "static" ]]; then
|
||||
echo -e " ${YELLOW}→${NC} Timer won't start on boot (status: $timer_enabled)"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
|
||||
echo "=== End of Report ==="
|
||||
if [[ "$issues_found" == "false" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} All timers are properly configured!"
|
||||
fi
|
||||
|
||||
# Recent Executions - Simplified
|
||||
print_section "Last Execution Status"
|
||||
echo ""
|
||||
printf " %-12s %-20s %s\n" "Service" "Last Run" "Status"
|
||||
printf " %-12s %-20s %s\n" "-------" "--------" "------"
|
||||
|
||||
for service in "${SERVICES[@]}"; do
|
||||
full_service_name="nebuleair-${service}-data"
|
||||
|
||||
# Get last execution time and status
|
||||
last_log=$(journalctl -u ${full_service_name}.service -n 3 --no-pager 2>/dev/null | grep -E "(Started|Finished|Failed)" | tail -1)
|
||||
|
||||
if [[ -n "$last_log" ]]; then
|
||||
timestamp=$(echo "$last_log" | awk '{print $1, $2, $3}')
|
||||
if echo "$last_log" | grep -q "Finished"; then
|
||||
status="${GREEN}✓ Success${NC}"
|
||||
elif echo "$last_log" | grep -q "Failed"; then
|
||||
status="${RED}✗ Failed${NC}"
|
||||
elif echo "$last_log" | grep -q "Started"; then
|
||||
status="${YELLOW}⟳ Running${NC}"
|
||||
else
|
||||
status="${DIM}- Unknown${NC}"
|
||||
fi
|
||||
printf " %-12s %-20s %b\n" "$service" "$timestamp" "$status"
|
||||
else
|
||||
printf " %-12s %-20s %b\n" "$service" "-" "${DIM}- No data${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Summary
|
||||
print_section "Summary"
|
||||
echo ""
|
||||
|
||||
working=0
|
||||
needs_attention=0
|
||||
|
||||
for service in "${SERVICES[@]}"; do
|
||||
full_service_name="nebuleair-${service}-data"
|
||||
timer_status=$(systemctl is-active ${full_service_name}.timer 2>/dev/null | tr -d '\n')
|
||||
timer_enabled=$(systemctl is-enabled ${full_service_name}.timer 2>/dev/null | tr -d '\n')
|
||||
|
||||
if [[ "$timer_status" == "active" ]] && [[ "$timer_enabled" == "enabled" || "$timer_enabled" == "static" ]]; then
|
||||
((working++))
|
||||
else
|
||||
((needs_attention++))
|
||||
fi
|
||||
done
|
||||
|
||||
total=${#SERVICES[@]}
|
||||
|
||||
# Visual progress bar
|
||||
echo -n " Overall Health: ["
|
||||
for ((i=1; i<=10; i++)); do
|
||||
if ((i <= working * 10 / total)); then
|
||||
echo -n -e "${GREEN}▰${NC}"
|
||||
else
|
||||
echo -n -e "${RED}▱${NC}"
|
||||
fi
|
||||
done
|
||||
echo -e "] ${working}/${total}"
|
||||
|
||||
echo ""
|
||||
echo -e " ${GREEN}✓${NC} Working properly: ${BOLD}$working${NC} services"
|
||||
echo -e " ${RED}✗${NC} Need attention: ${BOLD}$needs_attention${NC} services"
|
||||
|
||||
# Quick Commands
|
||||
print_section "Quick Commands"
|
||||
echo ""
|
||||
echo -e " ${BOLD}Fix a timer that needs attention:${NC}"
|
||||
echo " $ sudo systemctl enable --now nebuleair-[service]-data.timer"
|
||||
echo ""
|
||||
echo -e " ${BOLD}View live logs:${NC}"
|
||||
echo " $ sudo journalctl -u nebuleair-[service]-data.service -f"
|
||||
echo ""
|
||||
echo -e " ${BOLD}Check timer details:${NC}"
|
||||
echo " $ systemctl status nebuleair-[service]-data.timer"
|
||||
echo ""
|
||||
echo -e " ${BOLD}Run service manually:${NC}"
|
||||
echo " $ sudo systemctl start nebuleair-[service]-data.service"
|
||||
|
||||
# Specific fixes needed
|
||||
if [[ $needs_attention -gt 0 ]]; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}${BOLD}Recommended Actions:${NC}"
|
||||
for service in "${SERVICES[@]}"; do
|
||||
full_service_name="nebuleair-${service}-data"
|
||||
timer_status=$(systemctl is-active ${full_service_name}.timer 2>/dev/null | tr -d '\n')
|
||||
timer_enabled=$(systemctl is-enabled ${full_service_name}.timer 2>/dev/null | tr -d '\n')
|
||||
|
||||
if [[ "$timer_status" != "active" ]] && [[ "$timer_status" != "not-found" ]]; then
|
||||
echo -e " ${RED}→${NC} sudo systemctl start ${full_service_name}.timer"
|
||||
fi
|
||||
if [[ "$timer_enabled" != "enabled" ]] && [[ "$timer_enabled" != "static" ]] && [[ "$timer_enabled" != "not-found" ]]; then
|
||||
echo -e " ${YELLOW}→${NC} sudo systemctl enable ${full_service_name}.timer"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "For detailed logs use:"
|
||||
echo " sudo journalctl -u nebuleair-[service]-data.service -f"
|
||||
echo "To restart a specific service timer:"
|
||||
echo " sudo systemctl restart nebuleair-[service]-data.timer"
|
||||
@@ -173,6 +173,38 @@ AccuracySec=1s
|
||||
WantedBy=timers.target
|
||||
EOL
|
||||
|
||||
# Create service and timer files for noise Data (every minutes)
|
||||
cat > /etc/systemd/system/nebuleair-noise-data.service << 'EOL'
|
||||
[Unit]
|
||||
Description=NebuleAir noise Data Collection Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/python3 /var/www/nebuleair_pro_4g/sound_meter/NSRT_mk4_get_data.py
|
||||
User=root
|
||||
WorkingDirectory=/var/www/nebuleair_pro_4g
|
||||
StandardOutput=append:/var/www/nebuleair_pro_4g/logs/noise_service.log
|
||||
StandardError=append:/var/www/nebuleair_pro_4g/logs/noise_service_errors.log
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
cat > /etc/systemd/system/nebuleair-noise-data.timer << 'EOL'
|
||||
[Unit]
|
||||
Description=Run NebuleAir MPPT Data Collection every 120 seconds
|
||||
Requires=nebuleair-noise-data.service
|
||||
|
||||
[Timer]
|
||||
OnBootSec=60s
|
||||
OnUnitActiveSec=60s
|
||||
AccuracySec=1s
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
EOL
|
||||
|
||||
# Create service and timer files for Database Cleanup
|
||||
cat > /etc/systemd/system/nebuleair-db-cleanup-data.service << 'EOL'
|
||||
[Unit]
|
||||
@@ -210,7 +242,7 @@ systemctl daemon-reload
|
||||
|
||||
# Enable and start all timers
|
||||
echo "Enabling and starting all services..."
|
||||
for service in npm envea sara bme280 mppt db-cleanup; do
|
||||
for service in npm envea sara bme280 mppt db-cleanup noise; do
|
||||
systemctl enable nebuleair-$service-data.timer
|
||||
systemctl start nebuleair-$service-data.timer
|
||||
echo "Started nebuleair-$service-data timer"
|
||||
|
||||
39
sound_meter/NSRT_MK4_change_config.py
Normal file
39
sound_meter/NSRT_MK4_change_config.py
Normal file
@@ -0,0 +1,39 @@
|
||||
'''
|
||||
____ ___ _ _ _ _ ____
|
||||
/ ___| / _ \| | | | \ | | _ \
|
||||
\___ \| | | | | | | \| | | | |
|
||||
___) | |_| | |_| | |\ | |_| |
|
||||
|____/ \___/ \___/|_| \_|____/
|
||||
|
||||
python3 /var/www/nebuleair_pro_4g/sound_meter/NSRT_MK4_change_config.py
|
||||
|
||||
1.Intervalle d'enregistrement
|
||||
L'intervalle d'enregistrement définit le temps entre deux points successifs enregistrés.
|
||||
Cela définit également la période d'intégration pour le LEQ, et la période d'observation pour L-min et L-max et Lpeak.
|
||||
L'intervalle d'enregistrement peut être réglé de 125 ms (1/8ème) à 2 H par incréments de 125 ms.
|
||||
|
||||
some parameters can be changed:
|
||||
write_tau(tau: float) -> time constant
|
||||
write_fs(frequency: int) -> sampling freq
|
||||
|
||||
'''
|
||||
|
||||
import nsrt_mk3_dev
|
||||
|
||||
nsrt = nsrt_mk3_dev.NsrtMk3Dev('/dev/ttyACM0')
|
||||
|
||||
#####################
|
||||
#change time constant
|
||||
nsrt.write_tau(60)
|
||||
#####################
|
||||
|
||||
freq_level = nsrt.read_fs() #current sampling frequency
|
||||
time_constant = nsrt.read_tau() #reads the current time constant
|
||||
leq_level = nsrt.read_leq() #current running LEQ and starts the integration of a new LEQ.
|
||||
weighting = nsrt.read_weighting() #weighting curve that is currently selected
|
||||
weighted_level = nsrt.read_level() #current running level in dB.
|
||||
|
||||
print(f'current sampling freq : {freq_level} Hz')
|
||||
print(f'current time constant : {time_constant} s')
|
||||
print(f'current LEQ level: {leq_level:0.2f} dB')
|
||||
print(f'{weighting} value: {weighted_level:0.2f} dBA')
|
||||
69
sound_meter/NSRT_mk4_get_data.py
Normal file
69
sound_meter/NSRT_mk4_get_data.py
Normal file
@@ -0,0 +1,69 @@
|
||||
'''
|
||||
____ ___ _ _ _ _ ____
|
||||
/ ___| / _ \| | | | \ | | _ \
|
||||
\___ \| | | | | | | \| | | | |
|
||||
___) | |_| | |_| | |\ | |_| |
|
||||
|____/ \___/ \___/|_| \_|____/
|
||||
|
||||
python3 /var/www/nebuleair_pro_4g/sound_meter/get_data.py
|
||||
|
||||
Script to get data from the NSRT_MK4 Sound Level Meter
|
||||
|
||||
Need to install "nsrt_mk3_dev"
|
||||
|
||||
1.Intervalle d'enregistrement
|
||||
L'intervalle d'enregistrement définit le temps entre deux points successifs enregistrés.
|
||||
Cela définit également la période d'intégration pour le LEQ, et la période d'observation pour L-min et L-max et Lpeak.
|
||||
L'intervalle d'enregistrement peut être réglé de 125 ms (1/8ème) à 2 H par incréments de 125 ms.
|
||||
|
||||
some parameters can be changed:
|
||||
write_tau(tau: float) -> time constant
|
||||
write_fs(frequency: int) -> sampling freq
|
||||
|
||||
'''
|
||||
|
||||
import nsrt_mk3_dev
|
||||
import sqlite3
|
||||
|
||||
nsrt = nsrt_mk3_dev.NsrtMk3Dev('/dev/ttyACM0')
|
||||
|
||||
# Connect to the SQLite database
|
||||
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db")
|
||||
cursor = conn.cursor()
|
||||
|
||||
#GET RTC TIME from SQlite
|
||||
cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
|
||||
row = cursor.fetchone() # Get the first (and only) row
|
||||
rtc_time_str = row[1] # '2025-02-07 12:30:45'
|
||||
|
||||
freq_level = nsrt.read_fs() #current sampling frequency
|
||||
time_constant = nsrt.read_tau() #reads the current time constant
|
||||
leq_level = nsrt.read_leq() #current running LEQ and starts the integration of a new LEQ.
|
||||
weighting = nsrt.read_weighting() #weighting curve that is currently selected
|
||||
weighted_level = nsrt.read_level() #current running level in dB.
|
||||
|
||||
#print(f'current sampling freq : {freq_level} Hz')
|
||||
#print(f'current time constant : {time_constant} s')
|
||||
#print(f'current LEQ level: {leq_level:0.2f} dB')
|
||||
#print(f'{weighting} value: {weighted_level:0.2f} dBA')
|
||||
# Round values to 2 decimal places before saving
|
||||
leq_level_rounded = round(leq_level, 2)
|
||||
weighted_level_rounded = round(weighted_level, 2)
|
||||
|
||||
#save to db
|
||||
#save to sqlite database
|
||||
try:
|
||||
cursor.execute('''
|
||||
INSERT INTO data_NOISE (timestamp,current_LEQ, DB_A_value) VALUES (?,?,?)'''
|
||||
, (rtc_time_str,leq_level_rounded,weighted_level_rounded))
|
||||
|
||||
# Commit and close the connection
|
||||
conn.commit()
|
||||
|
||||
#print("Sensor data saved successfully!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Database error: {e}")
|
||||
|
||||
|
||||
conn.close()
|
||||
0
sound_meter/sound_meter → sound_meter/old/sound_meter
Executable file → Normal file
0
sound_meter/sound_meter → sound_meter/old/sound_meter
Executable file → Normal file
0
sound_meter/sound_meter.c → sound_meter/old/sound_meter.c
Executable file → Normal file
0
sound_meter/sound_meter.c → sound_meter/old/sound_meter.c
Executable file → Normal file
0
sound_meter/sound_meter_moving_avg → sound_meter/old/sound_meter_moving_avg
Executable file → Normal file
0
sound_meter/sound_meter_moving_avg → sound_meter/old/sound_meter_moving_avg
Executable file → Normal file
0
sound_meter/sound_meter_moving_avg.c → sound_meter/old/sound_meter_moving_avg.c
Executable file → Normal file
0
sound_meter/sound_meter_moving_avg.c → sound_meter/old/sound_meter_moving_avg.c
Executable file → Normal file
0
sound_meter/sound_meter_nonStop → sound_meter/old/sound_meter_nonStop
Executable file → Normal file
0
sound_meter/sound_meter_nonStop → sound_meter/old/sound_meter_nonStop
Executable file → Normal file
0
sound_meter/sound_meter_nonStop.c → sound_meter/old/sound_meter_nonStop.c
Executable file → Normal file
0
sound_meter/sound_meter_nonStop.c → sound_meter/old/sound_meter_nonStop.c
Executable file → Normal file
@@ -127,6 +127,14 @@ CREATE TABLE IF NOT EXISTS data_MPPT (
|
||||
)
|
||||
""")
|
||||
|
||||
# Create a table noise capture (NSRT mk4)
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS data_NOISE (
|
||||
timestamp TEXT,
|
||||
current_LEQ REAL,
|
||||
DB_A_value REAL
|
||||
)
|
||||
""")
|
||||
|
||||
# Commit and close the connection
|
||||
conn.commit()
|
||||
|
||||
@@ -9,6 +9,9 @@ Script to flush (delete) data from a sqlite database
|
||||
|
||||
/usr/bin/python3 /var/www/nebuleair_pro_4g/sqlite/flush_old_data.py
|
||||
|
||||
Script that is triggered by a systemd
|
||||
sudo systemctl status nebuleair-db-cleanup-data.service
|
||||
|
||||
Available table are
|
||||
|
||||
data_NPM
|
||||
@@ -17,56 +20,183 @@ data_BME280
|
||||
data_envea
|
||||
timestamp_table
|
||||
data_MPPT
|
||||
data_NOISE
|
||||
data_WIND
|
||||
|
||||
'''
|
||||
|
||||
import sqlite3
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
|
||||
def table_exists(cursor, table_name):
|
||||
"""Check if a table exists in the database"""
|
||||
try:
|
||||
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,))
|
||||
return cursor.fetchone() is not None
|
||||
except sqlite3.Error as e:
|
||||
print(f"[ERROR] Failed to check if table '{table_name}' exists: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def get_table_count(cursor, table_name):
|
||||
"""Get the number of records in a table"""
|
||||
try:
|
||||
cursor.execute(f"SELECT COUNT(*) FROM {table_name}")
|
||||
return cursor.fetchone()[0]
|
||||
except sqlite3.Error as e:
|
||||
print(f"[WARNING] Could not get count for table '{table_name}': {e}")
|
||||
return 0
|
||||
|
||||
|
||||
def delete_old_records(cursor, table_name, cutoff_date_str):
|
||||
"""Delete old records from a specific table"""
|
||||
try:
|
||||
# First check how many records will be deleted
|
||||
cursor.execute(f"SELECT COUNT(*) FROM {table_name} WHERE timestamp < ?", (cutoff_date_str,))
|
||||
records_to_delete = cursor.fetchone()[0]
|
||||
|
||||
if records_to_delete == 0:
|
||||
print(f"[INFO] No old records to delete from '{table_name}'")
|
||||
return True
|
||||
|
||||
# Delete the records
|
||||
cursor.execute(f"DELETE FROM {table_name} WHERE timestamp < ?", (cutoff_date_str,))
|
||||
deleted_count = cursor.rowcount
|
||||
|
||||
print(f"[SUCCESS] Deleted {deleted_count} old records from '{table_name}'")
|
||||
return True
|
||||
|
||||
except sqlite3.Error as e:
|
||||
print(f"[ERROR] Failed to delete records from '{table_name}': {e}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
# Connect to the SQLite database
|
||||
print("[INFO] Connecting to database...")
|
||||
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db")
|
||||
cursor = conn.cursor()
|
||||
|
||||
#GET RTC TIME from SQlite
|
||||
cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
|
||||
row = cursor.fetchone() # Get the first (and only) row
|
||||
# Check database connection
|
||||
cursor.execute("SELECT sqlite_version()")
|
||||
version = cursor.fetchone()[0]
|
||||
print(f"[INFO] Connected to SQLite version: {version}")
|
||||
|
||||
# GET RTC TIME from SQLite
|
||||
print("[INFO] Getting timestamp from database...")
|
||||
|
||||
# First check if timestamp_table exists
|
||||
if not table_exists(cursor, "timestamp_table"):
|
||||
print("[ERROR] timestamp_table does not exist!")
|
||||
return False
|
||||
|
||||
cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
|
||||
row = cursor.fetchone()
|
||||
|
||||
if not row:
|
||||
print("[ERROR] No timestamp found in timestamp_table.")
|
||||
return False
|
||||
|
||||
if row:
|
||||
rtc_time_str = row[1] # Assuming timestamp is stored as TEXT (YYYY-MM-DD HH:MM:SS)
|
||||
print(f"[INFO] Last recorded timestamp: {rtc_time_str}")
|
||||
|
||||
# Convert last_updated to a datetime object
|
||||
try:
|
||||
last_updated = datetime.datetime.strptime(rtc_time_str, "%Y-%m-%d %H:%M:%S")
|
||||
except ValueError as e:
|
||||
print(f"[ERROR] Invalid timestamp format: {e}")
|
||||
return False
|
||||
|
||||
# Calculate the cutoff date (3 months before last_updated)
|
||||
# Calculate the cutoff date (60 days before last_updated)
|
||||
cutoff_date = last_updated - datetime.timedelta(days=60)
|
||||
cutoff_date_str = cutoff_date.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
print(f"[INFO] Deleting records older than: {cutoff_date_str}")
|
||||
|
||||
# List of tables to delete old data from
|
||||
tables_to_clean = ["data_NPM", "data_NPM_5channels", "data_BME280", "data_envea","data_WIND", "data_MPPT"]
|
||||
tables_to_clean = [
|
||||
"data_NPM",
|
||||
"data_NPM_5channels",
|
||||
"data_BME280",
|
||||
"data_envea",
|
||||
"data_WIND",
|
||||
"data_MPPT",
|
||||
"data_NOISE"
|
||||
]
|
||||
|
||||
# Check which tables actually exist
|
||||
existing_tables = []
|
||||
missing_tables = []
|
||||
|
||||
# Loop through each table and delete old data
|
||||
for table in tables_to_clean:
|
||||
delete_query = f"DELETE FROM {table} WHERE timestamp < ?"
|
||||
cursor.execute(delete_query, (cutoff_date_str,))
|
||||
print(f"[INFO] Deleted old records from {table}")
|
||||
|
||||
# **Commit changes before running VACUUM**
|
||||
conn.commit()
|
||||
print("[INFO] Changes committed successfully!")
|
||||
|
||||
# Now it's safe to run VACUUM
|
||||
print("[INFO] Running VACUUM to optimize database space...")
|
||||
cursor.execute("VACUUM")
|
||||
|
||||
print("[SUCCESS] Old data flushed successfully!")
|
||||
|
||||
if table_exists(cursor, table):
|
||||
existing_tables.append(table)
|
||||
record_count = get_table_count(cursor, table)
|
||||
print(f"[INFO] Table '{table}' exists with {record_count} records")
|
||||
else:
|
||||
print("[ERROR] No timestamp found in timestamp_table.")
|
||||
missing_tables.append(table)
|
||||
print(f"[WARNING] Table '{table}' does not exist - skipping")
|
||||
|
||||
if missing_tables:
|
||||
print(f"[INFO] Missing tables: {', '.join(missing_tables)}")
|
||||
|
||||
# Close the database connection
|
||||
if not existing_tables:
|
||||
print("[WARNING] No tables found to clean!")
|
||||
return True
|
||||
|
||||
# Loop through existing tables and delete old data
|
||||
successful_deletions = 0
|
||||
failed_deletions = 0
|
||||
|
||||
for table in existing_tables:
|
||||
if delete_old_records(cursor, table, cutoff_date_str):
|
||||
successful_deletions += 1
|
||||
else:
|
||||
failed_deletions += 1
|
||||
|
||||
# Commit changes before running VACUUM
|
||||
print("[INFO] Committing changes...")
|
||||
conn.commit()
|
||||
print("[SUCCESS] Changes committed successfully!")
|
||||
|
||||
# Only run VACUUM if at least some deletions were successful
|
||||
if successful_deletions > 0:
|
||||
print("[INFO] Running VACUUM to optimize database space...")
|
||||
try:
|
||||
cursor.execute("VACUUM")
|
||||
print("[SUCCESS] Database optimized successfully!")
|
||||
except sqlite3.Error as e:
|
||||
print(f"[WARNING] VACUUM failed: {e}")
|
||||
|
||||
# Summary
|
||||
print(f"\n[SUMMARY]")
|
||||
print(f"Tables processed successfully: {successful_deletions}")
|
||||
print(f"Tables with errors: {failed_deletions}")
|
||||
print(f"Tables skipped (missing): {len(missing_tables)}")
|
||||
|
||||
if failed_deletions == 0:
|
||||
print("[SUCCESS] Old data flushed successfully!")
|
||||
return True
|
||||
else:
|
||||
print("[WARNING] Some operations failed - check logs above")
|
||||
return False
|
||||
|
||||
except sqlite3.Error as e:
|
||||
print(f"[ERROR] Database error: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Unexpected error: {e}")
|
||||
return False
|
||||
finally:
|
||||
# Always close the database connection
|
||||
if 'conn' in locals():
|
||||
conn.close()
|
||||
print("[INFO] Database connection closed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = main()
|
||||
sys.exit(0 if success else 1)
|
||||
@@ -47,6 +47,7 @@ config_entries = [
|
||||
("windMeter", "0", "bool"),
|
||||
("BME280", "0", "bool"),
|
||||
("MPPT", "0", "bool"),
|
||||
("NOISE", "0", "bool"),
|
||||
("modem_version", "XXX", "str")
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user