Compare commits

..

13 Commits

Author SHA1 Message Date
sfeakes 6472e3ccd8 Version 2.6.3 2025-04-13 14:19:18 -05:00
sfeakes d789fc2cfb Update aqmanager.html 2025-04-13 14:04:56 -05:00
sfeakes 76f3adfcb9 Update aqmanager.html 2025-04-13 13:52:57 -05:00
sfeakes d23db569d0 Update 2.6.2 2025-04-13 13:42:13 -05:00
sfeakes c04ec5ce01 Update 2.6.2 2025-04-13 13:15:49 -05:00
sfeakes 47c56ee5d4 Update aqmanager.html 2025-04-13 12:17:05 -05:00
sfeakes 5fcbc2a2e9 Update README.md 2025-04-13 12:04:33 -05:00
sfeakes a410d31ad6 Updates 2.6.2 2025-04-13 12:03:42 -05:00
sfeakes 4faa2e0db0 Updates for 2.6.2 2025-04-13 12:03:02 -05:00
sfeakes a38a1c6e00 self update changes 2025-04-13 11:38:23 -05:00
sfeakes 1965a7460c Update upgrade.sh 2025-04-05 16:00:09 -05:00
sfeakes 39a8ca5684 Update upgrade.sh 2025-04-05 13:34:31 -05:00
sfeakes 411891fd88 Create upgrade.sh 2025-04-05 13:16:01 -05:00
25 changed files with 905 additions and 189 deletions

View File

@ -84,7 +84,7 @@ endif
SRCS = aqualinkd.c utils.c config.c aq_serial.c aq_panel.c aq_programmer.c allbutton.c allbutton_aq_programmer.c net_services.c json_messages.c rs_msg_utils.c\
onetouch.c onetouch_aq_programmer.c iaqtouch.c iaqtouch_aq_programmer.c iaqualink.c\
devices_jandy.c packetLogger.c devices_pentair.c color_lights.c serialadapter.c aq_timer.c aq_scheduler.c web_config.c\
serial_logger.c mongoose.c hassio.c simulator.c sensors.c aq_filesystem.c timespec_subtract.c
serial_logger.c mongoose.c hassio.c simulator.c sensors.c aq_systemutils.c timespec_subtract.c
AQ_FLAGS =

View File

@ -11,23 +11,29 @@ If you like this project, you can buy me a cup of coffee :)
<br>
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SEGN9UNS38TXJ)
## AqualinkD new home
AqualinkD has grown over the years and now has multiple repositories for software / hardware. We are brining them all together under one organization. [AqualinkD home page (under construction)](https://www.aqualinkd.com) -or- [AqualinkD organization](https://github.com/aqualinkd).<br>
AqualinkD will always be open source and so will every associated repository. Nothing will change from that perspective. You will always be able to run this on cheap off the shelf hardware.
## AqualinkD discussions
* Please use github Discussions for questions (Link at top of page).
https://github.com/sfeakes/AqualinkD/discussions
https://github.com/aqualinkd/AqualinkD/discussions
* For Bugs, please use issues link on top of page. ( please add AqualinkD version to posts )
https://github.com/sfeakes/AqualinkD/issues
https://github.com/aqualinkd/AqualinkD/issues
## Please see Wiki for installation instructions
https://github.com/sfeakes/AqualinkD/wiki
https://github.com/aqualinkd/AqualinkD/wiki
<!--
For information on Control panel versions and upgrading the chips.<br>
https://github.com/sfeakes/AqualinkD/wiki/Upgrading-Jandy-Aqualink-PDA-to-RS-panel
https://github.com/aqualinkd/AqualinkD/wiki/Upgrading-Jandy-Aqualink-PDA-to-RS-panel
-->
<!--
Here's where I started to document what I know about the Jandy RS485 protocol.<br>
https://github.com/sfeakes/AqualinkD/wiki/Jandy-Aqualink-RS485-protocol
https://github.com/aqualinkd/AqualinkD/wiki/Jandy-Aqualink-RS485-protocol
-->
## AqualinkD built in WEB Interface(s).
@ -80,9 +86,11 @@ Designed to mimic AqualinkRS devices, used to fully configure the master control
* http://aqualink.ip/onetouch_sim.html <- (One Touch Simulator)
* http://aqualink.ip/aquapda_sim.html <- (PDA simulator)
#<a name="release"></a>
# ToDo (future release)
* Create iAqualink Touch Simulator
* AuqlinkD to self configure. (Done for ID's, need to do for Panel type/size)
* AqualinkD to self configure. (Done for ID's, need to do for Panel type/size)
<!--
@ -100,7 +108,7 @@ Designed to mimic AqualinkRS devices, used to fully configure the master control
-->
# Call for Help.
* The only Jandy devices I have not decoded yet are LX heater & Chemical Feeder. If you have either of these devices and are willing to post some logs, please let me know, or post in the [Discussions area](https://github.com/sfeakes/AqualinkD/discussions)
* The only Jandy devices I have not decoded yet are LX heater & Chemical Feeder. If you have either of these devices and are willing to post some logs, please let me know, or post in the [Discussions area](https://github.com/aqualinkd/AqualinkD/discussions)
<!--
@ -111,10 +119,22 @@ NEED TO FIX FOR THIS RELEASE.
* update documentation on how vbutton / vpump / pump_max & min / enable_iauqalink2
* check rs serial adapter is active if light color mode 11 is used.
* Check SWG messages like "#1 TruClear", see log in this post https://github.com/sfeakes/AqualinkD/discussions/388
* Check SWG messages like "#1 TruClear", see log in this post https://github.com/aqualinkd/AqualinkD/discussions/388
* Heat Pump / Chiller for OneTouch
* Try an auto-update
* Update Mongoose
-->
# Updates in 2.6.3
* AqualinkD can how self-update directly from github. use `Upgrade AqualinkD` button in Aqmanager
* New install and remote_install scripts.
* Changed MQTT posting frequency when Timers are enabled for better
* Updates for new repo location. [AqualinkD organization](https://github.com/aqualinkd/AqualinkD)
* Please use the following to upgrade
* `curl -fsSL https://install.aqualinkd.com | sudo bash -s -- latest`
* -or-
* `curl -fsSL https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/release/remote_install.sh | sudo bash -s -- latest`
# Updates in 2.6.1
* Added External Sensors to Web UI & HomeKit.
@ -123,7 +143,7 @@ NEED TO FIX FOR THIS RELEASE.
* Link device/virtual/onetouch button with SWG BOOST. (Allows you to set VSP RPM when in Boost mode)
# Updates in 2.6.0
* Added configuration editor in aqmanager. [Wiki - AQManager](https://github.com/sfeakes/AqualinkD/wiki#AQManager)
* Added configuration editor in aqmanager. [Wiki - AQManager](https://github.com/aqualinkd/AqualinkD/wiki#AQManager)
* Can now self-configure on startup. set `device_id=0xFF`
* Added scheduling of pump after events (Power On, Freeze Protect, Boost)
* Fixed HA bug for thermostats not converting to °C when HA is set to display °C.
@ -195,10 +215,10 @@ NEED TO FIX FOR THIS RELEASE.
# Update in Release 2.3.5
* Added Home Assistant integration through MQTT discover
* Please read the Home Assistant section of the [Wiki - HASSIO](https://github.com/sfeakes/AqualinkD/wiki#HASSIO)
* Please read the Home Assistant section of the [Wiki - HASSIO](https://github.com/aqualinkd/AqualinkD/wiki#HASSIO)
* There are still some enhacments to come on this.
* Included Docker into main releases
* Please read Docker section of the [Wiki - Docker](https://github.com/sfeakes/AqualinkD/wiki#Docker)
* Please read Docker section of the [Wiki - Docker](https://github.com/aqualinkd/AqualinkD/wiki#Docker)
* Added support for reading extended information for Jandy JXi heaters.
* Added Color Light to iAqualinkTouch protocol.
* Fixed issue mqtt_timed_update (1~2 min rather than between 2 & 20 min)
@ -214,11 +234,11 @@ NEED TO FIX FOR THIS RELEASE.
# Update in Release 2.3.3
* Introduced Aqualink Manager UI http://aqualink.ip/aqmanager.html
* [AqualinkD Manager](https://github.com/sfeakes/AqualinkD/wiki#AQManager)
* [AqualinkD Manager](https://github.com/aqualinkd/AqualinkD/wiki#AQManager)
* Moved logging into systemd/journal (journalctl) from syslog
* [AqualinkD Log](https://github.com/sfeakes/AqualinkD/wiki#Log)
* [AqualinkD Log](https://github.com/aqualinkd/AqualinkD/wiki#Log)
* Updated to scheduler
* [AqualinkD Scheduler](https://github.com/sfeakes/AqualinkD/wiki#Scheduler)
* [AqualinkD Scheduler](https://github.com/aqualinkd/AqualinkD/wiki#Scheduler)
* Introduced RS485 frame delay / timer.
* Improve PDA panels reliability (PDA pannels are slower than RS panels)
* Potentially fixed Pentair VSP / SWG problems since Pentair VSP use a different protocol, this will allow a timed delay for the VSP to post a status messages. Seems to only effect RS485 bus when both a Pentair VSP and Jandy SWG are present.
@ -275,7 +295,7 @@ NEED TO FIX FOR THIS RELEASE.
* Fixed RS-4 panel bug.
* Fixed some AqualinkTouch programming issues.
* Increased timeout for startup probe.
* This release WILL require you to make aqualinkd.conf changes. <b>Make sure to read wiki section https://github.com/sfeakes/AqualinkD/wiki#Version_2</b>
* This release WILL require you to make aqualinkd.conf changes. <b>Make sure to read wiki section https://github.com/aqualinkd/AqualinkD/wiki#Version_2</b>
* Extensive work to reduce CPU cycles and unnesessary logic.
* iAqualink Touch protocol supported for VSP & extended programming.
* This protocol is a lot faster for programming, ID's are between 0x38 & 0x3B `extended_device_id`, use Serial_logger to find valid ID.
@ -292,7 +312,7 @@ NEED TO FIX FOR THIS RELEASE.
* AqualinkD startup changed to fix some 'systemctl restart' issues.
* More detailed API replys.
# Update in Release 2.1.0
* Big update, lots of core changes, <b>please read wiki section https://github.com/sfeakes/AqualinkD/wiki#Version_2</b>
* Big update, lots of core changes, <b>please read wiki section https://github.com/aqualinkd/AqualinkD/wiki#Version_2</b>
* Full Variable Speed Pump support. (Can read,set & change RPM,GPM)
* Full support for all Colored Lights (even if Jandy Control Panel doesn't support them)
* Chemlink pH & ORP now supported. (along with posting MQTT information)
@ -438,7 +458,7 @@ NEED TO FIX FOR THIS RELEASE.
* Freeze protect, heater temperature and SWG set-points have been added to support for standard HTTP requests (MQTT & WS always had support).
# Please see Wiki for install instructions
https://github.com/sfeakes/AqualinkD/wiki
https://github.com/aqualinkd/AqualinkD/wiki
#

View File

@ -19,9 +19,9 @@ RUN mkdir /home/AqualinkD
WORKDIR /home/AqualinkD
ARG AQUALINKD_VERSION
RUN curl -sL "https://github.com/sfeakes/AqualinkD/archive/refs/tags/$AQUALINKD_VERSION.tar.gz" | tar xz --strip-components=1
RUN curl -sL "https://github.com/aqualinkd/AqualinkD/archive/refs/tags/$AQUALINKD_VERSION.tar.gz" | tar xz --strip-components=1
# Get latest release
#RUN curl -sL $(curl -s https://api.github.com/repos/sfeakes/AqualinkD/releases/latest | grep "tarball_url" | cut -d'"' -f4) | tar xz --strip-components=1
#RUN curl -sL $(curl -s https://api.github.com/repos/aqualinkd/AqualinkD/releases/latest | grep "tarball_url" | cut -d'"' -f4) | tar xz --strip-components=1
# Build aqualinkd
RUN make clean && \
@ -48,9 +48,9 @@ RUN sed -i '/EXTRA_OPTS=.-l./s/^#//g' /etc/default/cron
# See: https://github.com/opencontainers/image-spec/blob/main/annotations.md
LABEL org.opencontainers.image.title="AqualinkD"
LABEL org.opencontainers.image.url="https://hub.docker.com/repository/docker/sfeakes/aqualinkd/general"
LABEL org.opencontainers.image.source="https://github.com/sfeakes/AqualinkD"
LABEL org.opencontainers.image.documentation="https://github.com/sfeakes/AqualinkD"
LABEL org.opencontainers.image.url="https://hub.docker.com/repository/docker/aqualinkd/aqualinkd/general"
LABEL org.opencontainers.image.source="https://github.com/aqualinkd/AqualinkD"
LABEL org.opencontainers.image.documentation="https://github.com/aqualinkd/AqualinkD"
LABEL org.opencontainers.image.version=$AQUALINKD_VERSION
@ -60,7 +60,7 @@ COPY --from=aqualinkd-build /home/AqualinkD/web/ /var/www/aqualinkd/
COPY --from=aqualinkd-build /home/AqualinkD/release/aqualinkd.conf /etc/aqualinkd.conf
#COPY --from=aqualinkd-build /home/AqualinkD/docker/aqualinkd-docker.cmd /usr/local/bin/aqualinkd-docker
RUN curl -s -o /usr/local/bin/aqualinkd-docker https://raw.githubusercontent.com/sfeakes/AqualinkD/master/docker/aqualinkd-docker.cmd && \
RUN curl -s -o /usr/local/bin/aqualinkd-docker https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/docker/aqualinkd-docker.cmd && \
chmod +x /usr/local/bin/aqualinkd-docker
CMD ["sh", "-c", "/usr/local/bin/aqualinkd-docker"]

View File

@ -59,9 +59,9 @@ WORKDIR /home/AqualinkD
ARG AQUALINKD_VERSION
RUN curl -sL "https://github.com/sfeakes/AqualinkD/archive/refs/tags/$AQUALINKD_VERSION.tar.gz" | tar xz --strip-components=1
RUN curl -sL "https://github.com/aqualinkd/AqualinkD/archive/refs/tags/$AQUALINKD_VERSION.tar.gz" | tar xz --strip-components=1
# Get latest release
#RUN curl -sL $(curl -s https://api.github.com/repos/sfeakes/AqualinkD/releases/latest | grep "tarball_url" | cut -d'"' -f4) | tar xz --strip-components=1
#RUN curl -sL $(curl -s https://api.github.com/repos/aqualinkd/AqualinkD/releases/latest | grep "tarball_url" | cut -d'"' -f4) | tar xz --strip-components=1
# Make AqualinkD
@ -87,8 +87,8 @@ RUN sed -i '/EXTRA_OPTS=.-l./s/^#//g' /etc/default/cron
LABEL org.opencontainers.image.title="AqualinkD"
LABEL org.opencontainers.image.url="https://hub.docker.com/repository/docker/sfeakes/aqualinkd/general"
LABEL org.opencontainers.image.source="https://github.com/sfeakes/AqualinkD"
LABEL org.opencontainers.image.documentation="https://github.com/sfeakes/AqualinkD"
LABEL org.opencontainers.image.source="https://github.com/aqualinkd/AqualinkD"
LABEL org.opencontainers.image.documentation="https://github.com/aqualinkd/AqualinkD"
LABEL org.opencontainers.image.version=$AQUALINKD_VERSION
EXPOSE 80/tcp

View File

@ -2,7 +2,7 @@ services:
aqualinkd:
image: sfeakes/aqualinkd:latest
#build:
# context: https://github.com/sfeakes/AqualinkD.git#master:docker
# context: https://github.com/aqualinkd/AqualinkD.git#master:docker
# args:
# AQUALINKD_VERSION: v2.3.6 # Make sure to change to correct version
# tags:

View File

@ -10,6 +10,25 @@
# curl --silent "https://raw.githubusercontent.com/sfeakes/AqualinkD/master/version.h" | grep AQUALINKD_VERSION | cut -d '"' -f 2
#
echo "This script has been updated!"
echo "Please use 'curl -fsSL https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/release/remote_install.sh | sudo bash -s -- latest' to install AqualinkD"
while true; do
read -p "Continue install with this script? (y/n): " response
case $response in
[yY] )
echo "Continuing..."
break
;;
[nN] )
echo "Exiting..."
exit 0
;;
* )
echo "Invalid input. Please enter y or n."
;;
esac
done
NAME="AqualinkD"
SOURCE_LOCATION="/extras/aqua.sh"

View File

@ -13,7 +13,7 @@
# * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# * See the GNU General Public License for more details.
# *
# * https://github.com/sfeakes/aqualinkd
# * https://github.com/aqualinkd/aqualinkd
# */

View File

@ -13,7 +13,7 @@
# * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# * See the GNU General Public License for more details.
# *
# * https://github.com/sfeakes/aqualinkd
# * https://github.com/aqualinkd/aqualinkd
# */
MAX_TEMP=78

Binary file not shown.

Binary file not shown.

0
release/aqualinkd.service Executable file → Normal file
View File

View File

@ -24,14 +24,41 @@ MDNSLocation="/etc/avahi/services/"
SOURCEBIN=$BIN
LOG_SYSTEMD=1 # 1=false in bash, 0=true
REMOUNT_RO=1
log()
{
echo "$*"
if [[ $LOG_SYSTEMD -eq 0 ]]; then
logger -p local0.notice -t aqualinkd "Upgrade: $*"
# Below is same as above but will only wotrk on journald (leaving it here if we use that rater then file)
#echo $* | systemd-cat -t aqualinkd_upgrade -p info
#echo "$*" >> "$OUTPUT"
fi
}
if ! tty > /dev/null 2>&1 || [ "$1" = "syslog" ]; then
# No stdin, probably called from upgrade script
LOG_SYSTEMD=0 # Set logger to systemd
fi
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
log "This script must be run as root"
exit 1
fi
if [[ $(mount | grep " / " | grep "(ro,") ]]; then
echo "Root filesystem is readonly, can't install"
exit 1
if mount / -o remount,rw &>/dev/null; then
# can mount RW.
#mount / -o remount,rw &>/dev/null
log "Root filesystem is readonly, remounted RW"
REMOUNT_RO=0;
else
log "Root filesystem is readonly, can't install"
exit 1
fi
fi
# Figure out what system we are on and set correct binary.
@ -41,7 +68,7 @@ if [ "$PARENT_COMMAND" != "make" ] && [ "$1" != "from-make" ] && [ "$1" != "igno
# dpkg --print-architecture
# Exit if we can't find systemctl
command -v dpkg >/dev/null 2>&1 || { echo -e "Can't detect system architecture, Please check path to 'dpkg' or install manually.\n"\
command -v dpkg >/dev/null 2>&1 || { log -e "Can't detect system architecture, Please check path to 'dpkg' or install manually.\n"\
"Or run '$0 ignorearch'" >&2; exit 1; }
ARCH=$(dpkg --print-architecture)
@ -49,19 +76,19 @@ if [ "$PARENT_COMMAND" != "make" ] && [ "$1" != "from-make" ] && [ "$1" != "igno
case $ARCH in
arm64)
echo "Arch is $ARCH, Using 64bit AqualinkD"
log "Arch is $ARCH, Using 64bit AqualinkD"
BINEXT="-arm64"
;;
armhf)
echo "Arch is $ARCH, Using 32bit AqualinkD"
log "Arch is $ARCH, Using 32bit AqualinkD"
BINEXT="-armhf"
;;
*)
if [ -f $BUILD/$SOURCEBIN-$ARCH ]; then
echo "Arch $ARCH is not officially supported, but we found a suitable binary"
log "Arch $ARCH is not officially supported, but we found a suitable binary"
BINEXT="-$ARCH"
else
echo "Arch $ARCH is unknown, Default to using 32bit HF AqualinkD, you may need to manually try ./release/aqualnkd_arm64"
log "Arch $ARCH is unknown, Default to using 32bit HF AqualinkD, you may need to manually try ./release/aqualnkd_arm64"
BINEXT=""
fi
;;
@ -72,18 +99,18 @@ if [ "$PARENT_COMMAND" != "make" ] && [ "$1" != "from-make" ] && [ "$1" != "igno
SOURCEBIN=$BIN$BINEXT
elif [ -f $BUILD/$SOURCEBIN ]; then
# Not good
echo "Can't find correct aqualnkd binary for $ARCH, '$BUILD/$SOURCEBIN$BINEXT' using '$BUILD/$SOURCEBIN' ";
log "Can't find correct aqualnkd binary for $ARCH, '$BUILD/$SOURCEBIN$BINEXT' using '$BUILD/$SOURCEBIN' ";
fi
fi
# Exit if we can't find binary
if [ ! -f $BUILD/$SOURCEBIN ]; then
echo "Can't find aqualnkd binary `$BUILD/$SOURCEBIN` ";
log "Can't find aqualnkd binary `$BUILD/$SOURCEBIN` ";
exit 1
fi
# Exit if we can't find systemctl
command -v systemctl >/dev/null 2>&1 || { echo "This script needs systemd's systemctl manager, Please check path or install manually" >&2; exit 1; }
command -v systemctl >/dev/null 2>&1 || { log "This script needs systemd's systemctl manager, Please check path or install manually" >&2; exit 1; }
# stop service, hide any error, as the service may not be installed yet
systemctl stop $SERVICE > /dev/null 2>&1
@ -91,7 +118,7 @@ SERVICE_EXISTS=$(echo $?)
# Clean everything if requested.
if [ "$1" == "clean" ]; then
echo "Deleting install"
log "Deleting install"
systemctl disable $SERVICE > /dev/null 2>&1
if [ -f $BINLocation/$BIN ]; then
rm -f $BINLocation/$BIN
@ -105,6 +132,9 @@ if [ "$1" == "clean" ]; then
if [ -f $DEFLocation/$DEF ]; then
rm -f $DEFLocation/$DEF
fi
if [ -f /etc/cron.d/aqualinkd ]; then
rm -f /etc/cron.d/aqualinkd
fi
if [ -d $WEBLocation ]; then
rm -rf $WEBLocation
fi
@ -115,17 +145,17 @@ fi
# Check cron.d options
if [ ! -d "/etc/cron.d" ]; then
echo "The version of Cron may not support chron.d, if so AqualinkD Scheduler will not work"
echo "Please check before starting"
log "The version of Cron may not support chron.d, if so AqualinkD Scheduler will not work"
log "Please check before starting"
else
if [ -f "/etc/default/cron" ]; then
CD=$(cat /etc/default/cron | grep -v ^# | grep "\-l")
if [ -z "$CD" ]; then
echo "Please enabled cron.d support, if not AqualinkD Scheduler will not work"
echo "Edit /etc/default/cron and look for the -l option, usually in EXTRA_OPTS"
log "Please enabled cron.d support, if not AqualinkD Scheduler will not work"
log "Edit /etc/default/cron and look for the -l option, usually in EXTRA_OPTS"
fi
else
echo "Please make sure the version if Cron supports chron.d, if not the AqualinkD Scheduler will not work"
log "Please make sure the version if Cron supports chron.d, if not the AqualinkD Scheduler will not work"
fi
fi
@ -134,10 +164,12 @@ fi
if [ -f "$WEBLocation/config.js" ]; then
# Test is if has AUX_V1 in file AND "Spa" is in file (Spa_mode changed to Spa)
# Version 2.6.0 added Chiller as well
if ! grep -q 'Aux_V1' $WEBLocation/$file || ! grep -q '"Spa"' $WEBLocation/$file || ! grep -q '"Chiller"' $WEBLocation/$file; then
if ! grep -q '"Aux_V1"' "$WEBLocation/config.js" ||
! grep -q '"Spa"' "$WEBLocation/config.js" ||
! grep -q '"Chiller"' "$WEBLocation/config.js"; then
dateext=`date +%Y%m%d_%H_%M_%S`
echo "AqualinkD web config is old, making copy to $WEBLocation/config.js.$dateext"
echo "Please make changes to new version $WEBLocation/config.js"
log "AqualinkD web config is old, making copy to $WEBLocation/config.js.$dateext"
log "Please make changes to new version $WEBLocation/config.js"
mv $WEBLocation/config.js $WEBLocation/config.js.$dateext
fi
fi
@ -150,24 +182,25 @@ cp $BUILD/$SOURCEBIN $BINLocation/$BIN
cp $BUILD/$SRV $SRVLocation/$SRV
if [ -f $CFGLocation/$CFG ]; then
echo "AqualinkD config exists, did not copy new config, you may need to edit existing! $CFGLocation/$CFG"
log "AqualinkD config exists, did not copy new config, you may need to edit existing! $CFGLocation/$CFG"
else
cp $BUILD/$CFG $CFGLocation/$CFG
fi
if [ -f $DEFLocation/$DEF ]; then
echo "AqualinkD defaults exists, did not copy new defaults to $DEFLocation/$DEF"
log "AqualinkD defaults exists, did not copy new defaults to $DEFLocation/$DEF"
else
cp $BUILD/$DEF.defaults $DEFLocation/$DEF
fi
if [ -f $MDNSLocation/$MDNS ]; then
echo "Avahi/mDNS defaults exists, did not copy new defaults to $MDNSLocation/$MDNS"
log "Avahi/mDNS defaults exists, did not copy new defaults to $MDNSLocation/$MDNS"
else
if [ -d "$MDNSLocation" ]; then
cp $BUILD/$MDNS.avahi $MDNSLocation/$MDNS
else
echo "Avahi/mDNS may not be installed, not copying $MDNSLocation/$MDNS"
log "Avahi/mDNS may not be installed, not copying $MDNSLocation/$MDNS"
fi
fi
@ -176,20 +209,38 @@ if [ ! -d "$WEBLocation" ]; then
fi
if [ -f "$WEBLocation/config.js" ]; then
echo "AqualinkD web config exists, did not copy new config, you may need to edit existing $WEBLocation/config.js "
rsync -avq --exclude='config.js' $BUILD/../web/* $WEBLocation
log "AqualinkD web config exists, did not copy new config, you may need to edit existing $WEBLocation/config.js "
if command -v "rsync" &>/dev/null; then
rsync -avq --exclude='config.js' $BUILD/../web/* $WEBLocation
else
# This isn;t the right way to do it, but seems to work.
shopt -s extglob
`cp -r "$BUILD/../web/"!(*config.js) "$WEBLocation"`
shopt -u extglob
# Below should work, but doesn't.
#shopt -s extglob
#cp -r "$BUILD/../web/"!(*config.js) "$WEBLocation"
#shopt -u extglob
fi
else
cp -r $BUILD/../web/* $WEBLocation
fi
# remount root ro
if [[ $REMOUNT_RO -eq 0 ]]; then
mount / -o remount,ro &>/dev/null
fi
systemctl enable $SERVICE
systemctl daemon-reload
if [ $SERVICE_EXISTS -eq 0 ]; then
echo "Starting daemon $SERVICE"
log "Starting daemon $SERVICE"
systemctl start $SERVICE
else
echo "Please edit $CFGLocation/$CFG, then start AqualinkD service"
log "Please edit $CFGLocation/$CFG, then start AqualinkD service with `sudo systemctl start aqualinkd`"
fi

332
release/remote_install.sh Executable file
View File

@ -0,0 +1,332 @@
#!/bin/bash
#
# run from curl or local will give different results.
# curl -fsSL https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/release/remote_install.sh | sudo bash -s -- latest
# ./upgrade.sh latest
#
# To get good / bad exit code from both curl and bash, use below. It will exit current term so be careful.
# curl -fsSL "https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/release/remote_install.sh" | ( sudo bash && exit 0 ) || exit $?
REQUIRED_SPACE_MB=18 # Need 17MB, use 18
TRUE=0
FALSE=1
REPO="https://api.github.com/repos/AqualinkD/AqualinkD"
#REPO="https://api.github.com/repos/sfeakes/AqualinkD"
INSTALLED_BINARY="/usr/local/bin/aqualinkd"
# Can't use $0 since this script is usually piped into bash
SELF="remote_install.sh"
REL_VERSION=""
DEV_VERSION=""
INSTALLED_VERSION=""
TEMP_INSTALL="/tmp/aqualinkd"
OUTPUT="/tmp/aqualinkd_upgrade.log"
FROM_CURL=$FASE
# Remember not to use (check for terminal, as it may not exist when pipe to bash)
# ie. if [ -t 0 ]; then
if command -v "systemd-cat" &>/dev/null; then SYSTEMD_LOG=$TRUE;fi
log()
{
echo "$*"
if [[ $SYSTEMD_LOG -eq $TRUE ]]; then
echo "Upgrade: $*" | systemd-cat -t aqualinkd -p info
else
logger -p local0.notice -t aqualinkd "Upgrade: $*"
fi
echo "$*" 2>/dev/null >> "$OUTPUT"
}
logerr()
{
echo "Error: $*" >&2
if [[ $SYSTEMD_LOG -eq $TRUE ]]; then
echo "Upgrade: $*" | systemd-cat -t aqualinkd -p err
else
logger -p local0.error -t aqualinkd "Upgrade: $*"
fi
echo "ERROR: $*" 2>/dev/null >> "$OUTPUT"
}
function check_tool() {
cmd=$1
if ! command -v "$cmd" &>/dev/null
then
log "Command '$cmd' could not be found!"
return "$FALSE"
fi
return "$TRUE"
}
function latest_release_version {
REL_VERSION=$(curl -fsSL "$REPO/releases/latest" | grep -Po '"tag_name": "\K.*?(?=")')
if [[ "$REL_VERSION" != "" ]]; then
return "$TRUE"
else
return "$FALSE"
fi
}
function latest_development_version {
#DEV_VERSION=$(curl --silent -L "https://raw.githubusercontent.com/sfeakes/AqualinkD/master/version.h" | grep AQUALINKD_VERSION | cut -d '"' -f 2)
DEV_VERSION=$(curl -fsSL -H "Accept: application/vnd.github.raw" "$REPO/contents/source/version.h" | grep AQUALINKD_VERSION | cut -d '"' -f 2)
if [[ "$DEV_VERSION" != "" ]]; then
return "$TRUE"
else
return "$FALSE"
fi
}
function installed_version {
if [ -f "$INSTALLED_BINARY" ]; then
if check_tool strings &&
check_tool grep &&
check_tool awk &&
check_tool tr; then
INSTALLED_VERSION=$(strings "$INSTALLED_BINARY" | grep sw_version | awk -v RS="," -v FS=":" '/sw_version/{print $2;exit;}' | tr -d ' "' )
log "Current installed version $INSTALLED_VERSION"
fi
else
log "AqualinkD is not installed"
fi
if [[ "$INSTALLED_VERSION" != "" ]]; then
return "$TRUE"
else
return "$FALSE"
fi
}
function check_system_arch {
ARCH=$(dpkg --print-architecture)
case $ARCH in
arm64 |\
armhf)
return "$TRUE"
;;
*)
logerr "System arch is $ARCH, this is not supported by AqualinkD"
return "$FALSE";
;;
esac
}
function check_can_upgrade {
#version=$1
output=""
# Check we have needed commands.
# curl, dpkg, systemctl
if ! command -v curl &>/dev/null; then output+="Command 'curl' not found, please check it's installed and in path\n"; fi
if ! command -v dpkg &>/dev/null; then output+="Command 'dpkg' not found, please check it's installed and in path\n"; fi
if ! command -v systemctl &>/dev/null; then output+="Command 'systemctl' not found, please check it's installed and in path\n"; fi
# Check root is rw
if mount | grep " / " | grep -q "(ro,"; then
# check if can remount rw.
if mount / -o remount,rw &>/dev/null; then
# can mount RW.
mount / -o remount,ro &>/dev/null
else
output+="Root filesystem is readonly & failed to remount read write, can't upgrade";
fi
fi
# Check we can get the latest version
if ! latest_release_version; then output+="Couldn't find latest version on github"; fi
# Check we can get the latest version
if command -v dpkg &>/dev/null; then
if ! check_system_arch; then output+="System Architecture not supported!"; fi
fi
# Check free diskspace
mkdir -p "$TEMP_INSTALL"
free_space_mb=$(df -mP "$TEMP_INSTALL" 2>/dev/null | awk 'NR==2{print $4}' )
# Check if the df command was successful and if free_space_mb is a number
if [ -z "$free_space_mb" ] || ! [[ "$free_space_mb" =~ ^[0-9]+$ ]]; then
output+="Could not retrieve free space for directory: $TEMP_INSTALL"
else
if [ "$free_space_mb" -lt "$REQUIRED_SPACE_MB" ]; then
output+="Not enough disk space on directory: $TEMP_INSTALL! (Required $REQUIRED_SPACE_MB MB)"
fi
fi
if [[ "$output" == "" ]] && [[ "$REL_VERSION" != "" ]]; then
return "$TRUE"
else [[ "$output" != "" ]]
logerr "$output";
return "$FALSE"
fi
return "$TRUE"
}
function download_latest_release {
mkdir -p "$TEMP_INSTALL"
tar_url=$(curl -fsSL "$REPO/releases/latest" | grep -Po '"tarball_url": "\K.*?(?=")')
if [[ "$tar_url" == "" ]]; then return "$FALSE"; fi
curl -fsSL "$tar_url" | tar xz --strip-components=1 --directory="$TEMP_INSTALL"
if [ $? -ne 0 ]; then return "$FALSE"; fi
return "$TRUE";
}
function download_latest_development {
mkdir -p "$TEMP_INSTALL"
tar_url="$REPO/tarball/master"
curl -fsSL "$tar_url" | tar xz --strip-components=1 --directory="$TEMP_INSTALL"
if [ $? -ne 0 ]; then return "$FALSE"; fi
return "$TRUE";
}
function download_version {
tar_url=$(curl -fsSL "$REPO/releases" | awk 'match($0,/.*"tarball_url": "(.*\/tarball\/.*)".*/)' | grep $1\" | awk -F '"' '{print $4}')
if [[ ! -n "$tar_url" ]]; then
return $"$FALSE"
fi
mkdir -p "$TEMP_INSTALL"
curl -fsSL "$tar_url" | tar xz --strip-components=1 --directory="$TEMP_INSTALL"
if [ $? -ne 0 ]; then return "$FALSE"; fi
return "$TRUE";
}
function get_all_versions {
curl -fsSL "$REPO/releases" | awk 'match($0,/.*"tarball_url": "(.*\/tarball\/.*)".*/)' | awk -F '/' '{split($NF,a,"\""); print a[1]}'
}
function run_install_script {
if [ ! -f "$TEMP_INSTALL/release/install.sh" ]; then
logerr "Can not find install script $TEMP_INSTALL/release/install.sh"
return "$FALSE"
fi
log "Installing AqualinkD $1"
# Can't run in background as it'll cleanup / delete files before install.
nohup "$TEMP_INSTALL/release/install.sh" >> "$OUTPUT" 2>&1
#source "/nas/data/Development/Raspberry/AqualinkD/release/install.sh" &>> "$OUTPUT"
#nohup "/nas/data/Development/Raspberry/AqualinkD/release/install.sh" >> "$OUTPUT" 2>&1 &
#nohup "$TEMP_INSTALL/release/install.sh" >> "$OUTPUT" 2>&1 &
}
function remove_install {
curl -fsSL -H "Accept: application/vnd.github.raw+json" "$REPO/contents/install/install.sh" | sudo bash clean
}
function cleanup {
rm -rf "$TEMP_INSTALL"
}
####################################################
#
# Main
#
# See if we are called from curl ot local dir.
# with curl no tty input and script name wil be blank.
if ! tty > /dev/null 2>&1; then
script=$(basename "$0")
if [ "$script" == "bash" ] || [ "$script" == "" ]; then
#echo "$(basename "$0") Script is likely running from curl"
# We don't actualy use this, but may in the future to leave it here
FROM_CURL=$TRUE
fi
fi
if [[ $EUID -ne 0 ]]; then
logerr "This script must be run as root"
exit 1
fi
#if [ ! -t 0 ]; then
#Don't use log function here as we will cleanout the file if it exists.
# Can't use $0 below as this script might be piped into bash from curl
echo "$SELF - $(date) " 2>/dev/null > "$OUTPUT"
#fi
if check_can_upgrade; then
installed_version
if [[ "$INSTALLED_VERSION" != "" ]]; then
log "Current AqualinkD installation $INSTALLED_VERSION"
log "System OK to upgrade AqualinkD to $REL_VERSION"
else
log "System OK to install AqualinkD $REL_VERSION"
fi
#exit $TRUE;
else
logerr "Can not upgrade, Please fix error(s)!"
exit $FALSE;
fi
case $1 in
check|checkupgradable)
# We have already done the check, and returned false at this point, so return true.
exit $TRUE
;;
development)
if ! latest_development_version; then logerr "getting development version";exit "$FALSE"; fi
if ! download_latest_development; then logerr "downloading latest development";exit "$FALSE"; fi
run_install_script "$REL_VERSION"
cleanup
;;
# Add Delete / remove / clean.
clean|delete|remove)
if ! remove_install; then logerr "Removing install";exit "$FALSE"; fi
log "Removed install"
;;
list|versions)
get_all_versions
;;
v*)
if ! download_version $1; then logerr "downloading version $1";exit "$FALSE"; fi
run_install_script "$REL_VERSION"
cleanup
;;
-h|help|h)
echo "AqualinkD Installation script"
echo "$SELF <- download and install latest AqualinkD version"
echo "$SELF latest <- download and install latest AqualinkD version"
echo "$SELF development <- download and install latest AqualinkD development version"
echo "$SELF clean <- Remove AqualinkD"
echo "$SELF list <- List available versions to install"
echo "$SELF v1.0.0 <- install AqualinkD v1.0.0 (use list option to see available versions)"
;;
latest|*)
if ! download_latest_release; then logerr "downloading latest"; exit "$FALSE"; fi
run_install_script "$REL_VERSION"
cleanup
;;
esac
exit
# List all versions
# curl -fsSL https://api.github.com/repos/sfeakes/aqualinkd/releases | awk 'match($0,/.*"html_url": "(.*\/releases\/tag\/.*)".*/)'
# curl -fsSL "https://api.github.com/repos/sfeakes/AqualinkD/releases" | awk 'match($0,/.*"tarball_url": "(.*\/tarball\/.*)".*/)' | awk -F '"' '{print $4}'

View File

@ -1,114 +0,0 @@
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mount.h>
#include <sys/statvfs.h>
#include "aqualink.h"
#include "aq_scheduler.h"
bool remount_root_ro(bool readonly)
{
#ifdef AQ_CONTAINER
// In container this is pointless
return false;
#endif
if (readonly)
{
LOG(AQUA_LOG, LOG_INFO, "reMounting root RO\n");
mount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
return true;
}
else
{
struct statvfs fsinfo;
statvfs("/", &fsinfo);
if ((fsinfo.f_flag & ST_RDONLY) == 0) // We are readwrite, ignore
return false;
LOG(AQUA_LOG, LOG_INFO, "reMounting root RW\n");
mount(NULL, "/", NULL, MS_REMOUNT, NULL);
return true;
}
}
FILE *aq_open_file(char *filename, bool *ro_root, bool *created_file)
{
FILE *fp;
*ro_root = remount_root_ro(false);
if (access(filename, F_OK) == 0)
{
*created_file = true;
}
fp = fopen(filename, "w");
if (fp == NULL)
{
remount_root_ro(*ro_root);
}
return fp;
}
bool aq_close_file(FILE *file, bool ro_root)
{
if (file != NULL)
fclose(file);
return remount_root_ro(ro_root);
}
#define BUFFER_SIZE 4096
bool copy_file(const char *source_path, const char *destination_path) {
bool ro_root = remount_root_ro(false);
FILE *source_file = fopen(source_path, "rb");
if (source_file == NULL) {
LOG(AQUA_LOG,LOG_ERR, "Error opening source file: %s\n",source_path);
remount_root_ro(ro_root);
return false;
}
FILE *destination_file = fopen(destination_path, "wb");
if (destination_file == NULL) {
LOG(AQUA_LOG,LOG_ERR, "Error opening source file: %s\n",destination_path);
fclose(source_file);
remount_root_ro(ro_root);
return false;
}
char buffer[BUFFER_SIZE];
size_t bytes_read;
while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, source_file)) > 0) {
if (fwrite(buffer, 1, bytes_read, destination_file) != bytes_read) {
LOG(AQUA_LOG,LOG_ERR, "Error writing to destination file: %s\n",destination_path);
fclose(source_file);
fclose(destination_file);
remount_root_ro(ro_root);
return false;
}
}
if (ferror(source_file)) {
LOG(AQUA_LOG,LOG_ERR, "Error reading from source: %s\n",source_path);
fclose(source_file);
fclose(destination_file);
remount_root_ro(ro_root);
return false;
}
fclose(source_file);
fclose(destination_file);
remount_root_ro(ro_root);
return true;
}

View File

@ -29,7 +29,7 @@
#include "config.h"
#include "aq_panel.h"
//#include "utils.h"
#include "aq_filesystem.h"
#include "aq_systemutils.h"

247
source/aq_systemutils.c Normal file
View File

@ -0,0 +1,247 @@
/*
* Copyright (c) 2017 Shaun Feakes - All rights reserved
*
* You may use redistribute and/or modify this code under the terms of
* the GNU General Public License version 2 as published by the
* Free Software Foundation. For the terms of this license,
* see <http://www.gnu.org/licenses/>.
*
* You are free to use this software under the terms of the GNU General
* Public License, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* https://github.com/sfeakes/aqualinkd
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mount.h>
#include <sys/statvfs.h>
#include <sys/wait.h>
#include "aqualink.h"
#include "aq_scheduler.h"
bool remount_root_ro(bool readonly)
{
#ifdef AQ_CONTAINER
// In container this is pointless
return false;
#endif
if (readonly)
{
LOG(AQUA_LOG, LOG_INFO, "reMounting root RO\n");
mount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
return true;
}
else
{
struct statvfs fsinfo;
statvfs("/", &fsinfo);
if ((fsinfo.f_flag & ST_RDONLY) == 0) // We are readwrite, ignore
return false;
LOG(AQUA_LOG, LOG_INFO, "reMounting root RW\n");
mount(NULL, "/", NULL, MS_REMOUNT, NULL);
return true;
}
}
FILE *aq_open_file(char *filename, bool *ro_root, bool *created_file)
{
FILE *fp;
*ro_root = remount_root_ro(false);
if (access(filename, F_OK) == 0)
{
*created_file = true;
}
fp = fopen(filename, "w");
if (fp == NULL)
{
remount_root_ro(*ro_root);
}
return fp;
}
bool aq_close_file(FILE *file, bool ro_root)
{
if (file != NULL)
fclose(file);
return remount_root_ro(ro_root);
}
#define BUFFER_SIZE 4096
bool copy_file(const char *source_path, const char *destination_path)
{
bool ro_root = remount_root_ro(false);
FILE *source_file = fopen(source_path, "rb");
if (source_file == NULL)
{
LOG(AQUA_LOG, LOG_ERR, "Error opening source file: %s\n", source_path);
remount_root_ro(ro_root);
return false;
}
FILE *destination_file = fopen(destination_path, "wb");
if (destination_file == NULL)
{
LOG(AQUA_LOG, LOG_ERR, "Error opening source file: %s\n", destination_path);
fclose(source_file);
remount_root_ro(ro_root);
return false;
}
char buffer[BUFFER_SIZE];
size_t bytes_read;
while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, source_file)) > 0)
{
if (fwrite(buffer, 1, bytes_read, destination_file) != bytes_read)
{
LOG(AQUA_LOG, LOG_ERR, "Error writing to destination file: %s\n", destination_path);
fclose(source_file);
fclose(destination_file);
remount_root_ro(ro_root);
return false;
}
}
if (ferror(source_file))
{
LOG(AQUA_LOG, LOG_ERR, "Error reading from source: %s\n", source_path);
fclose(source_file);
fclose(destination_file);
remount_root_ro(ro_root);
return false;
}
fclose(source_file);
fclose(destination_file);
remount_root_ro(ro_root);
return true;
}
bool run_aqualinkd_upgrade(bool onlycheck)
{
int pipe_curl_to_bash[2];
pid_t pid_curl, pid_bash;
//char *curl_args[] = {"curl", "-fsSl", "http://tiger/scratch/remote_install.sh", NULL};
//char *curl_args[] = {"curl", "-fsSl", "-H", "Accept: application/vnd.github.raw", "https://api.github.com/repos/sfeakes/AqualinkD/contents/release/remote_install.sh", NULL};
char *curl_args[] = {"curl", "-fsSl", "-H", "Accept: application/vnd.github.raw", "https://api.github.com/repos/AqualinkD/AqualinkD/contents/release/remote_install.sh", NULL};
char *bash_args[] = {"bash", "-s", "--", "check", NULL};
int status_curl, status_bash;
if (!onlycheck) {
bash_args[3] = NULL;
}
if (pipe(pipe_curl_to_bash) == -1)
{
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, opening pipe");
return false;
}
// Fork for curl
pid_curl = fork();
if (pid_curl == -1)
{
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, fork (curl)");
return false;
}
if (pid_curl == 0)
{ // Child process (curl)
close(pipe_curl_to_bash[0]);
dup2(pipe_curl_to_bash[1], STDOUT_FILENO);
close(pipe_curl_to_bash[1]);
execvp("curl", curl_args);
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, execvp (curl)");
return false;
}
// Fork for bash
pid_bash = fork();
if (pid_bash == -1)
{
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, fork (bash)");
return false;
}
if (pid_bash == 0)
{ // Child process (bash)
close(pipe_curl_to_bash[1]);
dup2(pipe_curl_to_bash[0], STDIN_FILENO);
close(pipe_curl_to_bash[0]);
execvp("bash", bash_args);
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, execvp (bash)");
return false;
}
// Parent process
close(pipe_curl_to_bash[0]);
close(pipe_curl_to_bash[1]);
// Wait for curl and get its exit status
if (waitpid(pid_curl, &status_curl, 0) == -1)
{
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, waitpid (curl)");
return false;
}
// Wait for bash and get its exit status
if (waitpid(pid_bash, &status_bash, 0) == -1)
{
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, waitpid (bash)");
return false;
}
// Check the exit status of curl
if (WIFEXITED(status_curl))
{
//printf("curl exited with status: %d\n", WEXITSTATUS(status_curl));
if (WEXITSTATUS(status_curl) != 0) {
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, curl exited with status: %d\n", WEXITSTATUS(status_curl));
return false;
}
}
else if (WIFSIGNALED(status_curl))
{
//printf("curl terminated by signal: %d\n", WTERMSIG(status_curl));
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, curl terminated by signal: %d\n", WTERMSIG(status_curl));
return false;
}
// Check the exit status of bash
if (WIFEXITED(status_bash))
{
//printf("bash exited with status: %d\n", WEXITSTATUS(status_bash));
if (WEXITSTATUS(status_bash) != 0) {
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, bash exited with status: %d\n", WEXITSTATUS(status_bash));
return false;
}
}
else if (WIFSIGNALED(status_bash))
{
//printf("bash terminated by signal: %d\n", WTERMSIG(status_bash));
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, bash terminated by signal: %d\n", WTERMSIG(status_bash));
return false;
}
//printf("Command execution complete.\n");
LOG(AQUA_LOG, LOG_NOTICE, "AqualinkD is upgrading!");
return true;
}

View File

@ -5,7 +5,7 @@
FILE *aq_open_file( char *filename, bool *ro_root, bool* created_file);
bool aq_close_file(FILE *file, bool ro_root);
bool copy_file(const char *source_path, const char *destination_path);
bool run_aqualinkd_upgrade(bool onlycheck);

View File

@ -14,7 +14,8 @@
#define setMASK(bitmask, mask) (bitmask |= mask)
#define removeMASK(bitmask, mask) (bitmask &= ~mask)
#define SIGRESTART SIGUSR1
#define SIGRESTART SIGUSR1
#define SIGRUPGRADE SIGUSR2
#ifdef AQ_NO_THREAD_NETSERVICE
#define DEFAULT_POLL_SPEED -1

View File

@ -57,6 +57,7 @@
#include "debug_timer.h"
#include "aq_scheduler.h"
#include "json_messages.h"
#include "aq_systemutils.h"
#ifdef AQ_MANAGER
#include "serial_logger.h"
@ -102,11 +103,19 @@ bool isAqualinkDStopping() {
void intHandler(int sig_num)
{
if (sig_num == SIGRUPGRADE) {
if (! run_aqualinkd_upgrade(false)) {
LOG(AQUA_LOG,LOG_ERR, "AqualinkD upgrade failed!\n");
}
return; // Let the upgrade process terminate us.
}
LOG(AQUA_LOG,LOG_WARNING, "Stopping!\n");
_keepRunning = false;
if (sig_num == SIGRESTART) {
LOG(AQUA_LOG,LOG_WARNING, "Restarting AqualinkD!\n");
// If we are deamonized, we need to use the system
if (_aqconfig_.deamonize) {
if(fork() == 0) {
@ -502,6 +511,32 @@ int main(int argc, char *argv[])
return startup(argv[0], cfgFile);
}
void check_upgrade_log()
{
FILE *fp;
size_t len = 0;
ssize_t read_size;
char *line = NULL;
fp = fopen("/tmp/aqualinkd_upgrade.log", "r");
if (fp == NULL)
{
// No upgrade file
return;
}
LOG(AQUA_LOG,LOG_NOTICE, "--- AqualinkD Upgrade log ----\n");
while ((read_size = getline(&line, &len, fp)) != -1) {
LOG(AQUA_LOG,LOG_NOTICE, "%s", line);
}
LOG(AQUA_LOG,LOG_NOTICE, "--- End AqualinkD Upgrade log ----\n");
free(line);
fclose(fp);
remove("/tmp/aqualinkd_upgrade.log");
// Need to delete the file here.
}
int startup(char *self, char *cfgFile)
@ -539,6 +574,8 @@ int startup(char *self, char *cfgFile)
LOG(AQUA_LOG,LOG_NOTICE, "Starting %s v%s !\n", AQUALINKD_NAME, AQUALINKD_VERSION);
check_upgrade_log();
check_print_config(&_aqualink_data);
@ -938,6 +975,7 @@ void main_loop()
signal(SIGTERM, intHandler);
signal(SIGQUIT, intHandler);
signal(SIGRESTART, intHandler);
signal(SIGRUPGRADE, intHandler);
if (!start_net_services(&_aqualink_data))
{

View File

@ -46,7 +46,7 @@
#include "aq_scheduler.h"
#include "aq_panel.h"
#include "rs_msg_utils.h"
#include "aq_filesystem.h"
#include "aq_systemutils.h"
#define MAXCFGLINE 256
@ -1632,7 +1632,8 @@ void check_print_config (struct aqualinkdata *aqdata)
break;
}
}
LOG(AQUA_LOG,LOG_WARNING, "Config error, couldn't find button `%s` from config option `%s`\n",_aqconfig_.sched_chk_booston_device,CFG_N_event_check_booston_device);
if (i >= aqdata->total_buttons)
LOG(AQUA_LOG,LOG_WARNING, "Config error, couldn't find button `%s` from config option `%s`\n",_aqconfig_.sched_chk_booston_device,CFG_N_event_check_booston_device);
} else {
aqdata->boost_linked_device = AQ_UNKNOWN;
}

View File

@ -610,6 +610,8 @@ int build_aqualink_aqmanager_JSON(struct aqualinkdata *aqdata, char* buffer, int
length += sprintf(buffer+length, ",\"config_editor\": \"yes\"");
}
length += sprintf(buffer+length, ",\"aqualinkd_version\":\"%s\"",AQUALINKD_VERSION);
/*
length += sprintf(buffer+length, ",\"panel_type\":\"%s\"",getPanelString());
@ -655,6 +657,7 @@ int build_aqualink_aqmanager_JSON(struct aqualinkdata *aqdata, char* buffer, int
return length;
}
int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int size)
{
//strncpy(buffer, test_message, strlen(test_message)+1);

View File

@ -691,6 +691,8 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
int i;
const char *status;
int pumpStatus;
static struct timespec last_update_timestamp = {0, 0};
// We get called about every second, so check time every MQTT_TIMED_UDATE / 2
if (_aqconfig_.mqtt_timed_update) {
@ -926,8 +928,18 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
//send_mqtt_timer_duration_msg(nc, _aqualink_data->aqbuttons[i].name, &_aqualink_data->aqbuttons[i]);
// send_mqtt_timer_state_msg will call send_mqtt_timer_duration_msg so no need to do it here.
// Have to use send_mqtt_timer_state_msg due to a timer being set on a device that's already on, (ir no state change so above code does't get hit)
send_mqtt_timer_state_msg(nc, _aqualink_data->aqbuttons[i].name, &_aqualink_data->aqbuttons[i]);
struct timespec current_time;
clock_gettime(CLOCK_MONOTONIC, &current_time);
// Calculate the time difference in nanoseconds
long long time_difference_ns = (current_time.tv_sec - last_update_timestamp.tv_sec) * 1000000000LL + (current_time.tv_nsec - last_update_timestamp.tv_nsec);
// Check if 10 seconds (10 * 10^9 nanoseconds) have passed
if (time_difference_ns >= 10000000000LL || last_update_timestamp.tv_sec == 0) {
send_mqtt_timer_state_msg(nc, _aqualink_data->aqbuttons[i].name, &_aqualink_data->aqbuttons[i]);
last_update_timestamp = current_time;
}
}
}
@ -1174,6 +1186,10 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
LOG(NET_LOG,LOG_NOTICE, "Received restart request!\n");
raise(SIGRESTART);
return uActioned;
} else if (strncmp(ri1, "upgrade", 7) == 0 && from == NET_WS) { // Only valid from websocket.
LOG(NET_LOG,LOG_NOTICE, "Received upgrade request!\n");
raise(SIGRUPGRADE);
return uActioned;
} else if (strncmp(ri1, "seriallogger", 12) == 0 && from == NET_WS) { // Only valid from websocket.
LOG(NET_LOG,LOG_NOTICE, "Received request to run serial_logger!\n");
//LOG(NET_LOG,LOG_NOTICE, "Received request ri1=%s, ri2=%s, ri3=%s value=%f\n",ri1,ri2,ri3,value);
@ -1647,14 +1663,13 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
// If we have a get request, pass it
if (strncmp(http_msg->uri.p, "/api", 4 ) != 0) {
if (strstr(http_msg->method.p, "GET") && http_msg->query_string.len > 0) {
//LOG(NET_LOG,LOG_ERR, "WEB: Old API stanza requested, ignoring client request\n");
log_http_request(LOG_ERR, "Old API stanza requested, ignoring request :", http_msg);
} else {
//if (strstr(http_msg->method.p, "GET") && http_msg->query_string.len > 0) {
// log_http_request(LOG_ERR, "Old API stanza requested, ignoring request :", http_msg);
//} else {
DEBUG_TIMER_START(&tid);
mg_serve_http(nc, http_msg, _http_server_opts);
DEBUG_TIMER_STOP(tid, NET_LOG, "action_web_request() serve file took");
}
//}
//} else if (strstr(http_msg->method.p, "PUT")) {
} else {
char buf[JSON_BUFFER_SIZE];

View File

@ -4,4 +4,4 @@
#define AQUALINKD_SHORT_NAME "AqualinkD"
// Use Magor . Minor . Patch
#define AQUALINKD_VERSION "2.6.1"
#define AQUALINKD_VERSION "2.6.3"

View File

@ -337,6 +337,9 @@
var _config = {};
const _urlParams = new URLSearchParams(window.location.search);
// if loading confighelp.js failes, create a blank variable that it creates.
if (typeof _confighelp === 'undefined') {
var _confighelp = {};
@ -1284,6 +1287,7 @@
read panel_message, panel_type, version, aqualinkd_version
*/
/*
if (data['aqualinkd_version']) {
document.getElementById("aqualinkdversion").innerHTML = data['aqualinkd_version'];
if (data['aqualinkd_version'] == _latestVersionAvailable ) {
@ -1291,7 +1295,16 @@
} else {
document.getElementById("latesversionavailable").classList.add("newversion");
}
}
//const upgrade = _urlParams.get('upgrade');
//console.log("upgrade = "+upgrade);
if ( isNewerVersion(_latestVersionAvailable, data['aqualinkd_version'] ) || _urlParams.get('upgrade') != null) {
enablebutton("upgrade");
} else {
disablebutton("upgrade");
}
}*/
if (data['version']) {
document.getElementById("panelversion").innerHTML = data['version'];
}
@ -1326,16 +1339,38 @@
}
function setAqManagerOptions(data) {
/*
read deamonized logging2file logfilename debugmasks[] loglevels[]
if logfilename=NULL we can turn on/off logging to file.
logging2file will tell us if it's currently on or off
*/
try{
document.getElementById("aqualinkdversion").innerHTML = data['aqualinkd_version'];
} catch (e){}
if (data['deamonized'] == 'off') {
//console.log("deamonized=" + data['deamonized'] + " Need to rename Restart to Reload");
disablebutton("restart");
disablebutton("upgrade");
} else {
enablebutton("restart");
if (data['aqualinkd_version']) {
//document.getElementById("aqualinkdversion").innerHTML = data['aqualinkd_version'];
if (data['aqualinkd_version'] == _latestVersionAvailable ) {
document.getElementById("latesversionavailable").classList.add("hidden");
} else {
document.getElementById("latesversionavailable").classList.add("newversion");
}
if ( isNewerVersion(_latestVersionAvailable, data['aqualinkd_version'] ) || _urlParams.get('upgrade') != null) {
enablebutton("upgrade");
} else {
disablebutton("upgrade");
}
}
}
if (data['config_editor'] == 'yes') {
enablebutton("editconfig");
} else {
@ -1346,6 +1381,8 @@
}, 10000);
}
/*
if (data['logfilename'] == "(null)")
enabletoggle("logfile");
@ -1517,7 +1554,25 @@
socket_di.send(JSON.stringify(msg));
}
function isNewerVersion(version1, version2) {
try{
let [major1, minor1, patch1] = version1.split('.').map(Number => parseInt(Number, 10));
let [major2, minor2, patch2] = version2.split('.').map(Number => parseInt(Number, 10));
if (patch1 === undefined) { patch1 = 0; }
if (patch2 === undefined) { patch2 = 0; }
if (major1 > major2) return true;
if (major1 < major2) return false;
if (minor1 > minor2) return true;
if (minor1 < minor2) return false;
return patch1 > patch2;
} catch (e) {
return false;
}
}
/*
function reset() {
socket_di.send("reset\n");
@ -1526,9 +1581,12 @@
function init() {
// Resize log container
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
console.log("Height="+h+" Setting to "+(h-290) );
//console.log("Height="+h+" Setting to "+(h-290) );
document.documentElement.style.setProperty('--logcontainer-height', (h-290)+'px');
disablebutton("restart");
disablebutton("upgrade");
startWebsockets();
getLatestVersion();
}
@ -1566,6 +1624,16 @@
var cmd = {};
//cmd.uri = "rawcommand"
switch (source.id) {
case "upgrade":
if (confirm("Are you sure you want to proceed upgrading AqualinkD?")) {
console.log("Upgrading");
update_log_message("***** AqualinkD upgrade in progress *****");
} else {
return;
}
cmd.uri = "upgrade"
// NEED TO REGET aqmanager after restart.
break;
case "restart":
cmd.uri = "restart"
// NEED TO REGET aqmanager after restart.
@ -1640,7 +1708,8 @@
<td colspan="2" align="center"><label id="statusmsg" class="statusmsg">status</label></td>
</tr>
<tr>
<td colspan="2" align="center"><input id="restart" type="button" onclick="send(this);" value="Restart AqualinkD"></td>
<td colspan="1" align="center"><input id="restart" type="button" onclick="send(this);" value="Restart AqualinkD"></td>
<td colspan="1" align="center"><input id="upgrade" type="button" onclick="send(this);" value="Upgrade AqualinkD"></td>
</tr>
<!--
<tr>

View File

@ -647,6 +647,32 @@
showTileOptions(false);
startWebsockets();
resetBackgroundSize();
// Test for mobile-app mode
if (window.navigator.standalone === true || window.matchMedia('(display-mode: standalone)').matches) {
//console.log("Running in standalone mode");
//alert("Standalone");
// in webapp mode, remove the aqmanager link
try{
document.getElementById('td_cog').classList.add("hide");
} catch (e){}
} else {
//console.log("Not running in standalone mode");
//alert("NOT Standalone");
}
// Test for iframe
if (window.self !== window.top) {
//console.log("The code is running inside an iframe.");
// Change the link under the cog/hamburger icon
ele = document.getElementById('cog_link');
ele.setAttribute("href", "/");
ele.setAttribute("target", "_parent");
} else {
//console.log("The code is not running inside an iframe.");
}
}
function populateLightProgram(type=0, current_mode="") {
@ -2726,6 +2752,14 @@
<div id="header" class="head" onclick="showBackground();">
<table border='0' width='100%' cellpadding='0' cellspacing='0'>
<tr>
<td width="25px" align='left' id='td_cog' style="vertical-align:middle">
<a id="cog_link" href="/aqmanager.html">
<svg viewBox='0 0 10 8' width='18' height='18'>
<path d='M1 1h8M1 4h 8M1 7h8' stroke='#FFF' stroke-width='1.2' stroke-linecap='round'/>
</svg>
</a>
</td>
</td>
<td width="70px" align='left' id='td_name'><span class='title' id='name'
onclick="showVersion(this);event.stopPropagation();">AqualinkD</span>
</td>