diff --git a/.github/ISSUE_TEMPLATE/2-bug_report.yml b/.github/ISSUE_TEMPLATE/2-bug_report.yml
index d639ea2d0..9418fa4c7 100644
--- a/.github/ISSUE_TEMPLATE/2-bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/2-bug_report.yml
@@ -69,4 +69,4 @@ body:
If your problem is with an **Allsky Website**, also attach:
\* `~/allsky/html/allsky/configuration.json` (local Website)
- \* `~/allsky/config/remote_configuration.json` (remote Website)
+ \* `~/allsky/config/remote_configuration.json` (remote Website)
\ No newline at end of file
diff --git a/.github/workflows/ci_shellcheck.yml b/.github/workflows/ci_shellcheck.yml
index 7f6cdf115..8da64c54a 100644
--- a/.github/workflows/ci_shellcheck.yml
+++ b/.github/workflows/ci_shellcheck.yml
@@ -8,6 +8,7 @@ on:
paths:
- '*.sh'
- '*/*.sh'
+ - '*/*/*.sh'
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
diff --git a/.gitignore b/.gitignore
index 563506f66..f2b98a91b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,5 @@
images/*
darks/*
-scripts/endOfNight_additionalSteps.sh
# development artifacts
src/*.a
diff --git a/README.md b/README.md
index 004841586..1da11f750 100644
--- a/README.md
+++ b/README.md
@@ -1,43 +1,52 @@
-# Allsky Camera  [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=MEBU2KN75G2NG&source=url)
+# Allsky Camera  [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=MEBU2KN75G2NG&source=url)
This is the source code for the Allsky Camera project described [on Instructables](http://www.instructables.com/id/Wireless-All-Sky-Camera/).
-
+
-> **This README and the [Allsky documentation](https://htmlpreview.github.io/?https://raw.githubusercontent.com/thomasjacquin/allsky/master/html/documentation/index.html) will help get your allsky camera up and running.**
-
-
## Requirements
-You will need the following:
+In order to run the Allsky software you need:
- * A Raspberry Pi (Zero 2, 2, 3, 4, or 5) running Pi OS.
- * A camera (Raspberry Pi HQ, Module 3, or RPi compatible, or ZWO ASI released before October 2023)
+ * A Raspberry Pi Zero 2, Pi 2, Pi 3, Pi 4, Pi 5, or Le Potato.
+ * A camera:
+ * Any ZWO camera sold before October 2024.
+ * One of the following Raspberry Pi cameras:
+ * RPi HQ (IMX477 sensor)
+ * RPi Module 3 (IMX708 sensor)
+ * RPi Version 1 (OV5647 sensor; NOT RECOMMENDED: 0.9 second maximum exposure)
+ * IMX290 60.00 fps
+ * ArduCam 16 MP (IMX519 sensor)
+ * ArduCam 64 MP (arducam_64mp sensor)
+ * ArduCam 462 (arducam-pivariety sensor)
+ * Waveshare imx219-d160 (IMX290 sensor)
+ * ArduCam 64 MP Owlsight (OV64a40 sensor)
+ * OneInchEye IMX283 (IMX283 sensor)
-> **NOTES:**
-> - Only the Raspberry Pi OS is supported (Buster, Bullseye, or Bookworm). Other operating systems like Ubuntu are NOT supported.
-> - **NOTE**: support for Buster is going away so please upgrade to Bookworm.
-> - The ZWO ASI120-series cameras are not recommended due to somewhat poor quality and tendency to produce timeout errors. See [Troubleshooting --> ZWO Cameras](https://htmlpreview.github.io/?https://raw.githubusercontent.com/thomasjacquin/allsky/master/html/documentation/troubleshooting/ZWOCameras.html) for notes on the ASI120-series and related T7 / T7C cameras.
-> - The Pi Zero with its limited memory and _very_ limited CPU power (single CPU core), is **not** recommended. You will most likely not be able to create keograms, startrails, or timelapse videos.
-> - The Pi Zero 2 with its limited memory and somewhat limited CPU power, is not recommended unless cost is the only concern. Creating keograms, startrails, and timelapse videos may or may not be possible.
+> __NOTES:__
+> - Only the Raspberry Pi OS is supported. Other operating systems like Ubuntu are NOT supported. If possible use the newest Bookworm 64-bit release. Bullseye will also work. __Buster support will be dropped in the next major release__.
+> - The ZWO ASI120-series cameras are __not__ recommended due to their tendency to produce errors and poor-quality images.
+> - The Pi Zero with its limited memory and _very_ limited CPU power is not recommended. You probably won't be able to create keograms, startrails, or timelapse videos.
+> - The Pi Zero 2 with its limited memory and somewhat limited CPU power is not recommended unless cost is the only concern. Creating keograms, startrails, and timelapse videos may or may not be possible.
> - The Le Potato is the only "Pi-compatible" board that we've found to actually be compatible, so buyer beware.
----
## Software Installation
-
-Detailed installation instructions can be found at [Installing / Upgrading --> Allsky](https://htmlpreview.github.io/?https://raw.githubusercontent.com/thomasjacquin/allsky/master/html/documentation/installations/Allsky.html).
+
+See the [detailed installation instructions](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AllskyTeam/allsky/master/html/documentation/installations/Allsky.html).
---
@@ -47,12 +56,12 @@ Detailed installation instructions can be found at [Installing / Upgrading --> A
## Web User Interface (WebUI)
-
+
-The WebUI is now installed as part of Allsky and is used to administer Allsky, and to a lesser extent, your Pi. It can also be used to view the current image as well as all saved images, keograms, startrails, and timelapse videos.
+The WebUI is used to administer Allsky, and to a lesser extent, your Pi. It can also be used to view the current image as well as all saved images, keograms, startrails, and timelapse videos.
-A public page is also available in order to view the current image without having to log into the WebUI and without being able to do any administrative tasks. This can be useful for people who don't have a Allsky Website but still want to share a view of their sky:
+A public page is also available in order to view the current image without having to log into the WebUI and without being able to do any administrative tasks. This can be useful for people who don't use an Allsky Website but still want to share a view of their sky:
```
http://your_raspberry_IP/public.php
@@ -61,15 +70,21 @@ http://your_raspberry_IP/public.php
Make sure this page is publically viewable.
If it is behind a firewall consult the documentation for your network equipment for information on allowing inbound connections.
+The WebUI has a link to the Allsky Documentation which describes all the settings Allsky uses as well as troubleshooting information.
+It should be used before requesting support on GitHub.
+
---
-## Allsky Website
+## Allsky Website and remote server
+
+The local Allsky Website (i.e., on the Pi) is installed with Allsky but must be enabled in the WebUI in order to use it.
+You can also install the Allsky Website on a remote server so it can be viewable via the Internet.
-By installling the optional Allsky Website you can display your files on a website on the Pi, on another machine, or on both.
+See [Installation / Upgrading --> Website](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AllskyTeam/allsky/master/html/documentation/installations/AllskyWebsite.html) for information on how to install and configure an Allsky Website.
-See [Installation / Upgrading --> Website](https://htmlpreview.github.io/?https://raw.githubusercontent.com/thomasjacquin/allsky/master/html/documentation/installations/AllskyWebsite.html) for information on how to install and configure an Allsky Website.
+Allsky images, keograms, startrails, and timelapse videos can optionally be uploaded to a remote server __not__ running an Allsky Website. This is useful if you have a personal website and want to include the most recent Allsky images.
---
@@ -84,7 +99,7 @@ Allsky supports running "modules" after each picture is taken to change the imag
The Overlay Editor lets you easily specify what text and images you want in your overlay, and place them using drag-and-drop. Each field can be formatted however you want (font, color, size, position, rotation, etc.). The only limit is your imagination!!
-See [Explanations / How To -> Overlays](https://htmlpreview.github.io/?https://raw.githubusercontent.com/thomasjacquin/allsky/master/html/documentation/overlays/overlays.html) and [Explanations / How To -> Modules](https://htmlpreview.github.io/?https://raw.githubusercontent.com/thomasjacquin/allsky/master/html/documentation/modules/modules.html) for more information.
+See [Explanations / How To -> Overlays](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AllskyTeam/allsky/master/html/documentation/overlays/overlays.html) and [Explanations / How To -> Modules](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AllskyTeam/allsky/master/html/documentation/modules/modules.html) for more information.
---
@@ -93,9 +108,9 @@ See [Explanations / How To -> Overlays](https://htmlpreview.github.io/?https://r
## Dark frame subtraction
-Dark frame subtraction removes hot pixels from images by taking images at different temperatures with a cover on your camera lens and subtracting those images from nighttime images.
+Dark frame subtraction removes white (i.e., "hot") pixels from images by taking images with a cover over the camera lens and subtracting those images from images.
-See [Explanations / How To -> Dark frames](https://htmlpreview.github.io/?https://raw.githubusercontent.com/thomasjacquin/allsky/master/html/documentation/explanations/darkFrames.html) for more information.
+See [Explanations / How To -> Dark frames](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AllskyTeam/allsky/master/html/documentation/explanations/darkFrames.html) for more information.
---
@@ -116,13 +131,13 @@ By default, a timelapse video is generated at the end of nighttime from all of t
## Keograms
-
+
-A **Keogram** is an image giving a quick view of the day's activity.
+A __Keogram__ is an image giving a quick view of the day's activity.
For each image a central vertical column 1 pixel wide is extracted. All these columns are then stitched together from left to right. This results in a timeline that reads from dawn to the end of nighttime (the image above only shows nighttime data since daytime images were turned off).
-See [Explanations / How To --> Keograms](https://htmlpreview.github.io/?https://raw.githubusercontent.com/thomasjacquin/allsky/master/html/documentation/explanations/keograms.html).
+See [Explanations / How To --> Keograms](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AllskyTeam/allsky/master/html/documentation/explanations/keograms.html).
---
@@ -133,13 +148,13 @@ See [Explanations / How To --> Keograms](https://htmlpreview.github.io/?https://
## Startrails
-
+
-**Startrails** are generated by stacking all the images from a night on top of each other.
+__Startrails__ are generated by stacking all the images from a night on top of each other.
In the image above, Polaris is centered about one-fourth the way from the top.
-See [Explanations / How To --> Startrails](https://htmlpreview.github.io/?https://raw.githubusercontent.com/thomasjacquin/allsky/master/html/documentation/explanations/startrails.html).
+See [Explanations / How To --> Startrails](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AllskyTeam/allsky/master/html/documentation/explanations/startrails.html).
---
@@ -149,10 +164,10 @@ See [Explanations / How To --> Startrails](https://htmlpreview.github.io/?https:
## Automatic deletion of old data
-You can specify how many days worth of images to keep in order to keep the Raspberry Pi SD card from filling up. If you have the Allsky Website installed on your Pi, you can specify how many days worth of its imags to keep.
+You can specify how many days worth of images to keep in order to keep the Raspberry Pi SD card from filling up. If you are using the Allsky Website on your Pi, you can specify how many days worth of its imags to keep.
-See the **DAYS_TO_KEEP** and **WEB_DAYS_TO_KEEP** settings in [Settings --> Allsky](https://htmlpreview.github.io/?https://raw.githubusercontent.com/thomasjacquin/allsky/master/html/documentation/settings/allsky.html).
+See the __Days to Keep on Pi Website__ and __Web Days To Keep on Remote Website__ settings in [Settings --> Allsky](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AllskyTeam/allsky/master/html/documentation/settings/allsky.html).
---
@@ -163,13 +178,13 @@ See the **DAYS_TO_KEEP** and **WEB_DAYS_TO_KEEP** settings in [Settings --> Alls
## Share your sky
-If you want your allsky camera added to the [Allsky map](http://www.thomasjacquin.com/allsky-map), see [Put your camera on Allsky Map](https://htmlpreview.github.io/?https://raw.githubusercontent.com/thomasjacquin/allsky/master/html/documentation/miscellaneous/AllskyMap.html).
+If you want your allsky camera added to the [Allsky map](http://www.thomasjacquin.com/allsky-map), see [Put your camera on Allsky Map](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AllskyTeam/allsky/master/html/documentation/miscellaneous/AllskyMap.html).
If you know anyone in Greenland or Antartica, send them a camera!!
@@ -181,7 +196,7 @@ If you know anyone in Greenland or Antartica, send them a camera!!
## Release changes
See the
-[Allsky Version Change Log](https://htmlpreview.github.io/?https://raw.githubusercontent.com/thomasjacquin/allsky/master/html/documentation/changeLog.html)
+[Allsky Version Change Log](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AllskyTeam/allsky/master/html/documentation/changeLog.html)
for a list of changes in this release and all prior releases.
---
diff --git a/allsky.sh b/allsky.sh
index dc865dfde..0e5834935 100755
--- a/allsky.sh
+++ b/allsky.sh
@@ -1,131 +1,165 @@
#!/bin/bash
-# This EXIT code is also defined in variables.sh, but in case we can't open that file, we need it here.
-EXIT_ERROR_STOP=100 # unrecoverable error - need user action so stop service
-
# Make it easy to find the beginning of this run in the log file.
echo " ***** Starting AllSky *****"
-[[ -z ${ALLSKY_HOME} ]] && export ALLSKY_HOME="$(realpath "$(dirname "${BASH_ARGV0}")")"
-ME="$(basename "${BASH_ARGV0}")"
+[[ -z ${ALLSKY_HOME} ]] && export ALLSKY_HOME="$( realpath "$( dirname "${BASH_ARGV0}" )" )"
+ME="$( basename "${BASH_ARGV0}" )"
-cd "${ALLSKY_HOME}" || exit 1
+# NOT_STARTED_MSG, STOPPED_MSG, ERROR_MSG_PREFIX, and ZWO_VENDOR are globals
-NOT_STARTED_MSG="Unable to start Allsky!"
-STOPPED_MSG="Allsky Stopped!"
-ERROR_MSG_PREFIX="*** ERROR ***\n${STOPPED_MSG}\n"
-#shellcheck disable=SC2086 source-path=.
-source "${ALLSKY_HOME}/variables.sh" || exit ${ALLSKY_ERROR_STOP}
-if [[ -z ${ALLSKY_CONFIG} ]]; then
- MSG="FATAL ERROR: 'source variables.sh' did not work properly."
- echo -e "${RED}*** ${MSG}${NC}"
- doExit "${EXIT_ERROR_STOP}" "Error" \
- "${ERROR_MSG_PREFIX}\n$(basename "${ALLSKY_HOME}")/variables.sh\nis corrupted." \
- "${NOT_STARTED_MSG} ${MSG}"
+#shellcheck source-path=.
+source "${ALLSKY_HOME}/variables.sh" || exit "${EXIT_ERROR_STOP}"
+#shellcheck source-path=scripts
+source "${ALLSKY_SCRIPTS}/functions.sh" || exit "${EXIT_ERROR_STOP}"
+#shellcheck source-path=scripts
+source "${ALLSKY_SCRIPTS}/installUpgradeFunctions.sh" || exit "${EXIT_ERROR_STOP}"
+
+if [[ ! -d ${ALLSKY_CONFIG} ]]; then
+ {
+ echo "*** ====="
+ echo "Allsky needs to be installed. Run: cd ~/allsky; ./install.sh"
+ echo "*** ====="
+ } >&2
+ # Can't call addMessage.sh or copy_notification_image.sh or almost anything
+ # since they use ${ALLSKY_CONIG} and/or ${ALLSKY_TMP} which don't exist yet.
+ set_allsky_status "${ALLSKY_STATUS_NEVER_RUN}"
+ doExit "${EXIT_ERROR_STOP}" "no-image" "" ""
fi
-#shellcheck disable=SC2086 source-path=scripts
-source "${ALLSKY_SCRIPTS}/functions.sh" || exit ${ALLSKY_ERROR_STOP}
-#shellcheck disable=SC2086,SC1091 # file doesn't exist in GitHub
-source "${ALLSKY_CONFIG}/config.sh" || exit ${ALLSKY_ERROR_STOP}
-#shellcheck disable=SC2086 source-path=scripts
-source "${ALLSKY_SCRIPTS}/installUpgradeFunctions.sh" || exit ${ALLSKY_ERROR_STOP}
+# Make sure ${CAMERA_TYPE} is valid; if not, exit with a message.
+verify_CAMERA_TYPE "${CAMERA_TYPE}"
+
+cd "${ALLSKY_HOME}" || exit 1
# Make sure they rebooted if they were supposed to.
-NEEDS_REBOOT="false"
-reboot_needed && NEEDS_REBOOT="true"
+if reboot_needed ; then
+ NEEDS_REBOOT="true"
+else
+ NEEDS_REBOOT="false"
+fi
# Make sure the settings have been configured after an installation or upgrade.
-LAST_CHANGED="$( settings ".lastChanged" )"
-if [[ ${LAST_CHANGED} == "" ]]; then
- echo "*** ===== Allsky needs to be configured before it can be used. See the WebUI."
+LAST_CHANGED="$( settings ".lastchanged" )"
+if [[ -z ${LAST_CHANGED} ]]; then
+ set_allsky_status "${ALLSKY_STATUS_SEE_WEBUI}"
+ echo "*** ===== Allsky needs to be configured before it can be used. See the WebUI." >&2
if [[ ${NEEDS_REBOOT} == "true" ]]; then
- echo "*** ===== The Pi also needs to be rebooted."
- doExit "${EXIT_ERROR_STOP}" "Error" \
+ echo "*** ===== The Pi also needs to be rebooted." >&2
+ doExit "${EXIT_ERROR_STOP}" "ConfigurationNeeded" \
"Allsky needs\nconfiguration\nand the Pi needs\na reboot" \
- "Allsky needs to be configured then the Pi rebooted."
+ "Allsky needs to be configured and then the Pi rebooted."
else
- doExit "${EXIT_ERROR_STOP}" "ConfigurationNeeded" "" ""
- "${ALLSKY_SCRIPTS}/addMessage.sh" "Error" "Allsky needs to be configured."
+ doExit "${EXIT_ERROR_STOP}" "ConfigurationNeeded" "" "Allsky needs to be configured."
fi
elif [[ ${NEEDS_REBOOT} == "true" ]]; then
- doExit "${EXIT_ERROR_STOP}" "RebootNeeded" "" ""
- "${ALLSKY_SCRIPTS}/addMessage.sh" "Error" "The Pi needs to be rebooted."
+ set_allsky_status "${ALLSKY_STATUS_SEE_WEBUI}"
+ doExit "${EXIT_ERROR_STOP}" "RebootNeeded" "" "The Pi needs to be rebooted."
fi
SEE_LOG_MSG="See ${ALLSKY_LOG}"
ARGS_FILE="${ALLSKY_TMP}/capture_args.txt"
-# If a prior copy of Allsky exists, remind the user.
+# If a prior copy of Allsky exists, remind the user if we've never reminded before,
+# or it's been at least a week since the last reminder.
if [[ -d ${PRIOR_ALLSKY_DIR} ]]; then
- MSG="Reminder: your prior Allsky is still in '${PRIOR_ALLSKY_DIR}'."
- MSG="${MSG}\nIf you are no longer using it, it can be removed to save disk space:"
- MSG="${MSG}\n rm -fr '${PRIOR_ALLSKY_DIR}'\n"
- "${ALLSKY_SCRIPTS}/addMessage.sh" "info" "${MSG}"
+ DO_MSG="true"
+ if [[ -f ${OLD_ALLSKY_REMINDER} ]]; then
+ CHECK_DATE="$( date -d '1 week ago' +'%Y%m%d%H%M.%S' )"
+ CHECK_FILE="${ALLSKY_TMP}/check_date"
+ touch -t "${CHECK_DATE}" "${CHECK_FILE}"
+ [[ ${OLD_ALLSKY_REMINDER} -nt "${CHECK_FILE}" ]] && DO_MSG="false"
+ rm -f "${CHECK_FILE}"
+ fi
+ if [[ ${DO_MSG} == "true" ]]; then
+ MSG="Reminder: your prior Allsky is still in '${PRIOR_ALLSKY_DIR}'."
+ MSG+="\nIf you are no longer using it, it can be removed to save disk space:"
+ MSG+="\n rm -fr '${PRIOR_ALLSKY_DIR}'\n"
+ "${ALLSKY_SCRIPTS}/addMessage.sh" "info" "${MSG}"
+ touch "${OLD_ALLSKY_REMINDER}" # last time we displayed the message
+ fi
+fi
+
+# If there's some checkAllsky.sh output, remind the user.
+if [[ -f ${CHECK_ALLSKY_LOG} ]]; then
+ DO_MSG="true"
+ REMINDER="${ALLSKY_LOGS}/checkAllsky_reminder.txt"
+ if [[ -f ${REMINDER} ]]; then
+ CHECK_DATE="$( date -d '1 week ago' +'%Y%m%d%H%M.%S' )"
+ CHECK_FILE="${ALLSKY_TMP}/check_date-checkAllsky"
+ touch -t "${CHECK_DATE}" "${CHECK_FILE}"
+ [[ ${REMINDER} -nt "${CHECK_FILE}" ]] && DO_MSG="false"
+ rm -f "${CHECK_FILE}"
+ fi
+ if [[ ${DO_MSG} == "true" ]]; then
+ MSG="
"
+ MSG+="Reminder to make these changes to your settings"
+ MSG+="
"
+ MSG+="$( < "${CHECK_ALLSKY_LOG}" )"
+ MSG+="If you made the changes run:"
+ MSG+="\n rm -f '${CHECK_ALLSKY_LOG}'\n"
+ "${ALLSKY_SCRIPTS}/addMessage.sh" "warning" "${MSG}"
+ touch "${REMINDER}" # last time we displayed the message
+ fi
fi
# This file contains information the user needs to act upon after an installation.
if [[ -f ${POST_INSTALLATION_ACTIONS} ]]; then
- # If there's an initial message display an image and stop.
+ # If there's an initial message created during installation, display an image and stop.
F="${POST_INSTALLATION_ACTIONS}_initial_message"
if [[ -f ${F} ]]; then
# There is already a message so don't add another,
# and there's already an image, so don't overwrite it.
# shellcheck disable=SC2154
- rm "${F}" # so next time we'll remind them.
+ rm -f "${F}" # so next time we'll remind them.
+ set_allsky_status "${ALLSKY_STATUS_SEE_WEBUI}"
doExit "${EXIT_ERROR_STOP}" "no-image" "" ""
else
- MSG="Reminder to perform the action(s) in '${POST_INSTALLATION_ACTIONS}'."
- MSG="${MSG}\nIf you already have, remove the file so you will no longer see this message:"
- MSG="${MSG}\n rm -f '${POST_INSTALLATION_ACTIONS}'"
- "${ALLSKY_SCRIPTS}/addMessage.sh" "info" "${MSG}"
+ MSG="Reminder: Click here to see the action(s) that need to be performed."
+ MSG+="\nOnce you perform them run the following to remove this message:"
+ MSG+="\n rm -f '${POST_INSTALLATION_ACTIONS}'"
+ PIA="${POST_INSTALLATION_ACTIONS/${ALLSKY_HOME}/}"
+ "${ALLSKY_SCRIPTS}/addMessage.sh" "warning" "${MSG}" "${PIA}"
fi
fi
-USE_NOTIFICATION_IMAGES=$(settings ".notificationimages")
-
-if [[ -z ${CAMERA_TYPE} ]]; then
- MSG="FATAL ERROR: 'Camera Type' not set in WebUI."
- echo -e "${RED}*** ${MSG}${NC}"
- doExit "${EXIT_NO_CAMERA}" "Error" \
- "${ERROR_MSG_PREFIX}\nCamera Type\nnot specified\nin the WebUI." \
- "${NOT_STARTED_MSG} ${MSG}"
-fi
+USE_NOTIFICATION_IMAGES="$( settings ".notificationimages" )" || exit "${EXIT_ERROR_STOP}"
# Make sure we are not already running.
pgrep "${ME}" | grep -v $$ | xargs "sudo kill -9" 2>/dev/null
-if [[ ${CAMERA_TYPE} == "RPi" ]]; then
- # "true" means use doExit() on error
- RPi_COMMAND_TO_USE="$(determineCommandToUse "true" "${ERROR_MSG_PREFIX}" )"
-
-elif [[ ${CAMERA_TYPE} == "ZWO" ]]; then
+# Get the list of connected cameras and make sure the one we want is connected.
+if [[ ${CAMERA_TYPE} == "ZWO" ]]; then
RPi_COMMAND_TO_USE=""
RESETTING_USB_LOG="${ALLSKY_TMP}/resetting_USB.txt"
+
reset_usb() # resets the USB bus
{
- REASON="${1}" # why are we resetting the bus?
+ local REASON="${1}" # why are we resetting the bus?
+ local MSG IMAGE_MSG
# Only reset a couple times, then exit with fatal error.
if [[ -f ${RESETTING_USB_LOG} ]]; then
NUM_USB_RESETS=$( < "${RESETTING_USB_LOG}" )
- if [[ ${NUM_USB_RESETS} -eq 2 ]]; then
- MSG="FATAL ERROR: Too many consecutive USB bus resets done (${NUM_USB_RESETS})."
- echo -e "${RED}*** ${MSG} Stopping." >&2
+ if [[ ${NUM_USB_RESETS} -ge 2 ]]; then
rm -f "${RESETTING_USB_LOG}"
- doExit "${EXIT_ERROR_STOP}" "Error" \
- "${ERROR_MSG_PREFIX}\nToo many consecutive\nUSB bus resets done!\n${SEE_LOG_MSG}" \
- "${NOT_STARTED_MSG} ${MSG}"
+
+ MSG="Too many consecutive USB bus resets done (${NUM_USB_RESETS})."
+ echo -e "${RED}*** ${FATAL_MSG} ${MSG} Stopping Allsky.${NC}" >&2
+ IMAGE_MSG="${ERROR_MSG_PREFIX}"
+ IMAGE_MSG+="\nToo many consecutive\nUSB bus resets done!\n${SEE_LOG_MSG}"
+ doExit "${EXIT_ERROR_STOP}" "Error"
+ "${IMAGE_MSG}" "${NOT_STARTED_MSG}: ${MSG}"
fi
else
NUM_USB_RESETS=0
fi
- MSG="${YELLOW}WARNING: Resetting USB ports ${REASON/\\n/ }"
- if [[ ${ON_TTY} -eq 1 ]]; then
- echo "${MSG}; restart ${ME} when done.${NC}" >&2
+ MSG="WARNING: Resetting USB ports ${REASON/\\n/ }"
+ if [[ ${ON_TTY} == "true" ]]; then
+ echo "${YELLOW}${MSG}; restart ${ME} when done.${NC}" >&2
else
- echo "${MSG}, then restarting.${NC}" >&2
+ echo "${MSG}, then restarting." >&2
# The service will automatically restart this script.
fi
@@ -133,64 +167,66 @@ elif [[ ${CAMERA_TYPE} == "ZWO" ]]; then
echo "${NUM_USB_RESETS}" > "${RESETTING_USB_LOG}"
# Display a warning message
- "${ALLSKY_SCRIPTS}/generate_notification_images.sh" --directory "${ALLSKY_TMP}" "${FILENAME}" \
- "yellow" "" "85" "" "" \
- "" "5" "yellow" "${EXTENSION}" "" "WARNING:\n\nResetting USB bus\n${REASON}.\nAttempt ${NUM_USB_RESETS}."
- sudo "$UHUBCTL_PATH" -a cycle -l "$UHUBCTL_PORT"
+ "${ALLSKY_SCRIPTS}/generate_notification_images.sh" --directory "${ALLSKY_TMP}" \
+ "${FILENAME}" "yellow" "" "85" "" "" \
+ "" "5" "yellow" "${EXTENSION}" "" \
+ "WARNING:\n\nResetting USB bus\n${REASON}.\nAttempt ${NUM_USB_RESETS}."
+
+ SEARCH="${ZWO_VENDOR}:${ZWO_CAMERA_ID}"
+ sudo "${ALLSKY_BIN}/uhubctl" --action off --exact --search "${SEARCH}"
sleep 3 # give it a few seconds, plus, allow the notification images to be seen
+ sudo "${ALLSKY_BIN}/uhubctl" --action on --exact --search "${SEARCH}"
}
- # "03c3" is the USB ID for ZWO devices.
- ZWOdev=$(lsusb -d '03c3:' | awk '{ bus=$2; dev=$4; gsub(/[^0-9]/,"",dev); print "/dev/bus/usb/"bus"/"dev;}')
- # We have to run "lsusb -D" once for each device returned by "lsusb -d", and can't
- # use "echo x | while read" because variables set inside the "while" loop don't get exposed
- # to the calling code, so use a temp file.
-
- TEMP="${ALLSKY_TMP}/${CAMERA_TYPE}_cameras.txt"
- echo "${ZWOdev}" > "${TEMP}"
- NUM=0
- while read -r DEV
- do
- lsusb -D "${DEV}" 2>/dev/null | grep --silent 'iProduct .*ASI[0-9]' && ((NUM++))
- done < "${TEMP}"
-
- if [[ ${NUM} -eq 0 ]]; then
- if [[ -n ${UHUBCTL_PATH} ]] ; then
- reset_usb "looking for a\nZWO camera" # reset_usb exits if too many tries
- exit 0 # exit with 0 so the service is restarted
- else
- MSG="FATAL ERROR: ZWO Camera not found"
- echo -en "${RED}*** ${MSG}" >&2
- if [[ ${ZWOdev} == "" ]]; then
- echo " and no USB entry either.${NC}" >&2
- USB_MSG=""
- else
- echo " but ${ZWOdev} found.${NC}" >&2
- USB_MSG="\n${SEE_LOG_MSG}"
- fi
+else # RPi
+ # "true" means use doExit() on error
+ RPi_COMMAND_TO_USE="$( determineCommandToUse "true" "${ERROR_MSG_PREFIX}" "false" )"
+fi
- echo " If you have the 'uhubctl' command installed, add it to config.sh." >&2
- echo " In the meantime, try running it to reset the USB bus." >&2
- doExit "${EXIT_NO_CAMERA}" "Error" \
- "${ERROR_MSG_PREFIX}\nNo ZWO camera\nfound!${USB_MSG}" \
- "${NOT_STARTED_MSG} ${MSG} ${SEE_LOG_MSG}."
- fi
+# "true" means ignore errors
+get_connected_cameras_info "true" > "${CONNECTED_CAMERAS_INFO}"
+if grep --silent "^${CAMERA_TYPE}" "${CONNECTED_CAMERAS_INFO}" ; then
+ CAMERA_TYPE_FOUND="true"
+else
+ CAMERA_TYPE_FOUND="false"
+fi
+
+if [[ ${CAMERA_TYPE_FOUND} == "false" ]]; then
+ if [[ ${CAMERA_TYPE} == "ZWO" ]]; then
+ # reset_usb() exits if too many tries
+ reset_usb "looking for a\nZWO camera"
+ set_allsky_status "${ALLSKY_STATUS_SEE_WEBUI}"
+ exit 0 # exit with 0 so the service is restarted
fi
- rm -f "${RESETTING_USB_LOG}" # We found the camera so don't need to reset.
+ set_allsky_status "${ALLSKY_STATUS_SEE_WEBUI}"
+ MSG="${NOT_STARTED_MSG} No connected ${CAMERA_TYPE} cameras found!"
+ IMAGE_MSG="${ERROR_MSG_PREFIX}"
+ IMAGE_MSG+="${NOT_STARTED_MSG}\n"
+ IMAGE_MSG+="\nNo connected ${CAMERA_TYPE}\ncameras found!"
+ doExit "${EXIT_ERROR_STOP}" "Error" \
+ "${IMAGE_MSG}" "${MSG}"
+fi
-else
- MSG="FATAL ERROR: Unknown Camera Type: ${CAMERA_TYPE}."
- echo -e "${RED}${MSG} Stopping.${NC}" >&2
- doExit "${EXIT_NO_CAMERA}" "Error" \
- "${ERROR_MSG_PREFIX}\nUnknown Camera\nType: ${CAMERA_TYPE}" \
- "${NOT_STARTED_MSG} ${MSG}"
+# Make sure the current camera is supported and hasn't changed unexpectedly.
+CAM="${CAMERA_TYPE} ${CAMERA_NUMBER} ${CAMERA_MODEL}" # has TABS
+CCM="$( get_connected_camera_models --full "${CAMERA_TYPE}" )"
+read -r CC_TYPE CC_NUMBER CC_MODEL <<<"${CCM}"
+if ! echo -e "${CCM}" | grep --silent "${CAM}" ; then
+ # Something changed. validate_camera() displays the error message.
+ if ! validate_camera "${CC_TYPE}" "${CC_MODEL}" "${CC_NUMBER}" ; then
+ set_allsky_status "${ALLSKY_STATUS_SEE_WEBUI}"
+ IMAGE_MSG="${ERROR_MSG_PREFIX}"
+ IMAGE_MSG+="The camera changed."
+ IMAGE_MSG+="\nCheck Camera Type\n& Model in the WebUI."
+ doExit "${EXIT_ERROR_STOP}" "Error" "${IMAGE_MSG}"
+ fi
fi
# Make sure the settings file is linked to the camera-specific file.
if ! MSG="$( check_settings_link "${SETTINGS_FILE}" )" ; then
"${ALLSKY_SCRIPTS}/addMessage.sh" "error" "${MSG}"
- echo "ERROR: Settings file (${SETTINGS_FILE}) not linked correctly." >&2
+ echo "ERROR: ${MSG}" >&2
fi
# Make directories that need to exist.
@@ -216,118 +252,123 @@ mkdir "${ALLSKY_ABORTS_DIR}"
sudo chgrp "${WEBSERVER_GROUP}" "${ALLSKY_ABORTS_DIR}"
sudo chmod 775 "${ALLSKY_ABORTS_DIR}"
+rm -f "${ALLSKY_NOTIFICATION_LOG}" # clear out any notificatons from prior runs.
+
# Optionally display a notification image.
-if [[ $USE_NOTIFICATION_IMAGES -eq 1 ]]; then
+if [[ ${USE_NOTIFICATION_IMAGES} == "true" ]]; then
# Can do this in the background to speed up startup.
- "${ALLSKY_SCRIPTS}/copy_notification_image.sh" "StartingUp" 2>&1 &
+ "${ALLSKY_SCRIPTS}/copy_notification_image.sh" --expires 0 "StartingUp" 2>&1 &
fi
: > "${ARGS_FILE}"
-# If the locale isn't in the settings file, try to determine it.
-LOCALE="$(settings .locale)"
-if [[ -z ${LOCALE} ]]; then
- if [[ -n ${LC_ALL} ]]; then
- echo "-Locale=${LC_ALL}" >> "${ARGS_FILE}"
- elif [[ -n ${LANG} ]]; then
- echo "-lOcale=${LANG}" >> "${ARGS_FILE}"
- elif [[ -n ${LANGUAGE} ]]; then
- echo "-loCale=${LANGUAGE}" >> "${ARGS_FILE}"
- fi
+# Only pass settings that are used by the capture program.
+if ! ARGS="$( "${ALLSKY_SCRIPTS}/convertJSON.php" --capture-only )" ; then
+ echo "${ME}: ERROR: convertJSON.php returned: ${ARGS}"
+ set_allsky_status "${ALLSKY_STATUS_ERROR}"
+ exit "${EXIT_ERROR_STOP}"
fi
+# We must pass "-config ${ARGS_FILE}" on the command line and
+# other settings needed at the start of the capture program.
+echo "${ARGS}" |
+ grep -E -i -v "^config=|^debuglevel=^cmd=|^cameramodel|^cameranumber|^locale=" >> "${ARGS_FILE}"
-# We must pass "-config ${ARGS_FILE}" on the command line,
-# and debuglevel we did above, so don't do them again.
-TAB="$( echo -e "\t" )"
-convert_json_to_tabs "${SETTINGS_FILE}" |
- grep -E -i -v "^config${TAB}|^debuglevel${TAB}" |
- sed -e 's/^/-/' -e "s/${TAB}/=/" >> "${ARGS_FILE}"
+# When using a desktop environment a preview of the capture can be displayed.
+# The preview mode does not work if we are started as a service or
+# if the debian distribution has no desktop environment.
+{
+ [[ $1 == "preview" ]] && echo "preview=true"
-# When using a desktop environment a preview of the capture can be displayed in a separate window.
-# The preview mode does not work if we are started as a service or if the debian distribution has no desktop environment.
-[[ $1 == "preview" ]] && echo "-preview=1" >> "${ARGS_FILE}"
+ echo "version=${ALLSKY_VERSION}"
+ echo "save_dir=${CAPTURE_SAVE_DIR}"
-echo "-version=${ALLSKY_VERSION}" >> "${ARGS_FILE}"
-echo "-save_dir=${CAPTURE_SAVE_DIR}" >> "${ARGS_FILE}"
+} >> "${ARGS_FILE}"
-FREQUENCY_FILE="${ALLSKY_TMP}/IMG_UPLOAD_FREQUENCY.txt"
# If the user wants images uploaded only every n times, save that number to a file.
if [[ ${IMG_UPLOAD_FREQUENCY} -ne 1 ]]; then
# Save "1" so we upload the first image.
# saveImage.sh will write ${IMG_UPLOAD_FREQUENCY} to the file as needed.
- echo "1" > "${FREQUENCY_FILE}"
+ echo "1" > "${FREQUENCY_FILE}" # FREQUENCY_FILE is global
else
rm -f "${FREQUENCY_FILE}"
fi
CAPTURE="capture_${CAMERA_TYPE}"
-rm -f "${ALLSKY_NOTIFICATION_LOG}" # clear out any notificatons from prior runs.
-
# Clear up any flow timings
activate_python_venv
python3 "${ALLSKY_SCRIPTS}/flow-runner.py" --cleartimings
deactivate_python_venv
-# Run the main program - this is the main attraction...
-# -cmd needs to come first since the capture_RPi code checks for it first. It's ignored
-# in capture_ZWO.
-# Pass debuglevel on command line so the capture program knows if it should display debug output.
-"${ALLSKY_BIN}/${CAPTURE}" -cmd "${RPi_COMMAND_TO_USE}" -debuglevel "${ALLSKY_DEBUG_LEVEL}" -config "${ARGS_FILE}"
+function catch_signal() { return 0; }
+trap "catch_signal" SIGTERM SIGINT SIGHUP
+
+set_allsky_status "${ALLSKY_STATUS_STARTING}"
+
+# Run the camera-specific capture program - this is the main attraction...
+CAMERA_NUMBER="$( settings ".cameranumber" )"
+CAMERA_NUMBER="${CAMERA_NUMBER:-0}" # default
+"${ALLSKY_BIN}/${CAPTURE}" \
+ -debuglevel "${ALLSKY_DEBUG_LEVEL}" \
+ -cmd "${RPi_COMMAND_TO_USE}" \
+ -cameramodel "${CAMERA_MODEL}" \
+ -cameranumber "${CAMERA_NUMBER}" \
+ -locale "$( settings ".locale" )" \
+ -config "${ARGS_FILE}"
RETCODE=$?
-[[ ${RETCODE} -eq ${EXIT_OK} ]] && doExit "${EXIT_OK}" ""
+if [[ ${RETCODE} -eq ${EXIT_OK} ]]; then
+ [[ ${CAMERA_TYPE} == "ZWO" ]] && rm -f "${RESETTING_USB_LOG}"
+ set_allsky_status "${ALLSKY_STATUS_STOPPED}"
+ doExit "${EXIT_OK}" ""
+fi
if [[ ${RETCODE} -eq ${EXIT_RESTARTING} ]]; then
- if [[ ${ON_TTY} -eq 1 ]]; then
+ if [[ ${ON_TTY} == "true" ]]; then
echo "*** Can restart allsky now. ***"
NOTIFICATION_TYPE="NotRunning"
else
NOTIFICATION_TYPE="Restarting"
fi
+ set_allsky_status "${ALLSKY_STATUS_STOPPED}"
doExit 0 "${NOTIFICATION_TYPE}" # use 0 so the service is restarted
fi
if [[ ${RETCODE} -eq ${EXIT_RESET_USB} ]]; then
- # Reset the USB bus if possible
- if [[ ${UHUBCTL_PATH} != "" ]]; then
- reset_usb " (ASI_ERROR_TIMEOUTs)"
- if [[ ${ON_TTY} -eq 1 ]]; then
- echo "*** USB bus was reset; You can restart allsky now. ***"
- NOTIFICATION_TYPE="NotRunning"
- else
- NOTIFICATION_TYPE="Restarting"
- fi
- if [[ ${USE_NOTIFICATION_IMAGES} -eq 1 ]]; then
- "${ALLSKY_SCRIPTS}/copy_notification_image.sh" "${NOTIFICATION_TYPE}"
- fi
- doExit 0 "" # use 0 so the service is restarted
+ # Reset the USB bus
+ reset_usb " (too many capture errors)"
+ if [[ ${ON_TTY} == "true" ]]; then
+ echo "*** USB bus was reset; You can restart allsky now. ***"
+ NOTIFICATION_TYPE="NotRunning"
else
- # TODO: use ASI_ERROR_TIMEOUT message
- MSG="Non-recoverable ERROR found"
- [[ ${ON_TTY} -eq 1 ]] && echo "*** ${MSG} - ${SEE_LOG_MSG}. ***"
- doExit "${EXIT_ERROR_STOP}" "Error" \
- "${ERROR_MSG_PREFIX}Too many\nASI_ERROR_TIMEOUT\nerrors received!\n${SEE_LOG_MSG}" \
- "${STOPPED_MSG} ${MSG} ${SEE_LOG_MSG}."
+ NOTIFICATION_TYPE="Restarting"
+ fi
+ if [[ ${USE_NOTIFICATION_IMAGES} == "true" ]]; then
+ "${ALLSKY_SCRIPTS}/copy_notification_image.sh" "${NOTIFICATION_TYPE}"
fi
+ set_allsky_status "${ALLSKY_STATUS_ERROR}"
+ doExit 0 "" # use 0 so the service is restarted
fi
# RETCODE -ge ${EXIT_ERROR_STOP} means we should not restart until the user fixes the error.
if [[ ${RETCODE} -ge ${EXIT_ERROR_STOP} ]]; then
echo "***"
- if [[ ${ON_TTY} -eq 1 ]]; then
- echo "*** After fixing, restart ${ME}.sh. ***"
+ if [[ ${ON_TTY} == "true" ]]; then
+ echo "*** After fixing, restart ${ME}. ***"
else
echo "*** After fixing, restart the allsky service. ***"
fi
echo "***"
- doExit "${EXIT_ERROR_STOP}" "Error" # Can't do a custom message since we don't know the problem
+ set_allsky_status "${ALLSKY_STATUS_ERROR}"
+ doExit "${RETCODE}" "Error" # Can't do a custom message since we don't know the problem
fi
# Some other error
-if [[ ${USE_NOTIFICATION_IMAGES} -eq 1 ]]; then
+if [[ ${USE_NOTIFICATION_IMAGES} == "true" ]]; then
# If started by the service, it will restart us once we exit.
+ set_allsky_status "${ALLSKY_STATUS_NOT_RUNNING}"
doExit "${RETCODE}" "NotRunning"
else
+ set_allsky_status "${ALLSKY_STATUS_SEE_WEBUI}"
doExit "${RETCODE}" ""
fi
diff --git a/assets/TestPlan.xlsx b/assets/TestPlan.xlsx
new file mode 100644
index 000000000..53294aaf6
Binary files /dev/null and b/assets/TestPlan.xlsx differ
diff --git a/assets/image.psd b/assets/image.psd
new file mode 100644
index 000000000..4eda6edd2
Binary files /dev/null and b/assets/image.psd differ
diff --git a/config_repo/Makefile b/config_repo/Makefile
index 6d43ec165..2ab73a353 100644
--- a/config_repo/Makefile
+++ b/config_repo/Makefile
@@ -24,7 +24,7 @@ ifeq ($(PKGBUILD),)
endif
-CONFIGFILES := config.sh ftp-settings.sh
+ENVFILE := env.json
UNINSTALLFILES := $(DESTDIR)$(sysconfdir)/logrotate.d/allsky $(DESTDIR)$(sysconfdir)/rsyslog.d/allsky.conf $(DESTDIR)$(sysconfdir)/systemd/system/allsky.service $(DESTDIR)$(sysconfdir)/systemd/system/allskyperiodic.service
%:
@@ -42,7 +42,6 @@ uninstall:
@echo `date +%F\ %R:%S` Complete.
@echo `date +%F\ %R:%S` NOTE: Config files were \-NOT\- removed.
@echo `date +%F\ %R:%S` To remove config files, please run \'sudo make remove_configs\'
-
.PHONY : uninstall
ifeq ($(PKGBUILD),1)
@@ -57,17 +56,20 @@ createDirs:
@if [ ! -e $(DESTDIR)$(sysconfdir)/profile.d ]; then mkdir -p $(DESTDIR)$(sysconfdir)/profile.d; fi
@if [ ! -e $(DESTDIR)$(sysconfdir)/systemd/system ]; then mkdir -p $(DESTDIR)$(sysconfdir)/systemd/system; fi
@if [ ! -e $(DESTDIR)$(sysconfdir)/udev/rules.d ]; then mkdir -p $(DESTDIR)$(sysconfdir)/udev/rules.d; fi
-
.PHONY : createDirs
-$(CONFIGFILES):
+$(ENVFILE):
@if [ ! -e $(DESTDIR)$(sysconfdir)/allsky/$@ ]; then \
echo `date +%F\ %R:%S` Copying default $@; \
- install -m 0644 $@.repo $(DESTDIR)$(sysconfdir)/allsky/$@; \
+ sed -e "s|XX_HOME_XX|$(HOMEDIR)|" $@.repo > env; \
+ install -m 0664 env $(HOMEDIR)/$@; \
+ rm -f env; \
fi
-.PHONY : $(CONFIGFILES)
+# TODO: In PKGBUILD mode, where is the "allsky" directory? $(ENVFILE) needs to go in it.
+# Is $(HOMEDIR) the correct location, or should it be $(DESTDIR)$(sysconfdir)/allsky ?
+.PHONY : $(ENVFILE)
-install: createDirs $(CONFIGFILES)
+install: createDirs $(ENVFILE)
@echo `date +%F\ %R:%S` Setting up udev rules...
@install -D -m 0644 asi.rules $(DESTDIR)$(sysconfdir)/udev/rules.d/
@echo `date +%F\ %R:%S` Setting up logging...
@@ -86,22 +88,14 @@ else # Not in package build mode ######################################
remove_configs:
@echo `date +%F\ %R:%S` Removing config path and files ../config
@rm -rf ../config
-
.PHONY : remove_configs
createDirs:
@echo `date +%F\ %R:%S` Creating directory structures...
@if [ ! -e ../config ]; then mkdir -p ../config; chown $(SUDO_USER):$(SUDO_USER) ../config; fi
-
.PHONY : createDirs
-$(CONFIGFILES):
- @if [ ! -e ../config/$@ ]; then \
- echo `date +%F\ %R:%S` Copying default $@; \
- install -m 0644 -o $(SUDO_USER) -g $(SUDO_USER) $@.repo ../config/$@; \
- fi
-.PHONY : $(CONFIGFILES)
-install: createDirs $(CONFIGFILES)
+install: createDirs
@echo `date +%F\ %R:%S` Setting up udev rules...
@install -D -m 0644 asi.rules $(DESTDIR)$(sysconfdir)/udev/rules.d/
@echo `date +%F\ %R:%S` Setting up logging...
diff --git a/config_repo/RPi_cameraInfo.txt.repo b/config_repo/RPi_cameraInfo.txt.repo
new file mode 100644
index 000000000..a5f93039d
--- /dev/null
+++ b/config_repo/RPi_cameraInfo.txt.repo
@@ -0,0 +1,216 @@
+# TODO: This file should be JSON, but that requires a .cpp library that reads json.
+
+# Each supported camera has three sections:
+# 1. A single line for general camera info per ASI_CAMERA_INFO ASICameraInfoArray[].
+# 2. Multiple lines for ASI_CONTROL_CAPS ControlCapsArray[][] line for libcamera-still / rpicam-still.
+# The last line for this camera begins with "End".
+# 3. Multiple lines for ASI_CONTROL_CAPS ControlCapsArray[][] line for raspistill.
+# The last line for this camera begins with "End".
+# If there's only one line that camera isn't supported with raspistill.
+
+# ASI_CAMERA_INFO ASICameraInfoArray[]:
+# Module (sensor), Module_len, Name, CameraID, MaxHeight, MaxWidth, IsColorCam,
+# BayerPattern, SupportedBins, SupportedVideoFormat, PixelSize, IsCoolerCam,
+# BitDepth, SupportsTemperature, SupportAutoFocus
+
+# "Name" must be such that a filename with ${NAME} in it works, e.g., no "/".
+
+# ASI_CONTROL_CAPS ControlCapsArray[][]:
+# Name, Description, MaxValue, MinValue, DefaultValue, CurrentValue,
+# IsAutoSupported, IsWritable, ControlType
+
+# All data lines are tab-separated and empty lines and lines that begin with # are ignored.
+# The first field in every data entry lists what type of line it is:
+# camera, libcamera, raspistill
+
+camera imx477 0 HQ 0 3040 4056 ASI_TRUE BAYER_RG 1 2 0 ASI_IMG_RGB24 ASI_IMG_END 1.55 ASI_FALSE 12 ASI_TRUE ASI_FALSE
+
+# libcamera
+libcamera Gain Gain 16.0 1.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_GAIN
+libcamera Exposure Exposure Time (us) 694434742 114 10000 NOT_SET ASI_TRUE ASI_TRUE ASI_EXPOSURE
+libcamera WB_R White balance: Red component 32.0 0.0 2.5 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_R
+libcamera WB_B White balance: Blue component 32.0 0.0 2.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_B
+libcamera Flip Flip: 0->None 1->Horiz 2->Vert 3->Both 3 0 0 NOT_SET ASI_FALSE ASI_TRUE ASI_FLIP
+libcamera AutoExpMaxGain Auto exposure maximum gain value 16.0 1.0 16.0 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_GAIN
+libcamera AutoExpMaxExpMS Auto exposure maximum exposure value (ms) 230000 1 60000 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_EXP
+libcamera ExposureCompensation Exposure Compensation 8.0 -8.0 0.0 NOT_SET ASI_FALSE ASI_TRUE EV
+libcamera Saturation Saturation 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SATURATION
+libcamera Contrast Contrast 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE CONTRAST
+libcamera Sharpness Sharpness 16.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SHARPNESS
+libcamera End
+
+raspistill Gain Gain 16.0 1.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_GAIN
+raspistill Exposure Exposure Time (us) 230000000 114 10000 NOT_SET ASI_TRUE ASI_TRUE ASI_EXPOSURE
+raspistill WB_R White balance: Red component 10.0 0.1 2.5 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_R
+raspistill WB_B White balance: Blue component 10.0 0.1 2.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_B
+raspistill Flip Flip: 0->None 1->Horiz 2->Vert 3->Both 3 0 0 NOT_SET ASI_FALSE ASI_TRUE ASI_FLIP
+raspistill AutoExpMaxGain Auto exposure maximum gain value 16.0 1.0 16.0 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_GAIN
+raspistill AutoExpMaxExpMS Auto exposure maximum exposure value (ms) 230000 1 60000 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_EXP
+raspistill ExposureCompensation Exposure Compensation 10 -10 0.0 NOT_SET ASI_FALSE ASI_TRUE EV
+raspistill Saturation Saturation 100 -100 0 NOT_SET ASI_FALSE ASI_TRUE SATURATION
+raspistill Contrast Contrast 100 -100 0 NOT_SET ASI_FALSE ASI_TRUE CONTRAST
+raspistill Sharpness Sharpness 100 -100 0 NOT_SET ASI_FALSE ASI_TRUE SHARPNESS
+raspistill End
+
+
+# There are many versions of the imx708 (_wide, _wide_noir, _noir, etc.) so just
+# check for imx708 (6 characters).
+camera imx708 6 Module 3 0 2592 4608 ASI_TRUE BAYER_RG 1 2 0 ASI_IMG_RGB24 ASI_IMG_END 1.4 ASI_FALSE 10 ASI_TRUE ASI_TRUE
+
+libcamera Gain Gain 16.0 1.122807 1.122807 NOT_SET ASI_TRUE ASI_TRUE ASI_GAIN
+libcamera Exposure Exposure Time (us) 112015553 26 10000 NOT_SET ASI_TRUE ASI_TRUE ASI_EXPOSURE
+libcamera WB_R White balance: Red component 32.0 0.0 2.5 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_R
+libcamera WB_B White balance: Blue component 32.0 0.0 2.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_B
+libcamera Flip Flip: 0->None 1->Horiz 2->Vert 3->Both 3 0 0 NOT_SET ASI_FALSE ASI_TRUE ASI_FLIP
+libcamera AutoExpMaxGain Auto exposure maximum gain value 16.0 1.122807 16.0 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_GAIN
+libcamera AutoExpMaxExpMS Auto exposure maximum exposure value (ms) 112015553 / US_IN_MS 26.0 60000 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_EXP
+libcamera ExposureCompensation Exposure Compensation 8.0 -8.0 0.0 NOT_SET ASI_FALSE ASI_TRUE EV
+libcamera Saturation Saturation 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SATURATION
+libcamera Contrast Contrast 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE CONTRAST
+libcamera Sharpness Sharpness 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SHARPNESS
+libcamera End
+
+raspistill End
+
+
+camera ov5647 0 Version 1 0 1944 2592 ASI_TRUE BAYER_RG 1 2 0 ASI_IMG_RGB24 ASI_IMG_END 1.4 ASI_FALSE 10 ASI_FALSE ASI_FALSE
+
+libcamera Gain Gain 63.9375 1.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_GAIN
+libcamera Exposure Exposure Time (us) 969249 130 9000 NOT_SET ASI_TRUE ASI_TRUE ASI_EXPOSURE
+libcamera WB_R White balance: Red component 32.0 0.0 0.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_R
+libcamera WB_B White balance: Blue component 32.0 0.0 0.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_B
+libcamera Flip Flip: 0->None 1->Horiz 2->Vert 3->Both 3 0 0 NOT_SET ASI_FALSE ASI_TRUE ASI_FLIP
+libcamera AutoExpMaxGain Auto exposure maximum gain value 63.9375 1.0 63.9375 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_GAIN
+libcamera AutoExpMaxExpMS Auto exposure maximum exposure value (ms) 969249 / US_IN_MS 1.0 9000 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_EXP
+libcamera ExposureCompensation Exposure Compensation 8.0 -8.0 0.0 NOT_SET ASI_FALSE ASI_TRUE EV
+libcamera Saturation Saturation 32 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SATURATION
+libcamera Contrast Contrast 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE CONTRAST
+libcamera Sharpness Sharpness 16.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SHARPNESS
+libcamera End
+
+raspistill End
+
+
+camera imx290 0 imx290 60.00 fps 0 1080 1920 ASI_TRUE BAYER_RG 1 2 0 ASI_IMG_RGB24 ASI_IMG_END 2.9 ASI_FALSE 12 ASI_FALSE ASI_FALSE
+
+libcamera Gain Gain 16.0 1.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_GAIN
+libcamera Exposure Exposure Time (us) 200000000 1 10000 NOT_SET ASI_TRUE ASI_TRUE ASI_EXPOSURE
+libcamera WB_R White balance: Red component 10.0 0.1 2.5 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_R
+libcamera WB_B White balance: Blue component 10.0 0.1 2.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_B
+libcamera Flip Flip: 0->None 1->Horiz 2->Vert 3->Both 3 0 0 NOT_SET ASI_FALSE ASI_TRUE ASI_FLIP
+libcamera AutoExpMaxGain Auto exposure maximum gain value 16.0 1.0 16.0 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_GAIN
+libcamera AutoExpMaxExpMS Auto exposure maximum exposure value (ms) 200000 1 60000 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_EXP
+libcamera ExposureCompensation Exposure Compensation 10.0 -10.0 0.0 NOT_SET ASI_FALSE ASI_TRUE EV
+libcamera Saturation Saturation 15.99 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SATURATION
+libcamera Contrast Contrast 15.99 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE CONTRAST
+libcamera Sharpness Sharpness 15.99 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SHARPNESS
+libcamera End
+
+raspistill End
+
+
+camera imx519 0 Arducam 16 MP 0 3496 4656 ASI_TRUE BAYER_RG 1 2 0 ASI_IMG_RGB24 ASI_IMG_END 1.22 ASI_FALSE 10 ASI_FALSE ASI_TRUE
+
+libcamera Gain Gain 16.0 1.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_GAIN
+libcamera Exposure Exposure Time (us) 200000000 1 10000 NOT_SET ASI_TRUE ASI_TRUE ASI_EXPOSURE
+libcamera WB_R White balance: Red component 32.0 0.1 2.5 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_R
+libcamera WB_B White balance: Blue component 32.0 0.1 2.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_B
+libcamera Flip Flip: 0->None 1->Horiz 2->Vert 3->Both 3 0 0 NOT_SET ASI_FALSE ASI_TRUE ASI_FLIP
+libcamera AutoExpMaxGain Auto exposure maximum gain value 16.0 1.0 16.0 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_GAIN
+libcamera AutoExpMaxExpMS Auto exposure maximum exposure value (ms) 200000 1 60000 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_EXP
+libcamera ExposureCompensation Exposure Compensation 10.0 -10.0 0.0 NOT_SET ASI_FALSE ASI_TRUE EV
+libcamera Saturation Saturation 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SATURATION
+libcamera Contrast Contrast 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE CONTRAST
+libcamera Sharpness Sharpness 16.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SHARPNESS
+libcamera End
+
+raspistill End
+
+
+camera arducam_64mp 0 Arducam 64 MP 0 6944 9152 ASI_TRUE BAYER_RG 1 2 0 ASI_IMG_RGB24 ASI_IMG_END 0.8 ASI_FALSE 10 ASI_FALSE ASI_TRUE
+
+libcamera Exposure Exposure Time (us) 200000000 1 10000 NOT_SET ASI_TRUE ASI_TRUE ASI_EXPOSURE
+libcamera WB_R White balance: Red component 10.0 0.1 2.5 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_R
+libcamera WB_B White balance: Blue component 10.0 0.1 2.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_B
+libcamera Flip Flip: 0->None 1->Horiz 2->Vert 3->Both 3 0 0 NOT_SET ASI_FALSE ASI_TRUE ASI_FLIP
+libcamera AutoExpMaxGain Auto exposure maximum gain value 16.0 1.0 16.0 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_GAIN
+libcamera AutoExpMaxExpMS Auto exposure maximum exposure value (ms) 200000 1 60000 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_EXP
+libcamera ExposureCompensation Exposure Compensation 10.0 -10.0 0.0 NOT_SET ASI_FALSE ASI_TRUE EV
+libcamera Saturation Saturation 15.99 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SATURATION
+libcamera Contrast Contrast 15.99 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE CONTRAST
+libcamera Sharpness Sharpness 15.99 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SHARPNESS
+libcamera End
+
+raspistill End
+
+
+camera arducam-pivariety 0 Arducam 462 0 1080 1920 ASI_TRUE BAYER_RG 1 2 0 ASI_IMG_RGB24 ASI_IMG_END 2.9 ASI_FALSE 10 ASI_FALSE ASI_TRUE
+
+libcamera Gain Gain 200.0 1.0 1.33 NOT_SET ASI_TRUE ASI_TRUE ASI_GAIN
+libcamera Exposure Exposure Time (us) 15500000 14 10000000 NOT_SET ASI_TRUE ASI_TRUE ASI_EXPOSURE
+libcamera WB_R White balance: Red component 32.0 0.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_R
+libcamera WB_B White balance: Blue component 32.0 0.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_B
+libcamera Flip Flip: 0->None 1->Horiz 2->Vert 3->Both 3 0 0 NOT_SET ASI_FALSE ASI_TRUE ASI_FLIP
+libcamera AutoExpMaxGain Auto exposure maximum gain value 200.0 1.0 200.0 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_GAIN
+libcamera AutoExpMaxExpMS Auto exposure maximum exposure value (ms) 15.5000 1 15.5000 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_EXP
+libcamera ExposureCompensation Exposure Compensation 8.0 -8.0 0.0 NOT_SET ASI_FALSE ASI_TRUE EV
+libcamera Saturation Saturation 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SATURATION
+libcamera Contrast Contrast 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE CONTRAST
+libcamera Sharpness Sharpness 16.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SHARPNESS
+libcamera End
+
+raspistill End
+
+
+camera imx219 0 Waveshare imx219-d160 0 2464 3280 ASI_TRUE BAYER_RG 1 2 0 ASI_IMG_RGB24 ASI_IMG_END 1.12 ASI_FALSE 10 ASI_FALSE ASI_FALSE
+
+libcamera Gain Gain 10.666667 1.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_GAIN
+libcamera Exposure Exposure Time (us) 11767556.0 75 10000000 NOT_SET ASI_TRUE ASI_TRUE ASI_EXPOSURE
+libcamera WB_R White balance: Red component 32.0 0.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_R
+libcamera WB_B White balance: Blue component 32.0 0.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_B
+libcamera Flip Flip: 0->None 1->Horiz 2->Vert 3->Both 3 0 0 NOT_SET ASI_FALSE ASI_TRUE ASI_FLIP
+libcamera AutoExpMaxGain Auto exposure maximum gain value 10.666667 1.0 10.666667 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_GAIN
+libcamera AutoExpMaxExpMS Auto exposure maximum exposure value (ms) 11767.556000 1 11767.556000 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_EXP
+libcamera ExposureCompensation Exposure Compensation 8.0 -8.0 0.0 NOT_SET ASI_FALSE ASI_TRUE EV
+libcamera Saturation Saturation 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SATURATION
+libcamera Contrast Contrast 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE CONTRAST
+libcamera Sharpness Sharpness 16.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SHARPNESS
+libcamera End
+
+raspistill End
+
+
+camera ov64a40 0 Arducam 64MP Owlsight 0 6944 9248 ASI_TRUE BAYER_BG 1 2 0 ASI_IMG_RGB24 ASI_IMG_END 1.008 ASI_FALSE 10 ASI_FALSE ASI_TRUE
+
+libcamera Gain Gain 15.992188 1.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_GAIN
+libcamera Exposure Exposure Time (us) 608453664 580 10000000 NOT_SET ASI_TRUE ASI_TRUE ASI_EXPOSURE
+libcamera WB_R White balance: Red component 32.0 0.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_R
+libcamera WB_B White balance: Blue component 32.0 0.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_B
+libcamera Flip Flip: 0->None 1->Horiz 2->Vert 3->Both 3 0 0 NOT_SET ASI_FALSE ASI_TRUE ASI_FLIP
+libcamera AutoExpMaxGain Auto exposure maximum gain value 15.992188 1.0 1.0 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_GAIN
+libcamera AutoExpMaxExpMS Auto exposure maximum exposure value (ms) 608454 580 60000 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_EXP
+libcamera ExposureCompensation Exposure Compensation 8.0 -8.0 0.0 NOT_SET ASI_FALSE ASI_TRUE EV
+libcamera Saturation Saturation 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SATURATION
+libcamera Contrast Contrast 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE CONTRAST
+libcamera Sharpness Sharpness 16.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SHARPNESS
+libcamera End
+
+raspistill End
+
+
+camera imx283 0 OneInchEye IMX283 0 3648 5472 ASI_TRUE BAYER_RG 1 2 0 ASI_IMG_RGB24 ASI_IMG_END 2.4 ASI_FALSE 12 ASI_FALSE ASI_FALSE
+
+libcamera Gain Gain 22.505495 1.0 4.0 NOT_SET ASI_TRUE ASI_TRUE ASI_GAIN
+libcamera Exposure Exposure Time (us) 129373756 58 10000000 NOT_SET ASI_TRUE ASI_TRUE ASI_EXPOSURE
+libcamera WB_R White balance: Red component 32.0 0.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_R
+libcamera WB_B White balance: Blue component 32.0 0.0 1.0 NOT_SET ASI_TRUE ASI_TRUE ASI_WB_B
+libcamera Flip Flip: 0->None 1->Horiz 2->Vert 3->Both 3 0 0 NOT_SET ASI_FALSE ASI_TRUE ASI_FLIP
+libcamera AutoExpMaxGain Auto exposure maximum gain value 22.505495 1.0 4.0 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_GAIN
+libcamera AutoExpMaxExpMS Auto exposure maximum exposure value (ms) 129374 0.058 60000 NOT_SET ASI_FALSE ASI_TRUE ASI_AUTO_MAX_EXP
+libcamera ExposureCompensation Exposure Compensation 8.0 -8.0 0.0 NOT_SET ASI_FALSE ASI_TRUE EV
+libcamera Saturation Saturation 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SATURATION
+libcamera Contrast Contrast 32.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE CONTRAST
+libcamera Sharpness Sharpness 16.0 0.0 1.0 NOT_SET ASI_FALSE ASI_TRUE SHARPNESS
+libcamera End
+
+raspistill End
diff --git a/config_repo/allskyDefines.inc.repo b/config_repo/allskyDefines.inc.repo
index 5e26dfb48..2c1978ed9 100644
--- a/config_repo/allskyDefines.inc.repo
+++ b/config_repo/allskyDefines.inc.repo
@@ -1,12 +1,14 @@
";
- echo "";
+ echo "
";
echo "Please run the following from the 'allsky' directory before using the WebUI:";
- echo "";
- echo " ./install.sh --update";
+ echo "
";
+ echo " ./install.sh --fix";
echo "
";
- exit;
+ exit(1);
}
-
?>
diff --git a/config_repo/config.sh.repo b/config_repo/config.sh.repo
deleted file mode 100644
index 3af41ed81..000000000
--- a/config_repo/config.sh.repo
+++ /dev/null
@@ -1,199 +0,0 @@
-#!/bin/bash
-
-# X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*XX*X*X*X*X*X*X
-
-# For details on these settings, click on the "Allsky Documentation" link in the WebUI,
-# then click on the "Settings -> Allsky" link,
-# then, in the "Editor WebUI Page" section, open the "config.sh" sub-section.
-
-# X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*XX*X*X*X*X*X*X
-
-
-########## Images
-# Set to "true" to upload the current image to your website.
-IMG_UPLOAD="false"
-
-# Upload the image file as "image-YYYYMMDDHHMMSS.jpg" (true) or "image.jpg" (false).
-IMG_UPLOAD_ORIGINAL_NAME="false"
-
-# If IMG_UPLOAD is "true", upload images every IMG_UPLOAD_FREQUENCY frames, e.g., every 5 frames.
-# 1 uploades every frame.
-IMG_UPLOAD_FREQUENCY=1
-
-# Resize images before cropping, stretching, and saving.
-IMG_RESIZE="false"
-IMG_WIDTH=2028
-IMG_HEIGHT=1520
-
-# Crop images before stretching and saving.
-CROP_IMAGE="false"
-CROP_WIDTH=640
-CROP_HEIGHT=480
-CROP_OFFSET_X=0
-CROP_OFFSET_Y=0
-
-# Auto stretch images saved at night. The numbers below are good defaults.
-AUTO_STRETCH="false"
-AUTO_STRETCH_AMOUNT=10
-AUTO_STRETCH_MID_POINT="10%"
-
-# Resize uploaded images. Change the size to fit your sensor.
-RESIZE_UPLOADS="false"
-RESIZE_UPLOADS_WIDTH=962
-RESIZE_UPLOADS_HEIGHT=720
-
-# Create thumbnails of images. If you never look at them, consider changing this to "false".
-IMG_CREATE_THUMBNAILS="true"
-
-# Remove corrupt or too dim/bright images.
-REMOVE_BAD_IMAGES="true"
-REMOVE_BAD_IMAGES_THRESHOLD_LOW=1
-REMOVE_BAD_IMAGES_THRESHOLD_HIGH=90
-
-
-########## Timelapse
-# Set to "true" to generate a timelapse video at the end of each night.
-TIMELAPSE="true"
-
-# Set the resolution in pixels of the timelapse video.
-TIMELAPSEWIDTH=0
-TIMELAPSEHEIGHT=0
-
-# Bitrate of the timelapse video.
-TIMELAPSE_BITRATE="5000k"
-
-# Timelapse video Frames Per Second.
-FPS=25
-
-# Encoder for timelapse video.
-VCODEC="libx264"
-
-# Pixel format.
-PIX_FMT="yuv420p"
-
-# Amount of information displayed while creating a timelapse video.
-FFLOG="warning"
-
-# Set to "true" to keep the list of files used in creating the timelapse video.
-KEEP_SEQUENCE="false"
-
-# Any additional timelapse parameters. Run "ffmpeg -?" to see the options.
-TIMELAPSE_EXTRA_PARAMETERS=""
-
-# Set to "true" to upload the timelapse video to your website at the end of each night.
-UPLOAD_VIDEO="false"
-
-# Set to "true" to upload the timelapse video's thumbnail to your website at the end of each night.
-TIMELAPSE_UPLOAD_THUMBNAIL="true"
-
-###### Mini-timelapse
-# The number of images you want in the mini-timelapse. 0 disables mini-timelapse creation.
-TIMELAPSE_MINI_IMAGES=0
-
-# Should a mini-timelapse be created even if ${TIMELAPSE_MINI_IMAGES} haven't been captured yet?
-TIMELAPSE_MINI_FORCE_CREATION="false"
-
-# After how many images should the mini-timelapse be made?
-# If you have a slow Pi or short delays between images,
-# set this to a higher number (i.e., not as often).
-TIMELAPSE_MINI_FREQUENCY=5
-
-# The remaining TIMELAPSE_MINI_* variables serve the same function as the daily timelapse.
-TIMELAPSE_MINI_UPLOAD_VIDEO="true"
-TIMELAPSE_MINI_UPLOAD_THUMBNAIL="true"
-TIMELAPSE_MINI_FPS=5
-TIMELAPSE_MINI_BITRATE="2000k"
-TIMELAPSE_MINI_WIDTH=1014
-TIMELAPSE_MINI_HEIGHT=760
-
-
-########## Keogram
-# Set to "true" to generate a keogram at the end of each night.
-KEOGRAM="true"
-
-# Additional Keogram parameters.
-KEOGRAM_EXTRA_PARAMETERS="--font-size 1.0 --font-line 1 --font-color '255 255 255'"
-
-# Set to "true" to upload the keogram image to your website at the end of each night.
-UPLOAD_KEOGRAM="false"
-
-
-########## Startrails
-# Set to "true" to generate a startrails image of each night.
-STARTRAILS="true"
-
-# Images with a brightness higher than this threshold will be skipped for
-# startrails image generation.
-BRIGHTNESS_THRESHOLD=0.1
-
-# Any additional startrails parameters.
-STARTRAILS_EXTRA_PARAMETERS=""
-
-# Set to "true" to upload the startrails image to your website at the end of each night.
-UPLOAD_STARTRAILS="false"
-
-
-########## Other
-# Size of thumbnails.
-THUMBNAIL_SIZE_X=100
-THUMBNAIL_SIZE_Y=75
-
-# Set this value to the number of days images plus videos you want to keep.
-# Set to 0 to keep ALL days.
-DAYS_TO_KEEP=14
-
-# Same as DAYS_TO_KEEP, but for the Allsky Website, if installed.
-WEB_DAYS_TO_KEEP=0
-
-# See the documentation for a description of this setting.
-WEBUI_DATA_FILES=""
-
-# See the documentation for a description of these settings.
-UHUBCTL_PATH=""
-UHUBCTL_PORT=2
-
-
-# ================ DO NOT CHANGE ANYTHING BELOW THIS LINE ================
-ME2="$(basename "${BASH_SOURCE[0]}")"
-
-# CAMERA_TYPE is updated during installation
-CAMERA_TYPE=""
-if [ "${CAMERA_TYPE}" = "" ]; then
- echo -e "${RED}${ME2}: ERROR: Please set 'Camera Type' in the WebUI.${NC}"
- sudo systemctl stop allsky > /dev/null 2>&1
- exit ${EXIT_ERROR_STOP}
-fi
-
-IMG_DIR="current/tmp"
-CAPTURE_SAVE_DIR="${ALLSKY_TMP}"
-
-# Don't try to upload a mini-timelapse if they aren't using them.
-if [[ ${TIMELAPSE_MINI_IMAGES} -eq 0 ]]; then
- TIMELAPSE_MINI_UPLOAD_VIDEO="false"
- TIMELAPSE_MINI_UPLOAD_THUMBNAIL="false"
-fi
-
-if [[ -z ${SETTINGS_FILE} ]]; then # SETTINGS_FILE is defined in variables.sh
- echo -e "${RED}${ME2}: ERROR: SETTINGS_FILE variable not defined!${NC}"
- echo -e "${RED}Make sure 'variables.sh' is source'd in!${NC}"
- return 1
-fi
-if [[ ! -f ${SETTINGS_FILE} ]]; then
- echo -e "${RED}${ME2}: ERROR: Settings file '${SETTINGS_FILE}' not found!${NC}"
- sudo systemctl stop allsky > /dev/null 2>&1
- exit ${EXIT_ERROR_STOP}
-fi
-
-# Get the name of the file the websites will look for, and split into name and extension.
-FULL_FILENAME="$(settings ".filename")"
-EXTENSION="${FULL_FILENAME##*.}"
-FILENAME="${FULL_FILENAME%.*}"
-
-CAMERA_MODEL="$(settings '.cameraModel')"
-
-# So scripts can conditionally output messages.
-ALLSKY_DEBUG_LEVEL="$(settings '.debuglevel')"
-# ALLSKY_VERSION is updated during installation
-ALLSKY_VERSION="XX_ALLSKY_VERSION_XX"
-
-CONFIG_SH_VERSION=1
diff --git a/config_repo/configuration.json.repo b/config_repo/configuration.json.repo
index 71b01a050..fb2cd2c1b 100644
--- a/config_repo/configuration.json.repo
+++ b/config_repo/configuration.json.repo
@@ -1,233 +1,225 @@
{
- "comment": "See https://github.com/AllskyTeam/allsky/wiki/allsky-website-Settings for a description of these settings.",
- "config": {
- "comment": "These settings impact what appears in the popout and the constellation overlay",
- "imageName": "/current/tmp/image.jpg",
- "location": "XX_NEED_TO_UPDATE_XX",
- "latitude": "XX_NEED_TO_UPDATE_XX",
- "longitude": "XX_NEED_TO_UPDATE_XX",
- "camera": "XX_NEED_TO_UPDATE_XX",
- "lens": "XX_NEED_TO_UPDATE_XX",
- "computer": "XX_NEED_TO_UPDATE_XX",
- "owner": "XX_NEED_TO_UPDATE_XX",
- "auroraForecast": false,
- "auroraMap": "XX_NEED_TO_UPDATE_XX",
- "intervalSeconds": 5,
- "showOverlayAtStartup": false,
- "overlayWidth": 875,
- "overlayHeight": 875,
- "overlayOffsetLeft": 0,
- "overlayOffsetTop": 0,
- "az": 0,
- "imageWidth": 900,
- "opacity": 0.5,
- "objectsComment": "If you want the Messier objects on the overlay, remove the 'XXX_' below.",
- "XXX_objects": "virtualsky/messier.json",
- "meridian": false,
- "ecliptic": false,
- "fontsize": "14px",
- "cardinalpoints": true,
- "cardinalpoints_fontsize": "18px",
- "showstarlabels": true,
- "projection": "fisheye",
- "constellations": true,
- "constellationwidth": 0.75,
- "constellationlabels": false,
- "constellationboundaries": false,
- "constellationboundarieswidth": 0.75,
- "gridlines_eq": false,
- "gridlineswidth": 0.75,
- "showgalaxy": false,
- "galaxywidth": 0.75,
- "mouse": false,
- "keyboard": true,
- "showdate": false,
- "showposition": false,
- "sky_gradient": false,
- "gradient": false,
- "transparent": true,
- "lang": "en",
- "colours" : {
- "comment": "See the Wiki for how to change colors on the constellation overlay.",
- "normal" : {
- "XXX_cardinal": "rgba(0,255,0,1)"
- },
- "negative" : {
- "XXX_cardinal": "rgba(255,255,255,1)"
- }
- },
- "live": true,
- "id": "starmap",
- "AllskyVersion" : "XX_ALLSKY_VERSION_XX",
- "AllskyWebsiteVersion" : "XX_ALLSKY_WEBSITE_VERSION_XX"
- },
- "homePage": {
- "comment": "These settings impact the look and feel of the Website home page.",
- "onPi": true,
- "title": "XX_NEED_TO_UPDATE_XX",
- "og_description": "XX_NEED_TO_UPDATE_XX",
- "backgroundImage": {
- "url": "",
- "style": ""
- },
- "loadingImage": "loading.jpg",
- "imageBorder": false,
- "includeGoogleAnalytics": false,
- "includeLinkToMakeOwn": true,
- "personalLink": {
- "prelink": "",
- "message": "",
- "url": "",
- "title": "",
- "style": ""
- },
- "og_type": "website",
- "og_url": "http://www.thomasjacquin/allsky/",
- "og_image": "image.jpg",
- "favicon": "allsky-favicon.png",
- "leftSidebar": [
- {
- "comment": "Once you have modified the settings so the overlay fits, set 'display' to true.",
- "display": false,
- "title": "Show constellation overlay",
- "icon": "fa fa-2x fa-fw allsky-constellation",
- "other": "id='overlayBtn' ng-click='toggleOverlay()' ng-class=\"{'active': showOverlay}\"",
- "style": ""
- },
- {
- "display": true,
- "url": "videos",
- "title": "Archived Timelapes",
- "icon": "fa fa-2x fa-fw fa-play-circle",
- "style": ""
- },
- {
- "display": false,
- "url": "/current/tmp/mini-timelapse.mp4",
- "title": "Mini-timelapse",
- "icon": "fa fa-2x fa-fw icon-mini-timelapse",
- "style": ""
- },
- {
- "display": true,
- "url": "keograms",
- "title": "Archived Keograms",
- "icon": "fa fa-2x fa-fw fa-barcode",
- "style": ""
- },
- {
- "display": true,
- "url": "startrails",
- "title": "Archived Startrails",
- "icon": "fa fa-2x fa-fw fa-star",
- "style": ""
- },
- {
- "display": true,
- "variable": "imageName",
- "title": "Full-sized image",
- "icon": "fa fa-2x fa-fw fa-expand-arrows-alt",
- "style": ""
- },
- {
- "display": true,
- "title": "Display information about the camera and other settings",
- "icon": "fa fa-2x fa-fw fa-info-circle",
- "other": "ng-click='toggleInfo()' ng-class=\"{'active': showInfo}\"",
- "style": ""
- },
- {
- "display": false,
- "comment": "Add leftSidebar items above."
- }
- ],
- "leftSidebarStyle": "",
- "popoutIcons": [
- {
- "display": true,
- "label": "Location",
- "icon": "fa fa-fw fa-map-marker-alt",
- "variable": "location",
- "value": "",
- "style": ""
- },
- {
- "display": true,
- "label": "Latitude",
- "icon": "fa fa-fw fa-map-marker",
- "variable": "s_latitude",
- "value": "",
- "style": ""
- },
- {
- "display": true,
- "label": "Longitude",
- "icon": "fa fa-fw fa-map-marker",
- "variable": "s_longitude",
- "value": "",
- "style": ""
- },
- {
- "display": true,
- "label": "Camera",
- "icon": "fa fa-fw fa-camera-retro",
- "variable": "camera",
- "value": "",
- "style": ""
- },
- {
- "display": true,
- "label": "Lens",
- "icon": "fa fa-fw fa-dot-circle",
- "variable": "lens",
- "value": "",
- "style": ""
- },
- {
- "display": true,
- "label": "Computer",
- "icon": "fa fa-fw fa-microchip",
- "variable": "computer",
- "value": "",
- "style": ""
- },
- {
- "display": true,
- "label": "Owner",
- "icon": "fa fa-fw fa-user",
- "variable": "owner",
- "value": "",
- "style": ""
- },
- {
- "display": false,
- "label": "Allsky Settings",
- "icon": "fa fa-fw fa-cogs",
- "variable": "",
- "value": "Click to view",
- "style": ""
- },
- {
- "display": true,
- "label": "Allsky Version",
- "icon": "fa fa-fw fa-file-alt",
- "variable": "AllskyVersion",
- "value": "",
- "style": ""
- },
- {
- "display": true,
- "label": "Website Version",
- "icon": "fa fa-fw fa-file-alt",
- "variable": "AllskyWebsiteVersion",
- "value": "",
- "style": ""
- },
- {
- "comment": "Add popout items above.",
- "display": false
- }
- ]
- },
- "ConfigVersion" : "1"
+ "comment": "See the 'Settings -> Allsky Website' documentation page for a description of these settings.",
+ "config": {
+ "comment": "These settings impact what appears in the popout and the constellation overlay",
+ "imageName": "/current/tmp/image.jpg",
+ "location": "XX_NEED_TO_UPDATE_XX",
+ "latitude": "XX_NEED_TO_UPDATE_XX",
+ "longitude": "XX_NEED_TO_UPDATE_XX",
+ "camera": "XX_NEED_TO_UPDATE_XX",
+ "lens": "XX_NEED_TO_UPDATE_XX",
+ "computer": "XX_NEED_TO_UPDATE_XX",
+ "owner": "XX_NEED_TO_UPDATE_XX",
+ "auroraForecast": false,
+ "auroraMap": "XX_NEED_TO_UPDATE_XX",
+ "intervalSeconds": 5,
+ "showOverlayAtStartup": false,
+ "overlayWidth": 875,
+ "overlayHeight": 875,
+ "overlayOffsetLeft": 0,
+ "overlayOffsetTop": 0,
+ "az": 0,
+ "imageWidth": 900,
+ "opacity": 0.5,
+ "objectsComment": "If you want the Messier objects on the overlay remove the 'XXX_' below.",
+ "XXX_objects": "virtualsky/messier.json",
+ "meridian": false,
+ "ecliptic": false,
+ "fontsize": "14px",
+ "cardinalpoints": true,
+ "cardinalpoints_fontsize": "18px",
+ "showstarlabels": true,
+ "projection": "fisheye",
+ "constellations": true,
+ "constellationwidth": 0.75,
+ "constellationlabels": false,
+ "constellationboundaries": false,
+ "constellationboundarieswidth": 0.75,
+ "gridlines_eq": false,
+ "gridlineswidth": 0.75,
+ "showgalaxy": false,
+ "galaxywidth": 0.75,
+ "mouse": false,
+ "keyboard": true,
+ "showdate": false,
+ "showposition": false,
+ "sky_gradient": false,
+ "gradient": false,
+ "transparent": true,
+ "lang": "en",
+ "colours": {
+ "comment": "See the Wiki for how to change colors on the constellation overlay.",
+ "normal": {
+ "XXX_cardinal": "rgba(0,255,0,1)"
+ },
+ "negative": {
+ "XXX_cardinal": "rgba(255,255,255,1)"
+ }
+ },
+ "live": true,
+ "id": "starmap",
+ "AllskyVersion": "XX_ALLSKY_VERSION_XX"
+ },
+ "homePage": {
+ "comment": "These settings impact the look and feel of the Website home page.",
+ "title": "XX_NEED_TO_UPDATE_XX",
+ "og_description": "XX_NEED_TO_UPDATE_XX",
+ "backgroundImage": {
+ "url": "",
+ "style": ""
+ },
+ "loadingImage": "loading.jpg",
+ "imageBorder": false,
+ "includeGoogleAnalytics": false,
+ "includeLinkToMakeOwn": true,
+ "personalLink": {
+ "prelink": "",
+ "message": "",
+ "url": "",
+ "title": "",
+ "style": ""
+ },
+ "og_type": "website",
+ "og_url": "https://github.com/AllskyTeam/allsky/",
+ "og_image": "image.jpg",
+ "favicon": "allsky-favicon.png",
+ "thumbnailsizex": 100,
+ "thumbnailsizey": 75,
+ "thumbnailsortorder": "ascending",
+ "leftSidebar": [
+ {
+ "comment": "Once you have modified the settings so the overlay fits, set 'display' to true.",
+ "display": false,
+ "title": "Show constellation overlay",
+ "icon": "fa fa-2x fa-fw allsky-constellation",
+ "other": "id='overlayBtn' ng-click='toggleOverlay()' ng-class=\"{'active': showOverlay}\"",
+ "style": ""
+ },
+ {
+ "display": true,
+ "url": "videos/",
+ "title": "Archived Timelapes",
+ "icon": "fa fa-2x fa-fw fa-play-circle",
+ "style": ""
+ },
+ {
+ "display": false,
+ "url": "/current/tmp/mini-timelapse.mp4",
+ "title": "Mini-timelapse",
+ "icon": "fa fa-2x fa-fw icon-mini-timelapse",
+ "style": ""
+ },
+ {
+ "display": true,
+ "url": "keograms/",
+ "title": "Archived Keograms",
+ "icon": "fa fa-2x fa-fw fa-barcode",
+ "style": ""
+ },
+ {
+ "display": true,
+ "url": "startrails/",
+ "title": "Archived Startrails",
+ "icon": "fa fa-2x fa-fw fa-star",
+ "style": ""
+ },
+ {
+ "display": true,
+ "variable": "imageName",
+ "title": "Full-sized image",
+ "icon": "fa fa-2x fa-fw fa-expand-arrows-alt",
+ "style": ""
+ },
+ {
+ "display": true,
+ "title": "Display information about the camera and other settings",
+ "icon": "fa fa-2x fa-fw fa-info-circle",
+ "other": "ng-click='toggleInfo()' ng-class=\"{'active': showInfo}\"",
+ "style": ""
+ },
+ {
+ "display": false,
+ "comment": "Add leftSidebar items above."
+ }
+ ],
+ "leftSidebarStyle": "",
+ "popoutIcons": [
+ {
+ "display": true,
+ "label": "Location",
+ "icon": "fa fa-fw fa-map-marker-alt",
+ "variable": "location",
+ "value": "",
+ "style": ""
+ },
+ {
+ "display": true,
+ "label": "Latitude",
+ "icon": "fa fa-fw fa-map-marker",
+ "variable": "s_latitude",
+ "value": "",
+ "style": ""
+ },
+ {
+ "display": true,
+ "label": "Longitude",
+ "icon": "fa fa-fw fa-map-marker",
+ "variable": "s_longitude",
+ "value": "",
+ "style": ""
+ },
+ {
+ "display": true,
+ "label": "Camera",
+ "icon": "fa fa-fw fa-camera-retro",
+ "variable": "camera",
+ "value": "",
+ "style": ""
+ },
+ {
+ "display": true,
+ "label": "Lens",
+ "icon": "fa fa-fw fa-dot-circle",
+ "variable": "lens",
+ "value": "",
+ "style": ""
+ },
+ {
+ "display": true,
+ "label": "Computer",
+ "icon": "fa fa-fw fa-microchip",
+ "variable": "computer",
+ "value": "",
+ "style": ""
+ },
+ {
+ "display": true,
+ "label": "Owner",
+ "icon": "fa fa-fw fa-user",
+ "variable": "owner",
+ "value": "",
+ "style": ""
+ },
+ {
+ "display": false,
+ "label": "Allsky Settings",
+ "icon": "fa fa-fw fa-cogs",
+ "variable": "",
+ "value": "Click to view",
+ "style": ""
+ },
+ {
+ "display": true,
+ "label": "Allsky Version",
+ "icon": "fa fa-fw fa-file-alt",
+ "variable": "AllskyVersion",
+ "value": "",
+ "style": ""
+ },
+ {
+ "comment": "Add popout items above."
+ }
+ ]
+ },
+ "ConfigVersion": "2"
}
diff --git a/config_repo/env.json.repo b/config_repo/env.json.repo
new file mode 100644
index 000000000..45185f703
--- /dev/null
+++ b/config_repo/env.json.repo
@@ -0,0 +1,25 @@
+{
+ "WARNING" : "Do NOT edit this file manually. Use the WebUI's 'Allsky Settings' page.",
+ "REMOTEWEBSITE_HOST" : "",
+ "REMOTEWEBSITE_PORT" : "",
+ "REMOTEWEBSITE_USER" : "",
+ "REMOTEWEBSITE_PASSWORD" : "",
+ "REMOTEWEBSITE_LFTP_COMMANDS" : "",
+ "REMOTEWEBSITE_SSH_KEY_FILE" : "",
+ "REMOTEWEBSITE_AWS_CLI_DIR" : "",
+ "REMOTEWEBSITE_S3_BUCKET" : "allskybucket",
+ "REMOTEWEBSITE_S3_ACL" : "private",
+ "REMOTEWEBSITE_GCS_BUCKET" : "allskybucket",
+ "REMOTEWEBSITE_GCS_ACL" : "private",
+ "REMOTESERVER_HOST" : "",
+ "REMOTESERVER_PORT" : "",
+ "REMOTESERVER_USER" : "",
+ "REMOTESERVER_PASSWORD" : "",
+ "REMOTESERVER_LFTP_COMMANDS" : "",
+ "REMOTESERVER_SSH_KEY_FILE" : "",
+ "REMOTESERVER_AWS_CLI_DIR" : "",
+ "REMOTESERVER_S3_BUCKET" : "allskybucket",
+ "REMOTESERVER_S3_ACL" : "private",
+ "REMOTESERVER_GCS_BUCKET" : "allskybucket",
+ "REMOTESERVER_GCS_ACL" : "private"
+}
diff --git a/config_repo/ftp-settings.sh.repo b/config_repo/ftp-settings.sh.repo
deleted file mode 100644
index 89c91ebe3..000000000
--- a/config_repo/ftp-settings.sh.repo
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/bin/bash
-
-# X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*XX*X*X*X*X*X*X
-
-# For details on these settings, click on the "Allsky Documentation" link in the WebUI,
-# then click on the "Settings -> Allsky" link,
-# then, in the "Editor WebUI Page" section, open the "ftp-settings.sh" sub-section.
-
-# X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*XX*X*X*X*X*X*X
-
-
-
- # How will files be uploaded?
-PROTOCOL=""
-
- # The directory where the current image should be copied to.
-IMAGE_DIR=""
-WEB_IMAGE_DIR=""
-
- # The directory where the timelapse video should be uploaded to.
-VIDEOS_DIR=""
-VIDEOS_DESTINATION_NAME=""
-WEB_VIDEOS_DIR=""
-
- # The directory where the keogram image should be copied to.
-KEOGRAM_DIR=""
-KEOGRAM_DESTINATION_NAME=""
-WEB_KEOGRAM_DIR=""
-
- # The directory where the startrails image should be copied to.
-STARTRAILS_DIR=""
-STARTRAILS_DESTINATION_NAME=""
-WEB_STARTRAILS_DIR=""
-
-
-############### ftp, ftps, sftp, and scp PROTOCOLS only:
- # Name of the remote server.
-REMOTE_HOST=""
-
- # Optionally enter the port required by your server.
-REMOTE_PORT=""
-
-
-############### ftp, ftps, and sftp PROTOCOLS only. REMOTE_USER is also used by the scp PROTOCOL:
- # The username of the login on the remote server.
-REMOTE_USER=""
-
- # The password of the login on your FTP server. Does not apply to PROTOCOL=scp.
-REMOTE_PASSWORD=""
-
- # If you need special commands executed when connecting to the FTP server enter them here.
-LFTP_COMMANDS=""
-
-
-############### scp PROTOCOL only:
- # The path to the SSH key.
-SSH_KEY_FILE=""
-
-
-############### S3 PROTOCOL only:
- # AWS CLI directory where the AWS CLI tools are installed.
-AWS_CLI_DIR="/home/pi/.local/bin"
-
- # Name of S3 Bucket where the files will be uploaded.
-S3_BUCKET="allskybucket"
-
- # S3 Access Control List (ACL).
-S3_ACL="private"
-
-
-############### GCS PROTOCOL only:
- # Name of the GCS bucket where the files are uploaded.
-GCS_BUCKET="allskybucket"
-
- # GCS Access Control List (ACL).
-GCS_ACL="private"
-
-
-#### DO NOT CHANGE THE NEXT LINE
-FTP_SH_VERSION=1
diff --git a/config_repo/lighttpd.conf.repo b/config_repo/lighttpd.conf.repo
index 1891d27ac..79947638e 100644
--- a/config_repo/lighttpd.conf.repo
+++ b/config_repo/lighttpd.conf.repo
@@ -4,15 +4,14 @@ server.document-root = "XX_ALLSKY_WEBUI_XX"
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
server.errorlog = "/var/log/lighttpd/error.log"
server.pid-file = "/var/run/lighttpd.pid"
-#server.username = "www-data"
-#server.groupname = "www-data"
+server.username = "XX_WEBSERVER_OWNER_XX"
+server.groupname = "XX_WEBSERVER_GROUP_XX"
server.port = 80
server.tag = "Allsky"
dir-listing.activate = "enable"
setenv.add-response-header += ( "X-Content-Type-Options" => "nosniff" )
-
setenv.add-environment = (
"LANG" => env.LANG,
"ALLSKY_HOME" => "XX_ALLSKY_HOME_XX/"
@@ -23,32 +22,30 @@ alias.url += ("/images/" => "XX_ALLSKY_IMAGES_XX/")
alias.url += ("/config/" => "XX_ALLSKY_CONFIG_XX/")
alias.url += ("/website/" => "XX_ALLSKY_WEBSITE_XX/")
alias.url += ("/documentation" => "XX_ALLSKY_DOCUMENTATION_XX/")
+alias.url += ("/overlayTemplates" => "XX_MY_OVERLAY_TEMPLATES_XX/")
alias.url += ("/overlay" => "XX_ALLSKY_OVERLAY_XX/")
$HTTP["url"] =~ "^/cgi-bin/" {
- cgi.assign = ( ".py" => "/usr/bin/python3" )
+ cgi.assign = ( ".py" => "/usr/bin/python3" )
alias.url += ( "/cgi-bin/" => "XX_ALLSKY_HOME_XX/html/cgi-bin/" )
+} else $HTTP["url"] =~ "^/overlay/config/" {
+ url.access-deny = ("")
+} else $HTTP["url"] =~ "allsky/videos|allsky/startrails|allsky/keograms" {
+ # Output web pages with thumbnails as each thumbnail is read (or created) so the thumbnails appear quickly,
+ # rather than not outputing anything until the last thumbnail is created, which can be tens of seconds.
+ server.stream-response-body = 1
}
-
-$HTTP["url"] =~ "^/current|.json$" {
+$HTTP["url"] =~ "^/current|.json$|videos/$|startrails/$|keograms/$" {
# Don't cache the "current" image since it is constantly changing.
# Also don't cache .json files since they are configuration files that can change.
+ # And don't cache the videos, startrails, and keograms files since they will normally
+ # change every day by adding another thumbnail.
# This eliminates the need to add timestamps to URLs.
setenv.add-response-header += ( "Cache-Control" => "no-cache, proxy-revalidate" )
} else {
- $HTTP["url"] =~ "thumbnails|allsky/videos|allsky/startrails|allsky/keograms" {
- # Output web pages with thumbnails as each thumbnail is read (or created) so the thumbnails appear quickly,
- # rather than not outputing anything until the last thumbnail is created, which can be tens of seconds.
- server.stream-response-body = 1
- }
-
# Cache pages
- setenv.add-response-header += ( "Cache-Control" => "max-age=31536000, immutable" )
-}
-
-$HTTP["url"] =~ "^/overlay/config/" {
- url.access-deny = ("")
+ setenv.add-response-header += ( "Cache-Control" => "max-age=31536001, immutable" )
}
# strict parsing and normalization of URL for consistency and security
diff --git a/config_repo/options.json.md b/config_repo/options.json.md
new file mode 100644
index 000000000..314335bbc
--- /dev/null
+++ b/config_repo/options.json.md
@@ -0,0 +1,139 @@
+This file is for Allsky developers and describes the fields in an entry in the options.json file.
+Most entries are settings but a few, e.g., "header" tell the WebUI how to display the page.
+
+The options.json file tells the WebUI what settings the user can change and how to display them. Many settings and/or their minimum, maximum, and default values are camera-dependent. For example, only cameras with a cooler should display the "Cooling" setting for the user to change.
+
+The options.json.repo file has ALL possible settings and is used to create the options.json file based on the camera's capabilities. As described below, some values are placeholders and are replaced when the options file is created.
+
+Each field in the options file is listed below as well as it's purpose, Type, Default, and Notes.
+Unless otherwise specified, the Default value is what's used if the field isn't specified for a setting.
+If a Note contains the phrases __If specified__ or __Optional__ it means the field doesn't need to be specified.
+Other than the first few fields, fields can be in any order but are usually in the same order to make viewing the file easier.
+
+* __name__
+ * Name of the setting that appears in the settings file.
+ * Type: string
+ * Default: none - must be present
+ * Notes: __Must be the 1st field__. This is the json name and users generally won't see it. Must be all lowercase and contain no spaces. Names that start with "day" or "night" may have the same valid values (e.g., "daybin" and "nightbin") and the part of the name that comes after "day" or "night" e.g., "bin", may be used to lookup the common values.
+* __display__
+ * Determines whether or not the field is displayed in the WebUI.
+ * Type: boolean
+ * Default: true
+ * Notes: If specified, __must be the 2nd field__ (to keep the WebUI from parsing the rest of the setting if __false__). Can be __true__, __false__, or ___display__ which means the value depends on the camera and is determined when the options file is created.
+* __settingsonly__
+ * Determines if this setting ONLY appears in the settings file and not the WebUI. Used for "internal" settings.
+ * Type: boolean
+ * Default: false
+ * Notes: If specified, __must be 3rd field__. Overrides "display : true".
+* __minimum__
+ * The setting's minimum value, if any.
+ * Type: same as the setting's __type__.
+ * Default: none
+ * Notes: Optional. Values that contain a "_" e.g., "_min" or "day_min" are placeholders.
+* __maximum__
+ * The setting's maximum value, if any.
+ * Type: same as the setting's __type__.
+ * Default: none
+ * Notes: Optional. Values that contain a "_" e.g., "_min" or "night_max" are placeholders.
+* __default__
+ * The setting's default value, if any.
+ * Type: same as the setting's __type__.
+ * Default: none
+ * Notes: Optional. Values that contain a "_" e.g., "_default" or "night_default" are placeholders.
+* __description__
+ * A description of the settings.
+ * Type: text
+ * Default: none
+ * Notes: Any setting that's displayed in the WebUI must have a description. Can contain html since it's displayed in the WebUI. The text displayed after html substitutions should be at most several lines so it doesn't take too much space in the WebUI. If there's more to say, consider having a "click here for more info" link.
+* __label__
+ * The human-readable name of the setting displayed in the WebUI.
+ * Type: text
+ * Default: none
+ * Notes: Any setting that's displayed in the WebUI must have a label. Typically 1 - 3 words.
+* __label_prefix__
+ * A prefix for programs to prepend to the label.
+ * Type: text
+ * Default: none
+ * Notes: Optional. To improve readability, some labels are short, e.g., "Generate". The prefix can be used by programs to clarify the label, e.g., "Timelapse Generate". Typically 1 - 3 words.
+* __type__
+ * The setting's type.
+ * Type: text
+ * Default: none - MUST be specified.
+ * Notes: Valid values:
+ * _boolean_ - a setting whose value in the settings file is either "true" or "false".
+ * _color_ - a text value representing a color, e.g., "#fff". The WebUI should present a color wheel for the user to set the value so they don't see the actual value (which may not make sense to them).
+ * _float_ - a number with a decimal point (period or comma, depending on locale)
+ * _header_ - defines a section header in the WebUI which in turn contains one or (usually) more settings.
+ * _header-column_ - defines the column names when multiple settings are displayed in the WebUI on one line.
+ * _header-sub_ - a sub-header in the WebUI. There can be 0 or more sub-headings under a header.
+ * _header-tab_ - defines a new tab in the WebUI.
+ * _integer_ - a number without a decimal point.
+ * _password_ - same as "text" but displayed with "***" in the WebUI.
+ * _percent_ - a "float" that acts as a percent. The WebUI should display "%" after the number but the number must be stored in the settings file without the "%".
+ * _select*_ - a drop-down selection. Must have an __options__ field that defines the choices. The actual type of the setting is what comes after the underscore, e.g., __select_integer__.
+ * _text_ - a single, short line of text - usually a single word.
+ * _widetext_ - a longer line of text. Should fit in a single line in the WebUI to avoid having to scroll right and left.
+* __usage__
+ * Lists what this setting is used for.
+ * Type: text
+ * Default: none
+ * Notes: Optional - the only current value is "capture" which means the setting is used by the capture programs. If "capture" then the __action__ field MUST be present.
+* __readonly__
+ * A setting that's displayed in the WebUI but isn't editable. Is displayed as "text".
+ * Type: boolean
+ * Default: false
+ * Notes: Optional. Not used often.
+* __carryforward__
+ * When a new camera is detected and there's a settings file for another camera, this field determine whether or not the setting's value in the other file should be used in the new settings file. This minimizes the number of settings the user needs to change.
+ * Type: boolean
+ * Default: false
+ * Notes: Optional. Typically used for settings that aren't dependent on the camera type and model, e.g., latitude. This is somewhat subjective.
+* __options__
+ * Sets the options for drop-down lists.
+ * Type: json array
+ * Default: none - required if setting __type__ is _select*_.
+ * Notes: Settings that are camera-dependent like "bin" will usually have a single placeholder entry like __[ "bin_values" ]__. Hard-coded options must have one or more elements, each with a field called __value__ its value as well as a field called __label__ and its value, e.g., __{"value" : 1, "label" : "module"}__. The __value__ field's value is what's stored in the settings file. The type of the value stored in the settings file is either an integer/float or text depending on the value. The __label__ field's value is what's displayed in the drop-down as text.
+* __checkchanges__
+ * Should the setting's new value be verified after it's changed in the WebUI?
+ * Type: boolean
+ * Default: false
+ * Notes: Optional. The setting's new value is passed to the "makeChanges.sh" to validate it and/or perform "behind the scenes" actions like sending information to a remote Website. This is why users should NEVER edit the settings file directly.
+* __optional__
+ * Is this setting optional, i.e., can it be left blank.
+ * Type: boolean
+ * Default: false
+ * Notes: Optional. Normally does not apply to boolean settings.
+* __source__
+ * What is the source of this setting, i.e., what .json file is it stored in?
+ * Type: text
+ * Default: none, which means settings.json
+ * Notes: If specified, it's either a full pathname to the .json file or a variable that's replaced by the actual name of the file by the WebUI. Currently the valid variables are __${HOME}__, __${ALLSKY_ENV}__, and __${ALLSKY_HOME}__ although only __${ALLSKY_ENV}__ is currently used.
+* __action__
+ * Determines what should happen after the setting is changed.
+ * Type: text
+ * Default: none
+ * Notes: Optional. Current choices determine what the capture program should do:
+ * _reload_ - the program re-reads the file containing the command-line arguments (which is created partially using the settings file).
+ * _restart_ - the program restarts - other than for camera changes, this isn't needed very often.
+ * _stop_ - the program stops and requires the user to manually start it. For example, when enabling dark frame capture, this allows the user to cover the lens then start Allsky.
+* __booldependson__
+ * Lists which boolean setting(s) that when "true" (a.k.a., "on") will cause this setting to be displayed.
+ * Type: list of one or more setting __name__'s.
+ * Default: none
+ * Notes: __This field will be replaced when the "new WebUI" is available.__ It currently only exists to indicate which settings have a dependency and what those dependencies are.
+* __booldependsoff__
+ * Lists which boolean setting(s) that when "false" (a.k.a., "off") will cause this setting to be displayed.
+ * Type: list of one or more setting __name__'s.
+ * Default: none
+ * Notes: __This field will be replaced when the "new WebUI" is available.__ It currently only exists to indicate which settings have a dependency and what those dependencies are.
+* __popup-yesno__
+ * Text to display in a popup when the setting's value changes to the value specified in __popup-yesno-value__.
+ * Type: text
+ * Default: none
+ * Notes: __This field will be replaced when the "new WebUI" is available.__ It currently only exists to indicate which settings should have a popup.
+* __popup-yesno-value__
+ * A settings new value that causes a popup to be shown.
+ * Type: number - 0 (false) or 1 (true)
+ * Default: none
+ * Notes: __This field will be replaced when the "new WebUI" is available.__ It currently only exists to indicate what value should produce a popup.
+ * TODO: Need to specify the action to take based on the user's answer to the __popup-yesno__ text.
diff --git a/config_repo/options.json.repo b/config_repo/options.json.repo
index d0ce19480..93fecfce4 100644
--- a/config_repo/options.json.repo
+++ b/config_repo/options.json.repo
@@ -1,47 +1,67 @@
[
{
-"name" : "daytimeSettingsHeader",
-"description" : "Daytime settings",
-"type" : "header",
-"display" : 1
+"name" : "daynighttab========================================",
+"display" : false,
+"label" : "Day/Night Settings",
+"type" : "header-tab"
},
{
-"name" : "takeDaytimeImages",
-"default" : 1,
-"description" : "Activate to take daytime images.",
-"label" : "Daytime Capture",
+"name" : "daytimesettingsheader",
+"label" : "Daytime Settings",
+"type" : "header"
+},
+{
+"name" : "daynightcolumns",
+"display" : false,
+"label" : "Setting, Day Value, Description",
+"candrop" : "Description",
+"type" : "header-column"
+},
+{
+"name" : "takedaytimeimages",
+"default" : true,
+"description" : "Enable to take daytime images.",
+"label" : "Capture",
+"label_prefix" : "Daytime",
"type" : "boolean",
-"checkchanges" : 1,
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"checkchanges" : true,
+"action" : "reload"
},
{
-"name" : "saveDaytimeImages",
-"default" : 0,
-"description" : "Activate to save daytime images. Only applies if Daytime Capture is enabled.",
-"label" : "Daytime Save",
+"name" : "savedaytimeimages",
+"default" : false,
+"description" : "Enable to save daytime images.",
+"label" : "Save",
+"label_prefix" : "Daytime",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"carryforward" : true,
+"booldependson" : "takedaytimeimages"
},
{
"name" : "dayautoexposure",
-"default" : 1,
-"description" : "Activate to enable daytime auto-exposure.",
+"default" : true,
+"description" : "Enable to use daytime auto-exposure.",
"label" : "Auto-Exposure",
+"label_prefix" : "Daytime",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"booldependson" : "takedaytimeimages",
+"action" : "reload"
},
{
"name" : "daymaxautoexposure",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
-"description" : "Maximum daytime Auto-Exposure time in milliseconds (1000ms = 1 sec). Only applies if daytime Auto-Exposure is enabled.",
+"description" : "Maximum daytime Auto-Exposure time in milliseconds (1000ms = 1 sec).",
"label" : "Max Auto-Exposure",
+"label_prefix" : "Daytime",
"type" : "float",
-"display" : 1
+"usage" : "capture",
+"booldependson" : "takedaytimeimages AND daymaxautoexposure",
+"action" : "reload"
},
{
"name" : "dayexposure",
@@ -50,8 +70,11 @@
"default" : "day_default",
"description" : "Manual exposure time in milliseconds (1000ms = 1 sec). Can be a fraction. If using daytime Auto-Exposure, this number is used as a starting point.",
"label" : "Manual Exposure",
+"label_prefix" : "Daytime",
"type" : "float",
-"display" : 1
+"usage" : "capture",
+"booldependson" : "takedaytimeimages",
+"action" : "reload"
},
{
"name" : "daymean",
@@ -60,28 +83,24 @@
"default" : "day_default",
"description" : "The target mean brightness level when Auto-Exposure is on. 1.0 is pure white. Best used when Auto-Exposure and Auto-Gain are on. 0 disables this auto-exposure mode.",
"label" : "Mean Target",
+"label_prefix" : "Daytime",
"type" : "float",
-"display" : 1
+"usage" : "capture",
+"booldependson" : "takedaytimeimages",
+"action" : "reload"
},
{
"name" : "daymeanthreshold",
"minimum" : "day_min",
"maximum" : "day_max",
"default" : "day_default",
-"description" : "When using Mean Target this specifies how close to the target the brightness should be.",
+"description" : "When using Mean Target this specifies how close to the target the brightness should be.",
"label" : "Mean Threshold",
+"label_prefix" : "Daytime",
"type" : "float",
-"display" : 1
-},
-{
-"name" : "daybrightness",
-"minimum" : "_min",
-"maximum" : "_max",
-"default" : "_default",
-"description" : "Deprecated. Use Mean Target instead. Changes the amount of light in the image. Higher numbers are brighter.",
-"label" : "Brightness",
-"type" : "float",
-"display" : "_display"
+"usage" : "capture",
+"booldependson" : "takedaytimeimages AND daymean",
+"action" : "reload"
},
{
"name" : "daydelay",
@@ -90,18 +109,23 @@
"default" : 30000,
"description" : "Delay between daytime images in milliseconds (1000ms = 1 sec).",
"label" : "Delay",
+"label_prefix" : "Daytime",
"type" : "integer",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"booldependson" : "takedaytimeimages",
+"action" : "reload"
},
{
"name" : "dayautogain",
-"default" : 0,
-"description" : "Activate to enable dayime Auto-Gain.",
+"default" : "_default",
+"description" : "Enable to use dayime Auto-Gain.",
"label" : "Auto-Gain",
+"label_prefix" : "Daytime",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"booldependson" : "takedaytimeimages",
+"action" : "reload"
},
{
"name" : "daymaxautogain",
@@ -110,125 +134,205 @@
"default" : "_default",
"description" : "Maximum gain when using Auto-Gain.",
"label" : "Max Auto-Gain",
+"label_prefix" : "Daytime",
"type" : "float",
-"display" : 1
+"usage" : "capture",
+"booldependson" : "takedaytimeimages AND dayautogain",
+"action" : "reload"
},
{
"name" : "daygain",
"minimum" : "_min",
"maximum" : "_max",
"default" : "day_default",
-"description" : "Manually sets the light sensitivity of the camera. A high number returns a brighter image but more noise too. Can normally leave at the minimum value for daytime.",
+"description" : "Manually sets the light sensitivity of the camera. A high number returns a brighter image but more noise. Can normally leave at the minimum value for daytime.",
"label" : "Gain",
+"label_prefix" : "Daytime",
"type" : "float",
-"display" : 1
+"usage" : "capture",
+"booldependson" : "takedaytimeimages",
+"action" : "reload"
+},
+{
+"name" : "imagestretchamountdaytime",
+"minimum" : 0,
+"maximum" : 100,
+"default" : 0,
+"description" : "Amount to stretch daytime images. 0 means don't stretch.",
+"label" : "Stretch Amount",
+"label_prefix" : "Daytime",
+"type" : "integer",
+"booldependson" : "takedaytimeimages"
+},
+{
+"name" : "imagestretchmidpointdaytime",
+"minimum" : 1,
+"maximum" : 100,
+"default" : 10,
+"description" : "Mid point of image stretch. Lower numbers brighten darker parts of image; higher numbers brighten lighter parts. Only applies if Stretch Amount is greater than 0.",
+"label" : "Stretch Mid Point",
+"label_prefix" : "Daytime",
+"type" : "percent",
+"booldependson" : "takedaytimeimages"
},
{
"name" : "daybin",
"default" : 1,
"description" : "Binning level. 1x1 = OFF.",
"label" : "Binning",
-"type" : "select",
+"label_prefix" : "Daytime",
+"type" : "select_integer",
+"usage" : "capture",
"options" : [
"bin_values"
],
-"generic" : 1,
-"display" : 1
+"booldependson" : "takedaytimeimages",
+"action" : "reload"
},
{
"name" : "dayawb",
-"default" : 0,
-"description" : "Sets Auto White Balance.",
+"display" : "_display",
+"default" : false,
+"description" : "Sets Auto White Balance (camera adjusts color).",
"label" : "Auto White Balance",
+"label_prefix" : "Daytime",
"type" : "boolean",
-"generic" : 1,
-"display" : "_display"
+"usage" : "capture",
+"booldependson" : "takedaytimeimages",
+"action" : "reload"
},
{
"name" : "daywbr",
+"display" : "_display",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
"description" : "Red component for the white balance. When using Auto White Balance, this number is a starting point.",
"label" : "Red Balance",
+"label_prefix" : "Daytime",
"type" : "float",
-"display" : "_display"
+"usage" : "capture",
+"booldependson" : "takedaytimeimages AND dayawb",
+"action" : "reload"
},
{
"name" : "daywbb",
+"display" : "_display",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
"description" : "Blue component for the white balance. When using Auto White Balance, this number is a starting point.",
"label" : "Blue Balance",
+"label_prefix" : "Daytime",
"type" : "float",
-"display" : "_display"
+"usage" : "capture",
+"booldependson" : "takedaytimeimages AND dayawb",
+"action" : "reload"
},
{
"name" : "dayskipframes",
"minimum" : 0,
"maximum" : "none",
"default" : 5,
-"description" : "When starting Allsky during the day, skip up to this many frames while the software gets to the correct exposure. Only applies if daytime Auto-Exposure is on.",
+"description" : "When starting Allsky during the day, skip up to this many frames while the software gets to the correct exposure.",
"label" : "Frames To Skip",
+"label_prefix" : "Daytime",
"type" : "integer",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"booldependson" : "takedaytimeimages AND dayautoexposure",
+"action" : "reload"
},
{
-"name" : "dayEnableCooler",
-"default" : 0,
-"description" : "Activate to use cooling (works only on cooled cameras).",
+"name" : "dayenablecooler",
+"display" : "_display",
+"default" : false,
+"description" : "Enable to use cooling (on cooled cameras only).",
"label" : "Cooling",
+"label_prefix" : "Daytime",
"type" : "boolean",
-"generic" : 1,
-"display" : "_display"
+"usage" : "capture",
+"carryforward" : true,
+"booldependson" : "takedaytimeimages",
+"action" : "reload"
},
{
-"name" : "dayTargetTemp",
+"name" : "daytargettemp",
+"display" : "_display",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
"description" : "Sensor's target temperature when cooler is enabled (degrees Celsius).",
"label" : "Target Temp.",
+"label_prefix" : "Daytime",
"type" : "integer",
-"generic" : 1,
-"display" : "_display"
+"usage" : "capture",
+"booldependson" : "takedaytimeimages AND dayenablecooler",
+"action" : "reload"
},
{
-"name" : "dayTuningFile",
+"name" : "daytuningfile",
+"display" : "_display",
"default" : "",
-"description" : "Name of the day camera tuning file to use. Omit this option to preserve the default behavior of libcamera. Please read this documentation or this document if using a Raspberry camera with libcamera. For other Raspberry cameras read the camera manual for more information.",
+"description" : "Name of the optional day camera tuning file to use. See the documentation for a description of this setting.",
"label" : "Tuning File",
+"label_prefix" : "Daytime",
"type" : "widetext",
-"checkchanges" : 1,
-"optional" : 1,
-"display" : "_display"
+"usage" : "capture",
+"checkchanges" : true,
+"optional" : true,
+"booldependson" : "takedaytimeimages",
+"action" : "restart"
+},
+
+{
+"name" : "nighttimesettingsheader",
+"label" : "Nighttime Settings",
+"type" : "header"
+},
+{
+"name" : "takenighttimeimages",
+"default" : true,
+"description" : "Enable to take nighttime images.",
+"label" : "Capture",
+"label_prefix" : "Nighttime",
+"type" : "boolean",
+"usage" : "capture",
+"carryforward" : true,
+"checkchanges" : true,
+"action" : "reload"
},
{
-"name" : "nighttimeSettingsHeader",
-"description" : "Nighttime settings",
-"type" : "header",
-"display" : 1
+"name" : "savenighttimeimages",
+"default" : true,
+"description" : "Enable to save nighttime images.",
+"label" : "Save",
+"label_prefix" : "Nighttime",
+"type" : "boolean",
+"carryforward" : true,
+"booldependson" : "takenighttimeimages"
},
{
"name" : "nightautoexposure",
-"default" : 1,
-"description" : "Activate to enable nighttime auto-exposure.",
+"default" : true,
+"description" : "Enable to use nighttime auto-exposure.",
"label" : "Auto-Exposure",
+"label_prefix" : "Nighttime",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"action" : "reload"
},
{
"name" : "nightmaxautoexposure",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
-"description" : "Maximum nighttime Auto-Exposure time in milliseconds (1000ms = 1 sec). Only applies if nighttime Auto-Exposure is enabled.",
+"description" : "Maximum nighttime Auto-Exposure time in milliseconds (1000ms = 1 sec).",
"label" : "Max Auto-Exposure",
+"label_prefix" : "Nighttime",
"type" : "float",
-"display" : 1
+"usage" : "capture",
+"booldependson" : "nightautoexposure",
+"action" : "reload"
},
{
"name" : "nightexposure",
@@ -237,8 +341,10 @@
"default" : "night_default",
"description" : "Manual exposure time in milliseconds (1000ms = 1 sec). Can be a fraction. If using nighttime Auto-Exposure, this number is used as a starting point.",
"label" : "Manual Exposure",
+"label_prefix" : "Nighttime",
"type" : "float",
-"display" : 1
+"usage" : "capture",
+"action" : "reload"
},
{
"name" : "nightmean",
@@ -247,28 +353,23 @@
"default" : "night_default",
"description" : "The target mean brightness level when Auto-Exposure is on. 1.0 is pure white. Best used when Auto-Exposure and Auto-Gain are on. 0 disables this auto-exposure mode.",
"label" : "Mean Target",
+"label_prefix" : "Nighttime",
"type" : "float",
-"display" : 1
+"usage" : "capture",
+"action" : "reload"
},
{
"name" : "nightmeanthreshold",
"minimum" : "night_min",
"maximum" : "night_max",
"default" : "day_default",
-"description" : "When using Mean Target this specifies how close to the target the brightness should be.",
+"description" : "When using Mean Target this specifies how close to the target the brightness should be.",
"label" : "Mean Threshold",
+"label_prefix" : "Nighttime",
"type" : "float",
-"display" : 1
-},
-{
-"name" : "nightbrightness",
-"minimum" : "_min",
-"maximum" : "_max",
-"default" : "_default",
-"description" : "Deprecated. Use Mean Target instead. Changes the amount of light in the image. Higher numbers are brighter.",
-"label" : "Brightness",
-"type" : "float",
-"display" : "_display"
+"usage" : "capture",
+"booldependson" : "nightmean",
+"action" : "reload"
},
{
"name" : "nightdelay",
@@ -277,18 +378,21 @@
"default" : 30000,
"description" : "Delay between nighttime images in milliseconds (1000ms = 1 sec).",
"label" : "Delay",
+"label_prefix" : "Nighttime",
"type" : "integer",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"action" : "reload"
},
{
"name" : "nightautogain",
-"default" : 0,
-"description" : "Activate to enable nighttime Auto-Gain.",
+"default" : "_default",
+"description" : "Enable to use nighttime Auto-Gain.",
"label" : "Auto-Gain",
+"label_prefix" : "Nighttime",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"action" : "reload"
},
{
"name" : "nightmaxautogain",
@@ -297,106 +401,173 @@
"default" : "_default",
"description" : "Maximum gain when using Auto-Gain.",
"label" : "Max Auto-Gain",
+"label_prefix" : "Nighttime",
"type" : "float",
-"display" : 1
+"usage" : "capture",
+"booldependson" : "nightautogain",
+"action" : "reload"
},
{
"name" : "nightgain",
"minimum" : "_min",
"maximum" : "_max",
"default" : "night_default",
-"description" : "Manually sets the light sensitivity of the camera. A high number returns a brighter image but more noise too.",
+"description" : "Manually sets the light sensitivity of the camera. A high number returns a brighter image but more noise.",
"label" : "Gain",
+"label_prefix" : "Nighttime",
"type" : "float",
-"display" : 1
+"usage" : "capture",
+"action" : "reload"
+},
+{
+"name" : "imagestretchamountnighttime",
+"minimum" : 0,
+"maximum" : 100,
+"default" : 0,
+"description" : "Amount to stretch nighttime images. 0 means don't stretch.",
+"label" : "Stretch Amount",
+"label_prefix" : "Nighttime",
+"type" : "integer",
+"booldependson" : "takenighttimeimages"
+},
+{
+"name" : "imagestretchmidpointnighttime",
+"minimum" : 1,
+"maximum" : 100,
+"default" : 10,
+"description" : "Mid point of image stretch. Lower numbers brighten darker parts of image; higher numbers brighten lighter parts. Only applies if Stretch Amount is greater than 0.",
+"label" : "Stretch mid point",
+"label_prefix" : "Nighttime",
+"type" : "percent",
+"booldependson" : "takenighttimeimages"
},
{
"name" : "nightbin",
"default" : 1,
"description" : "Binning level. 1x1 = OFF.",
"label" : "Binning",
-"type" : "select",
+"label_prefix" : "Nighttime",
+"type" : "select_integer",
+"usage" : "capture",
"options" : [
"bin_values"
],
-"generic" : 1,
-"display" : 1
+"action" : "reload"
},
{
"name" : "nightawb",
-"default" : 0,
-"description" : "Activate to enable Auto White Balance (camera adjusts color).",
+"display" : "_display",
+"default" : false,
+"description" : "Enable to use Auto White Balance (camera adjusts color). NOTE: enabling this can significantly increase the time needed to capture a nighttime image.",
"label" : "Auto White Balance",
+"label_prefix" : "Nighttime",
"type" : "boolean",
-"generic" : 1,
-"display" : "_display"
+"usage" : "capture",
+"action" : "reload"
},
{
"name" : "nightwbr",
+"display" : "_display",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
"description" : "Red component for the white balance. When using Auto White Balance, this number is a starting point.",
"label" : "Red Balance",
+"label_prefix" : "Nighttime",
"type" : "float",
-"display" : "_display"
+"usage" : "capture",
+"booldependsoff" : "nightawb",
+"action" : "reload"
},
{
"name" : "nightwbb",
+"display" : "_display",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
"description" : "Blue component for the white balance. When using Auto White Balance, this number is a starting point.",
"label" : "Blue Balance",
+"label_prefix" : "Nighttime",
"type" : "float",
-"display" : "_display"
+"usage" : "capture",
+"booldependsoff" : "nightawb",
+"action" : "reload"
},
{
"name" : "nightskipframes",
"minimum" : 0,
"maximum" : "none",
"default" : 1,
-"description" : "When starting Allsky at night, skip up to this many frames while the software gets to the correct exposure. Only applies if nighttime Auto-Exposure is on.",
+"description" : "When starting Allsky at night, skip up to this many frames while the software gets to the correct exposure.",
"label" : "Frames To Skip",
+"label_prefix" : "Nighttime",
"type" : "integer",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"booldependson" : "nightautoexposure",
+"action" : "reload"
},
{
-"name" : "nightEnableCooler",
-"default" : 0,
-"description" : "Activate to use cooling (works only on cooled cameras).",
+"name" : "nightenablecooler",
+"display" : "_display",
+"default" : false,
+"description" : "Enable to use cooling (on cooled cameras only).",
"label" : "Cooling",
+"label_prefix" : "Nighttime",
"type" : "boolean",
-"generic" : 1,
-"display" : "_display"
+"usage" : "capture",
+"carryforward" : true,
+"action" : "reload"
},
{
-"name" : "nightTargetTemp",
+"name" : "nighttargettemp",
+"display" : "_display",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
"description" : "Sensor's target temperature when cooler is enabled (degrees Celsius).",
"label" : "Target Temp.",
+"label_prefix" : "Nighttime",
"type" : "integer",
-"generic" : 1,
-"display" : "_display"
+"usage" : "capture",
+"booldependson" : "nightenablecooler",
+"action" : "reload"
},
{
-"name" : "nightTuningFile",
+"name" : "nighttuningfile",
+"display" : "_display",
"default" : "",
"description" : "Name of the night camera tuning file to use.",
"label" : "Tuning File",
+"label_prefix" : "Nighttime",
"type" : "widetext",
-"checkchanges" : 1,
-"optional" : 1,
-"display" : "_display"
+"usage" : "capture",
+"checkchanges" : true,
+"optional" : true,
+"action" : "restart"
},
+
{
-"name" : "DayAndNightHeader",
-"description" : "Both daytime and nighttime settings",
-"type" : "header",
-"display" : 1
+"name" : "bothtab========================================",
+"display" : false,
+"label" : "24 Hours",
+"type" : "header-tab"
+},
+{
+"name" : "dayandnightheader",
+"label" : "Both Day and Night Settings",
+"type" : "header"
+},
+{
+"name" : "daystokeep",
+"minimum" : 0,
+"maximum" : "none",
+"default" : 14,
+"description" : "Number of days of images and videos to keep on the Pi. 0 keeps all days.",
+"label" : "Days To Keep",
+"type" : "integer",
+"carryforward" : true,
+"checkchanges" : true,
+"booldependson" : "savedaytimeimages OR savenighttimeimages"
},
{
"name" : "config",
@@ -404,122 +575,108 @@
"description" : "Configuration file to use for settings.",
"label" : "Configuration File",
"type" : "widetext",
-"checkchanges" : 1,
-"optional" : 1,
-"display" : 1
+"usage" : "capture",
+"checkchanges" : true,
+"optional" : true,
+"action" : "reload"
},
{
-"name" : "extraArgs",
+"name" : "extraargs",
+"display" : "_display",
"default" : "",
"description" : "Extra arguments to pass to the capture program that Allsky doesn't support.",
"label" : "Extra Arguments",
"type" : "widetext",
-"optional" : 1,
-"display" : "_display"
+"usage" : "capture",
+"optional" : true,
+"action" : "reload"
},
{
"name" : "saturation",
+"display" : "_display",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
"description" : "Changes the saturation level of the image. The lowest level produces a black and white image.",
"label" : "Saturation",
"type" : "float",
-"display" : "_display"
+"usage" : "capture",
+"action" : "reload"
},
{
"name" : "contrast",
+"display" : "_display",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
"description" : "Changes the contrast of an image.",
"label" : "Contrast",
"type" : "float",
-"display" : "_display"
+"usage" : "capture",
+"action" : "reload"
},
{
"name" : "sharpness",
+"display" : "_display",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
"description" : "Changes the sharpness of an image. Too sharp and images look unnatural.",
"label" : "Sharpness",
"type" : "float",
-"display" : "_display"
+"usage" : "capture",
+"action" : "reload"
},
{
"name" : "gamma",
+"display" : "_display",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
-"description" : "Changes the difference between light and dark areas. higher numbers increase contrast.",
+"description" : "Changes the difference between light and dark areas. Higher numbers increase contrast.",
"label" : "Gamma",
"type" : "integer",
-"display" : "_display"
-},
-{
-"name" : "offset",
-"minimum" : "_min",
-"maximum" : "_max",
-"default" : "_default",
-"description" : "Adds about 1/10 the specified number to every pixel to brighten everything.",
-"label" : "Offset",
-"type" : "integer",
-"display" : "_display"
+"usage" : "capture",
+"action" : "reload"
},
{
"name" : "aggression",
+"display" : "_display",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
"description" : "How much of a calculated exposure change should be made during Auto-Exposure? Lower numbers smooth out changes but take longer to react to brightness changes.",
"label" : "Aggression",
"type" : "percent",
-"generic" : 1,
-"display" : "_display"
+"usage" : "capture",
+"booldependson" : "dayautoexposure OR nightautoexposure",
+"action" : "reload"
},
{
"name" : "gaintransitiontime",
+"display" : "_display",
"minimum" : 0,
"maximum" : "none",
"default" : "_default",
-"description" : "Number of minutes over which to increase or decrease the gain when switching between day and night. This helps smooth brightness differences. Only works if nighttime Auto-Gain is off. 0 disables transitions.",
+"description" : "Number of minutes over which to increase or decrease the gain when switching between day and night. This helps smooth brightness differences. 0 disables transitions.",
"label" : "Gain Transition Time",
"type" : "integer",
-"generic" : 1,
-"display" : "_display"
-},
-{
-"name" : "width",
-"minimum" : "_min",
-"maximum" : "_max",
-"default" : 0,
-"description" : "Image width in pixels. 0 = max sensor width.",
-"label" : "Image Width",
-"type" : "integer",
-"display" : 1
-},
-{
-"name" : "height",
-"minimum" : "_min",
-"maximum" : "_max",
-"default" : 0,
-"description" : "Image height in pixels. 0 = max sensor height.",
-"label" : "Image Height",
-"type" : "integer",
-"display" : 1
+"usage" : "capture",
+"booldependsoff" : "nightautogain",
+"action" : "reload"
},
{
"name" : "type",
"default" : 99,
"description" : "'auto' uses color if possible, otherwise the best mono mode supported. RAW16 only works with PNG extension.",
"label" : "Image Type",
-"type" : "select",
+"type" : "select_integer",
+"usage" : "capture",
"options" : [
"type_values"
],
-"checkchanges" : 1,
-"display" : 1
+"checkchanges" : true,
+"action" : "reload"
},
{
"name" : "quality",
@@ -529,26 +686,32 @@
"description" : "JPG quality: 0-100. Higher numbers produce larger, clearer files. PNG compression: 0-9. Higher numbers produce smaller files but take longer to save.",
"label" : "Quality / Compression",
"type" : "integer",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"action" : "reload"
},
{
"name" : "autousb",
-"default" : 1,
+"display" : "_display",
+"default" : true,
"description" : "Automatically set the USB bandwidth.",
"label" : "Auto USB Bandwidth",
"type" : "boolean",
-"display" : "_display"
+"usage" : "capture",
+"action" : "reload"
},
{
"name" : "usb",
+"display" : "_display",
"minimum" : "_min",
"maximum" : "_max",
"default" : "_default",
"description" : "USB bandwidth. If you get ASI_ERROR_TIMEOUT errors in the log file, try changing this number.",
"label" : "USB Bandwidth",
"type" : "integer",
-"display" : "_display"
+"usage" : "capture",
+"booldependsoff" : "autousb",
+"action" : "reload"
},
{
"name" : "filename",
@@ -556,52 +719,57 @@
"description" : "Extensions allowed: .jpg or .png. WARNING: saving a .png file can take 10 or more seconds so be sure the time between successive images is long enough. To measure how long it takes your Pi to save a .png file, set the Debug Level to 4 and look in the log file.",
"label" : "Filename",
"type" : "text",
-"checkchanges" : 1,
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"checkchanges" : true,
+"action" : "reload"
},
{
"name" : "rotation",
+"display" : "_display",
"default" : 0,
"description" : "Set image rotation to enable proper orientation.",
"label" : "Rotation",
-"type" : "select",
+"type" : "select_integer",
+"usage" : "capture",
"options" : [
"rotation_values"
],
-"display" : "_display"
+"action" : "reload"
},
{
"name" : "flip",
"default" : 0,
"description" : "Flips the image along an axis.",
"label" : "Flip",
-"type" : "select",
+"type" : "select_integer",
+"usage" : "capture",
"options" : [
{"value" : 0, "label" : "None"},
{"value" : 1, "label" : "Horizontal"},
{"value" : 2, "label" : "Vertical"},
{"value" : 3, "label" : "Both"}
],
-"display" : 1
+"action" : "reload"
},
{
-"name" : "notificationimages",
-"default" : 1,
-"description" : "Activate to display notification images, e.g., 'Camera is off during the day'. While these messages appear in the WebUI and Allsky Website, they are not saved so don't appear in timelapse, startrails, or keograms.",
-"label" : "Notification Images",
+"name" : "determinefocus",
+"default" : false,
+"description" : "Enable to have the image focus determined and output via the 'FOCUS' variable.",
+"label" : "Record Focus",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"action" : "stop"
},
{
-"name" : "consistentDelays",
-"default" : 1,
-"description" : "Activate to have the delays between images be a consistent length. The time between the start of exposures will always be (max exposure + delay).",
+"name" : "consistentdelays",
+"default" : true,
+"description" : "Enable to have the delays between images be a consistent length. The time between the start of exposures will always be (max exposure + delay).",
"label" : "Consistent Delays Between Images",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"action" : "reload"
},
{
"name" : "timeformat",
@@ -609,28 +777,46 @@
"description" : "Determines the format of the displayed time. Run 'man 3 strftime' to see the options.",
"label" : "Time Format",
"type" : "text",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"action" : "reload"
+},
+{
+"name" : "temptype",
+"default" : "C",
+"description" : "Unit(s) to display temperature in.",
+"label" : "Temperature Units",
+"type" : "select_text",
+"usage" : "capture",
+"carryforward" : true,
+"options" : [
+ {"value" : "C", "label" : "Celsius"},
+ {"value" : "F", "label" : "Fahrenheit"},
+ {"value" : "B", "label" : "Both"}
+],
+"action" : "reload"
},
{
"name" : "latitude",
"default" : "",
-"description" : "Camera latitude - a number with a sign (-90 to +90) or a positive number with direction (N or S), for example: 60.7N.",
+"description" : "Camera latitude: a signed number from -90 to +90, or an unsigned number with direction (N or S), for example: 60.7N.",
"label" : "Latitude",
"type" : "text",
-"checkchanges" : 1,
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"checkchanges" : true,
+"action" : "reload"
},
{
"name" : "longitude",
"default" : "",
-"description" : "Camera longitude - a number with a sign (-180 to +180) or a positive number with a direction (E or W), for example: 135.05W.",
+"description" : "Camera longitude: a signed number from -180 to +180, or an unsigned number with a direction (E or W), for example: 135.05W.",
"label" : "Longitude",
"type" : "text",
-"checkchanges" : 1,
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"checkchanges" : true,
+"action" : "reload"
},
{
"name" : "angle",
@@ -638,58 +824,72 @@
"description" : "Altitude of the Sun in degrees relative to the horizon at which to switch between day and night.",
"label" : "Angle",
"type" : "float",
-"checkchanges" : 1,
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"checkchanges" : true,
+"action" : "reload"
},
{
-"name" : "takeDarkFrames",
-"default" : 0,
-"description" : "Activate to capture dark frames, which are used to decrease noise. Continues taking dark frames until Allsky is restarted.",
+"name" : "takedarkframes",
+"default" : false,
+"description" : "Enable to capture dark frames, which are used to decrease noise. See the Dark frames documentation on how to take dark frames.",
"label" : "Take Dark Frames",
"type" : "boolean",
-"display" : 1
+"usage" : "capture",
+"action" : "stop"
},
{
-"name" : "useDarkFrames",
-"default" : 0,
+"name" : "usedarkframes",
+"default" : false,
"description" : "Enables dark frame subtraction if you have dark frames.",
"label" : "Use Dark Frames",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"checkchanges" : true
},
{
"name" : "locale",
"default" : "",
-"description" : "Your locale, used to determine what the thousands and decimal separators are. Type locale at a command prompt to see your choices.",
+"description" : "Your locale, used to determine what the thousands and decimal separators are. Type locale --all-locales at a command prompt to see which locales are configured on your Pi.",
"label" : "Locale",
"type" : "text",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"action" : "reload"
},
{
-"name" : "experimentalExposure",
+"name" : "zwoexposuretype",
+"display" : "_display",
"default" : 0,
-"description" : "Activate to use a newer auto-exposure algorithm at night. Initial testing indictes the images taken during the day-to-night transition as well as at night have better exposures. If you use this, please add a Discussion item describing your results - good or bad. We need the feedback.",
-"label" : "New Exposure Algorithm",
-"type" : "boolean",
-"display" : "_display"
+"description" : "Select the type of exposure to use with ZWO cameras. Use Snapshot if possible since it should fix ASI_ERROR_TIMEOUT problems. If that doesn't work try Video Off. Note that Auto White Balance does not work in Snapshot",
+"label" : "ZWO Exposure Type",
+"type" : "select_integer",
+"usage" : "capture",
+"options" : [
+ {"value" : 0, "label" : "Snapshot"},
+ {"value" : 1, "label" : "Video Off"},
+ {"value" : 2, "label" : "Video (original)"}
+],
+"action" : "reload"
},
{
"name" : "histogrambox",
+"display" : "_display",
"default" : "500 500 50 50",
"description" : "Size of the histogram box (X and Y in pixels) and offset from left and top (0-100 percent). Sizes must be even numbers.",
"label" : "Histogram Box",
"type" : "text",
-"display" : "_display"
+"usage" : "capture",
+"booldependson" : "dayautoexposure OR nightautoexposure",
+"action" : "reload"
},
{
"name" : "debuglevel",
"default" : 1,
-"description" : "Debug level. 0 is errors only. 4 is for Allsky developers use.",
+"description" : "Debug level. 0 is errors only. 4 is for Allsky developers use.",
"label" : "Debug Level",
-"type" : "select",
+"type" : "select_integer",
+"usage" : "capture",
+"carryforward" : true,
"options" : [
{"value" : 0, "label" : 0},
{"value" : 1, "label" : 1},
@@ -697,137 +897,125 @@
{"value" : 3, "label" : 3},
{"value" : 4, "label" : 4}
],
-"display" : 1
-},
-{
-"name" : "newexposure",
-"default" : 1,
-"description" : "Activate to use the Allsky version 0.8 exposure method which decreases sensor temperature. If you see ASI_ERROR_TIMEOUTs in the log file, deactivate this.",
-"label" : "Version 0.8 Exposure",
-"type" : "boolean",
-"display" : "_display"
+"action" : "reload"
},
+
+
{
-"name" : "useLogin",
-"default" : 1,
-"description" : "Determines if you need to login to the WebUI or not. If your Pi is accessible on the Internet, do NOT turn this off!!.",
-"label" : "Require WebUI Login",
-"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"name" : "overlaytab========================================",
+"label" : "Overlay",
+"type" : "header-tab"
},
{
-"name" : "overlayHeader",
-"description" : "Image overlay settings",
-"type" : "header",
-"display" : 1
+"name" : "overlayheader",
+"label" : "Image Overlay Settings",
+"type" : "header"
},
{
-"name" : "overlayMethod",
-"default" : 0,
+"name" : "overlaymethod",
+"default" : 1,
"description" : "Determines how image overlays are done. module supports a visual editor. When set to module, the overlay settings below do NOT apply.",
"label" : "Overlay Method",
-"type" : "select",
+"usage" : "capture",
+"type" : "select_integer",
"options" : [
{"value" : 0, "label" : "legacy"},
{"value" : 1, "label" : "module"}
],
-"checkchanges" : 1,
-"generic" : 1,
-"display" : 1
+"carryforward" : true,
+"checkchanges" : true,
+"action" : "reload"
},
{
-"name" : "showTime",
-"default" : 1,
-"description" : "Activate to display the time an image was taken on the overlay.",
+"name" : "showtime",
+"default" : true,
+"description" : "Enable to display the time an image was taken on the overlay.",
"label" : "Show Time",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
-"name" : "showTemp",
-"default" : 1,
-"description" : "Activate to display the camera sensor temperature on the overlay.",
+"name" : "showtemp",
+"display" : "_display",
+"default" : true,
+"description" : "Enable to display the camera sensor temperature on the overlay.",
"label" : "Show Temperature",
"type" : "boolean",
-"generic" : 1,
-"display" : "_display"
-},
-{
-"name" : "temptype",
-"default" : "C",
-"description" : "Unit(s) to display temperature in.",
-"label" : "Temperature Units",
-"type" : "select",
-"options" : [
- {"value" : "C", "label" : "Celcius"},
- {"value" : "F", "label" : "Fahrenheit"},
- {"value" : "B", "label" : "Both"}
-],
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
-"name" : "showExposure",
-"default" : 1,
-"description" : "Activate to display the exposure length on the overlay. If Auto-Exposure is set, '(auto)' will appear after the exposure time.",
+"name" : "showexposure",
+"default" : true,
+"description" : "Enable to display the exposure length on the overlay. If Auto-Exposure is set, '(auto)' will appear after the exposure time.",
"label" : "Show Exposure",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
-"name" : "showGain",
-"default" : 0,
-"description" : "Activate to display the camera gain on the overlay. If Auto-Gain is set, '(auto)' will appear after the gain value.",
+"name" : "showgain",
+"default" : false,
+"description" : "Enable to display the camera gain on the overlay. If Auto-Gain is set, '(auto)' will appear after the gain value.",
"label" : "Show Gain",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
-},
-{
-"name" : "showBrightness",
-"default" : 0,
-"description" : "Activate to display the Brightness number you set on the overlay.",
-"label" : "Show Brightness",
-"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
-"name" : "showUSB",
-"default" : 0,
-"description" : "Activate to display the USB Bandwidth number on the overlay. This is primarily for troubleshooting.",
+"name" : "showusb",
+"display" : "_display",
+"default" : false,
+"description" : "Enable to display the USB Bandwidth number on the overlay. This is primarily for troubleshooting.",
"label" : "Show USB",
"type" : "boolean",
-"display" : "_display"
+"usage" : "capture",
+"carryforward" : true,
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
-"name" : "showMean",
-"default" : 0,
-"description" : "Activate to display the calculated mean image brightness on the overlay.",
+"name" : "showmean",
+"default" : false,
+"description" : "Enable to display the calculated mean image brightness on the overlay.",
"label" : "Show Mean Brightness",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "showhistogrambox",
-"default" : 0,
-"description" : "Activate to show an outline of the histogram box, useful for determining what the 'Histogram Box' numbers should be.",
+"display" : "_display",
+"default" : false,
+"description" : "Enable to show an outline of the histogram box, useful for determining what the 'Histogram Box' numbers should be.",
"label" : "Show Histogram Box",
"type" : "boolean",
-"display" : "_display"
+"usage" : "capture",
+"carryforward" : true,
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
-"name" : "showFocus",
-"default" : 0,
-"description" : "Activate to display a focus metric to help you focus the camera. This is only usefull while focusing.",
+"name" : "showfocus",
+"default" : false,
+"description" : "Enable to display a focus metric to help you focus the camera. This is only usefull while focusing.",
"label" : "Show Focus Metric",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "text",
@@ -835,9 +1023,10 @@
"description" : "Text that appears below the optional time with the same color and size.",
"label" : "Text Overlay",
"type" : "widetext",
-"optional" : 1,
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"optional" : true,
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "extratext",
@@ -845,10 +1034,11 @@
"description" : "Extra Text File (enter full path to the file). Leave blank if NOT using an extra text file.",
"label" : "Extra Text File",
"type" : "widetext",
-"checkchanges" : 1,
-"optional" : 1,
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"checkchanges" : true,
+"optional" : true,
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "extratextage",
@@ -858,8 +1048,11 @@
"description" : "The maximum age of the Extra Text File in seconds. After this time the contents of the file will no longer be displayed. Set to 0 to always display.",
"label" : "Max Age Of Extra",
"type" : "integer",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"valuedependson" : "extratext=*",
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "textlineheight",
@@ -869,8 +1062,9 @@
"description" : "The line height of the text in pixels. If increasing the font size causes the text to overlap then increase this number.",
"label" : "Line Height",
"type" : "integer",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "textx",
@@ -880,8 +1074,9 @@
"description" : "Text will begin this many pixels from the left.",
"label" : "Text X",
"type" : "integer",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "texty",
@@ -891,15 +1086,18 @@
"description" : "Text will begin this many pixels from the top.",
"label" : "Text Y",
"type" : "integer",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "fontname",
"default" : 0,
"description" : "Font name for the text overlay. Used for both large and small text.",
"label" : "Font Name",
-"type" : "select",
+"usage" : "capture",
+"carryforward" : true,
+"type" : "select_integer",
"options" : [
{"value" : 0, "label" : "Simplex"},
{"value" : 1, "label" : "Plain"},
@@ -910,8 +1108,8 @@
{"value" : 6, "label" : "Script Simplex"},
{"value" : 7, "label" : "Script Complex"}
],
-"generic" : 1,
-"display" : 1
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "fontcolor",
@@ -920,8 +1118,9 @@
"description" : "Blue, Green, and Red (BGR) values of text color. NOTE: When using RAW 16 only the first two numbers are used i.e., 255 128 0.",
"label" : "Font Color",
"type" : "text",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "smallfontcolor",
@@ -929,22 +1128,24 @@
"description" : "BGR value of text color. NOTE: When using RAW 16 only the first two numbers are used i.e., 255 128 0.",
"label" : "Small Font Color",
"type" : "text",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "fonttype",
"default" : 0,
"description" : "Choose between smooth font lines (antialiased), 8-pixel, or 4 pixel connectivity (harder edges).",
"label" : "Font Smoothness",
-"type" : "select",
+"type" : "select_integer",
+"usage" : "capture",
"options" : [
{"value" : 0, "label" : "Antialiased"},
{"value" : 1, "label" : "8 connected"},
{"value" : 2, "label" : "4 connected"}
],
-"generic" : 1,
-"display" : 1
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "fontsize",
@@ -954,8 +1155,9 @@
"description" : "Text Font Size. The time, if displayed, will use this size; other text displayed will be about 20% smaller.",
"label" : "Font Size",
"type" : "float",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "fontline",
@@ -965,160 +1167,1346 @@
"description" : "How thick the text line should be.",
"label" : "Font Weight",
"type" : "integer",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
{
"name" : "outlinefont",
-"default" : 0,
+"default" : false,
"description" : "Adds a black outline to the text overlay to improve contrast.",
"label" : "Use Outline Font",
"type" : "boolean",
-"generic" : 1,
-"display" : 1
+"usage" : "capture",
+"carryforward" : true,
+"booldependsoff" : "overlaymethod",
+"action" : "reload"
},
+
{
-"name" : "AllskyMapHeader",
-"description" : "Allsky Map and Website Settings",
-"type" : "header",
-"display" : 1
+"name" : "postcapturetab========================================",
+"display" : false,
+"label" : "Post Capture",
+"type" : "header-tab"
},
{
-"name" : "displaySettings",
-"default" : 0,
-"description" : "Activate to add a link to the Allsky Website to display the settings on this page. Only applies if you have a local or remote Allsky Website.",
-"label" : "Display Settings",
+"name" : "postcaptureheader",
+"label" : "Post Capture Settings",
+"type" : "header"
+},
+{
+"name" : "imageremovebadlow",
+"minimum" : 0,
+"maximum" : 0.5,
+"default" : 0.1,
+"description" : "Delete images whose mean is below this value. 0 disables this check.",
+"label" : "Remove Bad Images Threshold Low",
+"type" : "float",
+"booldependson" : "savedaytimeimages OR savenighttimeimages"
+},
+{
+"name" : "imageremovebadhigh",
+"minimum" : 0,
+"maximum" : 0.5,
+"default" : 0.9,
+"description" : "Delete images whose mean is above this value. 0 disables this check.",
+"label" : "Remove Bad Images Threshold High",
+"type" : "float",
+"booldependson" : "savedaytimeimages OR savenighttimeimages"
+},
+{
+"name" : "imagecreatethumbnails",
+"default" : true,
+"description" : "Enable to create thumbnails of images. If you never look at them, disable this.",
+"label" : "Create Image Thumbnails",
"type" : "boolean",
-"checkchanges" : 1,
-"generic" : 1,
-"display" : 1
+"carryforward" : true,
+"booldependson" : "savedaytimeimages OR savenighttimeimages"
},
{
-"name" : "showonmap",
+"name" : "thumbnailsizex",
+"minimum" : 25,
+"maximum" : "500",
+"default" : 100,
+"description" : "Width of image and video thumbnails.",
+"label" : "Thumbnail Width",
+"type" : "integer",
+"carryforward" : true,
+"booldependson" : "savedaytimeimages OR savenighttimeimages"
+},
+{
+"name" : "thumbnailsizey",
+"minimum" : 20,
+"maximum" : "400",
+"default" : 75,
+"description" : "Height of image and video thumbnails.",
+"label" : "Thumbnail Height",
+"type" : "integer",
+"carryforward" : true,
+"booldependson" : "savedaytimeimages OR savenighttimeimages"
+},
+{
+"name" : "imageresizewidth",
+"minimum" : 2,
+"maximum" : "none",
"default" : 0,
-"description" : "Activate to have your camera appear on the Allsky Map .",
-"label" : "Show on Map",
+"description" : "Width of resized image before cropping. 0 means don't resize.",
+"label" : "Image Resize Width",
+"type" : "integer",
+"checkchanges" : true,
+"booldependson" : "takedaytimeimages OR takenighttimeimages"
+},
+{
+"name" : "imageresizeheight",
+"minimum" : 2,
+"maximum" : "none",
+"default" : 0,
+"description" : "Height of resized image before cropping. 0 means don't resize.",
+"label" : "Image Resize Height",
+"type" : "integer",
+"checkchanges" : true,
+"booldependson" : "takedaytimeimages OR takenighttimeimages"
+},
+{
+"name" : "imagecroptop",
+"minimum" : 0,
+"maximum" : "_max",
+"default" : 0,
+"description" : "Number of pixels to crop off the top of image.",
+"label" : "Image Crop Top",
+"type" : "integer",
+"checkchanges" : true,
+"booldependson" : "takedaytimeimages OR takenighttimeimages"
+},
+{
+"name" : "imagecropright",
+"minimum" : 0,
+"maximum" : "_max",
+"default" : 0,
+"description" : "Number of pixels to crop off the right side of image.",
+"label" : "Image Crop Right",
+"type" : "integer",
+"checkchanges" : true,
+"booldependson" : "takedaytimeimages OR takenighttimeimages"
+},
+{
+"name" : "imagecropbottom",
+"minimum" : 0,
+"maximum" : "_max",
+"default" : 0,
+"description" : "Number of pixels to crop off the bottom of image.",
+"label" : "Image Crop Bottom",
+"type" : "integer",
+"checkchanges" : true,
+"booldependson" : "takedaytimeimages OR takenighttimeimages"
+},
+{
+"name" : "imagecropleft",
+"minimum" : 0,
+"maximum" : "_max",
+"default" : 0,
+"description" : "Number of pixels to crop off the left side of image.",
+"label" : "Image Crop Left",
+"type" : "integer",
+"checkchanges" : true,
+"booldependson" : "takedaytimeimages OR takenighttimeimages"
+},
+
+{
+"name" : "timelapsetab========================================",
+"label" : "Timelapses",
+"type" : "header-tab"
+},
+{
+"name" : "timelapseheader",
+"label" : "Timelapse Settings",
+"type" : "header"
+},
+{
+"name" : "timelapsesubheader",
+"label" : "Daily Timelapse",
+"type" : "header-sub"
+},
+{
+"name" : "timelapsegenerate",
+"default" : true,
+"description" : "Enable to generate a timelapse video at the end of night.",
+"label" : "Generate",
+"label_prefix" : "Daily Timelapse",
"type" : "boolean",
-"checkchanges" : 1,
-"generic" : 1,
-"display" : 1
+"carryforward" : true,
+"booldependson" : "savedaytimeimages OR savenighttimeimages"
},
{
-"name" : "websiteurl",
-"default" : "",
-"description" : "The URL of your Allsky Website, for example: https://www.thomasjacquin.com/allsky. If your camera is not accessible on the Internet, leave this field empty. Must begin with http or https.",
-"label" : "Website URL",
-"type" : "widetext",
-"checkchanges" : 1,
-"optional" : 1,
-"generic" : 1,
-"display" : 1
+"name" : "timelapseupload",
+"default" : true,
+"description" : "Enable to upload the timelapse video to an Allsky Website and/or remote server.",
+"label" : "Upload",
+"label_prefix" : "Daily Timelapse",
+"type" : "boolean",
+"carryforward" : true,
+"booldependson" : "timelapsegenerate"
},
{
-"name" : "imageurl",
-"default" : "",
-"description" : "The URL of the image on your Allsky Website, for example: https://www.thomasjacquin.com/allsky/image.jpg. Right-click on the image and select Copy Image Address. If your camera is not accessible on the Internet, leave this field empty. Must begin with http or https.",
-"label" : "Image URL",
-"type" : "widetext",
-"checkchanges" : 1,
-"optional" : 1,
-"generic" : 1,
-"display" : 1
+"name" : "timelapseuploadthumbnail",
+"default" : true,
+"description" : "Enable to upload the timelapse video thumbnail.",
+"label" : "Upload Thumbnail",
+"label_prefix" : "Daily Timelapse",
+"type" : "boolean",
+"carryforward" : true,
+"booldependson" : "timelapsegenerate AND timelapseupload AND (uselocalwebsite OR useremotewebsite OR useremoteserver)"
},
{
-"name" : "location",
-"default" : "",
-"description" : "The location of your camera, for example: Whitehorse, YT. No need to enter country since it'll be obvious looking at the map. This setting and the remaining ones also appear on the Allsky Website, if installed.",
-"label" : "Location",
-"type" : "widetext",
-"checkchanges" : 1,
-"optional" : 1,
-"generic" : 1,
-"display" : 1
+"name" : "timelapsewidth",
+"minimum" : 0,
+"maximum" : "_max",
+"default" : 0,
+"description" : "Width of resized timelapse video. 0 disables resize.",
+"label" : "Width",
+"label_prefix" : "Daily Timelapse",
+"type" : "integer",
+"booldependson" : "timelapsegenerate"
},
{
-"name" : "owner",
-"default" : "",
-"description" : "The owner of the camera. It can be your name or an association or observatory, etc.",
-"label" : "Owner",
-"type" : "text",
-"checkchanges" : 1,
-"optional" : 1,
-"generic" : 1,
-"display" : 1
+"name" : "timelapseheight",
+"minimum" : 0,
+"maximum" : "_max",
+"default" : 0,
+"description" : "Height of resized timelapse video. 0 disables resize.",
+"label" : "Height",
+"label_prefix" : "Daily Timelapse",
+"type" : "integer",
+"booldependson" : "timelapsegenerate"
},
{
-"name" : "camera",
-"default" : "",
-"description" : "The type and model of your camera, for example: ZWO 224MC or RPi HQ.",
-"label" : "Camera",
-"type" : "widetext",
-"checkchanges" : 1,
-"optional" : 1,
-"display" : 1
+"name" : "timelapsebitrate",
+"minimum" : 100,
+"maximum" : 30000,
+"default" : 5000,
+"description" : "Bitrate (in K) of timelapse video. Higher values produce higher quality but larger files. Do NOT add k.",
+"label" : "Bitrate",
+"label_prefix" : "Daily Timelapse",
+"type" : "integer",
+"booldependson" : "timelapsegenerate"
},
{
-"name" : "lens",
-"default" : "",
-"description" : "The lens you're using on your camera, for example: Arecont 1.55.",
-"label" : "Lens",
-"type" : "text",
-"checkchanges" : 1,
-"optional" : 1,
-"display" : 1
+"name" : "timelapsefps",
+"minimum" : 1,
+"maximum" : 200,
+"default" : 25,
+"description" : "Frames Per Second (FPS) of timelapse video. Higher values will produce smoother, but faster videos.",
+"label" : "FPS",
+"label_prefix" : "Daily Timelapse",
+"type" : "integer",
+"carryforward" : true,
+"booldependson" : "timelapsegenerate"
},
{
-"name" : "computer",
+"name" : "timelapsekeepsequence",
+"default" : false,
+"description": "Use for debugging purposes only. Enable to keep the list of files used in creating the timelapse video.",
+"label" : "Keep Sequence",
+"label_prefix" : "Daily Timelapse",
+"type" : "boolean",
+"booldependson" : "timelapsegenerate"
+},
+{
+"name" : "timelapseextraparameters",
"default" : "",
-"description" : "The computer running your allsky camera, for example: Raspberry Pi 3, 4 GB.",
-"label" : "Computer",
+"description" : "Optional additional timelapse creation parameters. Run ffmpeg -? to see the options. If quality is poor or the video does not plan on Apple devices, try adding -level 3.1.",
+"label" : "Extra Parameters",
+"label_prefix" : "Daily Timelapse",
"type" : "widetext",
-"checkchanges" : 1,
-"optional" : 1,
-"generic" : 1,
-"display" : 1
+"carryforward" : true,
+"optional" : true,
+"booldependson" : "timelapsegenerate"
},
+
{
-"name" : "CameraHeading",
-"description" : "Camera Type",
-"type" : "header",
-"display" : 1
+"name" : "minitimelapseheader",
+"label" : "Mini-Timelapse",
+"type" : "header-sub"
},
{
-"name" : "cameraType",
-"default" : "",
-"description" : "The type of camera you are using. Select Refresh to reset the Camera Type and Model.",
-"label" : "Camera Type",
-"type" : "select",
-"options" : [
- {"value" : "RPi", "label" : "RPi"},
- {"value" : "ZWO", "label" : "ZWO"},
- {"value" : "Refresh", "label" : "Refresh"}
-],
-"checkchanges" : 1,
-"display" : 1
+"name" : "minitimelapsenumimages",
+"minimum" : 0,
+"maximum" : "none",
+"default" : 0,
+"description" : "Number of images in a mini-timelapse. 0 disables mini-timelapse creation.",
+"label" : "Number Of Images",
+"label_prefix" : "Mini-Timelapse",
+"type" : "integer",
+"carryforward" : true,
+"booldependson" : "savedaytimeimages OR savenighttimeimages"
},
{
-"name" : "cameraModel",
-"default" : "",
-"description" : "The model of camera you are using. To change it, change the Camera Type above.",
-"label" : "Camera Model",
-"type" : "readonly",
-"display" : 1
+"name" : "minitimelapseforcecreation",
+"default" : false,
+"description" : "Create a mini-timelapse even if Number Of Images isn't reached?",
+"label" : "Force Creation",
+"label_prefix" : "Mini-Timelapse",
+"type" : "boolean",
+"carryforward" : true,
+"valuedependson" : "minitimelapsenumimages=[1-9]*"
},
{
-"name" : "cameraNumber",
-"minimum" : 0,
+"name" : "minitimelapsefrequency",
+"minimum" : 1,
"maximum" : "none",
+"default" : 5,
+"description" : "Make a mini-timelapse every X images. If you have a slow Pi or short delays between images, set this to a higher number (i.e., not as often).",
+"label" : "Frequency",
+"label_prefix" : "Mini-Timelapse",
+"type" : "integer",
+"carryforward" : true,
+"valuedependson" : "minitimelapsenumimages=[1-9]*"
+},
+{
+"name" : "minitimelapseupload",
+"default" : false,
+"description" : "Enable to upload the mini-timelapse video to an Allsky Website and/or remote server.",
+"label" : "Upload",
+"label_prefix" : "Mini-Timelapse",
+"type" : "boolean",
+"carryforward" : true,
+"valuedependson" : "minitimelapsenumimages=[1-9]*"
+},
+{
+"name" : "minitimelapseuploadthumbnail",
+"default" : true,
+"description" : "Enable to upload the mini-timelapse video thumbnail.",
+"label" : "Upload Thumbnail",
+"label_prefix" : "Mini-Timelapse",
+"type" : "boolean",
+"carryforward" : true,
+"booldependson" : "minitimelapseupload AND (uselocalwebsite OR useremotewebsite OR useremoteserver)",
+"valuedependson" : "minitimelapsenumimages=[1-9]*"
+},
+{
+"name" : "minitimelapsewidth",
+"minimum" : 0,
+"maximum" : "_max",
+"default" : 0,
+"description" : "Width of resized mini-timelapse video. 0 disables resize.",
+"label" : "Width",
+"label_prefix" : "Mini-Timelapse",
+"type" : "integer",
+"valuedependson" : "minitimelapsenumimages=[1-9]*"
+},
+{
+"name" : "minitimelapseheight",
+"minimum" : 0,
+"maximum" : "_max",
+"default" : 0,
+"description" : "Height of resized mini-timelapse video. 0 disables resize.",
+"label" : "Height",
+"label_prefix" : "Mini-Timelapse",
+"type" : "integer",
+"valuedependson" : "minitimelapsenumimages=[1-9]*"
+},
+{
+"name" : "minitimelapsebitrate",
+"minimum" : 100,
+"maximum" : 30000,
+"default" : 2000,
+"description" : "Bitrate (in K) of timelapse video. Higher values produce higher quality but larger files. Do NOT add k.",
+"label" : "Bitrate",
+"label_prefix" : "Mini-Timelapse",
+"type" : "integer",
+"carryforward" : true,
+"valuedependson" : "minitimelapsenumimages=[1-9]*"
+},
+{
+"name" : "minitimelapsefps",
+"minimum" : 1,
+"maximum" : 200,
+"default" : 5,
+"description" : "Frames Per Second (FPS) of mini-timelapse video.",
+"label" : "FPS",
+"label_prefix" : "Mini-Timelapse",
+"type" : "integer",
+"carryforward" : true,
+"valuedependson" : "minitimelapsenumimages=[1-9]*"
+},
+{
+"name" : "timelapsebothsubheader",
+"label" : "Both Timelapses",
+"type" : "header-sub"
+},
+{
+"name" : "timelapsevcodec",
+"default" : "libx264",
+"description" : "Video encoder for timelapse. Rarely changed.",
+"label" : "VCODEC",
+"label_prefix" : "Timelapse",
+"type" : "text",
+"carryforward" : true,
+"comment" : "check using ffmpeg -encoder looking at argument 2 for ' libxs264 '",
+"booldependson" : "timelapsegenerate",
+"checkchanges" : true
+},
+{
+"name" : "timelapsepixfmt",
+"default" : "yuv420p",
+"description" : "Pixel format for timelapse. Rarely changed.",
+"label" : "Pixel format",
+"label_prefix" : "Timelapse",
+"type" : "text",
+"carryforward" : true,
+"booldependson" : "timelapsegenerate",
+"comment" : "check using ffmpeg -pix_fmts looking at argument 2 for ' yuv420p '",
+"checkchanges" : true
+},
+{
+"name" : "timelapsefflog",
+"default" : "warning",
+"description" : "Amount of information to display while creating a timelapse. Rarely changed.",
+"label" : "Log Level",
+"label_prefix" : "Timelapse",
+"type" : "select_text",
+"carryforward" : true,
+"options" : [
+ { "value" : "quiet", "label" : "No output" },
+ { "value" : "fatal", "label" : "Fatal Errors" },
+ { "value" : "error", "label" : "Errors" },
+ { "value" : "warning", "label" : "Warnings + Errors" },
+ { "value" : "info", "label" : "Info + Warnings + Errors" }
+],
+"booldependson" : "timelapsegenerate"
+},
+
+{
+"name" : "keogramstartrailstab========================================",
+"label" : "Keogram and Startrails",
+"type" : "header-tab"
+},
+{
+"name" : "timelapseheader",
+"label" : "Keogram and Startrails Settings",
+"type" : "header"
+},
+{
+"name" : "keogramsubheader",
+"label" : "Keograms",
+"type" : "header-sub"
+},
+{
+"name" : "keogramgenerate",
+"default" : true,
+"description" : "Enable to generate a keogram at the end of night.",
+"label" : "Generate",
+"label_prefix" : "Keograms",
+"type" : "boolean",
+"carryforward" : true,
+"booldependson" : "savedaytimeimages OR savenighttimeimages"
+},
+{
+"name" : "keogramupload",
+"default" : true,
+"description" : "Enable to upload the keogram to an Allsky Website and/or remote server.",
+"label" : "Upload",
+"label_prefix" : "Keograms",
+"type" : "boolean",
+"carryforward" : true,
+"booldependson" : "keogramgenerate AND (uselocalwebsite OR useremotewebsite OR useremoteserver)"
+},
+
+{
+"name" : "keogramexpand",
+"default" : true,
+"description" : "Enable to expand keograms to the image width.",
+"label" : "Expand",
+"label_prefix" : "Keograms",
+"type" : "boolean",
+"carryforward" : true,
+"booldependsoff" : "keogramgenerate"
+},
+{
+"name" : "keogramfontname",
+"default" : "simplex",
+"description" : "Font name.",
+"label" : "Font Name",
+"label_prefix" : "Keograms",
+"type" : "select_text",
+"options" : [
+ {"value" : "simplex", "label" : "Simplex"},
+ {"value" : "plain", "label" : "Plain"},
+ {"value" : "duplex", "label" : "Duplex"},
+ {"value" : "complex", "label" : "Complex"},
+ {"value" : "complexsmall", "label" : "Complex Small"},
+ {"value" : "triplex", "label" : "Triplex"},
+ {"value" : "scriptsimplex", "label" : "Script Simplex"},
+ {"value" : "scriptcomplex", "label" : "Script Complex"}
+],
+"carryforward" : true,
+"booldependson" : "keogramgenerate"
+},
+{
+"name" : "keogramfontcolor",
+"default" : "#fff",
+"description" : "Font color.",
+"label" : "Font Color",
+"label_prefix" : "Keograms",
+"type" : "color",
+"booldependson" : "keogramgenerate"
+},
+{
+"name" : "keogramfontsize",
+"minimum" : 1.0,
+"maximum" : 10.0,
+"default" : 2.0,
+"description" : "Font size.",
+"label" : "Font Size",
+"label_prefix" : "Keograms",
+"type" : "integer",
+"booldependson" : "keogramgenerate"
+},
+{
+"name" : "keogramlinethickness",
+"minimum" : 1,
+"maximum" : 5,
+"default" : 3,
+"description" : "Font line thickness.",
+"label" : "Font Line Thickness",
+"label_prefix" : "Keograms",
+"type" : "integer",
+"booldependson" : "keogramgenerate"
+},
+{
+"name" : "keogramextraparameters",
+"default" : "",
+"description" : "Optional additional keogram creation parameters. Run ~/allsky/bin/keogram --help for a list of options.",
+"label" : "Extra Parameters",
+"label_prefix" : "Keograms",
+"type" : "widetext",
+"optional" : true,
+"booldependson" : "keogramgenerate"
+},
+
+{
+"name" : "startrailssubheader",
+"label" : "Startrails",
+"type" : "header-sub"
+},
+{
+"name" : "startrailsgenerate",
+"default" : true,
+"description" : "Enable to generate a startrails at the end of night.",
+"label" : "Generate",
+"label_prefix" : "Startrails",
+"type" : "boolean",
+"carryforward" : true,
+"booldependson" : "savedaytimeimages OR savenighttimeimages"
+},
+{
+"name" : "startrailsbrightnessthreshold",
+"minimum" : 0.0,
+"maximum" : 1.0,
+"default" : 0.1,
+"description" : "Images with a brightness higher than this threshold will not be included in the startrails.",
+"label" : "Brightness Threshold",
+"label_prefix" : "Startrails",
+"type" : "float",
+"booldependson" : "startrailsgenerate"
+},
+{
+"name" : "startrailsupload",
+"default" : true,
+"description" : "Enable to upload the startrails to an Allsky Website and/or remote server.",
+"label" : "Upload",
+"label_prefix" : "Startrails",
+"type" : "boolean",
+"carryforward" : true,
+"booldependson" : "startrailsgenerate AND (uselocalwebsite OR useremotewebsite OR useremoteserver)"
+},
+{
+"name" : "startrailsextraparameters",
+"default" : "",
+"description" : "Optional additional startrails creation parameters. Run ~/allsky/bin/startrails --help for a list of options.",
+"label" : "Extra Parameters",
+"label_prefix" : "Startrails",
+"type" : "widetext",
+"optional" : true,
+"booldependson" : "startrailsgenerate"
+},
+
+{
+"name" : "websitetab========================================",
+"label" : "Website",
+"type" : "header-tab"
+},
+{
+"name" : "websiteheader",
+"label" : "Websites and Remote Server Settings",
+"type" : "header"
+},
+{
+"name" : "imageresizeuploadswidth",
+"minimum" : 0,
+"maximum" : "_max",
+"default" : 0,
+"description" : "Resized width of uploaded images. 0 means don't resize.",
+"label" : "Resize Uploaded Images Width",
+"type" : "integer",
+"booldependson" : "imageupload"
+},
+{
+"name" : "imageresizeuploadsheight",
+"minimum" : 0,
+"maximum" : "_max",
+"default" : 0,
+"description" : "Resized height of uploaded images. 0 means don't resize.",
+"label" : "Resize Uploaded Images Height",
+"type" : "integer",
+"booldependson" : "imageupload"
+},
+{
+"name" : "imageuploadfrequency",
+"minimum" : 0,
+"maximum" : "none",
+"default" : 1,
+"description" : "How often should images be uploaded to an Allsky Website and/or remote server? 0 never uploads images, 1 uploads every frame, 2 every other frame, etc.",
+"label" : "Upload Every X Images",
+"type" : "integer",
+"carryforward" : true,
+"booldependson" : "uselocalwebsite OR useremotewebsite OR useremoteserver"
+},
+{
+"name" : "displaysettings",
+"default" : false,
+"description" : "Enable to add a link on the Allsky Website to display the settings on this page.",
+"label" : "Display Settings",
+"type" : "boolean",
+"carryforward" : true,
+"checkchanges" : true,
+"booldependson" : "uselocalwebsite OR useremotewebsite OR useremoteserver"
+},
+{
+"name" : "localwebsiteheader",
+"label" : "Local Website",
+"type" : "header-sub"
+},
+{
+"name" : "uselocalwebsite",
+"description" : "Enable to use the local Allsky Website. You should configure it in the Editor page first.",
+"default" : false,
+"label" : "Use Local Website",
+"type" : "boolean",
+"carryforward" : true,
+"checkchanges" : true,
+"popup-yesno" : "Do you want to remove all saved images, keograms, startrails, and videos in the local Website?",
+"popup-yesno-value" : 0
+},
+{
+"name" : "daystokeeplocalwebsite",
+"minimum" : 0,
+"maximum" : "none",
+"default" : 0,
+"description" : "Number of days of images and videos to keep on the Pi's Website. 0 keeps all days.",
+"label" : "Days To Keep on Pi Website",
+"type" : "integer",
+"carryforward" : true,
+"checkchanges" : true,
+"booldependson" : "uselocalwebsite"
+},
+{
+"name" : "remotewebsiteheader",
+"label" : "Remote Website",
+"type" : "header-sub"
+},
+{
+"name" : "useremotewebsite",
+"default" : false,
+"description" : "Enable to use a remote Allsky Website. See the Allsky Documentation for how to install the Website.",
+"label" : "Use Remote Website",
+"type" : "boolean",
+"carryforward" : true,
+"checkchanges" : true
+},
+{
+"name" : "daystokeepremotewebsite",
+"minimum" : 0,
+"maximum" : "none",
+"default" : 0,
+"description" : "Number of days of images and videos to keep on the remote Website. 0 keeps all days.",
+"label" : "Days To Keep on Remote Website",
+"type" : "integer",
+"carryforward" : true,
+"checkchanges" : true,
+"booldependson" : "useremotewebsite",
+"display" : false
+},
+{
+"name" : "remotewebsiteimagedir",
+"default" : "allsky",
+"description" : "Name of the top-level remote Website directory where images go.",
+"label" : "Image Directory",
+"label_prefix" : "Remote Website",
+"type" : "text",
+"carryforward" : true,
+"checkchanges" : true,
+"booldependson" : "useremotewebsite",
+"valuedependson" : "remotewebsiteprotocol=*ftp*",
+"optional" : true
+},
+{
+"name" : "remotewebsiteprotocol",
+"default" : "ftps",
+"description" : "Protocol for remote Website",
+"label" : "Protocol",
+"label_prefix" : "Remote Website",
+"type" : "select_text",
+"options" : [
+ {"value" : "ftps", "label" : "ftps"},
+ {"value" : "ftp", "label" : "ftp"},
+ {"value" : "sftp", "label" : "sftp"},
+ {"value" : "scp", "label" : "scp"},
+ {"value" : "rsync", "label" : "rsync"},
+ {"value" : "s3", "label" : "S3"},
+ {"value" : "gcs", "label" : "GCS"}
+],
+"carryforward" : true,
+"checkchanges" : true,
+"booldependson" : "useremotewebsite"
+},
+{
+"name" : "REMOTEWEBSITE_HOST",
+"default" : "",
+"description" : "Name of server hosting the remote Allsky Website.",
+"label" : "Server Name",
+"label_prefix" : "Remote Website",
+"type" : "widetext",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremotewebsite",
+"optional" : true
+},
+{
+"name" : "REMOTEWEBSITE_PORT",
+"default" : "",
+"description" : "Optional port required by server. Rarely required.",
+"label" : "Port",
+"label_prefix" : "Remote Website",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremotewebsite",
+"optional" : true
+},
+{
+"name" : "REMOTEWEBSITE_USER",
+"default" : "",
+"description" : "Username of the login on the remote Website server.",
+"label" : "User Name",
+"label_prefix" : "Remote Website",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremotewebsite",
+"optional" : true
+},
+{
+"name" : "REMOTEWEBSITE_PASSWORD",
+"default" : "",
+"description" : "Password of the login on the remote Website server.",
+"label" : "Password",
+"label_prefix" : "Remote Website",
+"type" : "password",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremotewebsite",
+"optional" : true
+},
+{
+"name" : "REMOTEWEBSITE_LFTP_COMMANDS",
+"default" : "",
+"description" : "Special commands needed when connecting to an FTP server.",
+"label" : "FTP Commands",
+"label_prefix" : "Remote Website",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremotewebsite",
+"valuedependson" : "remotewebsiteprotocol=*ftp*",
+"optional" : true
+},
+{
+"name" : "REMOTEWEBSITE_SSH_KEY_FILE",
+"default" : "",
+"description" : "Path on the Pi to the SSH key file.",
+"label" : "SSH Key File",
+"label_prefix" : "Remote Website",
+"type" : "widetext",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremotewebsite",
+"valuedependson" : "remotewebsiteprotocol=scp|rsync",
+"optional" : true
+},
+{
+"name" : "REMOTEWEBSITE_AWS_CLI_DIR",
+"default" : "",
+"description" : "AWS CLI directory where the AWS CLI tools are installed. Often stored in ${HOME}/.local/bin",
+"label" : "AWS CLI Directory",
+"label_prefix" : "Remote Website",
+"type" : "widetext",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremotewebsite",
+"valuedependson" : "remotewebsiteprotocol=s3",
+"optional" : true
+},
+{
+"name" : "REMOTEWEBSITE_S3_BUCKET",
+"default" : "allskybucket",
+"description" : "Name of S3 bucket where files will be upload.",
+"label" : "S3 Bucket",
+"label_prefix" : "Remote Website",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremotewebsite",
+"valuedependson" : "remotewebsiteprotocol=s3",
+"optional" : true
+},
+{
+"name" : "REMOTEWEBSITE_S3_ACL",
+"default" : "private",
+"description" : "S3 Access Control List (ACL).",
+"label" : "S3 ACL",
+"label_prefix" : "Remote Website",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremotewebsite",
+"valuedependson" : "remotewebsiteprotocol=s3",
+"optional" : true
+},
+{
+"name" : "REMOTEWEBSITE_GCS_BUCKET",
+"default" : "allskybucket",
+"description" : "Name of GCS bucket where files will be upload.",
+"label" : "GCS Bucket",
+"label_prefix" : "Remote Website",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremotewebsite",
+"valuedependson" : "remotewebsiteprotocol=gcs",
+"optional" : true
+},
+{
+"name" : "REMOTEWEBSITE_GCS_ACL",
+"default" : "private",
+"description" : "GCS Access Control List (ACL).",
+"label" : "GCS ACL",
+"label_prefix" : "Remote Website",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremotewebsite",
+"valuedependson" : "remotewebsiteprotocol=gcs",
+"optional" : true
+},
+{
+"name" : "remotewebsiteimageuploadoriginalname",
+"default" : false,
+"description" : "Enable to upload images using YYYYMMDDHHMMSS naming.",
+"label" : "Upload With Original Name",
+"label_prefix" : "Remote Website",
+"type" : "boolean",
+"carryforward" : true,
+"valuedependson" : "imageuploadfrequency=[1-9]*"
+},
+{
+"name" : "remotewebsitevideodestinationname",
+"default" : "",
+"description" : "Optional name of the remote video file.",
+"label" : "Remote Video File Name",
+"label_prefix" : "Remote Website",
+"type" : "text",
+"carryforward" : true,
+"booldependson" : "useremotewebsite",
+"optional" : true
+},
+{
+"name" : "remotewebsitekeogramdestinationname",
+"default" : "",
+"description" : "Optional name of the remote keogram file.",
+"label" : "Remote Keogram File Name",
+"label_prefix" : "Remote Website",
+"type" : "text",
+"carryforward" : true,
+"booldependson" : "useremotewebsite",
+"optional" : true
+},
+{
+"name" : "remotewebsitestartrailsdestinationname",
+"default" : "",
+"description" : "Optional name of the remote startrails file.",
+"label" : "Remote Startrails File Name",
+"label_prefix" : "Remote Website",
+"type" : "text",
+"carryforward" : true,
+"booldependson" : "useremotewebsite",
+"optional" : true
+},
+{
+"name" : "remotewebsiteurl",
+"default" : "",
+"description" : "The URL of your Allsky Website, for example: https://mywebsite.com/allsky/. Must begin with http or https.",
+"label" : "Website URL",
+"label_prefix" : "Remote Website",
+"type" : "widetext",
+"carryforward" : true,
+"checkchanges" : true,
+"booldependson" : "showonmap OR useremotewebsite OR remotewebsiteimageurl",
+"optional" : true
+},
+{
+"name" : "remotewebsiteimageurl",
+"default" : "",
+"description" : "The URL of the image on your Allsky Website, for example: https://mywebsite.com/allsky/image.jpg. Must begin with http or https.",
+"label" : "Image URL",
+"label_prefix" : "Remote Website",
+"type" : "widetext",
+"carryforward" : true,
+"checkchanges" : true,
+"booldependson" : "showonmap OR useremotewebsite OR remotewebsiteurl",
+"optional" : true
+},
+
+
+{
+"name" : "remoteserverheader",
+"label" : "Remote Server",
+"type" : "header-sub"
+},
+{
+"name" : "useremoteserver",
+"default" : false,
+"description" : "This is a remote server NOT running the Allsky Website. See the documentation for the necessary directory layout.",
+"label" : "Use Remote Server",
+"type" : "boolean",
+"carryforward" : true,
+"checkchanges" : true
+},
+{
+"name" : "remoteserverimagedir",
+"default" : "",
+"description" : "Name of the top-level remote server directory where images go.",
+"label" : "Image Directory",
+"label_prefix" : "Remote Server",
+"type" : "text",
+"carryforward" : true,
+"checkchanges" : true,
+"booldependson" : "useremoteserver",
+"optional" : true
+},
+{
+"name" : "remoteserverprotocol",
+"default" : "ftps",
+"description" : "Protocol for remote server",
+"label" : "Protocol",
+"label_prefix" : "Remote Server",
+"type" : "select_text",
+"options" : [
+ {"value" : "ftps", "label" : "ftps"},
+ {"value" : "ftp", "label" : "ftp"},
+ {"value" : "sftp", "label" : "sftp"},
+ {"value" : "scp", "label" : "scp"},
+ {"value" : "rsync", "label" : "rsync"},
+ {"value" : "s3", "label" : "S3"},
+ {"value" : "gcs", "label" : "GCS"}
+],
+"carryforward" : true,
+"checkchanges" : true,
+"booldependson" : "useremoteserver"
+},
+{
+"name" : "REMOTESERVER_HOST",
+"default" : "",
+"description" : "Name of remote server NOT hosting an Allsky Website.",
+"label" : "Server Name",
+"label_prefix" : "Remote Server",
+"type" : "widetext",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremoteserver",
+"optional" : true
+},
+{
+"name" : "REMOTESERVER_PORT",
+"default" : "",
+"description" : "Optional port required by remote server. Rarely required.",
+"label" : "Port",
+"label_prefix" : "Remote Server",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremoteserver",
+"optional" : true
+},
+{
+"name" : "REMOTESERVER_USER",
+"default" : "",
+"description" : "Username of the login on the remote server.",
+"label" : "User Name",
+"label_prefix" : "Remote Server",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremoteserver",
+"optional" : true
+},
+{
+"name" : "REMOTESERVER_PASSWORD",
+"default" : "",
+"description" : "Password of the remote server login.",
+"label" : "Password",
+"label_prefix" : "Remote Server",
+"type" : "password",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremoteserver",
+"optional" : true
+},
+{
+"name" : "REMOTESERVER_LFTP_COMMANDS",
+"default" : "",
+"description" : "Special commands needed when connecting to an FTP server.",
+"label" : "FTP Commands",
+"label_prefix" : "Remote Server",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremoteserver",
+"valuedependson" : "remoteserverprotocol=*ftp*",
+"optional" : true
+},
+{
+"name" : "REMOTESERVER_SSH_KEY_FILE",
+"default" : "",
+"description" : "Path on the Pi to the SSH key file.",
+"label" : "SSH Key File",
+"label_prefix" : "Remote Server",
+"type" : "widetext",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremoteserver",
+"valuedependson" : "remoteserverprotocol=scp|rsync",
+"optional" : true
+},
+{
+"name" : "REMOTESERVER_AWS_CLI_DIR",
+"default" : "",
+"description" : "AWS CLI directory where the AWS CLI tools are installed. Often stored in ${HOME}/.local/bin",
+"label" : "AWS CLI Directory",
+"label_prefix" : "Remote Server",
+"type" : "widetext",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremoteserver",
+"valuedependson" : "remoteserverprotocol=s3",
+"optional" : true
+},
+{
+"name" : "REMOTESERVER_S3_BUCKET",
+"default" : "allskybucket",
+"description" : "Name of S3 bucket where files will be upload.",
+"label" : "S3 Bucket",
+"label_prefix" : "Remote Server",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremoteserver",
+"valuedependson" : "remoteserverprotocol=s3",
+"optional" : true
+},
+{
+"name" : "REMOTESERVER_S3_ACL",
+"default" : "private",
+"description" : "S3 Access Control List (ACL).",
+"label" : "S3 ACL",
+"label_prefix" : "Remote Server",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremoteserver",
+"valuedependson" : "remoteserverprotocol=s3",
+"optional" : true
+},
+{
+"name" : "REMOTESERVER_GCS_BUCKET",
+"default" : "allskybucket",
+"description" : "Name of GCS bucket where files will be upload.",
+"label" : "GCS Bucket",
+"label_prefix" : "Remote Server",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremoteserver",
+"valuedependson" : "remoteserverprotocol=gcs",
+"optional" : true
+},
+{
+"name" : "REMOTESERVER_GCS_ACL",
+"default" : "private",
+"description" : "GCS Access Control List (ACL).",
+"label" : "GCS ACL",
+"label_prefix" : "Remote Server",
+"type" : "text",
+"checkchanges" : true,
+"source" : "${ALLSKY_ENV}",
+"booldependson" : "useremoteserver",
+"valuedependson" : "remoteserverprotocol=gcs",
+"optional" : true
+},
+{
+"name" : "remoteserverimageuploadoriginalname",
+"default" : false,
+"description" : "Enable to upload images using YYYYMMDDHHMMSS naming.",
+"label" : "Upload With Original Name",
+"label_prefix" : "Remote Server",
+"type" : "boolean",
+"carryforward" : true,
+"valuedependson" : "imageuploadfrequency=[1-9]*"
+},
+{
+"name" : "remoteservervideodestinationname",
+"default" : "",
+"description" : "Optional name of the remote video file.",
+"label" : "Remote Video File Name",
+"label_prefix" : "Remote Server",
+"type" : "text",
+"carryforward" : true,
+"booldependson" : "useremoteserver",
+"optional" : true
+},
+{
+"name" : "remoteserverkeogramdestinationname",
+"default" : "",
+"description" : "Optional name of the remote keogram file.",
+"label" : "Remote Keogram File Name",
+"label_prefix" : "Remote Server",
+"type" : "text",
+"carryforward" : true,
+"booldependson" : "useremoteserver",
+"optional" : true
+},
+{
+"name" : "remoteserverstartrailsdestinationname",
+"default" : "",
+"description" : "Optional name of the remote startrails file.",
+"label" : "Remote Startrails File Name",
+"label_prefix" : "Remote Server",
+"type" : "text",
+"carryforward" : true,
+"booldependson" : "useremoteserver",
+"optional" : true
+},
+
+{
+"name" : "allskymaptab========================================",
+"label" : "Map",
+"type" : "header-tab"
+},
+{
+"name" : "allskymapheader",
+"label" : "Allsky Map Settings",
+"type" : "header"
+},
+{
+"name" : "showonmap",
+"default" : false,
+"description" : "Enable to have your camera appear on the Allsky Map .",
+"label" : "Show on Map",
+"type" : "boolean",
+"carryforward" : true,
+"checkchanges" : true,
+"booldependson" : "uselocalwebsite OR useremotewebsite"
+},
+{
+"name" : "location",
+"default" : "",
+"description" : "The location of your camera, for example: Whitehorse, YT. This setting and the remaining ones also appear on the Allsky Website, if installed.",
+"label" : "Location",
+"type" : "widetext",
+"carryforward" : true,
+"checkchanges" : true,
+"optional" : true,
+"booldependson" : "showonmap OR useremotewebsite OR useremoteserver"
+},
+{
+"name" : "owner",
+"default" : "",
+"description" : "The owner of the camera. It can be your name, an association, or observatory, etc.",
+"label" : "Owner",
+"type" : "text",
+"carryforward" : true,
+"checkchanges" : true,
+"optional" : true,
+"booldependson" : "showonmap OR useremotewebsite OR useremoteserver"
+},
+{
+"name" : "camera",
+"default" : "",
+"description" : "The type and model of your camera, for example: ZWO 224MC or RPi HQ. Set automatically.",
+"label" : "Camera",
+"type" : "widetext",
+"checkchanges" : true,
+"optional" : true,
+"booldependson" : "showonmap OR useremotewebsite OR useremoteserver"
+},
+{
+"name" : "lens",
+"default" : "",
+"description" : "The lens you're using on your camera, for example: Arecont 1.55.",
+"label" : "Lens",
+"type" : "text",
+"checkchanges" : true,
+"optional" : true,
+"booldependson" : "showonmap OR useremotewebsite OR useremoteserver"
+},
+{
+"name" : "computer",
+"default" : "",
+"description" : "The computer running your allsky camera, for example: Raspberry Pi 3, 4 GB. Set automatically.",
+"label" : "Computer",
+"type" : "widetext",
+"carryforward" : true,
+"checkchanges" : true,
+"optional" : true,
+"booldependson" : "showonmap OR useremotewebsite OR useremoteserver"
+},
+
+{
+"name" : "webuitab========================================",
+"label" : "WebUI",
+"type" : "header-tab"
+},
+{
+"name" : "webuiheading",
+"label" : "WebUI Configuration",
+"type" : "header"
+},
+{
+"name" : "imagessortorder",
+"default" : "ascending",
+"description" : "The order the images on the 'Images' page are sorted in. 'Ascending' is oldest to newest. 'Descending' is newest to oldest.",
+"label" : "Images Sort Order",
+"type" : "select_text",
+"carryforward" : true,
+"options" : [
+ {"value" : "ascending", "label" : "Ascending"},
+ {"value" : "descending", "label" : "Descending"}
+]
+},
+{
+"name" : "showupdatedmessage",
+"default" : true,
+"description" : "Disable to hide the Daytime images updated every... message in the Live View page.",
+"label" : "Show Updated Message",
+"type" : "boolean",
+"carryforward" : true
+},
+{
+"name" : "uselogin",
+"default" : true,
+"description" : "Determines if you need to login to the WebUI or not. If your Pi is accessible on the Internet, do NOT turn this off!!.",
+"label" : "Require WebUI Login",
+"type" : "boolean",
+"checkchanges" : true,
+"carryforward" : true
+},
+{
+"name" : "notificationimages",
+"default" : true,
+"description" : "Enable to display notification images, e.g., 'Camera is off during the day'. While these messages appear in the WebUI and Allsky Website, they are not saved so don't appear in timelapse, startrails, or keograms.",
+"label" : "Notification Images",
+"type" : "boolean",
+"usage" : "capture",
+"carryforward" : true,
+"action" : "reload"
+},
+{
+"name" : "webuidatafiles",
+"default" : "",
+"description" : "See the documentation for a description of this setting.",
+"label" : "System Page Additions",
+"type" : "widetext",
+"carryforward" : true,
+"optional" : true
+},
+{
+"name" : "daytimeoverlay",
+"settingsonly" : true,
+"default" : "",
+"description" : "The overlay file to use during daytime",
+"label" : "NOT DISPLAYED IN WebUI",
+"type" : "text"
+},
+{
+"name" : "nighttimeoverlay",
+"settingsonly" : true,
+"default" : "",
+"description" : "The overlay file to use during nighttime",
+"label" : "NOT DISPLAYED IN WebUI",
+"type" : "text"
+},
+
+{
+
+"name" : "cameratab========================================",
+"label" : "Camera Type",
+"type" : "header-tab"
+},
+{
+"name" : "cameraheading",
+"label" : "Camera",
+"type" : "header"
+},
+{
+"name" : "cameratype",
+"default" : "",
+"description" : "The type of camera you are using. To change to a camera of a different type, select the new type then press the 'Save changes' button, THEN select the new Camera Model.",
+"label" : "Camera Type",
+"type" : "select_text",
+"options" : [
+ "cameratype_values"
+],
+"checkchanges" : true,
+"action" : "restart"
+},
+{
+"name" : "cameramodel",
+"default" : "",
+"description" : "The model of camera you are using.",
+"label" : "Camera Model",
+"readonly" : true,
+"type" : "select_text",
+"options" : [
+ "cameramodel_values"
+],
+"usage" : "capture",
+"checkchanges" : true,
+"action" : "restart"
+},
+{
+"name" : "cameranumber",
+"settingsonly" : true,
"default" : 0,
"description" : "If multiple cameras are connected to the Pi, this is the camera number (starts at 0).",
"label" : "Camera Number",
"type" : "integer",
-"checkchanges" : 1,
-"displayxxx" : "_display",
-"display" : 0
+"usage" : "capture",
+"checkchanges" : true,
+"action" : "restart"
},
+
{
-"name" : "XX_END_XX"
+"name" : "XX_END_XX",
+"type" : "boolean"
}
]
diff --git a/config_repo/overlay/config/fields.json b/config_repo/overlay/config/fields.json
index ee7f1c315..61aa6e350 100755
--- a/config_repo/overlay/config/fields.json
+++ b/config_repo/overlay/config/fields.json
@@ -5,7 +5,7 @@
"name": "${DATE}",
"description": "Date Image Taken",
"format": "%d-%m-%Y",
- "sample": "DATE",
+ "sample": "10-07-2024",
"type": "Date",
"source": "System"
},
@@ -14,7 +14,7 @@
"name": "${TIME}",
"description": "Time Image Taken",
"format": "%H:%M:%S",
- "sample": "TIME",
+ "sample": "21:04:05",
"type": "Time",
"source": "System"
},
@@ -48,7 +48,7 @@
{
"id": 5,
"name": "${EXPOSURE_US}",
- "description": "Frame Exposure Duration",
+ "description": "Frame Exposure Duration in us",
"format": "{:n}",
"sample": "10000",
"type": "Number",
@@ -66,7 +66,7 @@
{
"id": 7,
"name": "${sEXPOSURE}",
- "description": "Frame Exposure Auto String",
+ "description": "Frame Exposure String",
"format": "",
"sample": "32.00 ms (0.03 sec)",
"type": "Text",
@@ -85,8 +85,8 @@
"id": 9,
"name": "${GAIN}",
"description": "Camera Gain Amount",
- "format": "",
- "sample": "180",
+ "format": "{:.2f}",
+ "sample": "120.12",
"type": "Number",
"source": "System"
},
@@ -101,24 +101,15 @@
},
{
"id": 11,
- "name": "${BRIGHTNESS}",
- "description": "Brightness Amount",
- "format": "",
- "sample": "50",
- "type": "Number",
- "source": "System"
- },
- {
- "id": 12,
"name": "${MEAN}",
"description": "Mean Brightness Amount",
- "format": "",
+ "format": "{:.2f}",
"sample": "",
"type": "Number",
"source": "System"
},
{
- "id": 13,
+ "id": 12,
"name": "${AUTOWB}",
"description": "Auto White Balance Flag",
"format": "",
@@ -127,7 +118,7 @@
"source": "System"
},
{
- "id": 14,
+ "id": 13,
"name": "${sAUTOAWB}",
"description": "Auto White Balance Auto String",
"format": "",
@@ -136,25 +127,25 @@
"source": "System"
},
{
- "id": 15,
+ "id": 14,
"name": "${WBR}",
"description": "White Balance RED Amount",
- "format": "",
+ "format": "{:.2f}",
"sample": "3.47",
"type": "Number",
"source": "System"
},
{
- "id": 16,
+ "id": 15,
"name": "${WBB}",
"description": "White Balance Blue Amount",
- "format": "",
+ "format": "{:.2f}",
"sample": "1.00",
"type": "Number",
"source": "System"
},
{
- "id": 17,
+ "id": 16,
"name": "${FLIP}",
"description": "Flip",
"format": "",
@@ -163,34 +154,34 @@
"source": "System"
},
{
- "id": 18,
+ "id": 17,
"name": "${BIN}",
"description": "Binning",
- "format": "",
+ "format": "{:n}",
"sample": "1",
"type": "Number",
"source": "System"
},
{
- "id": 19,
+ "id": 18,
"name": "${BIT_DEPTH}",
"description": "Bit Depth",
- "format": "",
+ "format": "{:n}",
"sample": "12",
"type": "Number",
"source": "System"
},
{
- "id": 20,
+ "id": 19,
"name": "${FOCUS}",
"description": "Focus Metric",
- "format": "",
+ "format": "{:n}",
"sample": "",
"type": "Number",
"source": "System"
},
{
- "id": 21,
+ "id": 20,
"name": "${25544ALT}",
"description": "ISS Altitude",
"format": "",
@@ -199,7 +190,7 @@
"source": "System"
},
{
- "id": 22,
+ "id": 21,
"name": "${25544AZ}",
"description": "ISS Azimuth",
"format": "",
@@ -208,7 +199,7 @@
"source": "System"
},
{
- "id": 23,
+ "id": 22,
"name": "${25544VISIBLE}",
"description": "ISS Visible Flag",
"format": "",
@@ -217,7 +208,7 @@
"source": "System"
},
{
- "id": 24,
+ "id": 23,
"name": "${MOON_ELEVATION}",
"description": "Moon Altitude",
"format": "",
@@ -226,7 +217,7 @@
"source": "System"
},
{
- "id": 25,
+ "id": 24,
"name": "${MOON_AZIMUTH}",
"description": "Moon Azimuth",
"format": "",
@@ -235,7 +226,7 @@
"source": "System"
},
{
- "id": 26,
+ "id": 25,
"name": "${MOON_ILLUMINATION}",
"description": "Moon Illumination Percent",
"format": "{:.1f}",
@@ -244,61 +235,61 @@
"source": "System"
},
{
- "id": 27,
+ "id": 26,
"name": "${MOON_SYMBOL}",
- "description": "Moon Font Symbol",
+ "description": "Moon Font Symbol - must use moon_phases font",
"format": "",
"sample": "T",
"type": "Text",
"source": "System"
},
{
- "id": 28,
+ "id": 27,
"name": "${SUN_DAWN}",
"description": "Dawn",
"format": "%d-%m-%Y %H:%M:%S",
- "sample": "2023-07-10 05:38:27",
+ "sample": "10-07-2024 05:38:27",
"type": "Date",
"source": "System"
},
{
- "id": 29,
+ "id": 28,
"name": "${SUN_SUNRISE}",
"description": "Sunrise",
"format": "%d-%m-%Y %H:%M:%S",
- "sample": "2023-07-10 06:06:11",
+ "sample": "10-07-2024 06:06:11",
"type": "Date",
"source": "System"
},
{
- "id": 30,
+ "id": 29,
"name": "${SUN_NOON}",
"description": "Noon",
"format": "%d-%m-%Y %H:%M:%S",
- "sample": "2023-07-10 12:02:50",
+ "sample": "10-07-2024 12:02:50",
"type": "Date",
"source": "System"
},
{
- "id": 31,
+ "id": 30,
"name": "${SUN_SUNSET}",
"description": "Sunset",
"format": "%d-%m-%Y %H:%M:%S",
- "sample": "2023-07-10 18:59:28",
+ "sample": "10-07-2024 18:59:28",
"type": "Date",
"source": "System"
},
{
- "id": 32,
+ "id": 31,
"name": "${SUN_DUSK}",
"description": "Dusk",
"format": "%d-%m-%Y %H:%M:%S",
- "sample": "2023-07-11 18:27:12",
+ "sample": "10-07-2024 18:27:12",
"type": "Date",
"source": "System"
},
{
- "id": 33,
+ "id": 32,
"name": "${SUN_AZIMUTH}",
"description": "Sun Azimuth",
"format": "{:.1f}",
@@ -307,7 +298,7 @@
"source": "System"
},
{
- "id": 34,
+ "id": 33,
"name": "${SUN_ELEVATION}",
"description": "Sun Elevation",
"format": "{:.1f}",
@@ -316,7 +307,7 @@
"source": "System"
},
{
- "id": 35,
+ "id": 34,
"name": "${CAMERA_TYPE}",
"description": "Camera Type",
"format": "",
@@ -325,7 +316,7 @@
"source": "System"
},
{
- "id": 36,
+ "id": 35,
"name": "${CAMERA_MODEL}",
"description": "Camera Model",
"format": "",
@@ -334,7 +325,7 @@
"source": "System"
},
{
- "id": 37,
+ "id": 36,
"name": "${AUTOUSB}",
"description": "AUTOUSB Flag (ZWO Only)",
"format": "",
@@ -343,16 +334,16 @@
"source": "System"
},
{
- "id": 38,
+ "id": 37,
"name": "${USB}",
"description": "USB Bandwidth (ZWO Only)",
- "format": "",
+ "format": "{:n}",
"sample": "55",
"type": "Number",
"source": "System"
},
{
- "id": 39,
+ "id": 38,
"name": "${DARKFRAME}",
"description": "Taking Dark Frames Flag",
"format": "",
@@ -361,16 +352,16 @@
"source": "System"
},
{
- "id": 40,
+ "id": 39,
"name": "${eOVERLAY}",
- "description": "External Overlay",
- "format": "",
+ "description": "Overlay Method number",
+ "format": "{:n}",
"sample": "1",
"type": "Number",
"source": "System"
},
{
- "id": 41,
+ "id": 40,
"name": "${DAY_OR_NIGHT}",
"description": "Day\/Night string",
"format": "",
@@ -379,11 +370,11 @@
"source": "System"
},
{
- "id": 42,
+ "id": 41,
"name": "${ALLSKY_VERSION}",
"description": "Allsky version string",
"format": "",
- "sample": "v2023.03.09_tbd",
+ "sample": "v2024.11.15",
"type": "Text",
"source": "System"
}
diff --git a/config_repo/overlay/config/overlay-RPi.json b/config_repo/overlay/config/overlay-RPi.json
index 867b1bb4c..136609823 100644
--- a/config_repo/overlay/config/overlay-RPi.json
+++ b/config_repo/overlay/config/overlay-RPi.json
@@ -1,51 +1,49 @@
{
"fields": [
{
- "label": "${DATE} ${TIME}",
- "x": 330,
- "y": 50,
+ "label": "${DATE} ${TIME}",
+ "x": 260,
+ "y": 46,
"id": "oe-field-0",
- "format": "%d-%m-%Y,%H:%M:%S",
+ "format": "{%d-%m-%Y}{%H:%M:%S}",
"strokewidth": 0,
"sample": "DATE,TIME",
- "tlx": 10,
- "tly": 10,
- "font": "Arial",
- "fontsize": 80,
- "fill": "#ff0000"
+ "tlx": 20,
+ "tly": 16,
+ "fill": "#ff0000",
+ "fontsize": 60
},
{
"label": "Exposure: ${sEXPOSURE}",
- "x": 421,
- "y": 124,
+ "x": 309,
+ "y": 98,
"id": "oe-field-1",
- "font": "Arial",
- "fontsize": 68,
+ "fontsize": 48,
"strokewidth": 0,
- "tlx": 10,
- "tly": 90
+ "tlx": 20,
+ "tly": 74
},
{
"label": "Gain: ${GAIN}",
- "x": 226,
- "y": 194,
+ "x": 172,
+ "y": 158,
"id": "oe-field-2",
- "font": "Arial",
- "fontsize": 68,
+ "format": "{:.2f}",
+ "fontsize": 48,
"strokewidth": 0,
- "tlx": 10,
- "tly": 160
+ "tlx": 20,
+ "tly": 134
},
{
- "label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
- "x": 419,
- "y": 3002,
+ "label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
+ "x": 396,
+ "y": 214,
"id": "oe-field-3",
- "fontsize": 44,
+ "fontsize": 40,
"strokewidth": 0,
- "sample": "RPi HQ",
- "tlx": 10,
- "tly": 2980
+ "tlx": 20,
+ "tly": 194,
+ "sample": "RPi some_model"
}
],
"images": [],
@@ -71,5 +69,13 @@
"backgroundcolor": "white",
"fontopacity": 0.5
}
+ },
+ "metadata": {
+ "camerabrand": "RPi",
+ "cameramodel": "HQ",
+ "cameraresolutionwidth": "4056",
+ "cameraresolutionheight": "3040",
+ "tod": "both",
+ "name": "RPI generic"
}
}
diff --git a/config_repo/overlay/config/overlay-RPi_HQ-4056x3040-both.json b/config_repo/overlay/config/overlay-RPi_HQ-4056x3040-both.json
new file mode 100644
index 000000000..4fee37f2b
--- /dev/null
+++ b/config_repo/overlay/config/overlay-RPi_HQ-4056x3040-both.json
@@ -0,0 +1,81 @@
+{
+ "fields": [
+ {
+ "label": "${DATE} ${TIME}",
+ "x": 260,
+ "y": 46,
+ "id": "oe-field-0",
+ "format": "{%d-%m-%Y}{%H:%M:%S}",
+ "strokewidth": 0,
+ "sample": "DATE,TIME",
+ "tlx": 20,
+ "tly": 16,
+ "fill": "#ff0000",
+ "fontsize": 60
+ },
+ {
+ "label": "Exposure: ${sEXPOSURE}",
+ "x": 309,
+ "y": 98,
+ "id": "oe-field-1",
+ "fontsize": 48,
+ "strokewidth": 0,
+ "tlx": 20,
+ "tly": 74
+ },
+ {
+ "label": "Gain: ${GAIN}",
+ "x": 172,
+ "y": 158,
+ "id": "oe-field-2",
+ "format": "{:.2f}",
+ "fontsize": 48,
+ "strokewidth": 0,
+ "tlx": 20,
+ "tly": 134
+ },
+ {
+ "label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
+ "x": 396,
+ "y": 214,
+ "id": "oe-field-3",
+ "fontsize": 40,
+ "strokewidth": 0,
+ "tlx": 20,
+ "tly": 194,
+ "sample": "RPi some_model"
+ }
+ ],
+ "images": [],
+ "settings": {
+ "defaultdatafileexpiry": "550",
+ "defaultincludeplanets": false,
+ "defaultincludesun": false,
+ "defaultincludemoon": false,
+ "defaultimagetopacity": 0.63,
+ "defaultimagerotation": 0,
+ "defaulttextrotation": 0,
+ "defaultfontopacity": 1,
+ "defaultfontcolour": "white",
+ "defaultfont": "Arial",
+ "defaultfontsize": 52,
+ "defaultimagescale": 1,
+ "defaultnoradids": ""
+ },
+ "fonts": {
+ "moon_phases": {
+ "fontPath": "fonts\/moon_phases.ttf",
+ "fonttcolour": "red",
+ "backgroundcolor": "white",
+ "fontopacity": 0.5
+ }
+ },
+ "metadata": {
+ "camerabrand": "RPi",
+ "cameramodel": "HQ",
+ "cameraresolutionwidth": "4056",
+ "cameraresolutionheight": "3040",
+ "tod": "both",
+ "name": "RPI HQ"
+ }
+}
diff --git a/config_repo/overlay/config/overlay-RPi_Module_3-4608x2592-both.json b/config_repo/overlay/config/overlay-RPi_Module_3-4608x2592-both.json
new file mode 100644
index 000000000..7a0f295a9
--- /dev/null
+++ b/config_repo/overlay/config/overlay-RPi_Module_3-4608x2592-both.json
@@ -0,0 +1,81 @@
+{
+ "fields": [
+ {
+ "label": "${DATE} ${TIME}",
+ "x": 211,
+ "y": 44,
+ "id": "oe-field-0",
+ "format": "{%d-%m-%Y}{%H:%M:%S}",
+ "strokewidth": 0,
+ "sample": "DATE,TIME",
+ "tlx": 19,
+ "tly": 20,
+ "fontsize": 48,
+ "fill": "#ff0000"
+ },
+ {
+ "label": "Exposure: ${sEXPOSURE}",
+ "x": 237,
+ "y": 98,
+ "id": "oe-field-1",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 80
+ },
+ {
+ "label": "Gain: ${GAIN}",
+ "x": 134,
+ "y": 158,
+ "id": "oe-field-2",
+ "format": "{:.2f}",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 140
+ },
+ {
+ "label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
+ "x": 279,
+ "y": 214,
+ "id": "oe-field-3",
+ "fontsize": 28,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 200,
+ "sample": "RPi some_model"
+ }
+ ],
+ "images": [],
+ "settings": {
+ "defaultdatafileexpiry": "550",
+ "defaultincludeplanets": false,
+ "defaultincludesun": false,
+ "defaultincludemoon": false,
+ "defaultimagetopacity": 0.63,
+ "defaultimagerotation": 0,
+ "defaulttextrotation": 0,
+ "defaultfontopacity": 1,
+ "defaultfontcolour": "white",
+ "defaultfont": "Arial",
+ "defaultfontsize": 52,
+ "defaultimagescale": 1,
+ "defaultnoradids": ""
+ },
+ "fonts": {
+ "moon_phases": {
+ "fontPath": "fonts\/moon_phases.ttf",
+ "fonttcolour": "red",
+ "backgroundcolor": "white",
+ "fontopacity": 0.5
+ }
+ },
+ "metadata": {
+ "camerabrand": "RPi",
+ "cameramodel": "Module 3",
+ "cameraresolutionwidth": "4608",
+ "cameraresolutionheight": "2592",
+ "tod": "both",
+ "name": "RPI Module 3"
+ }
+}
diff --git a/config_repo/overlay/config/overlay.json b/config_repo/overlay/config/overlay-RPi_Version_1-2592x1944-both.json
similarity index 67%
rename from config_repo/overlay/config/overlay.json
rename to config_repo/overlay/config/overlay-RPi_Version_1-2592x1944-both.json
index bc8f77250..3f787a37d 100644
--- a/config_repo/overlay/config/overlay.json
+++ b/config_repo/overlay/config/overlay-RPi_Version_1-2592x1944-both.json
@@ -2,47 +2,48 @@
"fields": [
{
"label": "${DATE} ${TIME}",
- "x": 121,
+ "x": 122,
"y": 24,
"id": "oe-field-0",
- "format": "%d-%m-%Y,%H:%M:%S",
+ "format": "{%d-%m-%Y}{%H:%M:%S}",
"strokewidth": 0,
"sample": "DATE,TIME",
- "tlx": 9,
+ "tlx": 10,
"tly": 10,
"fontsize": 28,
"fill": "#ff0000"
},
{
"label": "Exposure: ${sEXPOSURE}",
- "x": 178,
- "y": 54,
+ "x": 131,
+ "y": 50,
"id": "oe-field-1",
- "fontsize": 28,
+ "fontsize": 20,
"strokewidth": 0,
- "tlx": 9,
+ "tlx": 10,
"tly": 40
},
{
"label": "Gain: ${GAIN}",
- "x": 98,
- "y": 84,
+ "x": 73,
+ "y": 75,
"id": "oe-field-2",
- "fontsize": 28,
+ "format": "{:.2f}",
+ "fontsize": 20,
"strokewidth": 0,
- "tlx": 9,
- "tly": 70
+ "tlx": 10,
+ "tly": 65
},
{
"label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
- "x": 158,
- "y": 1078,
+ "x": 157,
+ "y": 100,
"id": "oe-field-3",
"fontsize": 16,
"strokewidth": 0,
- "sample": "ZWO ASI174MC",
- "tlx": 9,
- "tly": 1070
+ "tlx": 10,
+ "tly": 90,
+ "sample": "RPi some_model"
}
],
"images": [],
@@ -68,5 +69,14 @@
"backgroundcolor": "white",
"fontopacity": 0.5
}
- }
+ },
+ "metadata": {
+ "camerabrand": "RPi",
+ "cameramodel": "Module 1",
+ "cameraresolutionwidth": "2592",
+ "cameraresolutionheight": "1944",
+ "tod": "both",
+ "name": "RPI Module 1"
+ }
}
+
diff --git a/config_repo/overlay/config/overlay-ZWO.json b/config_repo/overlay/config/overlay-ZWO.json
index 9e1c3817b..1ff99ac66 100644
--- a/config_repo/overlay/config/overlay-ZWO.json
+++ b/config_repo/overlay/config/overlay-ZWO.json
@@ -2,59 +2,60 @@
"fields": [
{
"label": "${DATE} ${TIME}",
- "x": 121,
+ "x": 132,
"y": 24,
"id": "oe-field-0",
- "format": "%d-%m-%Y,%H:%M:%S",
+ "format": "{%d-%m-%Y}{%H:%M:%S}",
"strokewidth": 0,
"sample": "DATE,TIME",
- "tlx": 9,
+ "tlx": 19,
"tly": 10,
"fontsize": 28,
"fill": "#ff0000"
},
{
"label": "Exposure: ${sEXPOSURE}",
- "x": 178,
- "y": 54,
+ "x": 141,
+ "y": 50,
"id": "oe-field-1",
- "fontsize": 28,
+ "fontsize": 20,
"strokewidth": 0,
- "tlx": 9,
+ "tlx": 19,
"tly": 40
},
{
"label": "Gain: ${GAIN}",
- "x": 98,
- "y": 84,
+ "x": 83,
+ "y": 75,
"id": "oe-field-2",
- "fontsize": 28,
+ "format": "{:n}",
+ "fontsize": 20,
"strokewidth": 0,
- "tlx": 9,
- "tly": 70
+ "tlx": 19,
+ "tly": 65
},
{
"label": "Sensor: ${TEMPERATURE_C} C",
- "x": 215,
- "y": 114,
+ "x": 167,
+ "y": 100,
"id": "oe-field-3",
"format": "{:.1f}",
- "fontsize": 28,
+ "fontsize": 20,
"strokewidth": 0,
- "tlx": 9,
- "tly": 100,
+ "tlx": 19,
+ "tly": 90,
"sample": "20.1"
},
{
"label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
- "x": 195,
- "y": 1080,
+ "x": 169,
+ "y": 128,
"id": "oe-field-4",
- "fontsize": 20,
+ "fontsize": 16,
"strokewidth": 0,
- "sample": "ZWO ASI174MC",
- "tlx": 9,
- "tly": 1070
+ "sample": "ZWO some_model",
+ "tlx": 19,
+ "tly": 120
}
],
"images": [],
@@ -80,5 +81,13 @@
"backgroundcolor": "white",
"fontopacity": 0.5
}
+ },
+ "metadata": {
+ "camerabrand": "ZWO",
+ "cameramodel": "generic",
+ "cameraresolutionwidth": "1920",
+ "cameraresolutionheight": "960",
+ "tod": "both",
+ "name": "ZWO"
}
}
diff --git a/config_repo/overlay/config/overlay-ZWO_ASI120MC-S-1280x960-both.json b/config_repo/overlay/config/overlay-ZWO_ASI120MC-S-1280x960-both.json
new file mode 100644
index 000000000..e55902683
--- /dev/null
+++ b/config_repo/overlay/config/overlay-ZWO_ASI120MC-S-1280x960-both.json
@@ -0,0 +1,93 @@
+{
+ "fields": [
+ {
+ "label": "${DATE} ${TIME}",
+ "x": 132,
+ "y": 24,
+ "id": "oe-field-0",
+ "format": "{%d-%m-%Y}{%H:%M:%S}",
+ "strokewidth": 0,
+ "sample": "DATE,TIME",
+ "tlx": 19,
+ "tly": 10,
+ "fontsize": 28,
+ "fill": "#ff0000"
+ },
+ {
+ "label": "Exposure: ${sEXPOSURE}",
+ "x": 141,
+ "y": 60,
+ "id": "oe-field-1",
+ "fontsize": 20,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 50
+ },
+ {
+ "label": "Gain: ${GAIN}",
+ "x": 83,
+ "y": 85,
+ "id": "oe-field-2",
+ "format": "{:n}",
+ "fontsize": 20,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 75
+ },
+ {
+ "label": "Sensor: ${TEMPERATURE_C} C",
+ "x": 167,
+ "y": 110,
+ "id": "oe-field-3",
+ "format": "{:.1f}",
+ "fontsize": 20,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 100,
+ "sample": "20.1"
+ },
+ {
+ "label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
+ "x": 169,
+ "y": 135,
+ "id": "oe-field-4",
+ "fontsize": 16,
+ "strokewidth": 0,
+ "sample": "ZWO some_model",
+ "tlx": 19,
+ "tly": 125
+ }
+ ],
+ "images": [],
+ "settings": {
+ "defaultdatafileexpiry": "550",
+ "defaultincludeplanets": false,
+ "defaultincludesun": false,
+ "defaultincludemoon": false,
+ "defaultimagetopacity": 0.63,
+ "defaultimagerotation": 0,
+ "defaulttextrotation": 0,
+ "defaultfontopacity": 1,
+ "defaultfontcolour": "white",
+ "defaultfont": "Arial",
+ "defaultfontsize": 52,
+ "defaultimagescale": 1,
+ "defaultnoradids": ""
+ },
+ "fonts": {
+ "moon_phases": {
+ "fontPath": "fonts\/moon_phases.ttf",
+ "fonttcolour": "red",
+ "backgroundcolor": "white",
+ "fontopacity": 0.5
+ }
+ },
+ "metadata": {
+ "camerabrand": "ZWO",
+ "cameramodel": "ASII120MC-S",
+ "cameraresolutionwidth": "1280",
+ "cameraresolutionheight": "960",
+ "tod": "both",
+ "name": "ASII120MC-S"
+ }
+}
diff --git a/config_repo/overlay/config/overlay-ZWO_ASI178MC-3096x2080-both.json b/config_repo/overlay/config/overlay-ZWO_ASI178MC-3096x2080-both.json
new file mode 100644
index 000000000..f8fafc98e
--- /dev/null
+++ b/config_repo/overlay/config/overlay-ZWO_ASI178MC-3096x2080-both.json
@@ -0,0 +1,95 @@
+{
+ "fields": [
+ {
+ "label": "${DATE} ${TIME}",
+ "x": 259,
+ "y": 50,
+ "id": "oe-field-0",
+ "format": "{%d-%m-%Y}{%H:%M:%S}",
+ "strokewidth": 0,
+ "sample": "DATE,TIME",
+ "tlx": 19,
+ "tly": 20,
+ "fontsize": 60,
+ "fill": "#ff0000"
+ },
+ {
+ "label": "Exposure: ${sEXPOSURE}",
+ "x": 237,
+ "y": 98,
+ "id": "oe-field-1",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 80
+ },
+ {
+ "label": "Gain: ${GAIN}",
+ "x": 134,
+ "y": 138,
+ "id": "oe-field-2",
+ "format": "{:n}",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 120
+ },
+ {
+ "label": "Sensor: ${TEMPERATURE_C} C",
+ "x": 284,
+ "y": 178,
+ "id": "oe-field-3",
+ "format": "{:.1f}",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 160,
+ "sample": "20.1"
+ },
+ {
+ "label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
+ "x": 242,
+ "y": 220,
+ "id": "oe-field-4",
+ "fontsize": 24,
+ "strokewidth": 0,
+ "sample": "ZWO some_model",
+ "tlx": 19,
+ "tly": 208
+ }
+ ],
+ "images": [],
+ "settings": {
+ "defaultdatafileexpiry": "600",
+ "defaultincludeplanets": true,
+ "defaultincludesun": true,
+ "defaultincludemoon": true,
+ "defaultimagetopacity": 0.63,
+ "defaultimagerotation": 0,
+ "defaulttextrotation": 0,
+ "defaultfontopacity": 1,
+ "defaultfontcolour": "white",
+ "defaultfont": "Arial",
+ "defaultfontsize": 52,
+ "defaultimagescale": 1,
+ "defaultnoradids": "25544",
+ "defaultstrokecolour": "",
+ "defaultexpirytext": ""
+ },
+ "fonts": {
+ "moon_phases": {
+ "fontPath": "fonts\/moon_phases.ttf",
+ "fonttcolour": "red",
+ "backgroundcolor": "white",
+ "fontopacity": 0.5
+ }
+ },
+ "metadata": {
+ "camerabrand": "ZWO",
+ "cameramodel": "ASI178MC",
+ "cameraresolutionwidth": "3096",
+ "cameraresolutionheight": "2080",
+ "tod": "both",
+ "name": "ASI178MC"
+ }
+}
diff --git a/config_repo/overlay/config/overlay-ZWO_ASI178MM-3096x2080-both.json b/config_repo/overlay/config/overlay-ZWO_ASI178MM-3096x2080-both.json
new file mode 100644
index 000000000..b246021bf
--- /dev/null
+++ b/config_repo/overlay/config/overlay-ZWO_ASI178MM-3096x2080-both.json
@@ -0,0 +1,95 @@
+{
+ "fields": [
+ {
+ "label": "${DATE} ${TIME}",
+ "x": 259,
+ "y": 50,
+ "id": "oe-field-0",
+ "format": "{%d-%m-%Y}{%H:%M:%S}",
+ "strokewidth": 0,
+ "sample": "DATE,TIME",
+ "tlx": 19,
+ "tly": 20,
+ "fontsize": 60,
+ "fill": "#ff0000"
+ },
+ {
+ "label": "Exposure: ${sEXPOSURE}",
+ "x": 237,
+ "y": 108,
+ "id": "oe-field-1",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 90
+ },
+ {
+ "label": "Gain: ${GAIN}",
+ "x": 134,
+ "y": 158,
+ "id": "oe-field-2",
+ "format": "{:n}",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 140
+ },
+ {
+ "label": "Sensor: ${TEMPERATURE_C} C",
+ "x": 284,
+ "y": 178,
+ "id": "oe-field-3",
+ "format": "{:.1f}",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 160,
+ "sample": "20.1"
+ },
+ {
+ "label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
+ "x": 242,
+ "y": 220,
+ "id": "oe-field-4",
+ "fontsize": 24,
+ "strokewidth": 0,
+ "sample": "ZWO some_model",
+ "tlx": 19,
+ "tly": 208
+ }
+ ],
+ "images": [],
+ "settings": {
+ "defaultdatafileexpiry": "600",
+ "defaultincludeplanets": true,
+ "defaultincludesun": true,
+ "defaultincludemoon": true,
+ "defaultimagetopacity": 0.63,
+ "defaultimagerotation": 0,
+ "defaulttextrotation": 0,
+ "defaultfontopacity": 1,
+ "defaultfontcolour": "white",
+ "defaultfont": "Arial",
+ "defaultfontsize": 52,
+ "defaultimagescale": 1,
+ "defaultnoradids": "25544",
+ "defaultstrokecolour": "",
+ "defaultexpirytext": ""
+ },
+ "fonts": {
+ "moon_phases": {
+ "fontPath": "fonts\/moon_phases.ttf",
+ "fonttcolour": "red",
+ "backgroundcolor": "white",
+ "fontopacity": 0.5
+ }
+ },
+ "metadata": {
+ "camerabrand": "ZWO",
+ "cameramodel": "ASI178MM",
+ "cameraresolutionwidth": "3096",
+ "cameraresolutionheight": "2080",
+ "tod": "both",
+ "name": "ASI178MM"
+ }
+}
diff --git a/config_repo/overlay/config/overlay-ZWO_ASI290MC-1936x1096-both.json b/config_repo/overlay/config/overlay-ZWO_ASI290MC-1936x1096-both.json
new file mode 100644
index 000000000..2783ebe1b
--- /dev/null
+++ b/config_repo/overlay/config/overlay-ZWO_ASI290MC-1936x1096-both.json
@@ -0,0 +1,95 @@
+{
+ "fields": [
+ {
+ "label": "${DATE} ${TIME}",
+ "x": 259,
+ "y": 50,
+ "id": "oe-field-0",
+ "format": "{%d-%m-%Y}{%H:%M:%S}",
+ "strokewidth": 0,
+ "sample": "DATE,TIME",
+ "tlx": 19,
+ "tly": 20,
+ "fontsize": 60,
+ "fill": "#ff0000"
+ },
+ {
+ "label": "Exposure: ${sEXPOSURE}",
+ "x": 237,
+ "y": 115,
+ "id": "oe-field-1",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 90
+ },
+ {
+ "label": "Gain: ${GAIN}",
+ "x": 134,
+ "y": 180,
+ "id": "oe-field-2",
+ "format": "{:n}",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 155
+ },
+ {
+ "label": "Sensor: ${TEMPERATURE_C} C",
+ "x": 157,
+ "y": 245,
+ "id": "oe-field-3",
+ "format": "{:.1f}",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 220,
+ "sample": "20.1"
+ },
+ {
+ "label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
+ "x": 159,
+ "y": 310,
+ "id": "oe-field-4",
+ "fontsize": 24,
+ "strokewidth": 0,
+ "sample": "ZWO some_model",
+ "tlx": 19,
+ "tly": 285
+ }
+ ],
+ "images": [],
+ "settings": {
+ "defaultdatafileexpiry": "600",
+ "defaultincludeplanets": true,
+ "defaultincludesun": true,
+ "defaultincludemoon": true,
+ "defaultimagetopacity": 0.63,
+ "defaultimagerotation": 0,
+ "defaulttextrotation": 0,
+ "defaultfontopacity": 1,
+ "defaultfontcolour": "white",
+ "defaultfont": "Arial",
+ "defaultfontsize": 52,
+ "defaultimagescale": 1,
+ "defaultnoradids": "25544",
+ "defaultstrokecolour": "",
+ "defaultexpirytext": ""
+ },
+ "fonts": {
+ "moon_phases": {
+ "fontPath": "fonts\/moon_phases.ttf",
+ "fonttcolour": "red",
+ "backgroundcolor": "white",
+ "fontopacity": 0.5
+ }
+ },
+ "metadata": {
+ "camerabrand": "ZWO",
+ "cameramodel": "ASI290MC",
+ "cameraresolutionwidth": "1936",
+ "cameraresolutionheight": "1096",
+ "tod": "both",
+ "name": "ASI290MC"
+ }
+}
diff --git a/config_repo/overlay/config/overlay-ZWO_ASI290MM-1936x1096-both.json b/config_repo/overlay/config/overlay-ZWO_ASI290MM-1936x1096-both.json
new file mode 100644
index 000000000..9301697ef
--- /dev/null
+++ b/config_repo/overlay/config/overlay-ZWO_ASI290MM-1936x1096-both.json
@@ -0,0 +1,96 @@
+{
+ "fields": [
+ {
+ "label": "${DATE} ${TIME}",
+ "x": 259,
+ "y": 50,
+ "id": "oe-field-0",
+ "format": "{%d-%m-%Y}{%H:%M:%S}",
+ "strokewidth": 0,
+ "sample": "DATE,TIME",
+ "tlx": 19,
+ "tly": 20,
+ "fontsize": 60,
+ "fill": "#ff0000"
+ },
+ {
+ "label": "Exposure: ${sEXPOSURE}",
+ "x": 237,
+ "y": 115,
+ "id": "oe-field-1",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 90
+ },
+ {
+ "label": "Gain: ${GAIN}",
+ "x": 134,
+ "y": 180,
+ "id": "oe-field-2",
+ "format": "{:n}",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 155
+ },
+ {
+ "label": "Sensor: ${TEMPERATURE_C} C",
+ "x": 157,
+ "y": 245,
+ "id": "oe-field-3",
+ "format": "{:.1f}",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 220,
+ "sample": "20.1"
+ },
+ {
+ "label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
+ "x": 159,
+ "y": 310,
+ "id": "oe-field-4",
+ "fontsize": 24,
+ "strokewidth": 0,
+ "sample": "ZWO some_model",
+ "tlx": 19,
+ "tly": 285
+ }
+ ],
+ "images": [],
+ "settings": {
+ "defaultdatafileexpiry": "600",
+ "defaultincludeplanets": true,
+ "defaultincludesun": true,
+ "defaultincludemoon": true,
+ "defaultimagetopacity": 0.63,
+ "defaultimagerotation": 0,
+ "defaulttextrotation": 0,
+ "defaultfontopacity": 1,
+ "defaultfontcolour": "white",
+ "defaultfont": "Arial",
+ "defaultfontsize": 52,
+ "defaultimagescale": 1,
+ "defaultnoradids": "25544",
+ "defaultstrokecolour": "",
+ "defaultexpirytext": ""
+ },
+ "fonts": {
+ "moon_phases": {
+ "fontPath": "fonts\/moon_phases.ttf",
+ "fonttcolour": "red",
+ "backgroundcolor": "white",
+ "fontopacity": 0.5
+ }
+ },
+ "metadata": {
+ "camerabrand": "ZWO",
+ "cameramodel": "ASI290MM",
+ "cameraresolutionwidth": "1936",
+ "cameraresolutionheight": "1096",
+ "tod": "both",
+ "name": "ASI290MM"
+ }
+}
+
diff --git a/config_repo/overlay/config/overlay-ZWO_ASI585MC-3840x2160-both.json b/config_repo/overlay/config/overlay-ZWO_ASI585MC-3840x2160-both.json
new file mode 100644
index 000000000..dd9dcea5a
--- /dev/null
+++ b/config_repo/overlay/config/overlay-ZWO_ASI585MC-3840x2160-both.json
@@ -0,0 +1,91 @@
+{
+ "fields": [
+ {
+ "label": "${DATE} ${TIME}",
+ "x": 259,
+ "y": 50,
+ "id": "oe-field-0",
+ "format": "{%d-%m-%Y}{%H:%M:%S}",
+ "strokewidth": 0,
+ "sample": "DATE,TIME",
+ "tlx": 19,
+ "tly": 20,
+ "fontsize": 60,
+ "fill": "#ff0000"
+ },
+ {
+ "label": "Exposure: ${sEXPOSURE} ${sAUTOEXPOSURE}",
+ "x": 601,
+ "y": 116,
+ "id": "oe-field-1",
+ "strokewidth": 0,
+ "tlx": 20,
+ "tly": 90
+ },
+ {
+ "label": "Gain: ${GAIN} ${sAUTOGAIN}",
+ "x": 372.1298828125,
+ "y": 176,
+ "id": "oe-field-2",
+ "strokewidth": 0,
+ "tlx": 20,
+ "tly": 150
+ },
+ {
+ "label": "Sensor: ${TEMPERATURE_C} C, ${TEMPERATURE_F} F",
+ "x": 696,
+ "y": 236,
+ "id": "oe-field-3",
+ "format": "{:.1f},{:.1f}",
+ "strokewidth": 0,
+ "sample": "32.2",
+ "tlx": 19,
+ "tly": 200
+ },
+ {
+ "label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
+ "x": 354.1337890625,
+ "y": 296,
+ "id": "oe-field-4",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 20,
+ "tly": 278,
+ "sample": "ZWO ASI585MC"
+ }
+ ],
+ "images": [],
+ "settings": {
+ "defaultdatafileexpiry": "600",
+ "defaultincludeplanets": true,
+ "defaultincludesun": true,
+ "defaultincludemoon": true,
+ "defaultimagetopacity": 0.63,
+ "defaultimagerotation": 0,
+ "defaulttextrotation": 0,
+ "defaultfontopacity": 1,
+ "defaultfontcolour": "white",
+ "defaultfont": "Arial",
+ "defaultfontsize": 52,
+ "defaultimagescale": 1,
+ "defaultnoradids": "25544",
+ "defaultstrokecolour": "",
+ "defaultexpirytext": ""
+ },
+ "fonts": {
+ "moon_phases": {
+ "fontPath": "fonts\/moon_phases.ttf",
+ "fonttcolour": "red",
+ "backgroundcolor": "white",
+ "fontopacity": 0.5
+ }
+ },
+ "metadata": {
+ "camerabrand": "ZWO",
+ "cameramodel": "ASI585MC",
+ "cameraresolutionwidth": "3840",
+ "cameraresolutionheight": "2160",
+ "tod": "both",
+ "name": "ASI585MC"
+ }
+}
diff --git a/config_repo/overlay/config/overlay-ZWO_ASI676MC-3552x3552-both.json b/config_repo/overlay/config/overlay-ZWO_ASI676MC-3552x3552-both.json
new file mode 100644
index 000000000..744156b3c
--- /dev/null
+++ b/config_repo/overlay/config/overlay-ZWO_ASI676MC-3552x3552-both.json
@@ -0,0 +1,95 @@
+{
+ "fields": [
+ {
+ "label": "${DATE} ${TIME}",
+ "x": 259,
+ "y": 50,
+ "id": "oe-field-0",
+ "format": "{%d-%m-%Y}{%H:%M:%S}",
+ "strokewidth": 0,
+ "sample": "DATE,TIME",
+ "tlx": 19,
+ "tly": 20,
+ "fontsize": 60,
+ "fill": "#ff0000"
+ },
+ {
+ "label": "Exposure: ${sEXPOSURE}",
+ "x": 237,
+ "y": 115,
+ "id": "oe-field-1",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 100
+ },
+ {
+ "label": "Gain: ${GAIN}",
+ "x": 134,
+ "y": 155,
+ "id": "oe-field-2",
+ "format": "{:n}",
+ "fontsize": 36,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 140
+ },
+ {
+ "label": "Sensor: ${TEMPERATURE_C} C",
+ "x": 167,
+ "y": 195,
+ "id": "oe-field-3",
+ "format": "{:.1f}",
+ "fontsize": 20,
+ "strokewidth": 0,
+ "tlx": 19,
+ "tly": 180,
+ "sample": "20.1"
+ },
+ {
+ "label": "${CAMERA_TYPE} ${CAMERA_MODEL}",
+ "x": 169,
+ "y": 220,
+ "id": "oe-field-4",
+ "fontsize": 16,
+ "strokewidth": 0,
+ "sample": "ZWO some_model",
+ "tlx": 19,
+ "tly": 205
+ }
+ ],
+ "images": [],
+ "settings": {
+ "defaultdatafileexpiry": "600",
+ "defaultincludeplanets": true,
+ "defaultincludesun": true,
+ "defaultincludemoon": true,
+ "defaultimagetopacity": 0.63,
+ "defaultimagerotation": 0,
+ "defaulttextrotation": 0,
+ "defaultfontopacity": 1,
+ "defaultfontcolour": "white",
+ "defaultfont": "Arial",
+ "defaultfontsize": 52,
+ "defaultimagescale": 1,
+ "defaultnoradids": "25544",
+ "defaultstrokecolour": "",
+ "defaultexpirytext": ""
+ },
+ "fonts": {
+ "moon_phases": {
+ "fontPath": "fonts\/moon_phases.ttf",
+ "fonttcolour": "red",
+ "backgroundcolor": "white",
+ "fontopacity": 0.5
+ }
+ },
+ "metadata": {
+ "camerabrand": "ZWO",
+ "cameramodel": "ASI676MC",
+ "cameraresolutionwidth": "3552",
+ "cameraresolutionheight": "3552",
+ "tod": "both",
+ "name": "ASI676MC"
+ }
+}
diff --git a/config_repo/requirements-buster.txt b/config_repo/requirements-buster.txt
index c079217a3..726592113 100644
--- a/config_repo/requirements-buster.txt
+++ b/config_repo/requirements-buster.txt
@@ -7,7 +7,6 @@ astral
pytz
scipy<=1.8.1
paho-mqtt
-astropy==4.3.1
suncalc
Adafruit-Blinka
vcgencmd
diff --git a/config_repo/sudoers.repo b/config_repo/sudoers.repo
index 2fbdb383f..73ce47db2 100644
--- a/config_repo/sudoers.repo
+++ b/config_repo/sudoers.repo
@@ -1,8 +1,8 @@
# Permissions for allsky webserver
-www-data ALL=(ALL) NOPASSWD:/sbin/ifdown wlan0
-www-data ALL=(ALL) NOPASSWD:/sbin/ifup wlan0
-www-data ALL=(ALL) NOPASSWD:/sbin/ifdown eth0
-www-data ALL=(ALL) NOPASSWD:/sbin/ifup eth0
+www-data ALL=(ALL) NOPASSWD:/sbin/ifdown
+www-data ALL=(ALL) NOPASSWD:/sbin/ifup
+www-data ALL=(ALL) NOPASSWD:/sbin/ifdown
+www-data ALL=(ALL) NOPASSWD:/sbin/ifup
www-data ALL=(ALL) NOPASSWD:/bin/cat /etc/wpa_supplicant/wpa_supplicant.conf
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/wifidata /etc/wpa_supplicant/wpa_supplicant.conf
www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli scan_results
@@ -24,9 +24,11 @@ www-data ALL=(ALL) NOPASSWD:/bin/rm
www-data ALL=(ALL) NOPASSWD:/bin/cp
www-data ALL=(ALL) NOPASSWD:/bin/mv
www-data ALL=(ALL) NOPASSWD:/usr/bin/vcgencmd
-www-data ALL=(ALL) NOPASSWD:XX_ALLSKY_SCRIPTS_XX/postData.sh
www-data ALL=(ALL) NOPASSWD:/usr/sbin/ifconfig
www-data ALL=(ALL) NOPASSWD:/usr/bin/truncate
www-data ALL=(ALL) NOPASSWD:XX_ALLSKY_SCRIPTS_XX/upload.sh
www-data ALL=(ALL) NOPASSWD:XX_ALLSKY_SCRIPTS_XX/makeChanges.sh
+www-data ALL=(ALL) NOPASSWD:XX_ALLSKY_SCRIPTS_XX/postData.sh
+www-data ALL=(ALL) NOPASSWD:XX_ALLSKY_SCRIPTS_XX/checkAllsky.sh
www-data ALL=(ALL) NOPASSWD:/usr/bin/date
+www-data ALL=(ALL) NOPASSWD:/usr/bin/touch
diff --git a/html/allsky/NoThumbnail.png b/html/allsky/NoThumbnail.png
new file mode 100644
index 000000000..47480fe15
Binary files /dev/null and b/html/allsky/NoThumbnail.png differ
diff --git a/html/allsky/allsky-favicon.png b/html/allsky/allsky-favicon.png
new file mode 100644
index 000000000..7b350606e
Binary files /dev/null and b/html/allsky/allsky-favicon.png differ
diff --git a/html/allsky/allsky-font.css b/html/allsky/allsky-font.css
new file mode 100755
index 000000000..cb0edaedd
--- /dev/null
+++ b/html/allsky/allsky-font.css
@@ -0,0 +1,60 @@
+@font-face {
+ font-family: 'allsky';
+ src: url('fonts/allsky.eot?thds7v');
+ src: url('fonts/allsky.eot?thds7v#iefix') format('embedded-opentype'),
+ url('fonts/allsky.ttf?thds7v') format('truetype'),
+ url('fonts/allsky.woff?thds7v') format('woff'),
+ url('fonts/allsky.svg?thds7v#allsky') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+
+[class^="allsky-"], [class*=" allsky-"] {
+ /* use !important to prevent issues with browser extensions that change fonts */
+ font-family: 'allsky' !important;
+ speak: none;
+ font-style: normal;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+
+ /* Better Font Rendering =========== */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.allsky-constellation:before {
+ content: "\e900";
+}
+
+@font-face {
+ font-family: 'mini-timelapse';
+ src: url('fonts/mini-timelapse.eot?dynh3c');
+ src: url('fonts/mini-timelapse.eot?dynh3c#iefix') format('embedded-opentype'),
+ url('fonts/mini-timelapse.ttf?dynh3c') format('truetype'),
+ url('fonts/mini-timelapse.woff?dynh3c') format('woff'),
+ url('fonts/mini-timelapse.svg?dynh3c#mini-timelapse') format('svg');
+ font-weight: normal;
+ font-style: normal;
+ font-display: block;
+}
+
+[class^="icon-"], [class*=" icon-"] {
+ /* use !important to prevent issues with browser extensions that change fonts */
+ font-family: 'mini-timelapse' !important;
+ speak: never;
+ font-style: normal;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+
+ /* Better Font Rendering =========== */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-mini-timelapse:before {
+ content: "\ea15";
+}
diff --git a/html/allsky/allsky-logo.png b/html/allsky/allsky-logo.png
new file mode 100644
index 000000000..8fc3b426f
Binary files /dev/null and b/html/allsky/allsky-logo.png differ
diff --git a/html/allsky/allsky.css b/html/allsky/allsky.css
new file mode 100755
index 000000000..20979ed03
--- /dev/null
+++ b/html/allsky/allsky.css
@@ -0,0 +1,299 @@
+:root {
+ --error-color: #dc3545;
+ --warning-color: #ffc107;
+ --notice-color: white;
+}
+
+body {
+ color:white;
+ font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;
+ background-color: black;
+ max-width: 960px;
+ margin: auto;
+ overflow-y: scroll;
+}
+img.current {
+ width: 100%;
+ max-width: 960px;
+}
+
+#starmap_container {
+ position: absolute;
+ overflow: hidden;
+}
+
+.header {
+ display:block;
+ width: 100%;
+}
+
+.title {
+ float: left;
+ color: #DDD;
+ font-size: 20px;
+ padding-left: 65px;
+ padding-top: 4px;
+ margin-left: 5px;
+ margin-top: 2px;
+ background: url('allsky-logo.png') left center;
+ background-size: 57px;
+ background-repeat: no-repeat;
+ font-family: 'Ubuntu', sans-serif;
+ font-weight: 400;
+ height: 35px;
+}
+
+.personalLink {
+ text-align: center;
+ font-size: 150%;
+}
+
+.info {
+ font-size: 90%;
+ padding: 8px;
+ position: fixed;
+ top: 150px;
+ right: 0px;
+ border-top-left-radius: 5px;
+ border-bottom-left-radius: 5px;
+ background-color: #333;
+ border: 2px solid #888;
+ border-right: none;
+ z-index: 1;
+}
+
+.info ul {
+ list-style: none;
+ padding-left: 2px;
+ margin-bottom: 0;
+}
+
+.info ul li i {
+ margin-right: 3px;
+}
+
+#leftSidebar {
+ position: fixed;
+ left: 0;
+ top: 150px;
+ padding: 5px;
+ border-top-right-radius: 5px;
+ border-bottom-right-radius: 5px;
+ background-color: #333;
+ border: 2px solid #888;
+ border-left: none;
+ z-index: 2;
+}
+
+#leftSidebar li {
+ list-style: none;
+ padding: 2px 0
+}
+
+#leftSidebar li i {
+ cursor: pointer;
+ color: #888;
+ margin: 2px 0;
+}
+
+#leftSidebar li i:hover,
+#leftSidebar li i.active {
+ color: orange;
+}
+
+#imageContainer {
+ margin: auto;
+}
+.imageContainer {
+ border: 1px solid #5a5a5a;
+}
+
+.starmap_credit {
+ display: none !important;
+}
+
+.diy {
+ position: fixed;
+ bottom: 10px;
+ right: 10px;
+ opacity: 0.5;
+}
+
+.diy:hover {
+ opacity: 1;
+}
+
+.diy a {
+ color: white;
+}
+
+.diy i {
+ margin-right: 5px;
+}
+
+.noImages {
+ text-align: center;
+ font-size: 200%;
+ color: #ffc107;
+ border: 2px solid gray;
+ margin: 4px;
+}
+
+.imagesHeader { /* the whole table */
+ width: 100%;
+ padding: 5px 5px 20px 20px;
+}
+.imagesHeader .headerButton {
+ text-align: left;
+ width: 5%; /* want headerTitle to be as wide as possible */
+}
+.imagesHeader .headerTitle {
+ text-align: center;
+ font-weight: bold;
+ font-size: 150%;
+}
+
+.back-button {
+ text-decoration: none;
+ margin: 5px;
+ padding: 5px 10px;
+ color: white;
+ background-color: #5D5D5D;
+ border-radius: 5px;
+ white-space: nowrap;
+}
+
+.back-button i {
+ margin-right: 5px;
+}
+
+.archived-files {
+}
+
+.archived-files .day-container{
+ /* width: 10%; */
+ min-width: 100px; /* same as thumbnail width */
+ float: left;
+ padding: 8px;
+ text-align: center; /* so text is centered below thumbnail */
+}
+
+.archived-files .img-text {
+ border: 1px solid #333;
+}
+
+.archived-files .day-container .day-text {
+ padding-top: 2px;
+ color: #7777ff;
+}
+
+.archived-files .day-container .image-container {
+ height: 100px; /* based on 100px wide thumbnail */
+}
+
+.archived-files .day-container .image-container img{
+ max-width: 100%;
+ max-height: 100%;
+}
+
+.archived-files-end {
+ clear: both;
+}
+
+.archived-files hr {
+ margin-top: 25px;
+ width: 50%;
+ height: 2px;
+ background-color: #7777ffaa;
+ border-radius: 2px;
+ border: 1px solid #7777ffaa;
+}
+
+.forecast {
+ padding: 9px;
+}
+
+.forecast-day {
+ font-weight: bold;
+ margin: 0 3px;
+}
+
+.forecast .Very_Quite,
+.forecast .Quiet {
+ color: green;
+}
+
+.forecast .Unsettled,
+.forecast .Active {
+ color: #ffc107;
+}
+
+.forecast .Minor_Storm,
+.forecast .Moderate_Storm {
+ color: darkorange;
+}
+
+.forecast .Strong_Storm,
+.forecast .Severe_Storm,
+.forecast .Extreme_Storm {
+ color: #dc3545;
+}
+
+.forecast .WARNING { /* for Aurora activity */
+ color: #ffc107;
+ font-weight: bold;
+ font-size: 125%;
+}
+
+.forecast-map {
+ width: 75%;
+ max-width: 800px;
+ margin-top: 30px;
+}
+
+.virtualsky_help {
+ color: black;
+}
+
+.thumbnailError {
+ color: #dc3545;
+}
+
+/* Messages on the home page */
+.msg {
+ background-color: #222;
+ text-align: center;
+ font-size: 145%;
+ font-weight: bold;
+ margin: 10px 0 20px 0;
+ padding: 20px 0 20px 0;
+ border-radius: 10px;
+}
+.error-msg {
+ font-size: 150%;
+ margin: 10px;
+ padding: 10px;
+ color: var(--error-color);
+ border: 3px dashed var(--error-color);
+}
+.warning-msg {
+ font-size: 125%;
+ margin: 10px;
+ padding: 10px;
+ color: var(--warning-color);
+ border: 3px dashed var(--warning-color);
+}
+.notice-msg {
+ font-size: 110%;
+ margin: 10px;
+ padding: 10px;
+ color: var(--notice-color);
+ border: 3px solid var(--notice-color);
+}
+
+@media screen and (max-width: 480px) {
+ .msg {
+ font-size: 100%;
+ }
+}
+
diff --git a/html/allsky/analyticsTracking.js b/html/allsky/analyticsTracking.js
new file mode 100644
index 000000000..d117a106c
--- /dev/null
+++ b/html/allsky/analyticsTracking.js
@@ -0,0 +1 @@
+// Include your Google Analytics code here
\ No newline at end of file
diff --git a/html/allsky/animate.min.css b/html/allsky/animate.min.css
new file mode 100755
index 000000000..b6f612953
--- /dev/null
+++ b/html/allsky/animate.min.css
@@ -0,0 +1,11 @@
+@charset "UTF-8";
+
+/*!
+ * animate.css -http://daneden.me/animate
+ * Version - 3.5.1
+ * Licensed under the MIT license - http://opensource.org/licenses/MIT
+ *
+ * Copyright (c) 2016 Daniel Eden
+ */
+
+.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.hinge{-webkit-animation-duration:2s;animation-duration:2s}.animated.bounceIn,.animated.bounceOut,.animated.flipOutX,.animated.flipOutY{-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounce{0%,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transform:translateZ(0);transform:translateZ(0)}40%,43%{-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}40%,43%,70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06)}70%{-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}@keyframes bounce{0%,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transform:translateZ(0);transform:translateZ(0)}40%,43%{-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}40%,43%,70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06)}70%{-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;transform-origin:center bottom}@-webkit-keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}@keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes pulse{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes rubberBand{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{0%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}@keyframes shake{0%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}.headShake{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-name:headShake;animation-name:headShake}@-webkit-keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}.swing{-webkit-transform-origin:top center;transform-origin:top center;-webkit-animation-name:swing;animation-name:swing}@-webkit-keyframes tada{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate(-3deg);transform:scale3d(.9,.9,.9) rotate(-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(3deg);transform:scale3d(1.1,1.1,1.1) rotate(3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(-3deg);transform:scale3d(1.1,1.1,1.1) rotate(-3deg)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes tada{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate(-3deg);transform:scale3d(.9,.9,.9) rotate(-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(3deg);transform:scale3d(1.1,1.1,1.1) rotate(3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(-3deg);transform:scale3d(1.1,1.1,1.1) rotate(-3deg)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate(-5deg);transform:translate3d(-25%,0,0) rotate(-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate(3deg);transform:translate3d(20%,0,0) rotate(3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate(-3deg);transform:translate3d(-15%,0,0) rotate(-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate(2deg);transform:translate3d(10%,0,0) rotate(2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate(-1deg);transform:translate3d(-5%,0,0) rotate(-1deg)}to{-webkit-transform:none;transform:none}}@keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate(-5deg);transform:translate3d(-25%,0,0) rotate(-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate(3deg);transform:translate3d(20%,0,0) rotate(3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate(-3deg);transform:translate3d(-15%,0,0) rotate(-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate(2deg);transform:translate3d(10%,0,0) rotate(2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate(-1deg);transform:translate3d(-5%,0,0) rotate(-1deg)}to{-webkit-transform:none;transform:none}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes jello{0%,11.1%,to{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}@keyframes jello{0%,11.1%,to{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}.jello{-webkit-animation-name:jello;animation-name:jello;-webkit-transform-origin:center;transform-origin:center}@-webkit-keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scaleX(1);transform:scaleX(1)}}.bounceIn{-webkit-animation-name:bounceIn;animation-name:bounceIn}@-webkit-keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:none;transform:none}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInLeft{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:none;transform:none}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:none;transform:none}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInUp{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}to{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}to{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-name:bounceOut;animation-name:bounceOut}@-webkit-keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{0%{-webkit-transform:perspective(400px) rotateY(-1turn);transform:perspective(400px) rotateY(-1turn)}0%,40%{-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-190deg);transform:perspective(400px) translateZ(150px) rotateY(-190deg)}50%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-170deg);transform:perspective(400px) translateZ(150px) rotateY(-170deg)}50%,80%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95)}to{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}@keyframes flip{0%{-webkit-transform:perspective(400px) rotateY(-1turn);transform:perspective(400px) rotateY(-1turn)}0%,40%{-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-190deg);transform:perspective(400px) translateZ(150px) rotateY(-190deg)}50%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-170deg);transform:perspective(400px) translateZ(150px) rotateY(-170deg)}50%,80%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95)}to{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}.animated.flip{-webkit-backface-visibility:visible;backface-visibility:visible;-webkit-animation-name:flip;animation-name:flip}@-webkit-keyframes flipInX{0%{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg)}60%{-webkit-transform:perspective(400px) rotateX(10deg);transform:perspective(400px) rotateX(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateX(-5deg);transform:perspective(400px) rotateX(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInX{0%{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg)}60%{-webkit-transform:perspective(400px) rotateX(10deg);transform:perspective(400px) rotateX(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateX(-5deg);transform:perspective(400px) rotateX(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInX{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInX;animation-name:flipInX}@-webkit-keyframes flipInY{0%{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateY(-20deg);transform:perspective(400px) rotateY(-20deg)}60%{-webkit-transform:perspective(400px) rotateY(10deg);transform:perspective(400px) rotateY(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateY(-5deg);transform:perspective(400px) rotateY(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInY{0%{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateY(-20deg);transform:perspective(400px) rotateY(-20deg)}60%{-webkit-transform:perspective(400px) rotateY(10deg);transform:perspective(400px) rotateY(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateY(-5deg);transform:perspective(400px) rotateY(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInY;animation-name:flipInY}@-webkit-keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg);opacity:1}to{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}}@keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg);opacity:1}to{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}}.flipOutX{-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-backface-visibility:visible!important;backface-visibility:visible!important}@-webkit-keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateY(-15deg);transform:perspective(400px) rotateY(-15deg);opacity:1}to{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}}@keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateY(-15deg);transform:perspective(400px) rotateY(-15deg);opacity:1}to{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}}.flipOutY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipOutY;animation-name:flipOutY}@-webkit-keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg)}60%,80%{opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg)}to{-webkit-transform:none;transform:none;opacity:1}}@keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg)}60%,80%{opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg)}to{-webkit-transform:none;transform:none;opacity:1}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}@keyframes lightSpeedOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{0%{transform-origin:center;-webkit-transform:rotate(-200deg);transform:rotate(-200deg);opacity:0}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateIn{0%{transform-origin:center;-webkit-transform:rotate(-200deg);transform:rotate(-200deg);opacity:0}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{0%{transform-origin:right bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownRight{0%{transform-origin:right bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{0%{transform-origin:right bottom;-webkit-transform:rotate(-90deg);transform:rotate(-90deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpRight{0%{transform-origin:right bottom;-webkit-transform:rotate(-90deg);transform:rotate(-90deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{0%{transform-origin:center;opacity:1}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:rotate(200deg);transform:rotate(200deg);opacity:0}}@keyframes rotateOut{0%{transform-origin:center;opacity:1}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:rotate(200deg);transform:rotate(200deg);opacity:0}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}}@keyframes rotateOutDownLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}@keyframes rotateOutDownRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}@keyframes rotateOutUpLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(90deg);transform:rotate(90deg);opacity:0}}@keyframes rotateOutUpRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(90deg);transform:rotate(90deg);opacity:0}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{transform-origin:top left}0%,20%,60%{-webkit-transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate(80deg);transform:rotate(80deg);transform-origin:top left}40%,80%{-webkit-transform:rotate(60deg);transform:rotate(60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}@keyframes hinge{0%{transform-origin:top left}0%,20%,60%{-webkit-transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate(80deg);transform:rotate(80deg);transform-origin:top left}40%,80%{-webkit-transform:rotate(60deg);transform:rotate(60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}.hinge{-webkit-animation-name:hinge;animation-name:hinge}@-webkit-keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate(-120deg);transform:translate3d(-100%,0,0) rotate(-120deg)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate(-120deg);transform:translate3d(-100%,0,0) rotate(-120deg)}to{opacity:1;-webkit-transform:none;transform:none}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate(120deg);transform:translate3d(100%,0,0) rotate(120deg)}}@keyframes rollOut{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate(120deg);transform:translate3d(100%,0,0) rotate(120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{0%{opacity:1}50%{-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%,to{opacity:0}}@keyframes zoomOut{0%{opacity:1}50%{-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%,to{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}@keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}@keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp}@-webkit-keyframes slideInDown{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInDown{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInDown{-webkit-animation-name:slideInDown;animation-name:slideInDown}@-webkit-keyframes slideInLeft{0%{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInLeft{0%{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInLeft{-webkit-animation-name:slideInLeft;animation-name:slideInLeft}@-webkit-keyframes slideInRight{0%{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInRight{0%{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInRight{-webkit-animation-name:slideInRight;animation-name:slideInRight}@-webkit-keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}@-webkit-keyframes slideOutLeft{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes slideOutLeft{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.slideOutLeft{-webkit-animation-name:slideOutLeft;animation-name:slideOutLeft}@-webkit-keyframes slideOutRight{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes slideOutRight{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.slideOutRight{-webkit-animation-name:slideOutRight;animation-name:slideOutRight}@-webkit-keyframes slideOutUp{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes slideOutUp{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.slideOutUp{-webkit-animation-name:slideOutUp;animation-name:slideOutUp}
\ No newline at end of file
diff --git a/html/allsky/controller.js b/html/allsky/controller.js
new file mode 100755
index 000000000..aa15124e5
--- /dev/null
+++ b/html/allsky/controller.js
@@ -0,0 +1,759 @@
+var app = angular.module('allsky', ['ngLodash']);
+
+var overlayBuilt = false; // has the overlay been built yet?
+
+var virtualSkyData = null;
+var sunData = "data.json"; // contains sunrise/sunset times and related data
+var configData = "configuration.json"; // contains web configuration data
+var dateTimeF = "YYYY-MM-DD HH:mm:ss";
+var dateF = "YYYY-MM-DD";
+var timeF = "HH:mm";
+var timeAmPmF = "h:mm a";
+
+// This returns the height INCLUDING the border: $("#imageContainer").css('height')
+// This returns the height NOT including the border: $("#imageContainer").height()
+
+// These two are used by virtualsky.js to set the overlay width and height,
+// if there was a difference.
+var overlayWidth = 0, overlayHeight = 0;
+var overlayWidthMax = 0, overlayHeightMax = 0;
+var starmapWidth = 0, starmapHeight = 0;
+var wasDiff = true;
+var last_s_iW = 0, last_s_iH = 0;
+var icWidth = 0;
+var icHeight = 0;
+var icImageAspectRatio = 0;
+var overlayAspectRatio = 0;
+var myLatitude = 0, myLongitude = 0;
+
+$(window).resize(function () {
+ if (overlayBuilt) { // only rebuild if already built once
+ var newW = Math.round($("#imageContainer").width(), 0);
+ var newH = Math.round($("#imageContainer").height(), 0);
+
+ $("#starmap_container").css("width", newW + "px").css("height", newH + "px");
+
+ var diffW = newW - icWidth;
+ // Scale the height based on the aspect ratio of the image.
+ var diffH = (newH - icHeight);
+ icWidth = newW;
+ icHeight = newH;
+
+ if (diffW == 0 && diffH == 0) {
+ wasDiff = false;
+ console.log(">>> No change in image size.");
+ return;
+ }
+
+ wasDiff = true;
+
+ // Refresh the page if there was a difference
+ if (0 && wasDiff) {
+ location.reload();
+ }
+
+ // This holds the starmap button, so needs to resize
+ starmapWidth += diffW;
+ starmapHeight += diffH;
+ $("#starmap").css("width", starmapWidth + "px").css("height", starmapHeight + "px");
+
+ overlayWidth += diffW;
+ if (overlayWidth > overlayWidthMax) overlayWidth = overlayWidthMax;
+ overlayHeight += diffH;
+ if (overlayHeight > overlayHeightMax) overlayHeight = overlayHeightMax;
+ $("#starmap_inner")
+ .css("width", overlayWidth + "px")
+ .css("height", overlayHeight + "px");
+ }
+});
+
+function buildOverlay(){
+ if (overlayBuilt) {
+ S.virtualsky(virtualSkyData);
+ } else {
+ $.ajax({
+ // No need for ?_ts= since $.ajax adds one
+ url: configData,
+ cache: false,
+ dataType: 'json',
+ error: function(jqXHR, textStatus, errorThrown) {
+ // TODO: Display the message on the screen.
+ if (jqXHR.status == 404) {
+ console.log(configData + " not found!");
+ } else {
+ console.log("Error reading '" + configData + "': " + errorThrown);
+ }
+ },
+ success: function (data) {
+ var c = data.config;
+ // "config" was defined in index.php to include ALL the variables we need,
+ // including ones not in the "config" section of the configuration file.
+ // However, "array" types like "colour" aren't handled in index.php.
+
+ // TODO: I tried not doing the ajax call, but the overlay wouldn't show.
+ // It's a shame - there's no reason to re-read the file.
+
+ virtualSkyData = c;
+ virtualSkyData.latitude = myLatitude;
+ virtualSkyData.longitude = myLongitude;
+
+ // These variables have different names in virtualsky.js and our config file.
+ virtualSkyData.width = c.overlayWidth;
+ virtualSkyData.height = c.overlayHeight;
+
+ S.virtualsky(virtualSkyData); // Creates overlay
+ overlayBuilt = true;
+
+ // Save overlay offset values
+ overlayOffsetTop = c.overlayOffsetTop;
+ overlayOffsetLeft = c.overlayOffsetLeft;
+
+ // max-width of #imageContainer is set in index.php based on
+ // width user specified (imageWidth)
+ icWidth = $("#imageContainer").width();
+ icHeight = $("#imageContainer").height();
+ icImageAspectRatio = icWidth / icHeight;
+
+ $("#starmap_container")
+ .css("width", icWidth + "px")
+ .css("height", icHeight + "px");
+
+ overlayWidth = c.overlayWidth;
+ overlayHeight = c.overlayHeight;
+ overlayAspectRatio = overlayWidth / overlayHeight;
+
+ // never go larger than what user specified
+ overlayHeightMax = overlayHeight;
+ overlayWidthMax = overlayWidth;
+
+ starmapWidth = $("#starmap").width();
+ starmapHeight = $("#starmap").height();
+
+ var imageWidth = c.imageWidth
+ if (icWidth < imageWidth) {
+ // The actual image on the screen is smaller than the
+ // imageWidth requested by the user.
+ // Determine the percent smaller, then shrink the overlay that amount.
+ var percentSmaller = icWidth / c.imageWidth;
+
+ // #starmap holds the starmap button, so needs to resize it as well.
+ var w = starmapWidth * percentSmaller;
+ var h = Math.round(w / overlayAspectRatio, 0);
+ w = Math.round(w, 0);
+ $("#starmap")
+ .css("width", w + "px")
+ .css("height", h + "px");
+ starmapWidth = w;
+ starmapHeight = h;
+
+ // Offset of overlay + New Margins
+ var scalemargins = icWidth / overlayWidthMax;
+ $("#starmap")
+ .css("margin-top", c.overlayOffsetTop * scalemargins + "px")
+ .css("margin-left", c.overlayOffsetLeft * scalemargins + "px");
+
+ overlayWidth = Math.round(overlayWidth * percentSmaller, 0);
+ overlayHeight = Math.round(overlayWidth / overlayAspectRatio, 0);
+ $("#starmap_inner")
+ .css("width", overlayWidth + "px")
+ .css("height", overlayHeight + "px");
+ } else {
+ $("#starmap")
+ .css("margin-top", c.overlayOffsetTop + "px")
+ .css("margin-left", Math.round(c.overlayOffsetLeft, 0) + "px");
+
+ }
+
+ // id="live_container" is where the image goes.
+ var image_w = c.imageWidth;
+ var image_h = Math.round((image_w / icImageAspectRatio), 0);
+
+ // Put "?" icon on upper right of image. +2 moves off border.
+ var x = w
+ - document.getElementById("imageContainer").offsetWidth
+ - document.getElementById("imageContainer").offsetLeft
+ + 2; // 2 to move off border
+ $(".starmap_btn_help").css("right", Math.round(x, 0) + "px");
+
+ // Keep track of the sizes. virtualsky.js seems to change them,
+ // so we need to change them based on our last known sizes.
+ last_s_iW = $("#starmap_inner").width();
+ last_s_iH = $("#starmap_inner").height();
+ }
+ });
+ }
+};
+
+function compile($compile) {
+ // directive factory creates a link function
+ return function (scope, element, attrs) {
+ scope.$watch(
+ function (scope) {
+ // watch the 'compile' expression for changes
+ return scope.$eval(attrs.compile);
+ },
+ function (value) {
+ // when the 'compile' expression changes
+ // assign it into the current DOM
+ element.html(value);
+
+ // compile the new DOM and link it to the current
+ // scope.
+ // NOTE: we only compile .childNodes so that
+ // we don't get into infinite loop compiling ourselves
+ $compile(element.contents())(scope);
+ }
+ );
+ };
+}
+
+function convertLatitude(sc, lat) { // sc == scope
+ var convertToString = false;
+ var len, direction;
+
+ if (typeof lat === "string") {
+ sc.s_latitude = lat; // string version
+
+ len = lat.length;
+ direction = lat.substr(len-1, 1).toUpperCase();
+ if (direction == "N")
+ sc.latitude = lat.substr(0, len-2) * 1;
+ else if (direction == "S")
+ sc.latitude = lat.substr(0, len-2) * -1;
+ else {
+ // a number with quotes around it which is treated as a string
+ sc.latitude = lat * 1;
+ convertToString = true;
+ }
+ } else {
+ sc.latitude = lat;
+ convertToString = true;
+ }
+
+ if (convertToString) {
+ if (lat >= 0)
+ sc.s_latitude = lat + "N";
+ else
+ sc.s_latitude = -lat + "S";
+ }
+
+ return sc.latitude;
+}
+
+function convertLongitude(sc, lon) {
+ var convertToString = false;
+ var len, direction;
+
+ if (typeof lon === "string") {
+ sc.s_longitude = lon;
+
+ len = config.longitude.length;
+ direction = lon.substr(len-1, 1).toUpperCase();
+ if (direction == "E")
+ sc.longitude = lon.substr(0, len-2) * 1;
+ else if (direction == "W")
+ sc.longitude = lon.substr(0, len-2) * -1;
+ else {
+ // a number with quotes around it which is treated as a string
+ sc.longitude = lon * 1;
+ convertToString = true;
+ }
+ } else {
+ sc.longitude = lon;
+ convertToString = true;
+ }
+
+ if (convertToString) {
+ if (config.longitude >= 0)
+ sc.s_longitude = lon + "E";
+ else
+ sc.s_longitude = -lon + "W";
+ }
+
+ return sc.longitude;
+}
+
+function AppCtrl($scope, $timeout, $http, _) {
+
+ // Allow latitude and longitude to have or not have N, S, E, W,
+ // but in the popout, always use the letters for consistency.
+ // virtualsky.js expects decimal numbers so we need both.
+ // Need to convert them before building the overlay.
+ $scope.latitude = convertLatitude($scope, config.latitude);
+ myLatitude = $scope.latitude;
+ $scope.longitude = convertLongitude($scope, config.longitude);
+ myLongitude = $scope.longitude;
+
+ $scope.imageURL = config.loadingImage;
+ $scope.showInfo = false;
+ $scope.showOverlay = config.showOverlayAtStartup;
+ if ($scope.showOverlay) {
+ console.log("@@ Building overlay at startup for showOverlay...");
+ buildOverlay();
+ }
+ $scope.notification = "";
+ $scope.location = config.location;
+ $scope.camera = config.camera;
+ $scope.lens = config.lens;
+ $scope.computer = config.computer;
+ $scope.owner = config.owner;
+ $scope.auroraForecast = config.auroraForecast;
+ $scope.imageName = config.imageName;
+ $scope.AllskyVersion = config.AllskyVersion;
+
+ function getHiddenProp() {
+ var prefixes = ['webkit', 'moz', 'ms', 'o'];
+
+ // if 'hidden' is natively supported just return it
+ if ('hidden' in document) return 'hidden';
+
+ // otherwise loop over all the known prefixes until we find one
+ for (var i = 0; i < prefixes.length; i++) {
+ if ((prefixes[i] + 'Hidden') in document)
+ return prefixes[i] + 'Hidden';
+ }
+
+ // otherwise it's not supported
+ return null;
+ }
+ var hiddenProperty = getHiddenProp();
+
+ function isHidden() {
+ if (! hiddenProperty) return false;
+ return document[hiddenProperty];
+ }
+
+ // If the "sunData" file wasn't found, or for some reason "sunset" isn't in it,
+ // the routine that reads "sunData" will set "dataMissingMsg" so display it.
+ // If the file's old "dataOldMsg" will be set.
+ var dataMissingMsg = "";
+ var dataOldMsg = "";
+
+ function formatMessage(msg, msgType) {
+ return("
" + msg + "
");
+ }
+
+ // How old should the data file be, or the sunset time be, in order to warn the user?
+ // In the morning before a new file is uploaded,
+ // it'll be a day old so use a value at least greater than 1.
+ const oldDataLimit = 2;
+
+ // The defaultInterval should ideally be based on the time between day and night images - why
+ // check every 5 seconds if new images only appear once a minute?
+ var defaultInterval = (config.intervalSeconds * 1000); // Time to wait between normal images.
+ var intervalTimer = defaultInterval; // Amount of time we're currently waiting
+
+ // If we're not taking pictures during the day, we don't need to check for updated images as often.
+ // If we're displaying an aurora picture, it's only updated every 5 mintutes.
+ // If we're not displaying an aurora picture the picture we ARE displaying doesn't change so
+ // there's no need to check until nightfall.
+ // However, in case the image DOES change, check every minute. Seems like a good compromise.
+ // Also, in both cases, if we wait too long, when the user returns to the web page after
+ // it's been hidden, they'll have to wait a long time for the page to update.
+ var auroraIntervalTimer = (60 * 1000); // seconds
+ var auroraIntervalTimerShortened = (15 * 1000); // seconds
+ var nonAuroraIntervalTimer = (60 * 1000); // seconds
+
+ // When there is only this much time to nightime,
+ // shorten the timeout value for quicker message updates.
+ const startShortenedTimeout = (10 * 60 * 1000); // minutes
+
+ var lastType = "";
+ var loggedTimes = false;
+ var numImagesRead = 0;
+ var numCalls = 0;
+
+ $scope.getImage = function () {
+ var url= "";
+ var imageClass= "";
+ // Go through the loop occassionally even when hidden so we re-read the sunData file
+ // if needed.
+ if (! isHidden() || ++numCalls % 5 == 0) {
+ $scope.notification = "";
+ if (dataMissingMsg !== "") {
+ $scope.notification += formatMessage(dataMissingMsg, "error");
+ }
+ if (dataOldMsg !== "") {
+ $scope.notification += formatMessage(dataOldMsg, "warning");
+ }
+
+ var rereadSunriseSunset = false;
+
+ numImagesRead++;
+
+ // the "m_" prefix means it's a moment() object.
+ var m_now = moment(new Date());
+ var m_nowTime = m_now.format(timeF);
+ var m_sunriseTime = moment($scope.sunrise).format(timeF);
+ var m_sunsetTime = moment($scope.sunset).format(timeF);
+ var beforeSunriseTime = m_nowTime < m_sunriseTime;
+ var afterSunsetTime = m_nowTime > m_sunsetTime;
+
+ // Check if the sunset time is too old.
+ // If the data file is old, don't bother checking sunset time since it'll be old too.
+ // However, we may need "daysOld" below so calculate it.
+ var m_nowDate = moment(m_now.format(dateF)); // needs to be moment() object
+ var m_sunsetDate = moment($scope.sunset.format(dateF));
+ var daysOld = moment.duration(m_nowDate.diff(m_sunsetDate)).days();
+ var oldMsg = "";
+
+ // This check assumes sunrise and sunset are both in the same day,
+ // which they should be since postData.sh runs at the end of nighttime and calculates
+ // sunrise and sunset for the current day.
+
+ // It's nighttime if we're either before sunrise (e.g., 3 am and sunrise is 6 am) OR
+ // it's after sunset (e.g., 9 pm and sunset is 8 pm).
+ // Both only work if we're in the same day.
+ var is_nighttime;
+ if (beforeSunriseTime || afterSunsetTime) {
+ // sunrise is in the future so it's currently nighttime
+ is_nighttime = true;
+ } else {
+ is_nighttime = false;
+ }
+
+ // The sunrise and sunset times change every day, and the user may have changed
+ // when they're taking images, so re-read the "sunData" file when something changes.
+ if (is_nighttime) {
+ // Only add to the console log once per message type
+ if (lastType !== "nighttime") {
+ console.log("=== Night Time imaging starts at " + m_now.format(timeAmPmF));
+ lastType = "nighttime";
+ loggedTimes = false;
+ rereadSunriseSunset = true;
+ }
+ url = config.imageName;
+ imageClass = 'current';
+ intervalTimer = defaultInterval;
+
+ } else if ($scope.takedaytimeimages) {
+ if (lastType !== "daytime") {
+ console.log("=== Day Time imaging starts at " + m_now.format(timeAmPmF));
+ lastType = "daytime";
+ loggedTimes = false;
+ rereadSunriseSunset = true;
+ }
+ url = config.imageName;
+ imageClass = 'current';
+ intervalTimer = defaultInterval;
+
+ } else { // daytime but we're not taking pictures
+ if (lastType !== "daytimeoff") {
+ console.log("=== Camera turned off during Day Time at " + m_now.format(timeAmPmF));
+ lastType = "daytimeoff";
+ loggedTimes = false;
+ rereadSunriseSunset = true;
+ }
+
+ // Countdown calculation
+ // The sunset time only has hours and minutes so could be off by up to a minute,
+ // so add some time. Better to tell the user to come back in 2 minutes and
+ // have the actual time be 1 minute, than to tell them 1 minute and a new
+ // picture doesn't appear for 2 minutes after they return so they sit around waiting.
+ // Need to compare on the same date, but different times.
+ var ms = moment($scope.sunset, dateTimeF)
+ .add(daysOld,"days")
+ .diff(moment(m_now, dateTimeF));
+
+ // Testing showed that 1 minute wasn't enough to add, and we need to account for
+ // long nighttime exposures, so add 2.5 minutes.
+ const add = 2.5 * 60 * 1000;
+ ms += add;
+ const time_to_come_back = moment($scope.sunset + add).format(timeAmPmF);
+
+ var d = moment.duration(ms);
+ var hours = Math.floor(d.asHours());
+ var minutes = moment.utc(ms).format("m");
+ var seconds = moment.utc(ms).format("s");
+ var h = hours !== 0 ? hours + " hour" + (hours > 1 ? "s " : " ") : "";
+ // Have to use != instead of !== because "minutes" is a string.
+ var m = minutes != 0 ? minutes + " minute" + (minutes > 1 ? "s" : "") : "";
+ var s
+ if (hours == 0 && minutes == 0)
+ s = seconds + " seconds";
+ else
+ s = h + m;
+ $scope.notification += formatMessage("It's not dark yet in " + config.location + ". Come back at " + time_to_come_back + " (" + s + ").", "notice");
+
+ if (! loggedTimes) {
+ console.log("=== Resuming at nighttime in " + s);
+ }
+ if ($scope.auroraForecast) {
+ url = "https://services.swpc.noaa.gov/images/animations/ovation/";
+ url += config.auroraMap + "/latest.jpg";
+ imageClass = 'forecast-map';
+ // If less than startShortenedTimeout time left, shorten the timer.
+ if (ms < startShortenedTimeout) {
+ intervalTimer = auroraIntervalTimerShortened;
+ } else {
+ intervalTimer = auroraIntervalTimer;
+ }
+ } else {
+ url = config.imageName;
+ imageClass = 'current';
+ intervalTimer = nonAuroraIntervalTimer;
+ }
+
+ }
+
+ if (! loggedTimes) { // for debugging
+ loggedTimes = true;
+ console.log(" m_now = " + m_now.format(dateTimeF));
+ if (oldMsg !== "") console.log(" > " + oldMsg);
+
+ console.log(" m_now="+m_nowTime + ", m_sunrise="+m_sunriseTime + ", m_sunset="+m_sunsetTime);
+ console.log(" beforeSunriseTime = " + beforeSunriseTime);
+ console.log(" afterSunsetTime = " + afterSunsetTime);
+ }
+
+// TODO: Is there a way to specify not to cache this without using "?_ts" ?
+ var img = $("")
+ .attr('src', url + '?_ts=' + new Date().getTime())
+ .addClass(imageClass)
+ .on('load', function() {
+ if (!this.complete || typeof this.naturalWidth === "undefined" || this.naturalWidth === 0) {
+ alert('broken image!');
+ $timeout(function(){
+ $scope.getImage();
+ }, 500);
+ } else {
+ $("#live_container").empty().append(img);
+ }
+ });
+
+ // Don't re-read after the 1st image of this period since we read it right before the image.
+ if (rereadSunriseSunset && numImagesRead > 1) {
+ $scope.getSunRiseSet();
+ }
+ } // if (! isHidden()))
+ };
+
+ // Set a default sunrise if we can't get it from "sunData".
+ var usingDefaultSunrise = false;
+ function getDefaultSunrise(today) {
+ return(moment(new Date(today.getFullYear(), today.getMonth(), today.getDate(), 6, 0, 0)));
+ }
+ // Set a default sunset if we can't get it from "sunData".
+ var usingDefaultSunset = false;
+ function getDefaultSunset(today) {
+ return(moment(new Date(today.getFullYear(), today.getMonth(), today.getDate(), 18, 0, 0)));
+ }
+
+ function writeSunriseSunsetToConsole() {
+ console.log(" * sunrise = " + $scope.sunrise.format(dateTimeF) +
+ (usingDefaultSunrise ? " (default)" : ""));
+ console.log(" * sunset = " + $scope.sunset.format(dateTimeF) +
+ (usingDefaultSunset ? " (default)" : ""));
+ console.log(" * takedaytimeimages == " + $scope.takedaytimeimages);
+ console.log(" * takenighttimeimages == " + $scope.takenighttimeimages);
+ if (lastModifiedSunriseSunsetFile !== null)
+ console.log(" * last modified = " + lastModifiedSunriseSunsetFile.format(dateTimeF));
+ }
+
+ var usingDefaultTakingDaytime = false;
+ var usingDefaultTakingNighttime = false;
+ var lastModifiedSunriseSunsetFile = null;
+
+ $scope.getSunRiseSet = function () {
+ now = new Date();
+ var url = sunData;
+// TODO: is ?_ts needed if we are not cache'ing ?
+ url += '?_ts=' + now.getTime();
+ console.log("Read " + sunData + " on " + moment(now).format("MM-DD h:mm:ss a") + ":");
+ $http.get(url, {
+ cache: false
+ }).then(
+ function (data) {
+ // Make sure all the data is there.
+ if (data.data.sunrise) {
+ $scope.sunrise = moment(data.data.sunrise);
+ usingDefaultSunrise = false;
+ } else if (! usingDefaultSunrise) {
+ $scope.sunrise = getDefaultSunrise(now);
+ usingDefaultSunrise = true;
+ }
+ if (data.data.sunset) {
+ $scope.sunset = moment(data.data.sunset);
+ usingDefaultSunset = false;
+ } else if (! usingDefaultSunset) {
+ $scope.sunset = getDefaultSunset(now);
+ usingDefaultSunset = true;
+ }
+ if (data.data.takedaytimeimages) {
+ $scope.takedaytimeimages = data.data.takedaytimeimages === "true";
+// TODO: streamDaytime is old name - delete in next release
+ } else if (data.data.streamDaytime) {
+ $scope.takedaytimeimages = data.data.streamDaytime === "true";
+ } else {
+ $scope.takedaytimeimages = true;
+ usingDefaultTakingDaytime = true;
+ }
+ if (data.data.takenighttimeimages) {
+ $scope.takenighttimeimages = data.data.takenighttimeimages === "true";
+ } else {
+ $scope.takenighttimeimages = true;
+ usingDefaultTakingNighttime = true;
+ }
+
+ dataMissingMsg = "";
+ if (usingDefaultSunset || usingDefaultSunrise ||
+ usingDefaultTakingDaytime || usingDefaultTakingNighttime) {
+ dataMissingMsg = "ERROR: Data missing from '" + sunData + "':";
+ dataMissingMsg += "
";
+ if (usingDefaultSunrise) {
+ dataMissingMsg += "
";
+ $retMsg .= "ERROR: Bad configuration file '$configurationFileName'.";
+ $retMsg .= " Cannot continue.";
+ $retMsg .= " Check for missing quotes or commas at the end of every line except the last one.";
+ $retMsg .= "
";
+ $retMsg .= "
$webSettings_str
";
+ return($retMsg);
+ }
+
+ return("");
+}
+$initializeErrorMessage = initialize();
+if ($initializeErrorMessage !== "" && $exitOnInitializationError) {
+ echo "$initializeErrorMessage";
+ exit(1);
+}
+
+
+/*
+ * Look for $var in the $a array and return its value.
+ * If not found, return $default.
+ * If the value is a boolean and is false, an empty string is given to us so return 0;
+ * A true boolean value returns 1.
+*/
+function v($var, $default, $a) {
+ if (isset($a[$var])) {
+ $value = $a[$var];
+ if (gettype($default) === "boolean" && $value == "")
+ return(0);
+ else
+ return($value);
+ } else if (gettype($default) === "boolean") {
+ return(0);
+ } else {
+ return($default);
+ }
+}
+
+/*
+ * Does the exec() function work? It's needed to make thumbnails from video files.
+*/
+$yes_no = null;
+function can_make_video_thumbnails() {
+ global $yes_no;
+ if ($yes_no !== null) return($yes_no);
+
+ $disabled = explode(',', ini_get('disable_functions'));
+ // On some servers the disabled array contains leading spaces, so check both ways.
+ $exec_disabled = in_array('exec', $disabled) || in_array(' exec', $disabled);
+
+ if ($exec_disabled) {
+ echo "";
+ $yes_no = false;
+ } else {
+ // See if ffmpeg exists.
+ @exec("which ffmpeg 2> /dev/null", $ret, $retvalue);
+ if ($retvalue == 0) {
+ $yes_no = true;
+ } else {
+ echo "";
+ $yes_no = false;
+ }
+ }
+ return($yes_no);
+}
+
+/*
+ * Disable buffering.
+*/
+function disableBuffering() {
+ ini_set('output_buffering', false);
+ ini_set('implicit_flush', true);
+ ob_implicit_flush(true);
+ for ($i = 0; $i < ob_get_level(); $i++)
+ ob_end_clean();
+}
+
+/**
+*
+* Get a variable from a file and return its value; if not there, return the default.
+* NOTE: The variable's value is anything after the equal sign, so there shouldn't be a comment on the line.
+* NOTE: There may be something before $searchfor, e.g., "export X=1", where "X" is $searchfor.
+*/
+function get_variable($file, $searchfor, $default)
+{
+ // get the file contents
+ if (! file_exists($file)) return($default);
+
+ $contents = file_get_contents($file);
+ if ("$contents" == "") return($default); // file not readable
+
+ // escape special characters in the query
+ $pattern = preg_quote($searchfor, '/');
+ // finalise the regular expression, matching the whole line
+ $pattern = "/^.*$pattern.*\$/m";
+
+ // search, and store all matching occurences in $matches, but only return the last one
+ $num_matches = preg_match_all($pattern, $contents, $matches);
+ if ($num_matches) {
+ $double_quote = '"';
+
+ // Format: [stuff]$searchfor=$value or [stuff]$searchfor="$value"
+ // Need to delete [stuff]$searchfor= and optional double quotes
+ $last = $matches[0][$num_matches - 1]; // get the last one
+ $both = explode( '=', $last);
+ if (isset($both[1])) {
+ $last = $both[1]; // everything after equal sign
+ $last = str_replace($double_quote, "", $last);
+ } else {
+ return($default); // nothing after "="
+ }
+ return($last);
+ } else {
+ return($default);
+ }
+}
+
+$displayed_thumbnail_error_message = false;
+function make_thumb($src, $dest, $desired_width)
+{
+ if (! file_exists($src)) {
+ echo "
Unable to make thumbnail: '$src' is empty! Removed it.
";
+ unlink($src);
+ return(false);
+ }
+
+ /* Make sure the imagecreatefromjpeg() function is in PHP. */
+ global $displayed_thumbnail_error_message;
+ if ( preg_match("/\.(jpg|jpeg)$/", $src ) ) {
+ $funcext='jpeg';
+ } elseif ( preg_match("/\.png$/", $src ) ) {
+ $funcext='png';
+ }
+ if (function_exists("imagecreatefrom${funcext}") == false)
+ {
+ if ($displayed_thumbnail_error_message == false)
+ {
+ echo "
";
+ echo "Unable to make thumbnail(s); imagecreatefrom{$funcext}() does not exist.";
+ echo "
";
+ echo "If this is on a remote Allsky Website, ask the server administrator to";
+ echo " support imagecreatefrom{$funcext}() in PHP.";
+
+ echo "
";
+ echo "If this is on a Pi and you do not have the file '/etc/php/8.2/mods-available/gd.ini'";
+ echo " (or another php release), you need to download the latest PHP.";
+ echo "
";
+
+ $displayed_thumbnail_error_message = true;
+ }
+ return(false);
+ }
+
+ /* read the source image */
+ $funcname="imagecreatefrom{$funcext}";
+ $source_image = $funcname($src);
+ $width = imagesx($source_image);
+ $height = imagesy($source_image);
+
+ /* find the "desired height" of this thumbnail, relative to the desired width */
+ if ($desired_width > $width)
+ $desired_width = $width; // This might create a very tall thumbnail...
+ $desired_height = floor($height * ($desired_width / $width));
+
+ /* create a new, "virtual" image */
+ $virtual_image = imagecreatetruecolor($desired_width, $desired_height);
+
+ /* copy source image at a resized size */
+ imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, $desired_height, $width, $height);
+
+ /* create the physical thumbnail image to its destination */
+ @imagejpeg($virtual_image, $dest);
+
+ // flush so user sees thumbnails as they are created, instead of waiting for them all.
+ flush(); // flush even if we couldn't make the thumbnail so the user sees this file immediately.
+ if (file_exists($dest)) {
+ if (filesize($dest) === 0) {
+ echo "
Unable to make thumbnail for '$src': thumbnail was empty! Using full-size image for thumbnail.
Unable to create thumbnail for '$src': " . error_get_last()['message'] . "
";
+ return(false);
+ }
+}
+
+// Did creation of last thumbnail work?
+// If not, don't try to create any more since they likely won't work either.
+$last_thumbnail_worked = true;
+
+// Similar to make_thumb() but using a video for the input file.
+function make_thumb_from_video($src, $dest, $desired_width, $attempts)
+{
+ global $last_thumbnail_worked;
+ if (! $last_thumbnail_worked) {
+ return(false);
+ }
+
+ if (! can_make_video_thumbnails()) {
+ return(false);
+ }
+
+ if (! file_exists($src)) {
+ echo "
Unable to make thumbnail: '$src' is empty! Removed it.
";
+ unlink($src);
+ return(false);
+ }
+
+ // Start 5 seconds in to skip any auto-exposure changes at the beginning.
+ // This of course assumes the video is at least 5 sec long. If it's not, we won't be able
+ // to create a thumbnail, so call ourselfs a second time using 1 second.
+ // If the file is less than 1 second long, well, too bad.
+ // "-1" scales the height to the original aspect ratio.
+ if ($attempts === 1)
+ $sec = "05";
+ else
+ $sec = "00";
+ $command = "ffmpeg -loglevel warning -ss 00:00:$sec -i '$src' -filter:v scale='$desired_width:-1' -frames:v 1 '$dest' 2>&1";
+ $output = array();
+ exec($command, $output);
+ if (file_exists($dest)) {
+ if (filesize($dest) === 0) {
+ echo "
Unable to make thumbnail for '$src': thumbnail was empty! Using full-size image for thumbnail.
Unable to make '$thumb_dir' directory. You will need to create it manually.
";
+ print_r(error_get_last());
+ }
+
+ echo "
";
+ echo "
$back_button
";
+ echo "
$title
";
+ echo "
";
+ echo "
\n";
+
+ $thumbnailSizeX = v("thumbnailsizex", 100, $webSettings_array['homePage']);
+ foreach ($files as $file) {
+ // The thumbnail should be a .jpg.
+ $thumbnail = preg_replace($ext, ".jpg", "$dir/thumbnails/$file");
+ if (! file_exists($thumbnail)) {
+ if ($file_prefix == "allsky") {
+ if (! make_thumb_from_video("$dir/$file", $thumbnail, $thumbnailSizeX, 1)) {
+ // We can't use the video file as a thumbnail
+ $thumbnail = "../NoThumbnail.png";
+ }
+ } else {
+ if (! make_thumb("$dir/$file", $thumbnail, $thumbnailSizeX)) {
+ // Using the full-sized file as a thumbnail is overkill,
+ // but it's better than no thumbnail.
+ $thumbnail = "$dir/$file";
+ }
+ }
+ // flush so user sees thumbnails as they are created, instead of waiting for them all.
+ //echo " flushing after $file:";
+ flush();
+ }
+ $year = substr($file, $file_prefix_len + 1, 4);
+ $month = substr($file, $file_prefix_len + 5, 2);
+ $day = substr($file, $file_prefix_len + 7, 2);
+ $date = $year.$month.$day;
+ echo "