@@ -1,2 +1,3 @@ | |||||
predict/ | predict/ | ||||
map/ | map/ | ||||
panel.db |
@@ -11,6 +11,7 @@ | |||||
- [Install the default configuration files](#install-the-default-configuration-files) | - [Install the default configuration files](#install-the-default-configuration-files) | ||||
- [Install Meteor software](#install-meteor-software) | - [Install Meteor software](#install-meteor-software) | ||||
- [Setup Nginx](#setup-nginx) | - [Setup Nginx](#setup-nginx) | ||||
- [Setup Database](#setup-database) | |||||
- [Setup RamFS](#setup-ramfs) | - [Setup RamFS](#setup-ramfs) | ||||
- [Cron the scheduling job](#cron-the-scheduling-job) | - [Cron the scheduling job](#cron-the-scheduling-job) | ||||
- [Set your Twitter credentials](#set-your-twitter-credentials) | - [Set your Twitter credentials](#set-your-twitter-credentials) | ||||
@@ -60,7 +61,13 @@ sudo apt install -yq predict \ | |||||
python3-pip \ | python3-pip \ | ||||
imagemagick \ | imagemagick \ | ||||
libxft-dev \ | libxft-dev \ | ||||
libxft2 | |||||
libxft2 \ | |||||
libjpeg9 \ | |||||
libjpeg9-dev \ | |||||
socat \ | |||||
php7.2-fpm \ | |||||
php7.2-sqlite \ | |||||
sqlite3 | |||||
``` | ``` | ||||
``` | ``` | ||||
@@ -145,6 +152,12 @@ sudo chmod 775 /var/www/wx | |||||
sudo cp templates/index.html /var/www/wx/index.html | sudo cp templates/index.html /var/www/wx/index.html | ||||
sudo cp templates/logo-small.png /var/www/wx/logo-small.png | sudo cp templates/logo-small.png /var/www/wx/logo-small.png | ||||
sudo systemctl restart nginx | sudo systemctl restart nginx | ||||
sudo cp -rp templates/webpanel/* /var/www/wx/ | |||||
``` | |||||
### Setup Database | |||||
``` | |||||
sqlite3 "panel.db" < "templates/webpanel_schema.sql" | |||||
``` | ``` | ||||
### Setup RamFS | ### Setup RamFS | ||||
@@ -4,6 +4,7 @@ | |||||
Most of the code and setup stolen from: [Instructables](https://www.instructables.com/id/Raspberry-Pi-NOAA-Weather-Satellite-Receiver/) | Most of the code and setup stolen from: [Instructables](https://www.instructables.com/id/Raspberry-Pi-NOAA-Weather-Satellite-Receiver/) | ||||
## New Features! | ## New Features! | ||||
- A webpanel! | |||||
- [Meteor M2 full decoding!](METEOR.md) | - [Meteor M2 full decoding!](METEOR.md) | ||||
- Nginx webserver to show images | - Nginx webserver to show images | ||||
- Timestamp and satellite name overlay on every image | - Timestamp and satellite name overlay on every image | ||||
@@ -25,7 +25,6 @@ log() { | |||||
## current date and folder structure | ## current date and folder structure | ||||
START_DATE=$(date '+%d-%m-%Y %H:%M') | START_DATE=$(date '+%d-%m-%Y %H:%M') | ||||
FOLDER_DATE="$(date +%Y)/$(date +%m)/$(date +%d)" | |||||
## sane checks | ## sane checks | ||||
if [ ! -d "${NOAA_HOME}" ]; then | if [ ! -d "${NOAA_HOME}" ]; then | ||||
@@ -44,8 +43,8 @@ if [ ! -d "${RAMFS_AUDIO}/audio/" ]; then | |||||
mkdir -m 775 -p "${RAMFS_AUDIO}/audio/" | mkdir -m 775 -p "${RAMFS_AUDIO}/audio/" | ||||
fi | fi | ||||
if [ ! -d "${NOAA_OUTPUT}/image/" ]; then | |||||
mkdir -m 775 -p "${NOAA_OUTPUT}/image/" | |||||
if [ ! -d "${NOAA_OUTPUT}/images/thumb" ]; then | |||||
mkdir -m 775 -p "${NOAA_OUTPUT}/images/thumb" | |||||
fi | fi | ||||
if [ ! -d "${NOAA_HOME}/map/" ]; then | if [ ! -d "${NOAA_HOME}/map/" ]; then | ||||
@@ -55,7 +54,3 @@ fi | |||||
if [ ! -d "${NOAA_HOME}/predict/" ]; then | if [ ! -d "${NOAA_HOME}/predict/" ]; then | ||||
mkdir -m 775 -p "${NOAA_HOME}/predict/" | mkdir -m 775 -p "${NOAA_HOME}/predict/" | ||||
fi | fi | ||||
if [ ! -d "${NOAA_OUTPUT}/image/${FOLDER_DATE}" ]; then | |||||
mkdir -m 775 -p "${NOAA_OUTPUT}/image/${FOLDER_DATE}" | |||||
fi |
@@ -54,11 +54,22 @@ sudo apt install -yq predict \ | |||||
libxft2 \ | libxft2 \ | ||||
libjpeg9 \ | libjpeg9 \ | ||||
libjpeg9-dev \ | libjpeg9-dev \ | ||||
socat | |||||
socat \ | |||||
php7.2-fpm \ | |||||
php7.2-sqlite \ | |||||
sqlite3 | |||||
sudo pip3 install numpy ephem tweepy Pillow | sudo pip3 install numpy ephem tweepy Pillow | ||||
log_done "Packages installed" | log_done "Packages installed" | ||||
### Create the database schema | |||||
if [ -e "$HOME/raspberry-noaa/panel.db" ]; then | |||||
log_done "Database already created" | |||||
else | |||||
sqlite3 "panel.db" < "templates/webpanel_schema.sql" | |||||
log_done "Database schema created" | |||||
fi | |||||
### Blacklist DVB modules | ### Blacklist DVB modules | ||||
if [ -e /etc/modprobe.d/rtlsdr.conf ]; then | if [ -e /etc/modprobe.d/rtlsdr.conf ]; then | ||||
log_done "DVB modules were already blacklisted" | log_done "DVB modules were already blacklisted" | ||||
@@ -173,12 +184,8 @@ sudo cp templates/nginx.cfg /etc/nginx/sites-enabled/default | |||||
sudo chmod 775 /var/www/wx | sudo chmod 775 /var/www/wx | ||||
) | ) | ||||
sudo systemctl restart nginx | sudo systemctl restart nginx | ||||
if [ ! -e /var/www/wx/index.html ]; then | |||||
sudo cp templates/index.html /var/www/wx/index.html | |||||
fi | |||||
if [ ! -e /var/www/wx/logo-small.png ]; then | |||||
sudo cp templates/logo-small.png /var/www/wx/logo-small.png | |||||
fi | |||||
sudo cp -rp templates/webpanel/* /var/www/wx/ | |||||
log_done "Nginx configured" | log_done "Nginx configured" | ||||
### Setup ramFS | ### Setup ramFS | ||||
@@ -229,8 +236,10 @@ sed -i -e "s/change_latitude/${lat}/g;s/change_longitude/${lon}/g" "$HOME/.wxtoi | |||||
sed -i -e "s/change_latitude/${lat}/g;s/change_longitude/$(echo "$lon * -1" | bc)/g" "$HOME/.predict/predict.qth" | sed -i -e "s/change_latitude/${lat}/g;s/change_longitude/$(echo "$lon * -1" | bc)/g" "$HOME/.predict/predict.qth" | ||||
sed -i -e "s/change_latitude/${lat}/g;s/change_longitude/${lon}/g;s/change_tz/$(echo "$timezone * -1" | bc)/g" "sun.py" | sed -i -e "s/change_latitude/${lat}/g;s/change_longitude/${lon}/g;s/change_tz/$(echo "$timezone * -1" | bc)/g" "sun.py" | ||||
# Running WXTOIMG to have the user accept the licensing agreement | |||||
wxtoimg | |||||
### Launch scheduler | |||||
newgrp www-data << END | |||||
/home/pi/raspberry-noaa/schedule.sh | |||||
END | |||||
success "Install done! Double check your $HOME/.noaa.conf settings" | success "Install done! Double check your $HOME/.noaa.conf settings" | ||||
@@ -238,3 +247,6 @@ echo " | |||||
If you want to post your images to Twitter, please setup | If you want to post your images to Twitter, please setup | ||||
your Twitter credentials on $HOME/.tweepy.conf | your Twitter credentials on $HOME/.tweepy.conf | ||||
" | " | ||||
### Running WXTOIMG to have the user accept the licensing agreement | |||||
wxtoimg |
@@ -0,0 +1,94 @@ | |||||
#!/bin/bash | |||||
## import common lib | |||||
. "$HOME/.noaa.conf" | |||||
. "$HOME/.tweepy.conf" | |||||
. "$NOAA_HOME/common.sh" | |||||
# Free disk space | |||||
FREE_DISK="$(df | grep "/dev/root" | awk {'print $3'})" | |||||
# This is the original path where images were stored | |||||
BASEPATH="/var/www/wx/image" | |||||
# Size of the old images folder | |||||
IMAGEPATH_SIZE="$(du -s $BASEPATH | awk {'print $1'})" | |||||
SPACE_NEEDED="$((IMAGEPATH_SIZE * 2))" | |||||
if [ "$SPACE_NEEDED" -gt "$FREE_DISK" ]; then | |||||
echo "You need more free space" | |||||
exit 1 | |||||
fi | |||||
# This is the destination path (AKA the new path) | |||||
FINALPATH="/var/www/wx/images" | |||||
# This is a list of satellite names | |||||
SAT_NAMES="NOAA15 NOAA18 NOAA19 METEOR-M2" | |||||
# Here's where the database will live | |||||
DB_PATH="${NOAA_HOME}/panel.db" | |||||
( | |||||
# To speed up the migration process and | |||||
# reduce the SD card wear, the database | |||||
# operations are done over the RAMFS | |||||
# partition | |||||
cd "${RAMFS_AUDIO}" || exit 1 | |||||
sqlite3 "$DB_PATH" < "${NOAA_HOME}/templates/webpanel_schema.sql" | |||||
) | |||||
cd "$BASEPATH" || exit 1 | |||||
# The webpanel have thumbnails! | |||||
mkdir -p "$FINALPATH/thumb" | |||||
# Find all the images | |||||
for filename in $(find . -name *.jpg); do | |||||
# Grab just the filename without the yyyy/mm/dd path | |||||
basename="$(echo "$filename" | sed 's~.*/~~')" | |||||
for prefix in $SAT_NAMES; do | |||||
basedate="$(echo "$basename" | sed -e "s/^$prefix//" | cut -f1,2 -d'-' | sed -e "s/-//")" | |||||
if [[ $basename == *"$prefix"* ]]; then | |||||
# Grab the satellite name from the file name | |||||
sat_name=$prefix | |||||
fi | |||||
done | |||||
date_normalized=$(echo "$basedate" | sed -e "s/^$sat_name//;s/./&:/12;s/./&:/10;s/./& /8;s/./&\//6;s/./&\//4") | |||||
epoch_date=$(date "+%s" -d "$date_normalized") | |||||
if [[ $basename == *"METEOR"* ]]; then | |||||
# Meteor files have one more dash on its name | |||||
passname=$(echo "$basename" | cut -f1,2,3 -d'-') | |||||
else | |||||
passname=$(echo "$basename" | cut -f1,2 -d'-') | |||||
fi | |||||
echo "Migration in progress: $basename" | |||||
cp "$BASEPATH/$filename" "$FINALPATH" | |||||
# Create thumbnails for old images | |||||
convert -thumbnail 300 "$BASEPATH/$filename" "$FINALPATH/thumb/$basename" | |||||
if [[ $basename == *"METEOR"* ]]; then | |||||
# Insert each pass on the database. Also insert the pass prediction | |||||
sqlite3 "${RAMFS_AUDIO}/panel.db" "INSERT INTO decoded_passes (pass_start, file_path, daylight_pass, is_noaa) VALUES ($epoch_date,\"$passname\",1,0);" | |||||
sqlite3 "${RAMFS_AUDIO}/panel.db" "INSERT OR REPLACE INTO predict_passes (sat_name,pass_start,pass_end,max_elev) VALUES (\"$sat_name\",$epoch_date,$epoch_date,0);" | |||||
elif [[ $basename == *"ZA"* ]]; then | |||||
sqlite3 "${RAMFS_AUDIO}/panel.db" "INSERT OR REPLACE INTO predict_passes (sat_name,pass_start,pass_end,max_elev) VALUES (\"$sat_name\",$epoch_date,$epoch_date,0);" | |||||
if [[ -f "$FINALPATH/$passname-MSA.jpg" ]]; then | |||||
# MSA requires a daylight pass and daylight pass is a column of decoded_passes so this is the way to grab them | |||||
sqlite3 "${RAMFS_AUDIO}/panel.db" "INSERT INTO decoded_passes (pass_start, file_path, daylight_pass, is_noaa) VALUES ($epoch_date,\"$passname\",1,1);" | |||||
else | |||||
sqlite3 "${RAMFS_AUDIO}/panel.db" "INSERT INTO decoded_passes (pass_start, file_path, daylight_pass, is_noaa) VALUES ($epoch_date,\"$passname\",0,1);" | |||||
fi | |||||
fi | |||||
# Move the database file to its final destination | |||||
mv "${RAMFS_AUDIO}/panel.db" "$DB_PATH" | |||||
echo "Done." | |||||
echo "" | |||||
done | |||||
@@ -23,4 +23,4 @@ for filename in filenames: | |||||
res = api.media_upload(filename) | res = api.media_upload(filename) | ||||
media_ids.append(res.media_id) | media_ids.append(res.media_id) | ||||
api.update_status(status=argentinaFlag + ' Imagen satelital: ' + sys.argv[1] + '. Elevacion maxima: ' + sys.argv[2] + ' grados. #NOAA #weather #argentinaimagenes #noaasatellite #clima #wxtoimg #raspberrypi #argentina #argentinasat', media_ids=media_ids) | |||||
api.update_status(status=argentinaFlag + ' Imagen satelital: ' + sys.argv[1] + '. Elevacion maxima: ' + sys.argv[2] + ' grados. #NOAA #weather #argentinaimagenes #noaasatellite #clima #wxtoimg #raspberrynoaa #argentina #argentinasat', media_ids=media_ids) |
@@ -28,39 +28,48 @@ fi | |||||
log "Starting rtl_fm record" "INFO" | log "Starting rtl_fm record" "INFO" | ||||
timeout "${6}" /usr/local/bin/rtl_fm ${BIAS_TEE} -f "${2}"M -s 60k -g 50 -E wav -E deemp -F 9 - | /usr/bin/sox -t raw -e signed -c 1 -b 16 -r 60000 - "${RAMFS_AUDIO}/audio/${3}.wav" rate 11025 | timeout "${6}" /usr/local/bin/rtl_fm ${BIAS_TEE} -f "${2}"M -s 60k -g 50 -E wav -E deemp -F 9 - | /usr/bin/sox -t raw -e signed -c 1 -b 16 -r 60000 - "${RAMFS_AUDIO}/audio/${3}.wav" rate 11025 | ||||
if [ ! -d "{NOAA_OUTPUT}/image/${FOLDER_DATE}" ]; then | |||||
mkdir -m 775 -p "${NOAA_OUTPUT}/image/${FOLDER_DATE}" | |||||
fi | |||||
if [ "${SUN_ELEV}" -gt "${SUN_MIN_ELEV}" ]; then | if [ "${SUN_ELEV}" -gt "${SUN_MIN_ELEV}" ]; then | ||||
ENHANCEMENTS="ZA MCIR MCIR-precip MSA MSA-precip HVC-precip HVCT-precip HVC HVCT" | ENHANCEMENTS="ZA MCIR MCIR-precip MSA MSA-precip HVC-precip HVCT-precip HVC HVCT" | ||||
daylight="true" | |||||
else | else | ||||
ENHANCEMENTS="ZA MCIR MCIR-precip" | ENHANCEMENTS="ZA MCIR MCIR-precip" | ||||
daylight="false" | |||||
fi | fi | ||||
log "Bulding pass map" "INFO" | log "Bulding pass map" "INFO" | ||||
/usr/local/bin/wxmap -T "${1}" -H "${4}" -p 0 -l 0 -o "${PASS_START}" "${NOAA_HOME}/map/${3}-map.png" | /usr/local/bin/wxmap -T "${1}" -H "${4}" -p 0 -l 0 -o "${PASS_START}" "${NOAA_HOME}/map/${3}-map.png" | ||||
for i in $ENHANCEMENTS; do | for i in $ENHANCEMENTS; do | ||||
log "Decoding image" "INFO" | log "Decoding image" "INFO" | ||||
/usr/local/bin/wxtoimg -o -m "${NOAA_HOME}/map/${3}-map.png" -e "$i" "${RAMFS_AUDIO}/audio/${3}.wav" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/${3}-$i.jpg" | |||||
/usr/bin/convert -quality 90 -format jpg "${NOAA_OUTPUT}/image/${FOLDER_DATE}/${3}-$i.jpg" -undercolor black -fill yellow -pointsize 18 -annotate +20+20 "${1} $i ${START_DATE} Elev: $7°" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/${3}-$i.jpg" | |||||
/usr/local/bin/wxtoimg -o -m "${NOAA_HOME}/map/${3}-map.png" -e "$i" "${RAMFS_AUDIO}/audio/${3}.wav" "${NOAA_OUTPUT}/images/${3}-$i.jpg" | |||||
/usr/bin/convert -quality 90 -format jpg "${NOAA_OUTPUT}/images/${3}-$i.jpg" -undercolor black -fill yellow -pointsize 18 -annotate +20+20 "${1} $i ${START_DATE} Elev: $7°" "${NOAA_OUTPUT}/images/${3}-$i.jpg" | |||||
/usr/bin/convert -thumbnail 300 "${NOAA_OUTPUT}/images/${3}-$i.jpg" "${NOAA_OUTPUT}/images/thumb/${3}-$i.jpg" | |||||
done | done | ||||
rm "${NOAA_HOME}/map/${3}-map.png" | rm "${NOAA_HOME}/map/${3}-map.png" | ||||
if [ "${SUN_ELEV}" -gt "${SUN_MIN_ELEV}" ]; then | |||||
sqlite3 /home/pi/raspberry-noaa/panel.db "insert into decoded_passes (pass_start, file_path, daylight_pass, is_noaa) values ($5,\"$3\", 1,1);" | |||||
else | |||||
sqlite3 /home/pi/raspberry-noaa/panel.db "insert into decoded_passes (pass_start, file_path, daylight_pass, is_noaa) values ($5,\"$3\", 0,1);" | |||||
fi | |||||
pass_id=$(sqlite3 /home/pi/raspberry-noaa/panel.db "select id from decoded_passes order by id desc limit 1;") | |||||
if [ -n "$CONSUMER_KEY" ]; then | if [ -n "$CONSUMER_KEY" ]; then | ||||
log "Posting to Twitter" "INFO" | log "Posting to Twitter" "INFO" | ||||
if [ "${SUN_ELEV}" -gt "${SUN_MIN_ELEV}" ]; then | if [ "${SUN_ELEV}" -gt "${SUN_MIN_ELEV}" ]; then | ||||
python3 "${NOAA_HOME}/post.py" "$1 ${START_DATE}" "$7" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/$3-MCIR-precip.jpg" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/$3-MSA-precip.jpg" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/$3-HVC-precip.jpg" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/$3-HVCT-precip.jpg" | |||||
python3 "${NOAA_HOME}/post.py" "$1 ${START_DATE} Mas imagenes: https://weather.reyni.co/detail.php?id=$pass_id" "$7" "${NOAA_OUTPUT}/images/$3-MCIR-precip.jpg" "${NOAA_OUTPUT}/images/$3-MSA-precip.jpg" "${NOAA_OUTPUT}/images/$3-HVC-precip.jpg" "${NOAA_OUTPUT}/images/$3-HVCT-precip.jpg" | |||||
else | else | ||||
python3 "${NOAA_HOME}/post.py" "$1 ${START_DATE}" "$7" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/$3-MCIR-precip.jpg" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/$3-MCIR.jpg" | |||||
python3 "${NOAA_HOME}/post.py" "$1 ${START_DATE} Mas imagenes: https://weather.reyni.co/detail.php?id=$pass_id" "$7" "${NOAA_OUTPUT}/images/$3-MCIR-precip.jpg" "${NOAA_OUTPUT}/images/$3-MCIR.jpg" | |||||
fi | fi | ||||
fi | fi | ||||
sqlite3 /home/pi/raspberry-noaa/panel.db "update predict_passes set is_active = 0 where (predict_passes.pass_start) in (select predict_passes.pass_start from predict_passes inner join decoded_passes on predict_passes.pass_start = decoded_passes.pass_start where decoded_passes.id = $pass_id);" | |||||
if [ "$DELETE_AUDIO" = true ]; then | if [ "$DELETE_AUDIO" = true ]; then | ||||
log "Deleting audio files" "INFO" | log "Deleting audio files" "INFO" | ||||
rm "${RAMFS_AUDIO}/audio/${3}.wav" | |||||
rm "${RAMFS_AUDIO}/audio/${3}.wav" | |||||
else | else | ||||
log "Moving audio files out of the SD card" "INFO" | |||||
mv "${RAMFS_AUDIO}/audio/${3}.wav" "${NOAA_OUTPUT}/audio/${3}.wav" | |||||
log "Moving audio files out to the SD card" "INFO" | |||||
mv "${RAMFS_AUDIO}/audio/${3}.wav" "${NOAA_OUTPUT}/audio/${3}.wav" | |||||
fi | fi |
@@ -25,8 +25,8 @@ SUN_ELEV=$(python3 "$NOAA_HOME"/sun.py "$PASS_START") | |||||
if pgrep "rtl_fm" > /dev/null | if pgrep "rtl_fm" > /dev/null | ||||
then | then | ||||
log "There is an already running rtl_fm instance but I dont care for now, I prefer this pass" "INFO" | |||||
pkill -9 -f rtl_fm | |||||
log "There is an already running rtl_fm instance but I dont care for now, I prefer this pass" "INFO" | |||||
pkill -9 -f rtl_fm | |||||
fi | fi | ||||
# $1 = Satellite Name | # $1 = Satellite Name | ||||
@@ -40,14 +40,15 @@ fi | |||||
log "Starting rtl_fm record" "INFO" | log "Starting rtl_fm record" "INFO" | ||||
timeout "${6}" /usr/local/bin/rtl_fm ${BIAS_TEE} -M raw -f "${2}"M -s 288k -g 48 | sox -t raw -r 288k -c 2 -b 16 -e s - -t wav "${RAMFS_AUDIO}/audio/${3}.wav" rate 96k | timeout "${6}" /usr/local/bin/rtl_fm ${BIAS_TEE} -M raw -f "${2}"M -s 288k -g 48 | sox -t raw -r 288k -c 2 -b 16 -e s - -t wav "${RAMFS_AUDIO}/audio/${3}.wav" rate 96k | ||||
log "Normalization in progress" "INFO" | |||||
sox "${RAMFS_AUDIO}/audio/${3}.wav" "${METEOR_OUTPUT}/${3}.wav" gain -n | |||||
log "Demodulation in progress (QPSK)" "INFO" | log "Demodulation in progress (QPSK)" "INFO" | ||||
meteor_demod -B -o "${METEOR_OUTPUT}/${3}.qpsk" "${METEOR_OUTPUT}/${3}.wav" | |||||
meteor_demod -B -o "${METEOR_OUTPUT}/${3}.qpsk" "${RAMFS_AUDIO}/audio/${3}.wav" | |||||
if [ "$DELETE_AUDIO" = true ]; then | if [ "$DELETE_AUDIO" = true ]; then | ||||
log "Deleting audio files" "INFO" | log "Deleting audio files" "INFO" | ||||
rm "${RAMFS_AUDIO}/audio/${3}.wav" | |||||
else | |||||
log "Moving audio files out to the SD card" "INFO" | |||||
mv "${RAMFS_AUDIO}/audio/${3}.wav" "${NOAA_OUTPUT}/audio/${3}.wav" | |||||
rm "${METEOR_OUTPUT}/audio/${3}.wav" | rm "${METEOR_OUTPUT}/audio/${3}.wav" | ||||
rm "${RAMFS_AUDIO}/audio/${3}.wav" | rm "${RAMFS_AUDIO}/audio/${3}.wav" | ||||
fi | fi | ||||
@@ -61,23 +62,29 @@ if [ -f "${METEOR_OUTPUT}/${3}.dec" ]; then | |||||
if [ "${SUN_ELEV}" -lt "${SUN_MIN_ELEV}" ]; then | if [ "${SUN_ELEV}" -lt "${SUN_MIN_ELEV}" ]; then | ||||
log "I got a successful ${3}.dec file. Decoding APID 68" "INFO" | log "I got a successful ${3}.dec file. Decoding APID 68" "INFO" | ||||
medet_arm "${METEOR_OUTPUT}/${3}.dec" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/${3}-122" -r 68 -g 68 -b 68 -d | |||||
/usr/bin/convert -negate $FLIP "${NOAA_OUTPUT}/image/${FOLDER_DATE}/${3}-122.bmp" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/${3}-122.bmp" | |||||
medet_arm "${METEOR_OUTPUT}/${3}.dec" "${NOAA_OUTPUT}/images/${3}-122" -r 68 -g 68 -b 68 -d | |||||
/usr/bin/convert $FLIP -negate "${NOAA_OUTPUT}/images/${3}-122.bmp" "${NOAA_OUTPUT}/images/${3}-122.bmp" | |||||
else | else | ||||
log "I got a successful ${3}.dec file. Creating false color image" "INFO" | log "I got a successful ${3}.dec file. Creating false color image" "INFO" | ||||
medet_arm "${METEOR_OUTPUT}/${3}.dec" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/${3}-122" -r 65 -g 65 -b 64 -d | |||||
medet_arm "${METEOR_OUTPUT}/${3}.dec" "${NOAA_OUTPUT}/images/${3}-122" -r 65 -g 65 -b 64 -d | |||||
fi | fi | ||||
log "Rectifying image to adjust aspect ratio" "INFO" | log "Rectifying image to adjust aspect ratio" "INFO" | ||||
python3 "${NOAA_HOME}/rectify.py" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/${3}-122.bmp" | |||||
convert "${NOAA_OUTPUT}/image/${FOLDER_DATE}/${3}-122-rectified.jpg" -channel rgb -normalize -channel rgb -normalize -undercolor black -fill yellow -pointsize 60 -annotate +20+60 "${1} ${START_DATE} Elev: $7°" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/${3}-122-rectified.jpg" | |||||
python3 "${NOAA_HOME}/rectify.py" "${NOAA_OUTPUT}/images/${3}-122.bmp" | |||||
convert "${NOAA_OUTPUT}/images/${3}-122-rectified.jpg" -channel rgb -normalize -undercolor black -fill yellow -pointsize 60 -annotate +20+60 "${1} ${START_DATE} Elev: $7°" "${NOAA_OUTPUT}/images/${3}-122-rectified.jpg" | |||||
/usr/bin/convert -thumbnail 300 "${NOAA_OUTPUT}/images/${3}-122-rectified.jpg" "${NOAA_OUTPUT}/images/thumb/${3}-122-rectified.jpg" | |||||
rm "${NOAA_OUTPUT}/images/${3}-122.bmp" | |||||
rm "${METEOR_OUTPUT}/${3}.bmp" | rm "${METEOR_OUTPUT}/${3}.bmp" | ||||
rm "${METEOR_OUTPUT}/${3}-122.bmp" | |||||
rm "${METEOR_OUTPUT}/${3}.dec" | |||||
sqlite3 /home/pi/raspberry-noaa/panel.db "insert into decoded_passes (pass_start, file_path, daylight_pass, is_noaa) values ($5,\"$3\", 1,0);" | |||||
pass_id=$(sqlite3 /home/pi/raspberry-noaa/panel.db "select id from decoded_passes order by id desc limit 1;") | |||||
if [ -n "$CONSUMER_KEY" ]; then | if [ -n "$CONSUMER_KEY" ]; then | ||||
log "Posting to Twitter" "INFO" | log "Posting to Twitter" "INFO" | ||||
python3 "${NOAA_HOME}/post.py" "$1 EXPERIMENTAL ${START_DATE} Resolución completa: http://weather.reyni.co/image/${FOLDER_DATE}/${3}-122-rectified.jpg" "$7" "${NOAA_OUTPUT}/image/${FOLDER_DATE}/${3}-122-rectified.jpg" | |||||
python3 "${NOAA_HOME}/post.py" "$1 ${START_DATE} Resolución completa: https://weather.reyni.co/detail.php?id=$pass_id" "$7" "${NOAA_OUTPUT}/images/${3}-122-rectified.jpg" | |||||
fi | fi | ||||
sqlite3 /home/pi/raspberry-noaa/panel.db "update predict_passes set is_active = 0 where (predict_passes.pass_start) in (select predict_passes.pass_start from predict_passes inner join decoded_passes on predict_passes.pass_start = decoded_passes.pass_start where decoded_passes.id = $pass_id);" | |||||
else | else | ||||
log "Decoding failed, either a bad pass/low SNR or a software problem" "ERROR" | log "Decoding failed, either a bad pass/low SNR or a software problem" "ERROR" | ||||
fi | fi |
@@ -8,7 +8,7 @@ from math import atan,sin,cos,sqrt,tan,acos,ceil | |||||
from PIL import Image | from PIL import Image | ||||
EARTH_RADIUS = 6371.0 | EARTH_RADIUS = 6371.0 | ||||
SAT_HEIGHT = 822.5 | |||||
SAT_HEIGHT = 830.0 | |||||
SAT_ORBIT_RADIUS = EARTH_RADIUS + SAT_HEIGHT | SAT_ORBIT_RADIUS = EARTH_RADIUS + SAT_HEIGHT | ||||
SWATH_KM = 2800.0 | SWATH_KM = 2800.0 | ||||
THETA_C = SWATH_KM / EARTH_RADIUS | THETA_C = SWATH_KM / EARTH_RADIUS | ||||
@@ -25,6 +25,7 @@ while [ "$(date --date="@${var2}" +%D)" = "$(date +%D)" ]; do | |||||
echo "${SATNAME}" "${OUTDATE}" "$MAXELEV" | echo "${SATNAME}" "${OUTDATE}" "$MAXELEV" | ||||
echo "${NOAA_HOME}/receive_meteor.sh \"${1}\" $2 ${SATNAME}${OUTDATE} "${NOAA_HOME}"/predict/weather.tle \ | echo "${NOAA_HOME}/receive_meteor.sh \"${1}\" $2 ${SATNAME}${OUTDATE} "${NOAA_HOME}"/predict/weather.tle \ | ||||
${var1} ${TIMER} ${MAXELEV}" | at "$(date --date="TZ=\"UTC\" ${START_TIME}" +"%H:%M %D")" | ${var1} ${TIMER} ${MAXELEV}" | at "$(date --date="TZ=\"UTC\" ${START_TIME}" +"%H:%M %D")" | ||||
sqlite3 /home/pi/raspberry-noaa/panel.db "insert or replace into predict_passes (sat_name,pass_start,pass_end,max_elev,is_active) values (\"$SATNAME\",$var1,$var2,$MAXELEV,1);" | |||||
fi | fi | ||||
NEXTPREDICT=$(expr "${var2}" + 60) | NEXTPREDICT=$(expr "${var2}" + 60) | ||||
PREDICTION_START=$(/usr/bin/predict -t "${NOAA_HOME}"/predict/weather.tle -p "${1}" "${NEXTPREDICT}" | head -1) | PREDICTION_START=$(/usr/bin/predict -t "${NOAA_HOME}"/predict/weather.tle -p "${1}" "${NEXTPREDICT}" | head -1) | ||||
@@ -31,6 +31,7 @@ while [ "$(date --date="@${var2}" +%D)" = "$(date +%D)" ]; do | |||||
echo "${SATNAME}" "${OUTDATE}" "$MAXELEV" | echo "${SATNAME}" "${OUTDATE}" "$MAXELEV" | ||||
echo "${NOAA_HOME}/receive.sh \"${1}\" $2 ${SATNAME}${OUTDATE} "${NOAA_HOME}"/predict/weather.tle \ | echo "${NOAA_HOME}/receive.sh \"${1}\" $2 ${SATNAME}${OUTDATE} "${NOAA_HOME}"/predict/weather.tle \ | ||||
${var1} ${TIMER} ${MAXELEV}" | at "$(date --date="TZ=\"UTC\" ${START_TIME}" +"%H:%M %D")" | ${var1} ${TIMER} ${MAXELEV}" | at "$(date --date="TZ=\"UTC\" ${START_TIME}" +"%H:%M %D")" | ||||
sqlite3 /home/pi/raspberry-noaa/panel.db "insert or replace into predict_passes (sat_name,pass_start,pass_end,max_elev,is_active) values (\"$SATNAME\",$var1,$var2,$MAXELEV, 1);" | |||||
fi | fi | ||||
NEXTPREDICT=$(expr "${var2}" + 60) | NEXTPREDICT=$(expr "${var2}" + 60) | ||||
PREDICTION_START=$(/usr/bin/predict -t "${NOAA_HOME}"/predict/weather.tle -p "${1}" "${NEXTPREDICT}" | head -1) | PREDICTION_START=$(/usr/bin/predict -t "${NOAA_HOME}"/predict/weather.tle -p "${1}" "${NEXTPREDICT}" | head -1) | ||||
@@ -2,8 +2,8 @@ | |||||
import ephem | import ephem | ||||
import time | import time | ||||
import sys | import sys | ||||
timezone = change_tz | |||||
date = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(sys.argv[1])+(timezone*60*60))) | |||||
timezone = change_tz + time.localtime().tm_isdst | |||||
date = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(sys.argv[1])-(timezone*60*60))) | |||||
obs=ephem.Observer() | obs=ephem.Observer() | ||||
obs.lat='change_latitude' | obs.lat='change_latitude' | ||||
@@ -1,7 +1,7 @@ | |||||
server { | server { | ||||
listen 80 default_server; | listen 80 default_server; | ||||
root /var/www/wx; | root /var/www/wx; | ||||
index index.html index.htm index.nginx-debian.html; | |||||
index index.php index.html index.htm index.nginx-debian.html; | |||||
autoindex on; | autoindex on; | ||||
server_name wx.home; | server_name wx.home; | ||||
@@ -9,4 +9,12 @@ server { | |||||
location / { | location / { | ||||
try_files $uri $uri/ =404; | try_files $uri $uri/ =404; | ||||
} | } | ||||
location ~ \.php$ { | |||||
include snippets/fastcgi-php.conf; | |||||
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; | |||||
} | |||||
# Rewrite the old path yyyy/mm/dd/ to /images/ | |||||
rewrite "^/image/\d{4}/\d{2}/\d{2}/(.+)$" /images/$1 permanent; | |||||
} | } |
@@ -0,0 +1,7 @@ | |||||
<?php | |||||
return (object) array( | |||||
'base_url' => '/images/', | |||||
'img_per_page' => 12, | |||||
'lang' => 'es' | |||||
); | |||||
?> |
@@ -0,0 +1,6 @@ | |||||
<?php | |||||
require('Model/Conn.php'); | |||||
$con = new Conn(); | |||||
$passes = $con->getPasses(); | |||||
require('Views/V_viewPasses.php'); | |||||
?> |
@@ -0,0 +1,8 @@ | |||||
<?php | |||||
require('Model/Conn.php'); | |||||
$con = new Conn(); | |||||
if ($pass_id < 1) $pass_id = 1; | |||||
$enhacements = $con->getEnhacements($pass_id); | |||||
$path = $con->getPath($pass_id); | |||||
require('Views/V_viewDetail.php'); | |||||
?> |
@@ -0,0 +1,6 @@ | |||||
<?php | |||||
require('Model/Conn.php'); | |||||
$con = new Conn(); | |||||
$images = $con->getLastImage(); | |||||
require('Views/V_viewLastImage.php'); | |||||
?> |
@@ -0,0 +1,11 @@ | |||||
<?php | |||||
require('Model/Conn.php'); | |||||
$con = new Conn(); | |||||
if ($page < 1) $page = 1; | |||||
$img_per_page = $configs->img_per_page; | |||||
$page_count = $con->totalPages($img_per_page); | |||||
if ($page < 1) $page = 1; | |||||
if ($page > $page_count) $page = $page_count; | |||||
$images = $con->getImages($page, $img_per_page); | |||||
require('Views/V_viewLastImages.php'); | |||||
?> |
@@ -0,0 +1,74 @@ | |||||
<?php | |||||
class Conn { | |||||
private $con; | |||||
public function __construct() { | |||||
$this->con = new SQLite3("/home/pi/raspberry-noaa/panel.db"); | |||||
} | |||||
public function getPasses() { | |||||
$today = strtotime(date('Y-m-d', time())); | |||||
$query = $this->con->query("SELECT sat_name, is_active, | |||||
pass_start, pass_end, | |||||
max_elev FROM predict_passes | |||||
WHERE (pass_start > $today) ORDER BY | |||||
pass_start ASC;"); | |||||
$passes = []; | |||||
$i = 0; | |||||
while($row = $query->fetchArray()){ | |||||
$passes[$i] = $row; | |||||
$i++; | |||||
} | |||||
return $passes; | |||||
} | |||||
public function totalPages($img_per_page) { | |||||
$total_pages = $this->con->querySingle("SELECT count() from decoded_passes;"); | |||||
return ceil($total_pages/$img_per_page); | |||||
} | |||||
public function getImages($page, $img_per_page) { | |||||
$query = $this->con->prepare("SELECT decoded_passes.id, predict_passes.pass_start, | |||||
file_path, is_noaa, predict_passes.sat_name, predict_passes.max_elev | |||||
FROM decoded_passes INNER JOIN predict_passes | |||||
ON predict_passes.pass_start = decoded_passes.pass_start | |||||
ORDER BY decoded_passes.pass_start DESC LIMIT ? OFFSET ?;"); | |||||
$query->bindValue(1, $img_per_page); | |||||
$query->bindValue(2, $img_per_page * ($page-1)); | |||||
$result = $query->execute(); | |||||
$images = []; | |||||
$i = 0; | |||||
while($row = $result->fetchArray()){ | |||||
$images[$i] = $row; | |||||
$i++; | |||||
} | |||||
return $images; | |||||
} | |||||
public function getEnhacements($id) { | |||||
$query = $this->con->prepare('SELECT daylight_pass, is_noaa | |||||
FROM decoded_passes WHERE id = ?;'); | |||||
$query->bindValue(1, $id); | |||||
$result = $query->execute(); | |||||
$pass = $result->fetchArray(); | |||||
if ($pass['is_noaa'] == 0) { | |||||
$enhacements = ['-122-rectified.jpg']; | |||||
} else { | |||||
if ($pass['daylight_pass'] == 1) { | |||||
$enhacements = ['-ZA.jpg','-MCIR.jpg','-MCIR-precip.jpg','-MSA.jpg','-MSA-precip.jpg','-HVC.jpg','-HVC-precip.jpg','-HVCT.jpg','-HVCT-precip.jpg']; | |||||
} else { | |||||
$enhacements = ['-ZA.jpg','-MCIR.jpg','-MCIR-precip.jpg']; | |||||
} | |||||
} | |||||
return $enhacements; | |||||
} | |||||
public function getPath($id) { | |||||
$query = $this->con->prepare('SELECT file_path FROM decoded_passes | |||||
WHERE id = ?;'); | |||||
$query->bindValue(1, $id); | |||||
$result = $query->execute(); | |||||
$image = $result->fetchArray(); | |||||
return $image['file_path']; | |||||
} | |||||
} | |||||
?> |
@@ -0,0 +1,23 @@ | |||||
<div style="overflow-x:auto;"> | |||||
<table id="passes"> | |||||
<?php | |||||
$row_count=0; | |||||
$col_count=0; | |||||
$baseurl = $configs->base_url; | |||||
foreach ($enhacements as $enhacement) { | |||||
if($row_count%3==0) { | |||||
echo "<tr>"; | |||||
$col_count=1; | |||||
} | |||||
echo "<td><div id =\"satimgdiv\"><a href=". $baseurl . $path . $enhacement ."><img id=\"satimg\" src=". $baseurl . "thumb/" . $path . $enhacement ."></img></a></div>"; | |||||
if($col_count==3) { | |||||
echo "</tr>"; | |||||
} | |||||
$row_count++; | |||||
$col_count++; | |||||
} | |||||
?> | |||||
</table> | |||||
</div> | |||||
</body> | |||||
</html> |
@@ -0,0 +1,24 @@ | |||||
<table id="passes" class="img-grid"> | |||||
<?php | |||||
$row_count=0; | |||||
$col_count=0; | |||||
$baseurl = $configs->base_url; | |||||
foreach ($images as $image) { | |||||
if($row_count%3==0) { | |||||
echo "<tr>"; | |||||
$col_count=1; | |||||
} | |||||
echo "<td><div id =\"satimgdiv\"><a href=". $baseurl . $image['file_path'] ."><img id=\"satimg\" src=". $baseurl . "thumb/" . $image['file_path'] ."></img></a></div>"; | |||||
echo "<ul><li>". $image['sat_name'] ."</li>"; | |||||
echo "<li>". date('d/m/Y H:i:s', $image['pass_start']) ."</li></ul></td>"; | |||||
if($col_count==3) { | |||||
echo "</tr>"; | |||||
} | |||||
$row_count++; | |||||
$col_count++; | |||||
} | |||||
?> | |||||
</table> | |||||
</body> | |||||
</html> |
@@ -0,0 +1,42 @@ | |||||
<div style="overflow-x:auto;"> | |||||
<table id="passes" class="img-grid"> | |||||
<?php | |||||
if ($page > 1) { | |||||
echo "<tr><th><a href=\"?page=" . ($page-1) . "\">" . $lang['prev'] . "</a></th>"; | |||||
} else { | |||||
echo "<tr><th></th>"; | |||||
} | |||||
echo "<th>" . $lang['page'] . " $page " . $lang['of'] . " $page_count</th>"; | |||||
if ($page < $page_count) { | |||||
echo "<th><a href=\"?page=" . ($page+1) . "\">" . $lang['next'] . "</a></th></tr>"; | |||||
} else { | |||||
echo "<th></th></tr>"; | |||||
} | |||||
$row_count=0; | |||||
$col_count=0; | |||||
$baseurl = $configs->base_url; | |||||
foreach ($images as $image) { | |||||
if($row_count%3==0) { | |||||
echo "<tr>"; | |||||
$col_count=1; | |||||
} | |||||
if ($image['is_noaa'] == true) { | |||||
$ending = "-MCIR.jpg"; | |||||
} else { | |||||
$ending = "-122-rectified.jpg"; | |||||
} | |||||
echo "<td><div id =\"satimgdiv\"><a href=". "detail.php?id=" . $image['id'] ."><img id=\"satimg\" src=". $baseurl . "thumb/" . $image['file_path'] . $ending ."></img></a></div>"; | |||||
echo "<ul><li>". $image['sat_name'] ."</li>"; | |||||
echo "<li> " . $lang['elev'] . ": ". $image['max_elev'] ."°</li>"; | |||||
echo "<li>". date('d/m/Y H:i:s', $image['pass_start']) ."</li></ul></td>"; | |||||
if($col_count==3) { | |||||
echo "</tr>"; | |||||
} | |||||
$row_count++; | |||||
$col_count++; | |||||
} | |||||
?> | |||||
</table> | |||||
</div> | |||||
</body> | |||||
</html> |
@@ -0,0 +1,24 @@ | |||||
<div style="overflow-x:auto;"> | |||||
<table id="passes"> | |||||
<tr> | |||||
<th><?php echo $lang['satellite']; ?></th> | |||||
<th><?php echo $lang['pass_start']; ?></th> | |||||
<th><?php echo $lang['pass_end']; ?></th> | |||||
<th><?php echo $lang['max_elev']; ?></th> | |||||
</tr> | |||||
<?php | |||||
foreach ($passes as $pass) { | |||||
if ($pass['is_active'] == false) { | |||||
echo "<tr class='inactive'>"; | |||||
} else { | |||||
echo "<tr>"; | |||||
} | |||||
echo "<td>". $pass['sat_name'] ."</td>"; | |||||
echo "<td>". date('H:i:s', $pass['pass_start']) ."</td>"; | |||||
echo "<td>". date('H:i:s', $pass['pass_end']) ."</td>"; | |||||
echo "<td>". $pass['max_elev'] ."</td>"; | |||||
echo "</tr>"; | |||||
} | |||||
?> | |||||
</table> | |||||
</div> |
@@ -0,0 +1,7 @@ | |||||
<?php | |||||
$configs = include('Config.php'); | |||||
include_once('header.php'); | |||||
$pass_id = isset($_GET['id']) ? intval($_GET['id']) : 1; | |||||
require('Controller/C_showDetail.php'); | |||||
include_once("footer.php") | |||||
?> |
@@ -0,0 +1,6 @@ | |||||
</div> | |||||
<footer> | |||||
<a href="https://github.com/reynico/raspberry-noaa"><img class="img-footer" src="logo-small.png"></a> | |||||
</footer> | |||||
</body> | |||||
</html> |
@@ -0,0 +1,27 @@ | |||||
<?php | |||||
ini_set('display_errors', 1); | |||||
ini_set('display_startup_errors', 1); | |||||
error_reporting(E_ALL); | |||||
date_default_timezone_set('America/Argentina/Buenos_Aires'); | |||||
$page = basename($_SERVER['PHP_SELF']); | |||||
$configs = include('Config.php'); | |||||
$lang = $configs->lang; | |||||
include_once('language/' . $lang . '.php'); | |||||
?> | |||||
<!DOCTYPE html> | |||||
<html lang="en"> | |||||
<head> | |||||
<meta charset="UTF-8"> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |||||
<link rel="stylesheet" type="text/css" href="style.css"> | |||||
<title><?= isset($PageTitle) ? $PageTitle : "Raspberry NOAA"?></title> | |||||
</head> | |||||
<body> | |||||
<div class="topnav"> | |||||
<a class="<?php if($page == 'passes.php'){ echo ' active"';}?>" href="passes.php"><?php echo $lang['passes']; ?></a> | |||||
<a class="<?php if($page == 'index.php' || $page == 'detail.php'){ echo ' active"';}?>" href="index.php"><?php echo $lang['images']; ?></a> | |||||
</div> | |||||
<div class="container"> | |||||
@@ -0,0 +1,7 @@ | |||||
<?php | |||||
include_once('header.php'); | |||||
$page = isset($_GET['page']) ? intval($_GET['page']) : 1; | |||||
require('Controller/C_showLastImages.php'); | |||||
include_once("footer.php") | |||||
?> |
@@ -0,0 +1,15 @@ | |||||
<?php | |||||
$lang = array( | |||||
"passes" => "Passes", | |||||
"satellite" => "Satellite", | |||||
"images" => "Images", | |||||
"pass_start" => "Pass start", | |||||
"pass_end" => "Pass end", | |||||
"max_elev" => "Max elevation", | |||||
"elev" => "Elevation", | |||||
"page" => "Page", | |||||
"of" => "of", | |||||
"prev" => "Prev", | |||||
"next" => "Next", | |||||
); | |||||
?> |
@@ -0,0 +1,15 @@ | |||||
<?php | |||||
$lang = array( | |||||
"passes" => "Pasadas", | |||||
"satellite" => "Satélite", | |||||
"images" => "Imagenes", | |||||
"pass_start" => "Inicio", | |||||
"pass_end" => "Fin", | |||||
"max_elev" => "Elevación", | |||||
"elev" => "Elevación", | |||||
"page" => "Página", | |||||
"of" => "de", | |||||
"prev" => "Anterior", | |||||
"next" => "Siguiente", | |||||
); | |||||
?> |
@@ -0,0 +1,5 @@ | |||||
<?php | |||||
include_once('header.php'); | |||||
require('Controller/C_predict.php'); | |||||
include_once("footer.php") | |||||
?> |
@@ -0,0 +1,99 @@ | |||||
body { | |||||
margin: 0; | |||||
font-family: Arial, Helvetica, sans-serif; | |||||
} | |||||
.container { | |||||
margin: 20px auto; | |||||
max-width: 800px; | |||||
} | |||||
.topnav { | |||||
overflow: hidden; | |||||
background-color: #333; | |||||
} | |||||
.topnav a { | |||||
float: left; | |||||
color: #f2f2f2; | |||||
text-align: center; | |||||
padding: 14px 16px; | |||||
text-decoration: none; | |||||
font-size: 17px; | |||||
} | |||||
.topnav a:hover { | |||||
background-color: #ddd; | |||||
color: black; | |||||
} | |||||
.topnav a.active { | |||||
background-color: #4CAF50; | |||||
color: white; | |||||
} | |||||
#passes { | |||||
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; | |||||
border-collapse: collapse; | |||||
max-width: 500px; | |||||
width: 100%; | |||||
margin: auto; | |||||
} | |||||
#passes.img-grid { | |||||
max-width: 700px; | |||||
} | |||||
#passes td, | |||||
#passes th { | |||||
border: 1px solid #ddd; | |||||
padding: 8px; | |||||
} | |||||
#passes tr:nth-child(even) { | |||||
background-color: #f2f2f2; | |||||
} | |||||
/* #passes tr:hover {background-color: #ddd;} */ | |||||
#passes th { | |||||
padding-top: 12px; | |||||
padding-bottom: 12px; | |||||
background-color: #4CAF50; | |||||
text-align: center; | |||||
color: white; | |||||
} | |||||
#passes tr.inactive { | |||||
color: lightgray; | |||||
} | |||||
#satimg { | |||||
max-width: 200px; | |||||
max-height: 200px; | |||||
width: 100%; | |||||
} | |||||
#satimgdiv { | |||||
width: 100%; | |||||
height: 100%; | |||||
max-width: 200px; | |||||
background-color: antiquewhite; | |||||
/* margin: 10px; */ | |||||
display: inline-block; | |||||
vertical-align: middle; | |||||
text-align: center; | |||||
} | |||||
footer { | |||||
/* position: absolute; */ | |||||
margin: 20px; | |||||
bottom: 0; | |||||
max-width: 100%; | |||||
text-align: center; | |||||
} | |||||
img.img-footer { | |||||
max-width: 100%; | |||||
} |
@@ -0,0 +1,14 @@ | |||||
create table predict_passes( | |||||
sat_name text not null, | |||||
pass_start timestamp primary key default (strftime('%s', 'now')) not null, | |||||
pass_end timestamp default (strftime('%s', 'now')) not null, | |||||
max_elev int not null, | |||||
is_active boolean); | |||||
CREATE TABLE decoded_passes( | |||||
id integer primary key autoincrement, | |||||
pass_start integer, | |||||
file_path text not null, | |||||
daylight_pass boolean, is_noaa boolean, | |||||
foreign key(pass_start) references passes(pass_start)); |