2 # Desc: Ninfacyzga-1: Capture and store photograph from a camera to temporary directory for 24 hours 
   3 # Usage: update_temp_photo.sh arg1 
   4 # Input: arg1: camera tag name (e.g. "DC1") 
   5 # Depends: age, gnu coreutils, libgps, sleepRand.py 
   7 #==BEGIN Define Parameters== 
   8 temp_dir
="/dev/shm"; # default 
   9 iso_date
="$(date +%Y%m%dT%H%M%S%z)"; 
  10 #iso_date_ns="$(date +%Y%m%dT%H%M%S.%N%z)"; 
  11 device_hostname
="$(hostname)"; 
  12 nfg_base_dir
="../../"; # root directory of ninfacyzga-1 git repo 
  13 nfg_unitproc_path
="$nfg_base_dir"/exec
/unitproc
; 
  14 sleep_rand_path
="$nfg_base_dir"/exec
/unitproc
/sleepRand.py
; 
  15 PATH
="$nfg_unitproc_path:$PATH"; # include unitprocess nfg executables 
  17 declare -Ag appRollCall 
# Associative array for storing app status 
  18 declare -Ag fileRollCall 
# Associative array for storing file status 
  19 declare -Ag dirRollCall 
# Associative array for storing dir status 
  20 #==END Define Parameters== 
  22 #==BEGIN Define Functions== 
  23 yell
() { echo "$0: $*" >&2; }      #o Yell, Die, Try Three-Fingered Claw technique 
  24 die
() { yell 
"$*"; exit 111; }     #o Ref/Attrib: https://stackoverflow.com/a/25515370 
  25 try
() { "$@" || die 
"cannot $*"; } #o 
  27     # Desc: If arg is a command, save result in assoc array 'appRollCall' 
  28     # Usage: checkapp arg1 arg2 arg3 ... 
  30     # Input: global assoc. array 'appRollCall' 
  31     # Output: adds/updates key(value) to global assoc array 'appRollCall' 
  37         if command -v "$arg" 1>/dev
/null 
2>&1; then # Check if arg is a valid command 
  38             appRollCall
[$arg]="true"; 
  39             if ! [ "$returnState" = "false" ]; then returnState
="true"; fi; 
  41             appRollCall
[$arg]="false"; returnState
="false"; 
  45     #===Determine function return code=== 
  46     if [ "$returnState" = "true" ]; then 
  51 } # Check that app exists 
  53     # Desc: If arg is a file path, save result in assoc array 'fileRollCall' 
  54     # Usage: checkfile arg1 arg2 arg3 ... 
  56     # Input: global assoc. array 'fileRollCall' 
  57     # Output: adds/updates key(value) to global assoc array 'fileRollCall'; 
  58     # Output: returns 0 if app found, 1 otherwise 
  64         if [ -f "$arg" ]; then 
  65             fileRollCall
["$arg"]="true"; 
  66             if ! [ "$returnState" = "false" ]; then returnState
="true"; fi; 
  68             fileRollCall
["$arg"]="false"; returnState
="false"; 
  72     #===Determine function return code=== 
  73     if [ "$returnState" = "true" ]; then 
  78 } # Check that file exists 
  80     # Desc: If arg is a dir path, save result in assoc array 'dirRollCall' 
  81     # Usage: checkdir arg1 arg2 arg3 ... 
  83     # Input: global assoc. array 'dirRollCall' 
  84     # Output: adds/updates key(value) to global assoc array 'dirRollCall'; 
  85     # Output: returns 0 if app found, 1 otherwise 
  91         if [ -d "$arg" ]; then 
  92             dirRollCall
["$arg"]="true"; 
  93             if ! [ "$returnState" = "false" ]; then returnState
="true"; fi 
  95             dirRollCall
["$arg"]="false"; returnState
="false"; 
  99     #===Determine function return code=== 
 100     if [ "$returnState" = "true" ]; then 
 105 } # Check that dir exists 
 107     # Desc: Displays missing apps, files, and dirs 
 108     # Usage: displayMissing 
 110     # Input: associative arrays: appRollCall, fileRollCall, dirRollCall 
 111     # Output: stderr: messages indicating missing apps, file, or dirs 
 112     # Depends: bash 5, checkAppFileDir() 
 113     local missingApps value appMissing missingFiles fileMissing
 
 114     local missingDirs dirMissing
 
 116     #==BEGIN Display errors== 
 117     #===BEGIN Display Missing Apps=== 
 118     missingApps
="Missing apps  :"; 
 119     #for key in "${!appRollCall[@]}"; do echo "DEBUG:$key => ${appRollCall[$key]}"; done 
 120     for key 
in "${!appRollCall[@]}"; do 
 121         value
="${appRollCall[$key]}"; 
 122         if [ "$value" = "false" ]; then 
 123             #echo "DEBUG:Missing apps: $key => $value"; 
 124             missingApps
="$missingApps""$key "; 
 128     if [ "$appMissing" = "true" ]; then  # Only indicate if an app is missing. 
 129         echo "$missingApps" 1>&2; 
 132     #===END Display Missing Apps=== 
 134     #===BEGIN Display Missing Files=== 
 135     missingFiles
="Missing files:"; 
 136     #for key in "${!fileRollCall[@]}"; do echo "DEBUG:$key => ${fileRollCall[$key]}"; done 
 137     for key 
in "${!fileRollCall[@]}"; do 
 138         value
="${fileRollCall[$key]}"; 
 139         if [ "$value" = "false" ]; then 
 140             #echo "DEBUG:Missing files: $key => $value"; 
 141             missingFiles
="$missingFiles""$key "; 
 145     if [ "$fileMissing" = "true" ]; then  # Only indicate if an app is missing. 
 146         echo "$missingFiles" 1>&2; 
 149     #===END Display Missing Files=== 
 151     #===BEGIN Display Missing Directories=== 
 152     missingDirs
="Missing dirs:"; 
 153     #for key in "${!dirRollCall[@]}"; do echo "DEBUG:$key => ${dirRollCall[$key]}"; done 
 154     for key 
in "${!dirRollCall[@]}"; do 
 155         value
="${dirRollCall[$key]}"; 
 156         if [ "$value" = "false" ]; then 
 157             #echo "DEBUG:Missing dirs: $key => $value"; 
 158             missingDirs
="$missingDirs""$key "; 
 162     if [ "$dirMissing" = "true" ]; then  # Only indicate if an dir is missing. 
 163         echo "$missingDirs" 1>&2; 
 166     #===END Display Missing Directories=== 
 168     #==END Display errors== 
 169 } # Display missing apps, files, dirs 
 171     # Desc: Report seconds until next day. 
 173     # Output: stdout: integer seconds until next day 
 174     # Output: exit code 0 if stdout > 0; 1 if stdout = 0; 2 if stdout < 0 
 175     # Usage: timeUntilNextDay 
 176     # Usage: if ! myTTL="$(timeUntilNextDay)"; then yell "ERROR in if statement"; exit 1; fi 
 177     # Depends: date 8, echo 8, yell, try 
 179     local returnState timeCurrent timeNextDay secondsUntilNextDay
 
 180     timeCurrent
="$(date --iso-8601=seconds)" ; # Produce `date`-parsable current timestamp with resolution of 1 second. 
 181     timeNextDay
="$(date -d "$timeCurrent next day" --iso-8601=date)"; # Produce timestamp of beginning of tomorrow with resolution of 1 second. 
 182     secondsUntilNextDay
="$(( $(date +%s -d "$timeNextDay") - $(date +%s -d "$timeCurrent") ))" ; # Calculate seconds until closest future midnight (res. 1 second). 
 183     if [[ "$secondsUntilNextDay" -gt 0 ]]; then 
 185     elif [[ "$secondsUntilNextDay" -eq 0 ]]; then 
 186         returnState
="warning_zero"; 
 187         yell 
"WARNING:Reported time until next day exactly zero."; 
 188     elif [[ "$secondsUntilNextDay" -lt 0 ]]; then 
 189         returnState
="warning_negative"; 
 190         yell 
"WARNING:Reported time until next day is negative."; 
 193     try 
echo "$secondsUntilNextDay"; # Report 
 195     # Determine function return code 
 196     if [[ "$returnState" = "true" ]]; then 
 198     elif [[ "$returnState" = "warning_zero" ]]; then 
 200     elif [[ "$returnState" = "warning_negative" ]]; then 
 203 } # Report seconds until next day 
 205     #Desc: Sets script_ttl seconds 
 206     #Usage: set_script_ttl 
 208     #Output: var: script_ttl (integer seconds) 
 209     #Depends: timeUntilNextDay() 
 211     # Set script lifespan to end at start of next day 
 212     if ! script_ttl
="$(timeUntilNextDay)"; then # sets scriptTTL, then checks exit code 
 213         if [[ "$script_ttl" -eq 0 ]]; then 
 214             ((script_ttl
++)); # Add 1 because 0 would cause 'timeout' to never timeout. 
 217 } # Set script_ttl in seconds until next day 
 219     # Input: var: $temp_photo_path file path to save photo 
 220     # Depends: checkapp(), raspistill 
 222     try raspistill 
-gps -t 0 -q 95 -ex auto 
-e "$encoding" -o "$temp_photo_path"; 
 225     # Desc: Display script usage information 
 230     # Depends: GNU-coreutils 8.30 (cat) 
 233         update_temp_photograph.sh [camera_name] 
 236       update_temp_photograph.sh DC1 
 238 } # Display information on how to use this script. 
 242     #===BEGIN process arguments=== 
 243     if [[ $# -ge 1 ]]; then 
 246         die 
"ERROR:Not enough arguments."; 
 250     temp_photo_dir
="$temp_dir"/ninfacyzga
/photograph
; # generic-use dir 
 251     temp_photo_filename
="$camera_name".jpg
; # use jpg encoding 
 252     temp_photo_path
="$temp_photo_dir"/"$temp_photo_filename"; 
 253     #===END process arguments=== 
 254     #===BEGIN Check for required files, dirs, and apps=== 
 255     # Create output dir for photo dir 
 256     flag_exit_early
="false"; 
 257     if ! checkdir 
"$temp_photo_dir"; then 
 258         try 
mkdir -p "$temp_photo_dir"; 
 261     # Check for missing files 
 262     if ! checkfile 
"$sleep_rand_path"; then 
 263         flag_exit_early
="true"; 
 266     # Check for missing apps 
 267     if ! checkapp raspistill
; then 
 268         flag_exit_early
="true"; 
 273     if [[ $flag_exit_early == "true" ]]; then 
 274         die 
"ERROR:Exiting early."; 
 276     #===END Check for required files, dirs, and apps=== 
 278     #===BEGIN main loop=== 
 280     while [[ $SECONDS -lt "$script_ttl" ]]; do 
 281         # Capture new photograph 
 282         try update_temp_file
; 
 283         try python3 
"$sleep_rand_path" --upper 3600.0 60.0; 
 288 #==END Define Functions==