Updates 2.6.2

pull/428/head
sfeakes 2025-04-13 12:03:42 -05:00
parent 4faa2e0db0
commit a410d31ad6
24 changed files with 556 additions and 187 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\ 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\ 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\ 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 = AQ_FLAGS =

View File

@ -11,23 +11,29 @@ If you like this project, you can buy me a cup of coffee :)
<br> <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) [![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/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 ## AqualinkD discussions
* Please use github Discussions for questions (Link at top of page). * 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 ) * 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 ## 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> 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> 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). ## 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/onetouch_sim.html <- (One Touch Simulator)
* http://aqualink.ip/aquapda_sim.html <- (PDA simulator) * http://aqualink.ip/aquapda_sim.html <- (PDA simulator)
#<a name="release"></a> #<a name="release"></a>
# ToDo (future release) # ToDo (future release)
* Create iAqualink Touch Simulator * 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. # 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,18 @@ NEED TO FIX FOR THIS RELEASE.
* update documentation on how vbutton / vpump / pump_max & min / enable_iauqalink2 * 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 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 * Heat Pump / Chiller for OneTouch
* Try an auto-update
* Update Mongoose
--> -->
# Updates in 2.6.2
* 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)
# Updates in 2.6.1 # Updates in 2.6.1
* Added External Sensors to Web UI & HomeKit. * Added External Sensors to Web UI & HomeKit.
@ -123,7 +139,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) * Link device/virtual/onetouch button with SWG BOOST. (Allows you to set VSP RPM when in Boost mode)
# Updates in 2.6.0 # 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` * Can now self-configure on startup. set `device_id=0xFF`
* Added scheduling of pump after events (Power On, Freeze Protect, Boost) * 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. * Fixed HA bug for thermostats not converting to °C when HA is set to display °C.
@ -195,10 +211,10 @@ NEED TO FIX FOR THIS RELEASE.
# Update in Release 2.3.5 # Update in Release 2.3.5
* Added Home Assistant integration through MQTT discover * 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. * There are still some enhacments to come on this.
* Included Docker into main releases * 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 support for reading extended information for Jandy JXi heaters.
* Added Color Light to iAqualinkTouch protocol. * Added Color Light to iAqualinkTouch protocol.
* Fixed issue mqtt_timed_update (1~2 min rather than between 2 & 20 min) * Fixed issue mqtt_timed_update (1~2 min rather than between 2 & 20 min)
@ -214,11 +230,11 @@ NEED TO FIX FOR THIS RELEASE.
# Update in Release 2.3.3 # Update in Release 2.3.3
* Introduced Aqualink Manager UI http://aqualink.ip/aqmanager.html * 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 * 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 * 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. * Introduced RS485 frame delay / timer.
* Improve PDA panels reliability (PDA pannels are slower than RS panels) * 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. * 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 +291,7 @@ NEED TO FIX FOR THIS RELEASE.
* Fixed RS-4 panel bug. * Fixed RS-4 panel bug.
* Fixed some AqualinkTouch programming issues. * Fixed some AqualinkTouch programming issues.
* Increased timeout for startup probe. * 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. * Extensive work to reduce CPU cycles and unnesessary logic.
* iAqualink Touch protocol supported for VSP & extended programming. * 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. * 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 +308,7 @@ NEED TO FIX FOR THIS RELEASE.
* AqualinkD startup changed to fix some 'systemctl restart' issues. * AqualinkD startup changed to fix some 'systemctl restart' issues.
* More detailed API replys. * More detailed API replys.
# Update in Release 2.1.0 # 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 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) * 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) * Chemlink pH & ORP now supported. (along with posting MQTT information)
@ -438,7 +454,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). * 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 # 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 WORKDIR /home/AqualinkD
ARG AQUALINKD_VERSION 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 # 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 # Build aqualinkd
RUN make clean && \ 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 # See: https://github.com/opencontainers/image-spec/blob/main/annotations.md
LABEL org.opencontainers.image.title="AqualinkD" LABEL org.opencontainers.image.title="AqualinkD"
LABEL org.opencontainers.image.url="https://hub.docker.com/repository/docker/sfeakes/aqualinkd/general" LABEL org.opencontainers.image.url="https://hub.docker.com/repository/docker/aqualinkd/aqualinkd/general"
LABEL org.opencontainers.image.source="https://github.com/sfeakes/AqualinkD" LABEL org.opencontainers.image.source="https://github.com/aqualinkd/AqualinkD"
LABEL org.opencontainers.image.documentation="https://github.com/sfeakes/AqualinkD" LABEL org.opencontainers.image.documentation="https://github.com/aqualinkd/AqualinkD"
LABEL org.opencontainers.image.version=$AQUALINKD_VERSION 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/release/aqualinkd.conf /etc/aqualinkd.conf
#COPY --from=aqualinkd-build /home/AqualinkD/docker/aqualinkd-docker.cmd /usr/local/bin/aqualinkd-docker #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 chmod +x /usr/local/bin/aqualinkd-docker
CMD ["sh", "-c", "/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 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 # 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 # 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.title="AqualinkD"
LABEL org.opencontainers.image.url="https://hub.docker.com/repository/docker/sfeakes/aqualinkd/general" 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.source="https://github.com/aqualinkd/AqualinkD"
LABEL org.opencontainers.image.documentation="https://github.com/sfeakes/AqualinkD" LABEL org.opencontainers.image.documentation="https://github.com/aqualinkd/AqualinkD"
LABEL org.opencontainers.image.version=$AQUALINKD_VERSION LABEL org.opencontainers.image.version=$AQUALINKD_VERSION
EXPOSE 80/tcp EXPOSE 80/tcp

View File

@ -2,7 +2,7 @@ services:
aqualinkd: aqualinkd:
image: sfeakes/aqualinkd:latest image: sfeakes/aqualinkd:latest
#build: #build:
# context: https://github.com/sfeakes/AqualinkD.git#master:docker # context: https://github.com/aqualinkd/AqualinkD.git#master:docker
# args: # args:
# AQUALINKD_VERSION: v2.3.6 # Make sure to change to correct version # AQUALINKD_VERSION: v2.3.6 # Make sure to change to correct version
# tags: # 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 # 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" NAME="AqualinkD"
SOURCE_LOCATION="/extras/aqua.sh" SOURCE_LOCATION="/extras/aqua.sh"

View File

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

Binary file not shown.

Binary file not shown.

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

View File

@ -24,15 +24,42 @@ MDNSLocation="/etc/avahi/services/"
SOURCEBIN=$BIN 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 if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root" log "This script must be run as root"
exit 1 exit 1
fi fi
if [[ $(mount | grep " / " | grep "(ro,") ]]; then if [[ $(mount | grep " / " | grep "(ro,") ]]; then
echo "Root filesystem is readonly, can't install" 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 exit 1
fi fi
fi
# Figure out what system we are on and set correct binary. # Figure out what system we are on and set correct binary.
# If we have been called from make, this is a custom build and install, so ignore check. # If we have been called from make, this is a custom build and install, so ignore check.
@ -41,7 +68,7 @@ if [ "$PARENT_COMMAND" != "make" ] && [ "$1" != "from-make" ] && [ "$1" != "igno
# dpkg --print-architecture # dpkg --print-architecture
# Exit if we can't find systemctl # 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; } "Or run '$0 ignorearch'" >&2; exit 1; }
ARCH=$(dpkg --print-architecture) ARCH=$(dpkg --print-architecture)
@ -49,19 +76,19 @@ if [ "$PARENT_COMMAND" != "make" ] && [ "$1" != "from-make" ] && [ "$1" != "igno
case $ARCH in case $ARCH in
arm64) arm64)
echo "Arch is $ARCH, Using 64bit AqualinkD" log "Arch is $ARCH, Using 64bit AqualinkD"
BINEXT="-arm64" BINEXT="-arm64"
;; ;;
armhf) armhf)
echo "Arch is $ARCH, Using 32bit AqualinkD" log "Arch is $ARCH, Using 32bit AqualinkD"
BINEXT="-armhf" BINEXT="-armhf"
;; ;;
*) *)
if [ -f $BUILD/$SOURCEBIN-$ARCH ]; then 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" BINEXT="-$ARCH"
else 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="" BINEXT=""
fi fi
;; ;;
@ -72,18 +99,18 @@ if [ "$PARENT_COMMAND" != "make" ] && [ "$1" != "from-make" ] && [ "$1" != "igno
SOURCEBIN=$BIN$BINEXT SOURCEBIN=$BIN$BINEXT
elif [ -f $BUILD/$SOURCEBIN ]; then elif [ -f $BUILD/$SOURCEBIN ]; then
# Not good # 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
fi fi
# Exit if we can't find binary # Exit if we can't find binary
if [ ! -f $BUILD/$SOURCEBIN ]; then if [ ! -f $BUILD/$SOURCEBIN ]; then
echo "Can't find aqualnkd binary `$BUILD/$SOURCEBIN` "; log "Can't find aqualnkd binary `$BUILD/$SOURCEBIN` ";
exit 1 exit 1
fi fi
# Exit if we can't find systemctl # 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 # stop service, hide any error, as the service may not be installed yet
systemctl stop $SERVICE > /dev/null 2>&1 systemctl stop $SERVICE > /dev/null 2>&1
@ -91,7 +118,7 @@ SERVICE_EXISTS=$(echo $?)
# Clean everything if requested. # Clean everything if requested.
if [ "$1" == "clean" ]; then if [ "$1" == "clean" ]; then
echo "Deleting install" log "Deleting install"
systemctl disable $SERVICE > /dev/null 2>&1 systemctl disable $SERVICE > /dev/null 2>&1
if [ -f $BINLocation/$BIN ]; then if [ -f $BINLocation/$BIN ]; then
rm -f $BINLocation/$BIN rm -f $BINLocation/$BIN
@ -105,6 +132,9 @@ if [ "$1" == "clean" ]; then
if [ -f $DEFLocation/$DEF ]; then if [ -f $DEFLocation/$DEF ]; then
rm -f $DEFLocation/$DEF rm -f $DEFLocation/$DEF
fi fi
if [ -f /etc/cron.d/aqualinkd ]; then
rm -f /etc/cron.d/aqualinkd
fi
if [ -d $WEBLocation ]; then if [ -d $WEBLocation ]; then
rm -rf $WEBLocation rm -rf $WEBLocation
fi fi
@ -115,17 +145,17 @@ fi
# Check cron.d options # Check cron.d options
if [ ! -d "/etc/cron.d" ]; then if [ ! -d "/etc/cron.d" ]; then
echo "The version of Cron may not support chron.d, if so AqualinkD Scheduler will not work" log "The version of Cron may not support chron.d, if so AqualinkD Scheduler will not work"
echo "Please check before starting" log "Please check before starting"
else else
if [ -f "/etc/default/cron" ]; then if [ -f "/etc/default/cron" ]; then
CD=$(cat /etc/default/cron | grep -v ^# | grep "\-l") CD=$(cat /etc/default/cron | grep -v ^# | grep "\-l")
if [ -z "$CD" ]; then if [ -z "$CD" ]; then
echo "Please enabled cron.d support, if not AqualinkD Scheduler will not work" log "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 "Edit /etc/default/cron and look for the -l option, usually in EXTRA_OPTS"
fi fi
else 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
fi fi
@ -134,10 +164,12 @@ fi
if [ -f "$WEBLocation/config.js" ]; then if [ -f "$WEBLocation/config.js" ]; then
# Test is if has AUX_V1 in file AND "Spa" is in file (Spa_mode changed to Spa) # 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 # 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` dateext=`date +%Y%m%d_%H_%M_%S`
echo "AqualinkD web config is old, making copy to $WEBLocation/config.js.$dateext" log "AqualinkD web config is old, making copy to $WEBLocation/config.js.$dateext"
echo "Please make changes to new version $WEBLocation/config.js" log "Please make changes to new version $WEBLocation/config.js"
mv $WEBLocation/config.js $WEBLocation/config.js.$dateext mv $WEBLocation/config.js $WEBLocation/config.js.$dateext
fi fi
fi fi
@ -150,24 +182,25 @@ cp $BUILD/$SOURCEBIN $BINLocation/$BIN
cp $BUILD/$SRV $SRVLocation/$SRV cp $BUILD/$SRV $SRVLocation/$SRV
if [ -f $CFGLocation/$CFG ]; then 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 else
cp $BUILD/$CFG $CFGLocation/$CFG cp $BUILD/$CFG $CFGLocation/$CFG
fi fi
if [ -f $DEFLocation/$DEF ]; then 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 else
cp $BUILD/$DEF.defaults $DEFLocation/$DEF cp $BUILD/$DEF.defaults $DEFLocation/$DEF
fi fi
if [ -f $MDNSLocation/$MDNS ]; then 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 else
if [ -d "$MDNSLocation" ]; then if [ -d "$MDNSLocation" ]; then
cp $BUILD/$MDNS.avahi $MDNSLocation/$MDNS cp $BUILD/$MDNS.avahi $MDNSLocation/$MDNS
else 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
fi fi
@ -176,20 +209,38 @@ if [ ! -d "$WEBLocation" ]; then
fi fi
if [ -f "$WEBLocation/config.js" ]; then 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 " 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 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 else
cp -r $BUILD/../web/* $WEBLocation cp -r $BUILD/../web/* $WEBLocation
fi fi
# remount root ro
if [[ $REMOUNT_RO -eq 0 ]]; then
mount / -o remount,ro &>/dev/null
fi
systemctl enable $SERVICE systemctl enable $SERVICE
systemctl daemon-reload systemctl daemon-reload
if [ $SERVICE_EXISTS -eq 0 ]; then if [ $SERVICE_EXISTS -eq 0 ]; then
echo "Starting daemon $SERVICE" log "Starting daemon $SERVICE"
systemctl start $SERVICE systemctl start $SERVICE
else 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 fi

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 "config.h"
#include "aq_panel.h" #include "aq_panel.h"
//#include "utils.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); FILE *aq_open_file( char *filename, bool *ro_root, bool* created_file);
bool aq_close_file(FILE *file, bool ro_root); bool aq_close_file(FILE *file, bool ro_root);
bool copy_file(const char *source_path, const char *destination_path); bool copy_file(const char *source_path, const char *destination_path);
bool run_aqualinkd_upgrade(bool onlycheck);

View File

@ -15,6 +15,7 @@
#define removeMASK(bitmask, mask) (bitmask &= ~mask) #define removeMASK(bitmask, mask) (bitmask &= ~mask)
#define SIGRESTART SIGUSR1 #define SIGRESTART SIGUSR1
#define SIGRUPGRADE SIGUSR2
#ifdef AQ_NO_THREAD_NETSERVICE #ifdef AQ_NO_THREAD_NETSERVICE
#define DEFAULT_POLL_SPEED -1 #define DEFAULT_POLL_SPEED -1

View File

@ -57,6 +57,7 @@
#include "debug_timer.h" #include "debug_timer.h"
#include "aq_scheduler.h" #include "aq_scheduler.h"
#include "json_messages.h" #include "json_messages.h"
#include "aq_systemutils.h"
#ifdef AQ_MANAGER #ifdef AQ_MANAGER
#include "serial_logger.h" #include "serial_logger.h"
@ -102,11 +103,19 @@ bool isAqualinkDStopping() {
void intHandler(int sig_num) 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"); LOG(AQUA_LOG,LOG_WARNING, "Stopping!\n");
_keepRunning = false; _keepRunning = false;
if (sig_num == SIGRESTART) { if (sig_num == SIGRESTART) {
LOG(AQUA_LOG,LOG_WARNING, "Restarting AqualinkD!\n");
// If we are deamonized, we need to use the system // If we are deamonized, we need to use the system
if (_aqconfig_.deamonize) { if (_aqconfig_.deamonize) {
if(fork() == 0) { if(fork() == 0) {
@ -502,6 +511,32 @@ int main(int argc, char *argv[])
return startup(argv[0], cfgFile); 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) 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); LOG(AQUA_LOG,LOG_NOTICE, "Starting %s v%s !\n", AQUALINKD_NAME, AQUALINKD_VERSION);
check_upgrade_log();
check_print_config(&_aqualink_data); check_print_config(&_aqualink_data);
@ -938,6 +975,7 @@ void main_loop()
signal(SIGTERM, intHandler); signal(SIGTERM, intHandler);
signal(SIGQUIT, intHandler); signal(SIGQUIT, intHandler);
signal(SIGRESTART, intHandler); signal(SIGRESTART, intHandler);
signal(SIGRUPGRADE, intHandler);
if (!start_net_services(&_aqualink_data)) if (!start_net_services(&_aqualink_data))
{ {

View File

@ -46,7 +46,7 @@
#include "aq_scheduler.h" #include "aq_scheduler.h"
#include "aq_panel.h" #include "aq_panel.h"
#include "rs_msg_utils.h" #include "rs_msg_utils.h"
#include "aq_filesystem.h" #include "aq_systemutils.h"
#define MAXCFGLINE 256 #define MAXCFGLINE 256

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, ",\"config_editor\": \"yes\"");
} }
length += sprintf(buffer+length, ",\"aqualinkd_version\":\"%s\"",AQUALINKD_VERSION);
/* /*
length += sprintf(buffer+length, ",\"panel_type\":\"%s\"",getPanelString()); 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; return length;
} }
int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int size) int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int size)
{ {
//strncpy(buffer, test_message, strlen(test_message)+1); //strncpy(buffer, test_message, strlen(test_message)+1);

View File

@ -691,6 +691,8 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
int i; int i;
const char *status; const char *status;
int pumpStatus; int pumpStatus;
static struct timespec last_update_timestamp = {0, 0};
// We get called about every second, so check time every MQTT_TIMED_UDATE / 2 // We get called about every second, so check time every MQTT_TIMED_UDATE / 2
if (_aqconfig_.mqtt_timed_update) { 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_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. // 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) // 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"); LOG(NET_LOG,LOG_NOTICE, "Received restart request!\n");
raise(SIGRESTART); raise(SIGRESTART);
return uActioned; 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. } 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 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); //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 we have a get request, pass it
if (strncmp(http_msg->uri.p, "/api", 4 ) != 0) { if (strncmp(http_msg->uri.p, "/api", 4 ) != 0) {
if (strstr(http_msg->method.p, "GET") && http_msg->query_string.len > 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);
log_http_request(LOG_ERR, "Old API stanza requested, ignoring request :", http_msg); //} else {
} else {
DEBUG_TIMER_START(&tid); DEBUG_TIMER_START(&tid);
mg_serve_http(nc, http_msg, _http_server_opts); mg_serve_http(nc, http_msg, _http_server_opts);
DEBUG_TIMER_STOP(tid, NET_LOG, "action_web_request() serve file took"); DEBUG_TIMER_STOP(tid, NET_LOG, "action_web_request() serve file took");
} //}
//} else if (strstr(http_msg->method.p, "PUT")) { //} else if (strstr(http_msg->method.p, "PUT")) {
} else { } else {
char buf[JSON_BUFFER_SIZE]; char buf[JSON_BUFFER_SIZE];

View File

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

View File

@ -337,6 +337,9 @@
var _config = {}; var _config = {};
const _urlParams = new URLSearchParams(window.location.search);
// if loading confighelp.js failes, create a blank variable that it creates. // if loading confighelp.js failes, create a blank variable that it creates.
if (typeof _confighelp === 'undefined') { if (typeof _confighelp === 'undefined') {
var _confighelp = {}; var _confighelp = {};
@ -1284,6 +1287,7 @@
read panel_message, panel_type, version, aqualinkd_version read panel_message, panel_type, version, aqualinkd_version
*/ */
/*
if (data['aqualinkd_version']) { if (data['aqualinkd_version']) {
document.getElementById("aqualinkdversion").innerHTML = data['aqualinkd_version']; document.getElementById("aqualinkdversion").innerHTML = data['aqualinkd_version'];
if (data['aqualinkd_version'] == _latestVersionAvailable ) { if (data['aqualinkd_version'] == _latestVersionAvailable ) {
@ -1291,7 +1295,16 @@
} else { } else {
document.getElementById("latesversionavailable").classList.add("newversion"); 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']) { if (data['version']) {
document.getElementById("panelversion").innerHTML = data['version']; document.getElementById("panelversion").innerHTML = data['version'];
} }
@ -1335,7 +1348,25 @@
if (data['deamonized'] == 'off') { if (data['deamonized'] == 'off') {
//console.log("deamonized=" + data['deamonized'] + " Need to rename Restart to Reload"); //console.log("deamonized=" + data['deamonized'] + " Need to rename Restart to Reload");
disablebutton("restart"); 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') { if (data['config_editor'] == 'yes') {
enablebutton("editconfig"); enablebutton("editconfig");
} else { } else {
@ -1346,6 +1377,8 @@
}, 10000); }, 10000);
} }
/* /*
if (data['logfilename'] == "(null)") if (data['logfilename'] == "(null)")
enabletoggle("logfile"); enabletoggle("logfile");
@ -1517,7 +1550,25 @@
socket_di.send(JSON.stringify(msg)); 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() { function reset() {
socket_di.send("reset\n"); socket_di.send("reset\n");
@ -1526,9 +1577,12 @@
function init() { function init() {
// Resize log container // Resize log container
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); 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'); document.documentElement.style.setProperty('--logcontainer-height', (h-290)+'px');
disablebutton("restart");
disablebutton("upgrade");
startWebsockets(); startWebsockets();
getLatestVersion(); getLatestVersion();
} }
@ -1566,6 +1620,10 @@
var cmd = {}; var cmd = {};
//cmd.uri = "rawcommand" //cmd.uri = "rawcommand"
switch (source.id) { switch (source.id) {
case "upgrade":
cmd.uri = "upgrade"
// NEED TO REGET aqmanager after restart.
break;
case "restart": case "restart":
cmd.uri = "restart" cmd.uri = "restart"
// NEED TO REGET aqmanager after restart. // NEED TO REGET aqmanager after restart.
@ -1640,7 +1698,8 @@
<td colspan="2" align="center"><label id="statusmsg" class="statusmsg">status</label></td> <td colspan="2" align="center"><label id="statusmsg" class="statusmsg">status</label></td>
</tr> </tr>
<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>
<!-- <!--
<tr> <tr>

View File

@ -647,6 +647,32 @@
showTileOptions(false); showTileOptions(false);
startWebsockets(); startWebsockets();
resetBackgroundSize(); 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="") { function populateLightProgram(type=0, current_mode="") {
@ -2726,6 +2752,14 @@
<div id="header" class="head" onclick="showBackground();"> <div id="header" class="head" onclick="showBackground();">
<table border='0' width='100%' cellpadding='0' cellspacing='0'> <table border='0' width='100%' cellpadding='0' cellspacing='0'>
<tr> <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' <td width="70px" align='left' id='td_name'><span class='title' id='name'
onclick="showVersion(this);event.stopPropagation();">AqualinkD</span> onclick="showVersion(this);event.stopPropagation();">AqualinkD</span>
</td> </td>