Merging 2.2.7 Release Candidate
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
# Simple script to fetch interpreted QCAINFO results
|
||||
|
||||
INTERPRETED_FILE="/tmp/interpreted_result.json"
|
||||
|
||||
# Set content type for JSON
|
||||
echo "Content-Type: application/json"
|
||||
echo "Access-Control-Allow-Origin: *"
|
||||
echo "Access-Control-Allow-Methods: GET, POST, OPTIONS"
|
||||
echo "Access-Control-Allow-Headers: Content-Type"
|
||||
echo ""
|
||||
|
||||
# Check if file exists
|
||||
if [ ! -f "$INTERPRETED_FILE" ]; then
|
||||
echo "[]"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Return the JSON content
|
||||
cat "$INTERPRETED_FILE"
|
||||
@@ -0,0 +1,251 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Scheduled Reboot Configuration Script
|
||||
# Manages device reboot scheduling using cron
|
||||
# Author: dr-dolomite
|
||||
# Date: 2025-08-10
|
||||
|
||||
# Set content type and CORS headers
|
||||
echo "Content-Type: application/json"
|
||||
echo "Access-Control-Allow-Origin: *"
|
||||
echo "Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS"
|
||||
echo "Access-Control-Allow-Headers: Content-Type"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
CONFIG_DIR="/etc/quecmanager/settings"
|
||||
CONFIG_FILE="$CONFIG_DIR/scheduled_reboot.conf"
|
||||
LOG_FILE="/tmp/scheduled_reboot.log"
|
||||
CRON_FILE="/etc/crontabs/root"
|
||||
|
||||
# Logging function
|
||||
log_message() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Error response function
|
||||
send_error() {
|
||||
local error_code="$1"
|
||||
local error_message="$2"
|
||||
log_message "ERROR: $error_message"
|
||||
echo "{\"status\":\"error\",\"code\":\"$error_code\",\"message\":\"$error_message\"}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Success response function
|
||||
send_success() {
|
||||
local message="$1"
|
||||
local data="$2"
|
||||
log_message "SUCCESS: $message"
|
||||
if [ -n "$data" ]; then
|
||||
echo "{\"status\":\"success\",\"message\":\"$message\",\"data\":$data}"
|
||||
else
|
||||
echo "{\"status\":\"success\",\"message\":\"$message\"}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Ensure configuration directory exists
|
||||
ensure_config_directory() {
|
||||
if [ ! -d "$CONFIG_DIR" ]; then
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
if [ $? -ne 0 ]; then
|
||||
CONFIG_DIR="/tmp/quecmanager/settings"
|
||||
CONFIG_FILE="$CONFIG_DIR/scheduled_reboot.conf"
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
if [ $? -ne 0 ]; then
|
||||
send_error "DIRECTORY_ERROR" "Failed to create configuration directory"
|
||||
fi
|
||||
fi
|
||||
chmod 755 "$CONFIG_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
# Update cron entry
|
||||
update_cron() {
|
||||
local enabled="$1"
|
||||
local time="$2"
|
||||
local days="$3"
|
||||
|
||||
# Create a temporary file for the new crontab
|
||||
local temp_cron=$(mktemp)
|
||||
|
||||
# If crontab exists, copy all non-QuecManager reboot entries
|
||||
if [ -f "$CRON_FILE" ]; then
|
||||
grep -v "# QuecManager scheduled reboot$" "$CRON_FILE" > "$temp_cron"
|
||||
fi
|
||||
|
||||
if [ "$enabled" = "true" ]; then
|
||||
# Extract hours and minutes from time (HH:MM format)
|
||||
local minutes=$(echo "$time" | cut -d':' -f2)
|
||||
local hours=$(echo "$time" | cut -d':' -f1)
|
||||
|
||||
# Convert days array to cron format (0-6, where 0 is Sunday)
|
||||
local cron_days=""
|
||||
echo "$days" | grep -q '"sunday"' && cron_days="${cron_days}0,"
|
||||
echo "$days" | grep -q '"monday"' && cron_days="${cron_days}1,"
|
||||
echo "$days" | grep -q '"tuesday"' && cron_days="${cron_days}2,"
|
||||
echo "$days" | grep -q '"wednesday"' && cron_days="${cron_days}3,"
|
||||
echo "$days" | grep -q '"thursday"' && cron_days="${cron_days}4,"
|
||||
echo "$days" | grep -q '"friday"' && cron_days="${cron_days}5,"
|
||||
echo "$days" | grep -q '"saturday"' && cron_days="${cron_days}6,"
|
||||
|
||||
# Remove trailing comma
|
||||
cron_days=$(echo "$cron_days" | sed 's/,$//')
|
||||
|
||||
if [ -n "$cron_days" ]; then
|
||||
# Add new cron entry to our temporary file
|
||||
echo "$minutes $hours * * $cron_days /sbin/reboot # QuecManager scheduled reboot" >> "$temp_cron"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ensure the crontabs directory exists
|
||||
if [ ! -d "/etc/crontabs" ]; then
|
||||
mkdir -p /etc/crontabs
|
||||
chmod 755 /etc/crontabs
|
||||
fi
|
||||
|
||||
# Move the temporary file to the actual crontab and set permissions
|
||||
mv "$temp_cron" "$CRON_FILE"
|
||||
chmod 600 "$CRON_FILE"
|
||||
|
||||
# Always restart cron to ensure changes take effect
|
||||
/etc/init.d/cron restart
|
||||
}
|
||||
|
||||
# Save reboot configuration
|
||||
save_config() {
|
||||
local enabled="$1"
|
||||
local time="$2"
|
||||
local days="$3"
|
||||
|
||||
ensure_config_directory
|
||||
|
||||
# Validate days is a proper JSON array
|
||||
if ! echo "$days" | grep -q '^\[.*\]$'; then
|
||||
days='["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]'
|
||||
fi
|
||||
|
||||
# Create or update config file with proper JSON handling
|
||||
cat > "$CONFIG_FILE" << EOF
|
||||
REBOOT_ENABLED=$enabled
|
||||
REBOOT_TIME=$time
|
||||
REBOOT_DAYS=$days
|
||||
EOF
|
||||
|
||||
chmod 644 "$CONFIG_FILE"
|
||||
|
||||
# Update cron entry
|
||||
update_cron "$enabled" "$time" "$days"
|
||||
}
|
||||
|
||||
# Get current configuration
|
||||
get_config() {
|
||||
local enabled="false"
|
||||
local time="03:00"
|
||||
local days='["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]'
|
||||
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
# Read the config file line by line to handle JSON properly
|
||||
while IFS='=' read -r key value; do
|
||||
case "$key" in
|
||||
REBOOT_ENABLED)
|
||||
enabled="$value"
|
||||
;;
|
||||
REBOOT_TIME)
|
||||
time="$value"
|
||||
;;
|
||||
REBOOT_DAYS)
|
||||
# Only update days if the value is a valid JSON array
|
||||
if echo "$value" | grep -q '^\[.*\]$'; then
|
||||
days="$value"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done < "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
# Ensure proper JSON formatting
|
||||
echo "{\"enabled\":$enabled,\"time\":\"$time\",\"days\":$days}"
|
||||
}
|
||||
|
||||
# Handle GET request
|
||||
handle_get() {
|
||||
local config=$(get_config)
|
||||
send_success "Configuration retrieved" "$config"
|
||||
}
|
||||
|
||||
# Handle POST request
|
||||
handle_post() {
|
||||
# Read POST data
|
||||
local content_length=${CONTENT_LENGTH:-0}
|
||||
if [ "$content_length" -gt 0 ]; then
|
||||
local post_data=$(dd bs=$content_length count=1 2>/dev/null)
|
||||
|
||||
# Extract values using grep and sed
|
||||
local enabled=$(echo "$post_data" | grep -o '"enabled":\s*\(true\|false\)' | cut -d':' -f2 | tr -d ' ')
|
||||
local time=$(echo "$post_data" | grep -o '"time":"[^"]*"' | cut -d'"' -f4)
|
||||
local days=$(echo "$post_data" | grep -o '"days":\s*\[[^]]*\]' | cut -d':' -f2 | tr -d ' ')
|
||||
|
||||
# Validate input
|
||||
if [ -z "$enabled" ] || [ -z "$time" ] || [ -z "$days" ]; then
|
||||
send_error "INVALID_INPUT" "Missing required fields"
|
||||
return
|
||||
fi
|
||||
|
||||
# Validate time format (HH:MM)
|
||||
if ! echo "$time" | grep -qE '^([01]?[0-9]|2[0-3]):[0-5][0-9]$'; then
|
||||
send_error "INVALID_TIME" "Invalid time format. Use HH:MM (24-hour)"
|
||||
return
|
||||
fi
|
||||
|
||||
# Save configuration
|
||||
save_config "$enabled" "$time" "$days"
|
||||
send_success "Configuration updated successfully" "$(get_config)"
|
||||
|
||||
else
|
||||
send_error "NO_DATA" "No data provided"
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle DELETE request
|
||||
handle_delete() {
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
# Remove cron entry first
|
||||
update_cron "false" "00:00" "[]"
|
||||
|
||||
# Remove config file
|
||||
rm -f "$CONFIG_FILE"
|
||||
send_success "Configuration reset to default" "$(get_config)"
|
||||
else
|
||||
send_error "NOT_FOUND" "Configuration not found"
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle OPTIONS request
|
||||
handle_options() {
|
||||
echo "Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS"
|
||||
echo "Access-Control-Allow-Headers: Content-Type"
|
||||
echo "Access-Control-Max-Age: 86400"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Main execution
|
||||
log_message "Scheduled reboot script called with method: ${REQUEST_METHOD:-GET}"
|
||||
|
||||
case "${REQUEST_METHOD:-GET}" in
|
||||
GET)
|
||||
handle_get
|
||||
;;
|
||||
POST)
|
||||
handle_post
|
||||
;;
|
||||
DELETE)
|
||||
handle_delete
|
||||
;;
|
||||
OPTIONS)
|
||||
handle_options
|
||||
;;
|
||||
*)
|
||||
send_error "METHOD_NOT_ALLOWED" "HTTP method ${REQUEST_METHOD} not supported"
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,227 @@
|
||||
#!/bin/sh
|
||||
# Simple QCAINFO Interpreter
|
||||
|
||||
# Configuration
|
||||
QCAINFO_FILE="/www/signal_graphs/qcainfo.json"
|
||||
INTERPRETED_FILE="/tmp/interpreted_result.json"
|
||||
DEBUG_LOG="/tmp/qcainfo_interpreter.log"
|
||||
INTERVAL=15
|
||||
|
||||
# Simple logging function
|
||||
log() {
|
||||
echo "$(date): $1" >> "$DEBUG_LOG"
|
||||
}
|
||||
|
||||
# Parse QCAINFO output to extract band and EARFCN
|
||||
parse_entry() {
|
||||
local output="$1"
|
||||
local datetime="$2"
|
||||
|
||||
# Extract band and EARFCN using simple grep
|
||||
local band=$(echo "$output" | grep -o 'LTE BAND [0-9]*' | head -1)
|
||||
local earfcn=$(echo "$output" | grep -o '+QCAINFO: "PCC",[0-9]*' | grep -o '[0-9]*' | head -1)
|
||||
local pci=$(echo "$output" | grep -o '+QCAINFO: "PCC",[0-9]*,[0-9]*' | grep -o ',[0-9]*,' | tr -d ',' | head -1)
|
||||
|
||||
# Check for SCC (carrier aggregation)
|
||||
local has_scc=""
|
||||
if echo "$output" | grep -q '+QCAINFO: "SCC"'; then
|
||||
has_scc="yes"
|
||||
else
|
||||
has_scc="no"
|
||||
fi
|
||||
|
||||
echo "${datetime}|${band}|${earfcn}|${pci}|${has_scc}"
|
||||
}
|
||||
|
||||
# Compare two entries and generate interpretation
|
||||
generate_interpretation() {
|
||||
local old_entry="$1"
|
||||
local new_entry="$2"
|
||||
|
||||
# Parse entries
|
||||
local old_datetime=$(echo "$old_entry" | cut -d'|' -f1)
|
||||
local old_band=$(echo "$old_entry" | cut -d'|' -f2)
|
||||
local old_earfcn=$(echo "$old_entry" | cut -d'|' -f3)
|
||||
local old_pci=$(echo "$old_entry" | cut -d'|' -f4)
|
||||
local old_scc=$(echo "$old_entry" | cut -d'|' -f5)
|
||||
|
||||
local new_datetime=$(echo "$new_entry" | cut -d'|' -f1)
|
||||
local new_band=$(echo "$new_entry" | cut -d'|' -f2)
|
||||
local new_earfcn=$(echo "$new_entry" | cut -d'|' -f3)
|
||||
local new_pci=$(echo "$new_entry" | cut -d'|' -f4)
|
||||
local new_scc=$(echo "$new_entry" | cut -d'|' -f5)
|
||||
|
||||
local time_only=$(echo "$new_datetime" | awk '{print $2}' | cut -d: -f1,2)
|
||||
local interpretation=""
|
||||
|
||||
# Check for band change
|
||||
if [ "$old_band" != "$new_band" ]; then
|
||||
interpretation="${interpretation}At ${time_only}, your modem changed primary band from ${old_band} to ${new_band}. "
|
||||
fi
|
||||
|
||||
# Check for EARFCN change
|
||||
if [ "$old_earfcn" != "$new_earfcn" ]; then
|
||||
interpretation="${interpretation}At ${time_only}, your modem changed primary EARFCN from ${old_earfcn} to ${new_earfcn}. "
|
||||
fi
|
||||
|
||||
# Check for PCI change
|
||||
if [ "$old_pci" != "$new_pci" ]; then
|
||||
interpretation="${interpretation}At ${time_only}, your modem changed primary PCI from ${old_pci} to ${new_pci}. "
|
||||
fi
|
||||
|
||||
# Check for carrier aggregation changes
|
||||
if [ "$old_scc" = "no" ] && [ "$new_scc" = "yes" ]; then
|
||||
interpretation="${interpretation}At ${time_only}, your modem activated carrier aggregation. "
|
||||
elif [ "$old_scc" = "yes" ] && [ "$new_scc" = "no" ]; then
|
||||
interpretation="${interpretation}At ${time_only}, your modem deactivated carrier aggregation. "
|
||||
fi
|
||||
|
||||
echo "$interpretation"
|
||||
}
|
||||
|
||||
# Add interpretation to JSON file without jq
|
||||
add_interpretation() {
|
||||
local interpretation="$1"
|
||||
local datetime="$2"
|
||||
|
||||
if [ -z "$interpretation" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Initialize file if it doesn't exist
|
||||
if [ ! -f "$INTERPRETED_FILE" ]; then
|
||||
echo "[]" > "$INTERPRETED_FILE"
|
||||
fi
|
||||
|
||||
# Read existing content
|
||||
local existing_content=$(cat "$INTERPRETED_FILE")
|
||||
|
||||
# Escape quotes in interpretation
|
||||
local escaped_interpretation=$(echo "$interpretation" | sed 's/"/\\"/g')
|
||||
|
||||
# Create new entry
|
||||
local new_entry="{\"datetime\":\"$datetime\",\"interpretation\":\"$escaped_interpretation\"}"
|
||||
|
||||
# Add to array
|
||||
if [ "$existing_content" = "[]" ]; then
|
||||
echo "[$new_entry]" > "$INTERPRETED_FILE"
|
||||
else
|
||||
# Remove closing bracket, add comma and new entry
|
||||
echo "$existing_content" | sed 's/]$//' > "$INTERPRETED_FILE.tmp"
|
||||
echo ",$new_entry]" >> "$INTERPRETED_FILE.tmp"
|
||||
mv "$INTERPRETED_FILE.tmp" "$INTERPRETED_FILE"
|
||||
fi
|
||||
|
||||
log "Added interpretation: $interpretation"
|
||||
}
|
||||
|
||||
# Main processing function
|
||||
process_qcainfo() {
|
||||
if [ ! -f "$QCAINFO_FILE" ]; then
|
||||
log "QCAINFO file not found: $QCAINFO_FILE"
|
||||
return
|
||||
fi
|
||||
|
||||
# Get total entries
|
||||
local total_entries=$(jq 'length' "$QCAINFO_FILE" 2>/dev/null)
|
||||
if [ -z "$total_entries" ] || [ "$total_entries" = "null" ] || [ "$total_entries" -lt 2 ]; then
|
||||
log "Not enough entries to compare (need at least 2, found: $total_entries)"
|
||||
return
|
||||
fi
|
||||
|
||||
log "Found $total_entries entries in QCAINFO file"
|
||||
|
||||
# Get last two entries
|
||||
local last_entry=$(jq -r '.[-1]' "$QCAINFO_FILE" 2>/dev/null)
|
||||
local second_last_entry=$(jq -r '.[-2]' "$QCAINFO_FILE" 2>/dev/null)
|
||||
|
||||
if [ "$last_entry" = "null" ] || [ "$second_last_entry" = "null" ]; then
|
||||
log "Failed to get last two entries"
|
||||
return
|
||||
fi
|
||||
|
||||
# Extract data from JSON entries
|
||||
local last_datetime=$(echo "$last_entry" | jq -r '.datetime')
|
||||
local last_output=$(echo "$last_entry" | jq -r '.output')
|
||||
local second_datetime=$(echo "$second_last_entry" | jq -r '.datetime')
|
||||
local second_output=$(echo "$second_last_entry" | jq -r '.output')
|
||||
|
||||
log "Comparing entries: $second_datetime vs $last_datetime"
|
||||
|
||||
# Parse entries
|
||||
local parsed_second=$(parse_entry "$second_output" "$second_datetime")
|
||||
local parsed_last=$(parse_entry "$last_output" "$last_datetime")
|
||||
|
||||
log "Parsed second: $parsed_second"
|
||||
log "Parsed last: $parsed_last"
|
||||
|
||||
# Generate interpretation
|
||||
local interpretation=$(generate_interpretation "$parsed_second" "$parsed_last")
|
||||
|
||||
if [ -n "$interpretation" ]; then
|
||||
add_interpretation "$interpretation" "$last_datetime"
|
||||
log "Generated interpretation for $last_datetime"
|
||||
else
|
||||
log "No changes detected between $second_datetime and $last_datetime"
|
||||
fi
|
||||
}
|
||||
|
||||
# Initialize
|
||||
log "QCAINFO Interpreter started (PID: $$)"
|
||||
|
||||
# Initialize interpreted results file
|
||||
if [ ! -f "$INTERPRETED_FILE" ]; then
|
||||
echo "[]" > "$INTERPRETED_FILE"
|
||||
log "Initialized interpreted results file"
|
||||
fi
|
||||
|
||||
# Process all existing data once at startup
|
||||
log "Processing all existing QCAINFO data..."
|
||||
if [ -f "$QCAINFO_FILE" ]; then
|
||||
total=$(jq 'length' "$QCAINFO_FILE" 2>/dev/null)
|
||||
if [ "$total" -gt 1 ]; then
|
||||
# Process all consecutive pairs
|
||||
i=1
|
||||
while [ $i -lt $total ]; do
|
||||
prev_entry=$(jq -r ".[$((i-1))]" "$QCAINFO_FILE" 2>/dev/null)
|
||||
curr_entry=$(jq -r ".[$i]" "$QCAINFO_FILE" 2>/dev/null)
|
||||
|
||||
if [ "$prev_entry" != "null" ] && [ "$curr_entry" != "null" ]; then
|
||||
prev_datetime=$(echo "$prev_entry" | jq -r '.datetime')
|
||||
prev_output=$(echo "$prev_entry" | jq -r '.output')
|
||||
curr_datetime=$(echo "$curr_entry" | jq -r '.datetime')
|
||||
curr_output=$(echo "$curr_entry" | jq -r '.output')
|
||||
|
||||
parsed_prev=$(parse_entry "$prev_output" "$prev_datetime")
|
||||
parsed_curr=$(parse_entry "$curr_output" "$curr_datetime")
|
||||
|
||||
interpretation=$(generate_interpretation "$parsed_prev" "$parsed_curr")
|
||||
|
||||
if [ -n "$interpretation" ]; then
|
||||
add_interpretation "$interpretation" "$curr_datetime"
|
||||
fi
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
log "Completed processing all existing data ($total entries)"
|
||||
else
|
||||
log "Not enough existing data to process"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remember last processed entry count
|
||||
last_count=$(jq 'length' "$QCAINFO_FILE" 2>/dev/null)
|
||||
|
||||
# Main monitoring loop
|
||||
log "Starting continuous monitoring (checking every $INTERVAL seconds)"
|
||||
while true; do
|
||||
sleep "$INTERVAL"
|
||||
|
||||
current_count=$(jq 'length' "$QCAINFO_FILE" 2>/dev/null)
|
||||
|
||||
if [ "$current_count" -gt "$last_count" ]; then
|
||||
log "New entries detected: $last_count -> $current_count"
|
||||
process_qcainfo
|
||||
last_count="$current_count"
|
||||
fi
|
||||
done
|
||||
@@ -164,7 +164,23 @@ process_all_metrics() {
|
||||
"$logfile" > "$temp_file" 2>/dev/null && mv "$temp_file" "$logfile"
|
||||
chmod 644 "$logfile"
|
||||
fi
|
||||
|
||||
|
||||
sleep 0.5
|
||||
|
||||
# QCAINFO with time stamp
|
||||
local usage_output=$(execute_at_command "AT+QCAINFO")
|
||||
if [ -n "$usage_output" ] && echo "$usage_output" | grep -q "QCAINFO"; then
|
||||
local logfile="$LOGDIR/qcainfo.json"
|
||||
[ ! -s "$logfile" ] && echo "[]" > "$logfile"
|
||||
|
||||
local temp_file="${logfile}.tmp.$$"
|
||||
jq --arg dt "$timestamp" \
|
||||
--arg out "$usage_output" \
|
||||
'. + [{"datetime": $dt, "output": $out}] | .[-'"$MAX_ENTRIES"':]' \
|
||||
"$logfile" > "$temp_file" 2>/dev/null && mv "$temp_file" "$logfile"
|
||||
chmod 644 "$logfile"
|
||||
fi
|
||||
|
||||
# Release token
|
||||
release_token "$metrics_id"
|
||||
logger -t at_queue -p daemon.info "Metrics processing completed"
|
||||
|
||||
Reference in New Issue
Block a user