diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml index a9c1a77a..25149a18 100644 --- a/ansible/group_vars/all.yml +++ b/ansible/group_vars/all.yml @@ -11,10 +11,14 @@ db_file: "{{ noaa_home }}/db/panel.db" # website content directory web_home: "/var/www/wx-new" -# output root directories for images and audio +# output root directories for images, audio, and video output_root: /srv images_output: "{{ output_root }}/images" audio_output: "{{ output_root }}/audio" +videos_output: "{{ output_root }}/videos" + +# file used for NOAA animations +noaa_animation_output: "{{ videos_output }}/RollingAnimation.mp4" # ramfs location ramfs_path: "/var/ramfs" diff --git a/ansible/roles/common/tasks/tools.yml b/ansible/roles/common/tasks/tools.yml index 1d90bf3c..db1c6490 100644 --- a/ansible/roles/common/tasks/tools.yml +++ b/ansible/roles/common/tasks/tools.yml @@ -106,7 +106,7 @@ - name: create images directory become: yes file: - path: images_output + path: "{{ images_output }}" state: directory owner: pi mode: 0775 @@ -122,7 +122,7 @@ - name: create audio root directory become: yes file: - path: audio_output + path: "{{ audio_output }}" state: directory owner: pi group: pi @@ -145,4 +145,12 @@ owner: pi group: pi mode: 0775 + +- name: create videos directory + become: yes + file: + path: "{{ videos_output }}" + state: directory + owner: pi + mode: 0775 ... diff --git a/ansible/roles/common/templates/noaa-v2.conf.j2 b/ansible/roles/common/templates/noaa-v2.conf.j2 index 4152483f..61f8aa50 100644 --- a/ansible/roles/common/templates/noaa-v2.conf.j2 +++ b/ansible/roles/common/templates/noaa-v2.conf.j2 @@ -4,6 +4,7 @@ WEB_HOME={{ web_home }} IMAGE_OUTPUT={{ images_output }} NOAA_AUDIO_OUTPUT={{ audio_output }}/noaa METEOR_AUDIO_OUTPUT={{ audio_output }}/meteor +NOAA_ANIMATION_OUTPUT={{ noaa_animation_output }} RAMFS_AUDIO={{ ramfs_path }} NOAA_LOG={{ log_file }} LAT={{ latitude }} @@ -44,6 +45,8 @@ DELETE_AUDIO={{ delete_audio|lower }} FLIP_METEOR_IMG={{ flip_meteor_image|lower }} TZ_OFFSET={{ timezone_offset }} LOG_LEVEL={{ log_level }} +NOAA_CROP_TOPTOBOTTOM={{ noaa_crop_toptobottom|lower }} +NOAA_INTERPOLATE={{ noaa_interpolate|lower }} NOAA_MAP_CROSSHAIR_ENABLE={{ noaa_map_crosshair_enable|lower }} NOAA_MAP_CROSSHAIR_COLOR={{ noaa_map_crosshair_color }} NOAA_MAP_GRID_DEGREES={{ noaa_map_grid_degrees }} diff --git a/ansible/roles/webserver/tasks/main.yml b/ansible/roles/webserver/tasks/main.yml index 14df9a76..6f8a8b29 100644 --- a/ansible/roles/webserver/tasks/main.yml +++ b/ansible/roles/webserver/tasks/main.yml @@ -115,6 +115,13 @@ state: directory group: www-data +- name: update videos directory group + become: yes + file: + path: "{{ videos_output }}" + state: directory + group: www-data + - name: update database folder permissions become: yes file: diff --git a/ansible/roles/webserver/templates/Config.php.j2 b/ansible/roles/webserver/templates/Config.php.j2 index 2999f990..1d55a800 100644 --- a/ansible/roles/webserver/templates/Config.php.j2 +++ b/ansible/roles/webserver/templates/Config.php.j2 @@ -28,6 +28,10 @@ class Config { # whether to enable satvis visualization const ENABLE_SATVIS = '{{ enable_satvis|lower }}'; + # whether to enable image video + const ENABLE_ANIMATION = '{{ enable_animation|lower }}'; + const ANIMATION_VIDEO_FILE = '{{ noaa_animation_output }}'; + # lat and lon coordinates of base station const BASE_STATION_LAT = '{{ latitude }}'; const BASE_STATION_LON = '{{ longitude }}'; diff --git a/ansible/roles/webserver/templates/nginx_default.j2 b/ansible/roles/webserver/templates/nginx_default.j2 index 3a44bb81..bf533485 100644 --- a/ansible/roles/webserver/templates/nginx_default.j2 +++ b/ansible/roles/webserver/templates/nginx_default.j2 @@ -10,6 +10,10 @@ server { alias /srv/images/$1; } + location ~ /videos/(.*) { + alias /srv/videos/$1; + } + location / { try_files $uri $uri/ /index.php; } diff --git a/ansible/roles/webserver/templates/nginx_tls_default.j2 b/ansible/roles/webserver/templates/nginx_tls_default.j2 index d35ebbb2..70d44243 100644 --- a/ansible/roles/webserver/templates/nginx_tls_default.j2 +++ b/ansible/roles/webserver/templates/nginx_tls_default.j2 @@ -15,6 +15,10 @@ server { alias /srv/images/$1; } + location ~ /videos/(.*) { + alias /srv/videos/$1; + } + location / { try_files $uri $uri/ /index.php; } diff --git a/config/settings.yml.sample b/config/settings.yml.sample index 8eb272f3..83132775 100644 --- a/config/settings.yml.sample +++ b/config/settings.yml.sample @@ -97,6 +97,8 @@ delete_audio: false # (note: default value is total list of supported image processors) # noaa_nighttime_enhancements - list of enhancements to create images using during nighttime captures # (note: default value is total list of supported image processors) +# noaa_crop_toptobottom - whether to crop the top and bottom noise out of the noaa capture +# noaa_interpolate - whether to interpolate and oversample the images (larger images produced) flip_meteor_image: true produce_spectrogram: true noaa_crop_telemetry: false @@ -109,8 +111,10 @@ produce_polar_direction_graph: true ground_station_location: '' show_sun_elevation: true show_pass_direction: true -noaa_daytime_enhancements: 'ZA MCIR MCIR-precip MSA MSA-precip HVC-precip HVCT-precip HVC HVCT therm' -noaa_nighttime_enhancements: 'ZA MCIR MCIR-precip therm' +noaa_daytime_enhancements: 'ZA MCIR MCIR-precip MSA MSA-precip HVC-precip HVCT-precip HVC HVCT therm avi' +noaa_nighttime_enhancements: 'ZA MCIR HVCT MCIR-precip therm avi' +noaa_crop_toptobottom: true +noaa_interpolate: false # noaa map configurations # http://usradioguy.com/wp-content/uploads/2020/05/wxtoimgcommand-line.pdf @@ -198,6 +202,11 @@ log_level: DEBUG # the processing and space requirements enable_satvis: true +# whether to enable the image video in the passes view - note that this +# is by default disabled on "extra-small" devices such as phones due +# to the processing and space requirements +enable_animation: false + # pruning capabilities - must be configured in cron (see documentation) # delete_oldest_n - how many oldest captures to delete on each run # delete_older_than_n - delete all images older than this many days diff --git a/config/settings_schema.json b/config/settings_schema.json index 54c0dc77..994bae83 100644 --- a/config/settings_schema.json +++ b/config/settings_schema.json @@ -89,6 +89,8 @@ "show_pass_direction": { "type": "boolean" }, "noaa_daytime_enhancements": { "type": "string" }, "noaa_nighttime_enhancements": { "type": "string" }, + "noaa_crop_toptobottom": { "type": "boolean" }, + "noaa_interpolate": { "type": "boolean" }, "noaa_map_crosshair_enable": { "type": "boolean" }, "noaa_map_crosshair_color": { "type": "string" }, "noaa_map_grid_degrees": { "type": "number" }, @@ -195,6 +197,8 @@ "show_pass_direction", "noaa_daytime_enhancements", "noaa_nighttime_enhancements", + "noaa_crop_toptobottom", + "noaa_interpolate", "noaa_map_crosshair_enable", "noaa_map_crosshair_color", "noaa_map_grid_degrees", diff --git a/scripts/common.sh b/scripts/common.sh index b9e5914a..3001c6e0 100755 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -31,6 +31,7 @@ fi # binary helpers CONVERT="/usr/bin/convert" +FFMPEG="/usr/bin/ffmpeg" GMIC="/usr/bin/gmic" IDENTIFY="/usr/bin/identify" MEDET_ARM="/usr/bin/medet_arm" diff --git a/scripts/image_processors/noaa_avi.sh b/scripts/image_processors/noaa_avi.sh new file mode 100755 index 00000000..926fbe36 --- /dev/null +++ b/scripts/image_processors/noaa_avi.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# Purpose: Generate a slide show mp4 video of NOAA images. +# +# Input parameters: +# 1. Map overlap file +# 2. Input .wav file +# +# Example: +# ./noaa_avi.sh /path/to/map_overlay.png /path/to/input.wav + +# import common lib and settings +. "$HOME/.noaa-v2.conf" +. "$NOAA_HOME/scripts/common.sh" + +# input params +MAP_OVERLAY=$1 +INPUT_WAV=$2 + +# note that this is replaced in place to overwrite fixed file +OUTPUT_IMAGE="${NOAA_HOME}/tmp/RollingAnimation.avi" + +# calculate any extra args for the processor +extra_args="" +if [ "${NOAA_CROP_TELEMETRY}" == "true" ]; then + extra_args=${extra_args}" -c" +fi + +if [ "${NOAA_CROP_TOPTOBOTTOM}" == "false" ]; then + extra_args=${extra_args}" -A" +fi + +if [ "${NOAA_INTERPOLATE}" == "true" ]; then + extra_args=${extra_args}" -I" +fi + +# produce the output image +$WXTOIMG -o -M 49 -m "${MAP_OVERLAY}" ${extra_args} -e "MCIR" "${INPUT_WAV}" "${OUTPUT_IMAGE}" + +# convert updated AVI to web-display ready mp4 +# ffmpeg -i ${OUTPUT_IMAGE} -c:v libx264 -c:a copy -y /srv/images/RollingAnimation.mp4 +$FFMPEG -an -i ${OUTPUT_IMAGE} -vcodec libx264 -pix_fmt yuv420p -profile:v baseline -level 3 -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2" -y ${NOAA_ANIMATION_OUTPUT} diff --git a/scripts/image_processors/noaa_hvc.sh b/scripts/image_processors/noaa_hvc.sh index cfdbabd3..b2bb06a9 100755 --- a/scripts/image_processors/noaa_hvc.sh +++ b/scripts/image_processors/noaa_hvc.sh @@ -29,7 +29,15 @@ OUTPUT_IMAGE=$3 # calculate any extra args for the processor extra_args="" if [ "${NOAA_CROP_TELEMETRY}" == "true" ]; then - extra_args="-c" + extra_args=${extra_args}" -c" +fi + +if [ "${NOAA_CROP_TOPTOBOTTOM}" == "false" ]; then + extra_args=${extra_args}" -A" +fi + +if [ "${NOAA_INTERPOLATE}" == "true" ]; then + extra_args=${extra_args}" -I" fi # produce the output image diff --git a/scripts/image_processors/noaa_hvc_precip.sh b/scripts/image_processors/noaa_hvc_precip.sh index 9d7d67c6..029c55bf 100755 --- a/scripts/image_processors/noaa_hvc_precip.sh +++ b/scripts/image_processors/noaa_hvc_precip.sh @@ -29,8 +29,17 @@ OUTPUT_IMAGE=$3 # calculate any extra args for the processor extra_args="" if [ "${NOAA_CROP_TELEMETRY}" == "true" ]; then - extra_args="-c" + extra_args=${extra_args}" -c" fi +if [ "${NOAA_CROP_TOPTOBOTTOM}" == "false" ]; then + extra_args=${extra_args}" -A" +fi + +if [ "${NOAA_INTERPOLATE}" == "true" ]; then + extra_args=${extra_args}" -I" +fi + + # produce the output image $WXTOIMG -o -m "${MAP_OVERLAY}" ${extra_args} -e "HVC-precip" "${INPUT_WAV}" "${OUTPUT_IMAGE}" diff --git a/scripts/image_processors/noaa_hvct.sh b/scripts/image_processors/noaa_hvct.sh index b342a44e..df4d2351 100755 --- a/scripts/image_processors/noaa_hvct.sh +++ b/scripts/image_processors/noaa_hvct.sh @@ -23,7 +23,15 @@ OUTPUT_IMAGE=$3 # calculate any extra args for the processor extra_args="" if [ "${NOAA_CROP_TELEMETRY}" == "true" ]; then - extra_args="-c" + extra_args=${extra_args}" -c" +fi + +if [ "${NOAA_CROP_TOPTOBOTTOM}" == "false" ]; then + extra_args=${extra_args}" -A" +fi + +if [ "${NOAA_INTERPOLATE}" == "true" ]; then + extra_args=${extra_args}" -I" fi # produce the output image diff --git a/scripts/image_processors/noaa_hvct_precip.sh b/scripts/image_processors/noaa_hvct_precip.sh index 1494cf4f..683b0433 100755 --- a/scripts/image_processors/noaa_hvct_precip.sh +++ b/scripts/image_processors/noaa_hvct_precip.sh @@ -23,7 +23,15 @@ OUTPUT_IMAGE=$3 # calculate any extra args for the processor extra_args="" if [ "${NOAA_CROP_TELEMETRY}" == "true" ]; then - extra_args="-c" + extra_args=${extra_args}" -c" +fi + +if [ "${NOAA_CROP_TOPTOBOTTOM}" == "false" ]; then + extra_args=${extra_args}" -A" +fi + +if [ "${NOAA_INTERPOLATE}" == "true" ]; then + extra_args=${extra_args}" -I" fi # produce the output image diff --git a/scripts/image_processors/noaa_mcir.sh b/scripts/image_processors/noaa_mcir.sh index df630435..fe221619 100755 --- a/scripts/image_processors/noaa_mcir.sh +++ b/scripts/image_processors/noaa_mcir.sh @@ -25,7 +25,15 @@ OUTPUT_IMAGE=$3 # calculate any extra args for the processor extra_args="" if [ "${NOAA_CROP_TELEMETRY}" == "true" ]; then - extra_args="-c" + extra_args=${extra_args}" -c" +fi + +if [ "${NOAA_CROP_TOPTOBOTTOM}" == "false" ]; then + extra_args=${extra_args}" -A" +fi + +if [ "${NOAA_INTERPOLATE}" == "true" ]; then + extra_args=${extra_args}" -I" fi # produce the output image diff --git a/scripts/image_processors/noaa_mcir_precip.sh b/scripts/image_processors/noaa_mcir_precip.sh index cd5ec829..6a601b14 100755 --- a/scripts/image_processors/noaa_mcir_precip.sh +++ b/scripts/image_processors/noaa_mcir_precip.sh @@ -25,7 +25,15 @@ OUTPUT_IMAGE=$3 # calculate any extra args for the processor extra_args="" if [ "${NOAA_CROP_TELEMETRY}" == "true" ]; then - extra_args="-c" + extra_args=${extra_args}" -c" +fi + +if [ "${NOAA_CROP_TOPTOBOTTOM}" == "false" ]; then + extra_args=${extra_args}" -A" +fi + +if [ "${NOAA_INTERPOLATE}" == "true" ]; then + extra_args=${extra_args}" -I" fi # produce the output image diff --git a/scripts/image_processors/noaa_msa.sh b/scripts/image_processors/noaa_msa.sh index 79f4146b..18d3df83 100755 --- a/scripts/image_processors/noaa_msa.sh +++ b/scripts/image_processors/noaa_msa.sh @@ -24,7 +24,15 @@ OUTPUT_IMAGE=$3 # calculate any extra args for the processor extra_args="" if [ "${NOAA_CROP_TELEMETRY}" == "true" ]; then - extra_args="-c" + extra_args=${extra_args}" -c" +fi + +if [ "${NOAA_CROP_TOPTOBOTTOM}" == "false" ]; then + extra_args=${extra_args}" -A" +fi + +if [ "${NOAA_INTERPOLATE}" == "true" ]; then + extra_args=${extra_args}" -I" fi # produce the output image diff --git a/scripts/image_processors/noaa_msa_precip.sh b/scripts/image_processors/noaa_msa_precip.sh index 05fae5e5..29f502b1 100755 --- a/scripts/image_processors/noaa_msa_precip.sh +++ b/scripts/image_processors/noaa_msa_precip.sh @@ -24,7 +24,15 @@ OUTPUT_IMAGE=$3 # calculate any extra args for the processor extra_args="" if [ "${NOAA_CROP_TELEMETRY}" == "true" ]; then - extra_args="-c" + extra_args=${extra_args}" -c" +fi + +if [ "${NOAA_CROP_TOPTOBOTTOM}" == "false" ]; then + extra_args=${extra_args}" -A" +fi + +if [ "${NOAA_INTERPOLATE}" == "true" ]; then + extra_args=${extra_args}" -I" fi # produce the output image diff --git a/scripts/image_processors/noaa_therm.sh b/scripts/image_processors/noaa_therm.sh index 8de8e9e4..799b7cfc 100755 --- a/scripts/image_processors/noaa_therm.sh +++ b/scripts/image_processors/noaa_therm.sh @@ -24,7 +24,15 @@ OUTPUT_IMAGE=$3 # calculate any extra args for the processor extra_args="" if [ "${NOAA_CROP_TELEMETRY}" == "true" ]; then - extra_args="-c" + extra_args=${extra_args}" -c" +fi + +if [ "${NOAA_CROP_TOPTOBOTTOM}" == "false" ]; then + extra_args=${extra_args}" -A" +fi + +if [ "${NOAA_INTERPOLATE}" == "true" ]; then + extra_args=${extra_args}" -I" fi # produce the output image diff --git a/scripts/image_processors/noaa_za.sh b/scripts/image_processors/noaa_za.sh index 01b9b2ef..7c4fec1f 100755 --- a/scripts/image_processors/noaa_za.sh +++ b/scripts/image_processors/noaa_za.sh @@ -25,7 +25,15 @@ OUTPUT_IMAGE=$3 # calculate any extra args for the processor extra_args="" if [ "${NOAA_CROP_TELEMETRY}" == "true" ]; then - extra_args="-c" + extra_args=${extra_args}" -c" +fi + +if [ "${NOAA_CROP_TOPTOBOTTOM}" == "false" ]; then + extra_args=${extra_args}" -A" +fi + +if [ "${NOAA_INTERPOLATE}" == "true" ]; then + extra_args=${extra_args}" -I" fi # produce the output image diff --git a/scripts/receive_noaa.sh b/scripts/receive_noaa.sh index b295f25f..a6307d2a 100755 --- a/scripts/receive_noaa.sh +++ b/scripts/receive_noaa.sh @@ -223,6 +223,9 @@ for enhancement in $ENHANCEMENTS; do "therm") proc_script="noaa_therm.sh" ;; + "avi") + proc_script="noaa_avi.sh" + ;; esac if [ -z "${proc_script}" ]; then @@ -230,11 +233,11 @@ for enhancement in $ENHANCEMENTS; do else ${IMAGE_PROC_DIR}/${proc_script} $map_overlay "${AUDIO_FILE_BASE}.wav" "${IMAGE_FILE_BASE}-$enhancement.jpg" >> $NOAA_LOG 2>&1 - ${IMAGE_PROC_DIR}/noaa_normalize_annotate.sh "${IMAGE_FILE_BASE}-$enhancement.jpg" "${IMAGE_FILE_BASE}-$enhancement.jpg" 90 >> $NOAA_LOG 2>&1 - ${IMAGE_PROC_DIR}/thumbnail.sh 300 "${IMAGE_FILE_BASE}-$enhancement.jpg" "${IMAGE_THUMB_BASE}-$enhancement.jpg" >> $NOAA_LOG 2>&1 - - filesize=$(wc -c "${IMAGE_FILE_BASE}-$enhancement.jpg" | awk '{print $1}') if [ -f "${IMAGE_FILE_BASE}-$enhancement.jpg" ]; then + ${IMAGE_PROC_DIR}/noaa_normalize_annotate.sh "${IMAGE_FILE_BASE}-$enhancement.jpg" "${IMAGE_FILE_BASE}-$enhancement.jpg" 90 >> $NOAA_LOG 2>&1 + ${IMAGE_PROC_DIR}/thumbnail.sh 300 "${IMAGE_FILE_BASE}-$enhancement.jpg" "${IMAGE_THUMB_BASE}-$enhancement.jpg" >> $NOAA_LOG 2>&1 + filesize=$(wc -c "${IMAGE_FILE_BASE}-$enhancement.jpg" | awk '{print $1}') + # check that the file actually has content if [ $filesize -gt 20480 ]; then # at least one good image diff --git a/webpanel/App/Views/Passes/index.html b/webpanel/App/Views/Passes/index.html index 52bf7009..c85d0da3 100644 --- a/webpanel/App/Views/Passes/index.html +++ b/webpanel/App/Views/Passes/index.html @@ -5,11 +5,19 @@ {% endblock %} {% block pre_body %} - {% if constant('Config\\Config::ENABLE_SATVIS') == 'true' %} -
- -
- {% endif %} +
+ {% if constant('Config\\Config::ENABLE_SATVIS') == 'true' %} +
+ +
+ {% endif %} + + {% if constant('Config\\Config::ENABLE_ANIMATION') == 'true' %} +
+ +
+ {% endif %} +
{% endblock %} {% block body %} diff --git a/webpanel/public/assets/css/pass_list.css b/webpanel/public/assets/css/pass_list.css index c3faa938..45c90315 100644 --- a/webpanel/public/assets/css/pass_list.css +++ b/webpanel/public/assets/css/pass_list.css @@ -26,3 +26,12 @@ table#passes td.no-passes { font-weight: bold; font-style: italic; } + +.flex-container { + display: flex; +} + +.flex-child { + flex: 1; + max-height: 500px; +}