#!/bin/bash
# E-Paper Calendar System Control Script (cron-based version)
# This version is intended to be run via cron every 60 minutes and at boot.
# It features a recovery mechanism for screen script failures with a maximum of 3 reboot attempts.
# Once a script reaches GAVE_UP, its recovery flag is retained (with an incremented tally)
# and that script is run last during the full run.
#
# Recovery flags are stored separately:
# recovery_flag_runscreen1.txt for runscreen1.py
# recovery_flag_runscreen2.txt for runscreen2.py
#
# Flag file format: script_name:attempt:status
# - status can be: REBOOT_PENDING, REBOOT_COMPLETE, or GAVE_UP
# Set working directory to the script location
cd "$(dirname "$0")"
#######################################
# Function Definitions
#######################################
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
log_error() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1" >> errorLog.txt
}
log_stat() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> statsLog.txt
}
run_script() {
script_name=$1
log_message "Running $script_name..."
if python3 "$script_name"; then
log_message "$script_name completed successfully"
return 0
else
log_error "$script_name failed with exit code $?"
return 1
fi
}
run_screen_script_with_retry() {
script_name=$1
flag_file=$2
max_attempts=3
for attempt in $(seq 1 $max_attempts); do
log_message "Running $script_name (attempt $attempt of $max_attempts)..."
if python3 "$script_name"; then
log_message "$script_name completed successfully on attempt $attempt"
return 0
else
log_error "$script_name failed on attempt $attempt"
if [ $attempt -lt $max_attempts ]; then
log_message "Waiting 10 seconds before retrying $script_name..."
sleep 10
fi
fi
done
log_error "$script_name failed after $max_attempts attempts"
return 1
}
check_internet() {
log_message "Checking internet connectivity..."
attempt=1
max_attempts=5
while [ $attempt -le $max_attempts ]; do
if ping -c 1 8.8.8.8 &>/dev/null; then
log_message "Internet connection established on attempt $attempt"
return 0
else
log_message "Internet check failed (attempt $attempt/$max_attempts). Retrying in 5 seconds..."
sleep 5
attempt=$((attempt+1))
fi
done
log_error "Failed to establish internet connection after $max_attempts attempts"
return 1
}
update_refresh_count() {
if [ ! -f statsLog.txt ]; then
echo "REFRESH_COUNT=0" > statsLog.txt
fi
current_count=$(grep "REFRESH_COUNT=" statsLog.txt | tail -1 | cut -d'=' -f2)
new_count=$((current_count+1))
log_stat "REFRESH_COUNT=$new_count"
log_stat "LAST_REFRESH=$(date '+%Y-%m-%d %H:%M:%S')"
}
#######################################
# Early Recovery Mechanism
#######################################
# Process any recovery flag that is not in GAVE_UP state.
process_recovery_flag() {
flag_file=$1
if [ -f "$flag_file" ]; then
IFS=":" read -r failed_script attempt status < "$flag_file"
attempt=${attempt:-0}
if [ "$status" != "GAVE_UP" ]; then
log_message "Recovery mode: Detected $failed_script (attempt $attempt) with status $status in $flag_file"
if [ "$status" == "REBOOT_PENDING" ]; then
echo "$failed_script:$attempt:REBOOT_COMPLETE" > "$flag_file"
log_message "Recovery mode: Updated status to REBOOT_COMPLETE in $flag_file. Rebooting now..."
sudo reboot
exit 0
elif [ "$status" == "REBOOT_COMPLETE" ]; then
new_attempt=$((attempt+1))
if [ $new_attempt -ge 3 ]; then
echo "$failed_script:$new_attempt:GAVE_UP" > "$flag_file"
log_message "Recovery mode: Max attempts reached for $failed_script ($new_attempt). Marking as GAVE_UP and continuing full run."
# Do not exit; let full run proceed.
else
echo "$failed_script:$new_attempt:REBOOT_PENDING" > "$flag_file"
log_message "Recovery mode: Incremented attempt to $new_attempt for $failed_script. Running recovery mode now..."
if run_screen_script_with_retry "$failed_script" "$flag_file"; then
log_message "Recovery mode: $failed_script succeeded. Clearing $flag_file."
rm "$flag_file"
else
log_error "Recovery mode: $failed_script failed on recovery attempt."
fi
exit 0
fi
fi
else
log_message "Recovery flag in $flag_file is in GAVE_UP state. Skipping early recovery processing."
fi
fi
}
# Check both recovery flag files for early recovery.
process_recovery_flag "recovery_flag_runscreen1.txt"
process_recovery_flag "recovery_flag_runscreen2.txt"
#######################################
# Main Execution (Cron-based, single run)
#######################################
touch errorLog.txt
touch statsLog.txt
log_message "Starting e-paper calendar system..."
if [ -f calConfig.json ]; then
update_frequency=$(grep -o '"Update frequency (minutes)":[^,}]*' calConfig.json | cut -d':' -f2 | tr -d ' ')
if ! [[ "$update_frequency" =~ ^[0-9]+$ ]]; then
update_frequency=60
log_message "Using default update frequency of 60 minutes"
else
log_message "Using configured update frequency of $update_frequency minutes"
fi
else
update_frequency=60
log_message "Config file not found. Using default update frequency of 60 minutes"
fi
if check_internet; then
update_refresh_count
run_script fetchIcs.py
run_script alarmSet.py
run_script fetchData.py
run_script imageSave.py
run_script renderProcess.py
############################################################
# Execute Screen Scripts Normal vs. GAVE_UP Execution
############################################################
# Flags to indicate if a script is in GAVE_UP mode.
gave_up_screen1=false
gave_up_screen2=false
# --- Process runscreen2.py ---
flag2="recovery_flag_runscreen2.txt"
if [ -f "$flag2" ]; then
IFS=":" read -r script2 attempt2 status2 < "$flag2"
if [ "$status2" == "GAVE_UP" ]; then
gave_up_screen2=true
log_message "runscreen2.py is in GAVE_UP mode (attempt $attempt2). It will be run later."
else
# Not in GAVE_UP; overwrite with new attempt.
echo "runscreen2.py:1:REBOOT_PENDING" > "$flag2"
if run_screen_script_with_retry runscreen2.py "$flag2"; then
rm "$flag2"
else
log_error "runscreen2.py failed even with retries. Initiating recovery reboot..."
sudo reboot
fi
fi
else
# No existing flag; run normally.
echo "runscreen2.py:1:REBOOT_PENDING" > "$flag2"
if run_screen_script_with_retry runscreen2.py "$flag2"; then
rm "$flag2"
else
log_error "runscreen2.py failed even with retries. Initiating recovery reboot..."
sudo reboot
fi
fi
# --- Process runscreen1.py ---
flag1="recovery_flag_runscreen1.txt"
if [ -f "$flag1" ]; then
IFS=":" read -r script1 attempt1 status1 < "$flag1"
if [ "$status1" == "GAVE_UP" ]; then
gave_up_screen1=true
log_message "runscreen1.py is in GAVE_UP mode (attempt $attempt1). It will be run later."
else
echo "runscreen1.py:1:REBOOT_PENDING" > "$flag1"
if run_screen_script_with_retry runscreen1.py "$flag1"; then
rm "$flag1"
else
log_error "runscreen1.py failed even with retries. Initiating recovery reboot..."
sudo reboot
fi
fi
else
echo "runscreen1.py:1:REBOOT_PENDING" > "$flag1"
if run_screen_script_with_retry runscreen1.py "$flag1"; then
rm "$flag1"
else
log_error "runscreen1.py failed even with retries. Initiating recovery reboot..."
sudo reboot
fi
fi
############################################################
# Process any GAVE_UP screen scripts (execute them last)
############################################################
# To ensure the full Run.sh cycle completes, any screen script in GAVE_UP mode is run now.
# When running in GAVE_UP mode, we update (increment) the attempt count and run the script without rebooting.
if $gave_up_screen1; then
IFS=":" read -r script1 attempt1 status1 < "$flag1"
new_attempt=$((attempt1+1))
echo "runscreen1.py:$new_attempt:GAVE_UP" > "$flag1"
log_message "Attempting runscreen1.py in GAVE_UP mode (attempt $new_attempt)..."
if run_screen_script_with_retry runscreen1.py "$flag1"; then
log_message "runscreen1.py succeeded in GAVE_UP mode. Clearing flag."
rm "$flag1"
else
log_error "runscreen1.py failed in GAVE_UP mode. Tally updated (attempt $new_attempt)."
fi
fi
if $gave_up_screen2; then
IFS=":" read -r script2 attempt2 status2 < "$flag2"
new_attempt=$((attempt2+1))
echo "runscreen2.py:$new_attempt:GAVE_UP" > "$flag2"
log_message "Attempting runscreen2.py in GAVE_UP mode (attempt $new_attempt)..."
if run_screen_script_with_retry runscreen2.py "$flag2"; then
log_message "runscreen2.py succeeded in GAVE_UP mode. Clearing flag."
rm "$flag2"
else
log_error "runscreen2.py failed in GAVE_UP mode. Tally updated (attempt $new_attempt)."
fi
fi
log_message "Calendar refresh completed."
log_message "Shutting down the system..."
sudo shutdown -h now
else
log_message "Skipping refresh due to no internet connection."
log_message "Shutting down the system..."
sudo shutdown -h now
fi
Comments