diff --git a/Dockerfile.releaseBinaries2 b/Dockerfile.releaseBinaries2 new file mode 100755 index 0000000..8959652 --- /dev/null +++ b/Dockerfile.releaseBinaries2 @@ -0,0 +1,293 @@ + +##################################### +# +# Build container to compile AqualnkD Release binaries (armhf and arm64) +# +# armhf is 32 bit armv6l (armhf) stretch and newer - work on all Pi's running 32bit (Pi1 to Pi4) +# arm64 is 64 bit aarch64 buster and newer - work on Pi3/Pi4/2w running 64bit os +# +# docker build -f Dockerfile.releaseBinaries2 -t aqualinkd-releasebin2 . +# For better debug logs use --progress=plain +# docker build --progress=plain -f Dockerfile.releaseBinaries2 -t aqualinkd-releasebin2 . +# +# docker run -it --mount type=bind,source=./build,target=/build aqualinkd-releasebin2 bash +# +# clean method +# docker system prune +# docker buildx prune <- just build env +# +# armhf = +# COLLECT_GCC=arm-linux-gnueabihf-gcc +# COLLECT_LTO_WRAPPER=/opt/cross-pi-gcc/libexec/gcc/arm-linux-gnueabihf/6.3.0/lto-wrapper +# Target: arm-linux-gnueabihf +# Configured with: ../gcc-6.3.0/configure --prefix=/opt/cross-pi-gcc --target=arm-linux-gnueabihf --enable-languages=c,c++,fortran --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-multilib --enable-linker-build-id +# Thread model: posix +# gcc version 6.3.0 (GCC) +# GLIBC version 2.24 +# +# arm64 = +# COLLECT_GCC=aarch64-linux-gnu-gcc +# COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/aarch64-linux-gnu/8/lto-wrapper +# Target: aarch64-linux-gnu +# Configured with: ../src/configure -v --with-pkgversion='Debian 8.3.0-2' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --disable-libphobos --enable-multiarch --enable-fix-cortex-a53-843419 --disable-werror --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=aarch64-linux-gnu --program-prefix=aarch64-linux-gnu- --includedir=/usr/aarch64-linux-gnu/include +# Thread model: posix +# gcc version 8.3.0 (Debian 8.3.0-2) +# GLIBC 2.28-10+deb10u3 +##################################### + +FROM debian:buster + +# ############ +# Get arm64 build environment. +# + +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + libsystemd-dev \ + gcc-aarch64-linux-gnu \ + binutils-arm-linux-gnueabi \ + file + +RUN dpkg --add-architecture arm64 +RUN apt-get update && \ + apt-get install -y libsystemd-dev:arm64 + +# ############ +# Get armhf build environment +# prebuilt armhf doesn't support hard float, (or something that causes it to fail on armhf machines) +#RUN apt-get install -y \ +# gcc-arm-linux-gnueabihf \ +# binutils-arm-linux-gnueabihf + +#RUN dpkg --add-architecture armhf +#RUN apt-get update && \ +# apt-get install -y libsystemd-dev:armhf + +# So we need to build arnhf our selves. Since we are doing that, using debian/rasbian stretch versions of +# everthing for best compatibality + +ENV GCC_VERSION gcc-6.3.0 +ENV GLIBC_VERSION glibc-2.24 +ENV BINUTILS_VERSION binutils-2.28 +ARG DEBIAN_FRONTEND=noninteractive + +# Install some tools and compilers + clean up +RUN apt-get update && \ + #apt-get install -y rsync git wget gcc-6 g++-6 cmake gdb gdbserver bzip2 && \ + apt-get install -y rsync git wget cmake gdb gdbserver bzip2 && \ + apt-get clean autoclean && \ + apt-get autoremove -y && \ + rm -rf /var/lib/apt/lists/* + + +# Use GCC 6 as the default +#RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-6 999 \ +# && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-6 999 \ +# && update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-6 999 \ +# && update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-6 999 + +# Add a user called `develop` +RUN useradd -ms /bin/bash develop +RUN echo "develop ALL=(ALL:ALL) ALL" >> /etc/sudoers + +WORKDIR /home/develop + +# Download and extract GCC +RUN wget https://ftp.gnu.org/gnu/gcc/${GCC_VERSION}/${GCC_VERSION}.tar.gz && \ + tar xf ${GCC_VERSION}.tar.gz && \ + rm ${GCC_VERSION}.tar.gz +# Download and extract LibC +RUN wget https://ftp.gnu.org/gnu/libc/${GLIBC_VERSION}.tar.bz2 && \ + tar xjf ${GLIBC_VERSION}.tar.bz2 && \ + rm ${GLIBC_VERSION}.tar.bz2 +# Download and extract BinUtils +RUN wget https://ftp.gnu.org/gnu/binutils/${BINUTILS_VERSION}.tar.bz2 && \ + tar xjf ${BINUTILS_VERSION}.tar.bz2 && \ + rm ${BINUTILS_VERSION}.tar.bz2 +# Download the GCC prerequisites +RUN cd ${GCC_VERSION} && contrib/download_prerequisites && rm *.tar.* +#RUN cd gcc-9.2.0 && contrib/download_prerequisites && rm *.tar.* + +# Build BinUtils +RUN mkdir -p /opt/cross-pi-gcc +WORKDIR /home/develop/build-binutils +RUN ../${BINUTILS_VERSION}/configure \ + --prefix=/opt/cross-pi-gcc --target=arm-linux-gnueabihf \ + --with-arch=armv6 --with-fpu=vfp --with-float=hard \ + --disable-multilib +RUN make -j$(nproc) +RUN make install + + +# Apply batch to GCC +# https://github.com/qca/open-ath9k-htc-firmware/issues/135 +WORKDIR /home/develop +RUN sed -i '1474s/file ==/file[0] ==/' gcc-6.3.0/gcc/ubsan.c + +# Build the first part of GCC +WORKDIR /home/develop/build-gcc +RUN ../${GCC_VERSION}/configure \ + --prefix=/opt/cross-pi-gcc \ + --target=arm-linux-gnueabihf \ + --enable-languages=c,c++,fortran \ + --with-arch=armv6 --with-fpu=vfp --with-float=hard \ + --disable-multilib \ + --enable-linker-build-id +RUN make -j$(nproc) 'LIMITS_H_TEST=true' all-gcc +RUN make install-gcc +ENV PATH=/opt/cross-pi-gcc/bin:${PATH} + +# Install dependencies +RUN apt-get update && \ + apt-get install -y gawk bison python3 && \ + apt-get clean autoclean && \ + apt-get autoremove -y && \ + rm -rf /var/lib/apt/lists/* + +# Download and install the Linux headers +WORKDIR /home/develop +# Should probably use below and change branch. Known to build with rpi-6.1.y or rpi-6.9.y rpi-6.12.y +#RUN git clone -b --depth=1 https://github.com/raspberrypi/linux +RUN git clone --depth=1 https://github.com/raspberrypi/linux +WORKDIR /home/develop/linux +ENV KERNEL=kernel7 +RUN make ARCH=arm INSTALL_HDR_PATH=/opt/cross-pi-gcc/arm-linux-gnueabihf headers_install + +# Build GLIBC +WORKDIR /home/develop/build-glibc +RUN ../${GLIBC_VERSION}/configure \ + --prefix=/opt/cross-pi-gcc/arm-linux-gnueabihf \ + --build=$MACHTYPE --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf \ + --with-arch=armv6 --with-fpu=vfp --with-float=hard \ + --with-headers=/opt/cross-pi-gcc/arm-linux-gnueabihf/include \ + --disable-multilib libc_cv_forced_unwind=yes +RUN make install-bootstrap-headers=yes install-headers +RUN make -j8 csu/subdir_lib +RUN install csu/crt1.o csu/crti.o csu/crtn.o /opt/cross-pi-gcc/arm-linux-gnueabihf/lib +RUN arm-linux-gnueabihf-gcc -nostdlib -nostartfiles -shared -x c /dev/null \ + -o /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/libc.so +RUN touch /opt/cross-pi-gcc/arm-linux-gnueabihf/include/gnu/stubs.h + +# Continue building GCC +WORKDIR /home/develop/build-gcc +RUN make -j$(nproc) all-target-libgcc +RUN make install-target-libgcc + +# Finish building GLIBC +WORKDIR /home/develop/build-glibc +RUN make -j$(nproc) +RUN make install + +# Finish building GCC +WORKDIR /home/develop/build-gcc +RUN make -j$(nproc) +RUN make install + + +# Download systemd and it's dependancys. +RUN mkdir -p /home/develop/packages +WORKDIR /home/develop/packages + + +#################### +# Manually libsystemd-dev and all it's depandancys +# Commented out ones are what I really want, but couldn;t find. +#####RUN wget https://archive.debian.org/debian/pool/main/s/systemd/libsystemd-dev_232-25+deb9u14_armhf.deb +#RUN wget https://archive.debian.org/debian/pool/main/s/systemd/libsystemd-dev_232-25+deb9u12_armhf.deb +#####RUN wget https://archive.debian.org/debian/pool/main/s/systemd/libsystemd0_232-25+deb9u14_armhf.deb +#RUN wget https://archive.debian.org/debian/pool/main/s/systemd/libsystemd0_232-25+deb9u12_armhf.deb +#RUN wget https://archive.debian.org/debian/pool/main/g/glibc/libc6_2.24-11+deb9u4_armhf.deb +#RUN wget https://archive.debian.org/debian/pool/main/libg/libgpg-error/libgpg-error0_1.26-2_armhf.deb +#####RUN wget https://archive.debian.org/debian/pool/main/x/xz-utils/liblzma5_5.2.2-1.2+deb9u1_armhf.deb +#RUN wget https://archive.debian.org/debian/pool/main/x/xz-utils/liblzma5_5.2.2-1.2+b1_armhf.deb +#RUN wget https://archive.debian.org/debian/pool/main/libs/libselinux/libselinux1_2.6-3+b3_armhf.deb +#####RUN wget https://archive.debian.org/debian/pool/main/libg/libgcrypt20//libgcrypt20_1.7.6-2+deb9u4_armhf.deb +#RUN wget https://archive.debian.org/debian/pool/main/libg/libgcrypt20//libgcrypt20_1.7.6-2+deb9u3_armhf.deb +#####RUN wget https://archive.debian.org/debian/pool/main/l/lz4/liblz4-1_0.0~r131-2+deb9u1_armhf.deb +#RUN wget https://archive.debian.org/debian/pool/main/l/lz4/liblz4-1_0.0~r131-2+b1_armhf.deb +#####RUN wget https://archive.debian.org/debian/pool/main/p/pcre3/libpcre3_2%3a8.39-3_armhf.deb +#RUN wget https://archive.debian.org/debian/pool/main/p/pcre3/libpcre3_8.39-3_armhf.deb +# +# Now we have all packaged, let's unpack them. +# +# Install all packages into /opt/cross-pi-gcc/arm-linux-gnueabihf +#RUN for file in *; do dpkg-deb -x $file /opt/cross-pi-gcc/arm-linux-gnueabihf; done +# + +#################### +# Rather than manually, Let's do some modifications to apt and get that working (kinda) + +# Get just enough for apt-get and dpk to run. apt-get doesn't actually work, just enough to download +ENV APT_ROOT=/opt/cross-pi-gcc/apt-armhf +RUN mkdir -p $APT_ROOT +#RUN APT_ROOT=/opt/cross-pi-gcc/apt-armhf; export APT_ROOT + +RUN mkdir -p $APT_ROOT/etc/apt/sources.list.d/ +RUN mkdir -p $APT_ROOT/var/lib/dpkg/updates/ +RUN mkdir -p $APT_ROOT/var/lib/dpkg/info +RUN mkdir -p $APT_ROOT/var/cache/apt/archives/partial +RUN mkdir -p $APT_ROOT/var/log/apt/ +#mkdir -p $APT_ROOT/usr/share/ + +RUN echo "deb http://archive.debian.org/debian/ stretch main contrib non-free" > $APT_ROOT/etc/apt/sources.list +RUN echo "deb http://archive.debian.org/debian/ stretch-proposed-updates main contrib non-free" >> $APT_ROOT/etc/apt/sources.list +RUN echo "deb http://archive.debian.org/debian-security stretch/updates main contrib non-free" >> $APT_ROOT/etc/apt/sources.list + +RUN touch $APT_ROOT/var/lib/dpkg/status + +RUN ln -s /etc/apt/trusted.gpg.d $APT_ROOT/etc/apt/ +RUN ln -s /etc/apt/preferences.d $APT_ROOT/etc/apt/ +RUN ln -s /etc/apt/auth.conf.d $APT_ROOT/etc/apt/ + +# needed for download +RUN dpkg --add-architecture armhf +# needed for install +RUN dpkg --root=$APT_ROOT --add-architecture armhf + +RUN apt -o Dir=$APT_ROOT update + +RUN apt -o Dir=$APT_ROOT download libsystemd-dev:armhf \ + libsystemd0:armhf \ + libc6:armhf \ + libgcrypt20:armhf \ + liblz4-1:armhf \ + liblzma5:armhf \ + libselinux1:armhf \ + libpcre3:armhf \ + libgpg-error0:armhf + +############ +# Now we have all packaged, let's unpack them. + +# Install all packages into /opt/cross-pi-gcc/arm-linux-gnueabihf +# Could use `dpkg --root=$APT_ROOT --force-all -i` in below, but extract works without any warnings. +RUN for file in *; do dpkg -x $file /opt/cross-pi-gcc/arm-linux-gnueabihf; done + +# the above will ge installed in /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/arm-linux-gnueabihf, +# and we need them in /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/, so make come links. +WORKDIR /opt/cross-pi-gcc/arm-linux-gnueabihf/lib +RUN for file in ./arm-linux-gnueabihf/*; do ln -s $file ./`basename $file` 2> /dev/null; done; exit 0 + +# liblz4.so.1 is installed in a different directory, so link that as well. +RUN ln -s /opt/cross-pi-gcc/arm-linux-gnueabihf/usr/lib/arm-linux-gnueabihf/liblz4.so.1 /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/liblz4.so.1 + + +ENV C_INCLUDE_PATH=/opt/cross-pi-gcc/arm-linux-gnueabihf/usr/include + +ENV PATH=$PATH:/opt/cross-pi-gcc/bin:/opt/cross-pi-gcc/libexec/gcc/arm-linux-gnueabihf/6.3.0/ + +RUN mkdir /build +WORKDIR /build + +# Add a user called `build` uid 1001 & gid 10000 +# You chould change RB_UID & RB_GID to what works on your build setup +ENV RB_USER=build +ENV RB_UID=1001 +ENV RB_GID=1000 +RUN groupadd -g $RB_GID $RB_USER 2> /dev/null; exit 0 +RUN useradd $RB_USER -u $RB_UID -g $RB_GID -m -s /bin/bash +RUN echo "$RB_USER ALL=(ALL:ALL) ALL" >> /etc/sudoers + +USER $RB_USER + \ No newline at end of file diff --git a/Makefile b/Makefile index 0fe21a4..405559a 100755 --- a/Makefile +++ b/Makefile @@ -237,6 +237,10 @@ debugbinaries: sudo docker run -it --mount type=bind,source=./,target=/build aqualinkd-releasebin make debugbuild $(info Binaries for release have been built) +runindocker: + sudo docker run -it --mount type=bind,source=./,target=/build aqualinkd-releasebin make dockerbuildnrun + $(info Binaries for release have been built) + # This is run inside container Dockerfile.releaseBinariies (aqualinkd-releasebin) buildrelease: clean armhf arm64 $(shell cd release && ln -s ./aqualinkd-armhf ./aqualinkd && ln -s ./serial_logger-armhf ./serial_logger) @@ -245,6 +249,11 @@ buildrelease: clean armhf arm64 quickbuild: armhf arm64 $(shell cd release && [ ! -f "./aqualinkd-armhf" ] && ln -s ./aqualinkd-armhf ./aqualinkd && ln -s ./serial_logger-armhf ./serial_logger) +# This is run inside container Dockerfile.releaseBinariies (aqualinkd-releasebin) +dockerbuildnrun: ./release/aqualinkd + $(shell ./release/aqualinkd -d -c ./realease/aqualinkd.test.conf + + debugbuild: CFLAGS = $(DFLAGS) debugbuild: armhf arm64 $(shell cd release && [ ! -f "./aqualinkd-armhf" ] && ln -s ./aqualinkd-armhf ./aqualinkd && ln -s ./serial_logger-armhf ./serial_logger) diff --git a/README.md b/README.md index 7b80307..880ce95 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,12 @@ NEED TO FIX FOR THIS RELEASE. * Try an auto-update * Update Mongoose --> +# Updates in 2.6.4 +* Fix docker crash where journal not configured correctly. +* Updates to config editor. +* Increased number of virtual buttons. (previous limitation only effected RS 16 panels). +* Changed to dimmable lights. + # 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. diff --git a/docker/Dockerfile.buildx b/docker/Dockerfile.buildx index a63ef2d..ccace35 100644 --- a/docker/Dockerfile.buildx +++ b/docker/Dockerfile.buildx @@ -17,6 +17,7 @@ # # Clean the build env and start again # docker buildx prune +# docker builder prune # # # docker build -f ./Dockerfile.buildrelease . diff --git a/docker/Dockerfile.releaseBinaries b/docker/Dockerfile.releaseBinaries index e2e3708..7c75afb 100755 --- a/docker/Dockerfile.releaseBinaries +++ b/docker/Dockerfile.releaseBinaries @@ -6,11 +6,17 @@ # armhf is 32 bit armv6l (armhf) stretch and newer - work on all Pi's running 32bit (Pi1 to Pi4) # arm64 is 64 bit aarch64 buster and newer - work on Pi3/Pi4/2w running 64bit os # +# To build # docker build -f Dockerfile.releaseBinaries -t aqualinkd-releasebin . +# For better debug logs use --progress=plain +# docker build --progress=plain -f Dockerfile.releaseBinaries -t aqualinkd-releasebin . +# +# To Run # docker run -it --mount type=bind,source=./build,target=/build aqualinkd-releasebin bash # # clean method # docker system prune +# docker buildx prune <- just build env # # armhf = # COLLECT_GCC=arm-linux-gnueabihf-gcc @@ -142,6 +148,8 @@ RUN apt-get update && \ # Download and install the Linux headers WORKDIR /home/develop +# Should probably use below and change branch. Known to build with rpi-6.1.y or rpi-6.9.y rpi-6.12.y +#RUN git clone -b --depth=1 https://github.com/raspberrypi/linux RUN git clone --depth=1 https://github.com/raspberrypi/linux WORKDIR /home/develop/linux ENV KERNEL=kernel7 diff --git a/docker/buildx.sh b/docker/buildx.sh index 1324100..1e62228 100755 --- a/docker/buildx.sh +++ b/docker/buildx.sh @@ -15,16 +15,16 @@ if [ $# -eq 0 ] then # Below is safer, but not supported on all platforms. #VERSION=$(curl --silent "https://api.github.com/repos/sfeakes/AqualinkD/releases/latest" | grep -Po '"tag_name": "[^0-9|v|V]*\K.*?(?=")') - VERSION=$(curl --silent "https://api.github.com/repos/sfeakes/AqualinkD/releases/latest" | grep "tag_name" | awk -F'"' '$0=$4') + VERSION=$(curl --silent "https://api.github.com/repos/aqualinkd/AqualinkD/releases/latest" | grep "tag_name" | awk -F'"' '$0=$4') LATEST_TAG="-t ${DOCKER_HUB_NAME}/${IMAGE}:latest" else VERSION=$1 fi -URL="https://github.com/sfeakes/AqualinkD/archive/refs/tags/"$VERSION".tar.gz" -URL2="https://github.com/sfeakes/AqualinkD/archive/refs/tags/v"$VERSION".tar.gz" -URL3="https://github.com/sfeakes/AqualinkD/archive/refs/tags/V"$VERSION".tar.gz" -#BURL="https://github.com/sfeakes/AqualinkD/archive/refs/heads/"$VERSION".tar.gz" +URL="https://github.com/aqualinkd/AqualinkD/archive/refs/tags/"$VERSION".tar.gz" +URL2="https://github.com/aqualinkd/AqualinkD/archive/refs/tags/v"$VERSION".tar.gz" +URL3="https://github.com/aqualinkd/AqualinkD/archive/refs/tags/V"$VERSION".tar.gz" +#BURL="https://github.com/aqualinkd/AqualinkD/archive/refs/heads/"$VERSION".tar.gz" # Check version is accurate before running docker build @@ -46,7 +46,7 @@ fi # Check we are building a version not already on docker hub -DOCKER_TAGS=$(wget -q -O - "https://hub.docker.com/v2/namespaces/sfeakes/repositories/aqualinkd/tags" | grep -o '"name": *"[^"]*' | grep -o '[^"]*$') +DOCKER_TAGS=$(wget -q -O - "https://hub.docker.com/v2/namespaces/aqualinkd/repositories/aqualinkd/tags" | grep -o '"name": *"[^"]*' | grep -o '[^"]*$') if echo $DOCKER_TAGS | grep -q $VERSION; then echo "AqualinkD version $VERSION already exists on docker.io, are you sure you want to overide" diff --git a/release/aqualinkd-arm64 b/release/aqualinkd-arm64 index 0fb7186..798ba6f 100755 Binary files a/release/aqualinkd-arm64 and b/release/aqualinkd-arm64 differ diff --git a/release/aqualinkd-armhf b/release/aqualinkd-armhf index 6a51233..24d7c61 100755 Binary files a/release/aqualinkd-armhf and b/release/aqualinkd-armhf differ diff --git a/release/install.sh b/release/install.sh index ad1ba86..62267e8 100755 --- a/release/install.sh +++ b/release/install.sh @@ -27,18 +27,75 @@ SOURCEBIN=$BIN LOG_SYSTEMD=1 # 1=false in bash, 0=true REMOUNT_RO=1 +TRUE=0 +FALSE=1 + +_logfile=""; +_frommake=$FALSE; +_ignorearch=$FALSE; + log() { echo "$*" + if [[ -n "$_logfile" ]]; then + echo "$*" >> "$_logfile" + fi + if [[ $LOG_SYSTEMD -eq 0 ]]; then - logger -p local0.notice -t aqualinkd "Upgrade: $*" + logger -p local0.notice -t aqualinkd.upgrade "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 } +printHelp() +{ + echo "$0" + echo "ignorearch (don't check OS architecture, install what was made from Makefile)" + echo "--arch (install specific OS architecture - armhf | arm64)" + echo "--logfile (log to file)" +} + + +log "Called $0 with $*" + +while [[ $# -gt 0 ]]; do + case "$1" in + --logfile) + shift + _logfile="$1" + ;; + --arch | --forcearch) + shift + #_forcearch="$1" + if [[ -n "$1" ]]; then + _ignorearch=$TRUE + SOURCEBIN=$BIN-$1 + else + log "--arch requires parameter eg. ( --arch armhf | --arch arm64 )" + fi + ;; + from-make) + _frommake=$TRUE + ;; + ignorearch) + _ignorearch=$TRUE + ;; + help | -help | --help | -h) + printHelp + exit $TRUE; + ;; + *) + echo "Unknown argument: $1" + printHelp; + exit $FALSE; + ;; + esac + shift +done + if ! tty > /dev/null 2>&1 || [ "$1" = "syslog" ]; then # No stdin, probably called from upgrade script LOG_SYSTEMD=0 # Set logger to systemd @@ -63,7 +120,8 @@ fi # 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 [ "$PARENT_COMMAND" != "make" ] && [ "$1" != "from-make" ] && [ "$1" != "ignorearch" ]; then +#if [ "$PARENT_COMMAND" != "make" ] && [ "$1" != "from-make" ] && [ "$1" != "ignorearch" ]; then +if [ "$PARENT_COMMAND" != "make" ] && [ "$_frommake" -eq $FALSE ] && [ "$_ignorearch" -eq $FALSE ]; then # Use arch or uname -a to get above. # dpkg --print-architecture diff --git a/release/remote_install.sh b/release/remote_install.sh index fb5006f..34ea47e 100755 --- a/release/remote_install.sh +++ b/release/remote_install.sh @@ -224,9 +224,11 @@ function run_install_script { 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" - + temp_file=$(mktemp) + nohup "$TEMP_INSTALL/release/install.sh" "--logfile" "$temp_file" >> "$OUTPUT" 2>&1 + cat $temp_file + rm $temp_file + #nohup "/nas/data/Development/Raspberry/AqualinkD/release/install.sh" >> "$OUTPUT" 2>&1 & #nohup "$TEMP_INSTALL/release/install.sh" >> "$OUTPUT" 2>&1 & } diff --git a/release/serial_logger-arm64 b/release/serial_logger-arm64 index da313cb..0043e1a 100755 Binary files a/release/serial_logger-arm64 and b/release/serial_logger-arm64 differ diff --git a/release/serial_logger-armhf b/release/serial_logger-armhf index 85d8501..c81128a 100755 Binary files a/release/serial_logger-armhf and b/release/serial_logger-armhf differ diff --git a/source/aq_panel.c b/source/aq_panel.c index 4dbeb5d..6c7a1c7 100644 --- a/source/aq_panel.c +++ b/source/aq_panel.c @@ -680,6 +680,18 @@ bool setVirtualButtonAltLabel(aqkey *button, const char *label) { return true; } + +int getPumpDefaultSpeed(pump_detail *pump, bool max) +{ + if (pump == NULL) + return AQ_UNKNOWN; + + if (max) + return pump->pumpType==VFPUMP?PUMP_GPM_MAX:PUMP_RPM_MAX; + else + return pump->pumpType==VFPUMP?PUMP_GPM_MIN:PUMP_RPM_MIN; +} + // So the 0-100% should be 600-3450 RPM and 15-130 GPM (ie 1% would = 600 & 0%=off) // (value-600) / (3450-600) * 100 // (value) / 100 * (3450-600) + 600 @@ -1254,9 +1266,9 @@ bool programDeviceValue(struct aqualinkdata *aqdata, action_type type, int value } -void programDeviceLightBrightness(struct aqualinkdata *aqdata, int value, int button, bool expectMultiple) +void programDeviceLightBrightness(struct aqualinkdata *aqdata, int value, int deviceIndex, bool expectMultiple, request_source source) { - clight_detail *light = getProgramableLight(aqdata, button); + clight_detail *light = getProgramableLight(aqdata, deviceIndex); if (!isRSSA_ENABLED) { LOG(PANL_LOG,LOG_ERR, "Light mode brightness is only supported with `rssa_device_id` set\n"); @@ -1264,7 +1276,7 @@ void programDeviceLightBrightness(struct aqualinkdata *aqdata, int value, int bu } if (light == NULL) { - LOG(PANL_LOG,LOG_ERR, "Light mode control not configured for button %d\n",button); + LOG(PANL_LOG,LOG_ERR, "Light mode control not configured for button %d\n",deviceIndex); return; } @@ -1274,14 +1286,19 @@ void programDeviceLightBrightness(struct aqualinkdata *aqdata, int value, int bu } if (!expectMultiple) { - programDeviceLightMode(aqdata, value, button); + if (value <= 0) { + // Consider this a bad/malformed request to turn the light off. + panel_device_request(aqdata, ON_OFF, deviceIndex, 0, source); + } else { + programDeviceLightMode(aqdata, value, deviceIndex); + } return; } time(&aqdata->unactioned.requested); aqdata->unactioned.value = value; aqdata->unactioned.type = LIGHT_MODE; - aqdata->unactioned.id = button; + aqdata->unactioned.id = deviceIndex; return; } @@ -1289,7 +1306,7 @@ void programDeviceLightBrightness(struct aqualinkdata *aqdata, int value, int bu //void programDeviceLightMode(struct aqualinkdata *aqdata, char *value, int button) //void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button) -void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button) +void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int deviceIndex) { #ifdef AQ_PDA if (isPDA_PANEL && !isPDA_IAQT) { @@ -1308,10 +1325,10 @@ void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button) } }*/ - clight_detail *light = getProgramableLight(aqdata, button); + clight_detail *light = getProgramableLight(aqdata, deviceIndex); if (light == NULL) { - LOG(PANL_LOG,LOG_ERR, "Light mode control not configured for button %d\n",button); + LOG(PANL_LOG,LOG_ERR, "Light mode control not configured for button %d\n",deviceIndex); return; } @@ -1320,7 +1337,7 @@ void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button) if (light->lightType == LC_PROGRAMABLE ) { //sprintf(buf, "%-5s%-5d%-5d%-5d%.2f",value, sprintf(buf, "%-5d%-5d%-5d%-5d%.2f",value, - button, + deviceIndex, _aqconfig_.light_programming_initial_on, _aqconfig_.light_programming_initial_off, _aqconfig_.light_programming_mode ); @@ -1368,12 +1385,12 @@ void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button) set_aqualink_rssadapter_aux_extended_state(light->button, value);*/ } else { //sprintf(buf, "%-5s%-5d%-5d",value, button, light->lightType); - sprintf(buf, "%-5d%-5d%-5d",value, button, light->lightType); + sprintf(buf, "%-5d%-5d%-5d",value, deviceIndex, light->lightType); aq_programmer(AQ_SET_LIGHTCOLOR_MODE, buf, aqdata); } // Use function so can be called from programming thread if we decide to in future. - updateButtonLightProgram(aqdata, value, button); + updateButtonLightProgram(aqdata, value, deviceIndex); } /* @@ -1416,7 +1433,7 @@ bool panel_device_request(struct aqualinkdata *aqdata, action_type type, int dev start_timer(aqdata, deviceIndex, value); break; case LIGHT_BRIGHTNESS: - programDeviceLightBrightness(aqdata, value, deviceIndex, (source==NET_MQTT?true:false)); + programDeviceLightBrightness(aqdata, value, deviceIndex, (source==NET_MQTT?true:false), source); break; case LIGHT_MODE: if (value <= 0) { diff --git a/source/aq_panel.h b/source/aq_panel.h index d991f0a..07be90b 100644 --- a/source/aq_panel.h +++ b/source/aq_panel.h @@ -78,6 +78,7 @@ void addPanelIAQTouchInterface(); void addPanelRSserialAdapterInterface(); void changePanelToExtendedIDProgramming(); +int getPumpDefaultSpeed(pump_detail *pump, bool max); int getPumpSpeedAsPercent(pump_detail *pump); int convertPumpPercentToSpeed(pump_detail *pump, int value); // This is probable only needed internally @@ -127,14 +128,13 @@ int PANEL_SIZE(); // If we need to increase virtual buttons, then increase below. -// NEED TO FIX, IF WE CHANGE TO ANOTHING OTHER THAN 0 CORE DUMP (we also had "panel_type = RS-16 Combo" in config) -// FIX IS PROBABLY MAKE SURE LEDS IS SAME OR MORE. -#define VIRTUAL_BUTTONS 0 +#define VIRTUAL_BUTTONS 5 // This is the only parameter to change if we need more virtual buttons. -//#define TOTAL_BUTTONS 12+VIRTUAL_BUTTONS +#define TOTAL_BUTTONS 20+VIRTUAL_BUTTONS // Biggest jandy panel is 20 buttons (RS16) + +#define TOTAL_LEDS TOTAL_BUTTONS+4 // Only 20 exist in control panel, but need space for the 4 extra buttons on RS16 panel, + every virtual button -#define TOTAL_BUTTONS 20+VIRTUAL_BUTTONS // Biggest jandy panel // This needs to be called AFTER and as well as initButtons void initButtons_RS16(struct aqualinkdata *aqdata); diff --git a/source/aq_serial.h b/source/aq_serial.h index 565a159..d00f174 100644 --- a/source/aq_serial.h +++ b/source/aq_serial.h @@ -292,8 +292,6 @@ DEV_UNKNOWN_MASK = 0xF8; // Unknown mask, used to reset values #define BUTTON_LABEL_LENGTH 20 -//#define TOTAL_LEDS 20 -#define TOTAL_LEDS 24 // Only 20 exist in control panel, but need space for the extra buttons on RS16 panel // Index starting at 1 diff --git a/source/config.c b/source/config.c index bd84daf..650dcda 100644 --- a/source/config.c +++ b/source/config.c @@ -927,7 +927,6 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) { bool rtn = false; char *tmpval; - //#ifdef CONFIG_DEV_TEST //int val; //char *sval; @@ -1120,7 +1119,7 @@ if (strlen(cleanwhitespace(value)) <= 0) { } else if (strncasecmp(param, "light_program_", 14) == 0) { int num = strtoul(param + 14, NULL, 10); - if ( num >= LIGHT_COLOR_OPTIONS ) { + if ( num >= LIGHT_COLOR_OPTIONS || num < 0 ) { LOG(AQUA_LOG,LOG_ERR, "Config error, light_program_%d is out of range\n",num); } char *name = cleanalloc(value); @@ -1162,14 +1161,15 @@ if (strlen(cleanwhitespace(value)) <= 0) { #endif } else if (strncasecmp(param + 9, "_lightMode", 10) == 0) { int type = strtoul(value, NULL, 10); + // See if light is existing button / light if (isPLIGHT(aqdata->aqbuttons[num].special_mask)) { ((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lightType = type; } else if (aqdata->num_lights < MAX_LIGHTS) { - if (type < LC_PROGRAMABLE || type > NUMBER_LIGHT_COLOR_TYPES) { - LOG(AQUA_LOG,LOG_ERR, "Config error, unknown light mode '%s'\n",type); + if (type < LC_PROGRAMABLE || type >= NUMBER_LIGHT_COLOR_TYPES) { + LOG(AQUA_LOG,LOG_ERR, "Config error, unknown light mode '%d' for '%s'\n",type,param); } else { aqdata->lights[aqdata->num_lights].button = &aqdata->aqbuttons[num]; aqdata->lights[aqdata->num_lights].lightType = type; @@ -1584,11 +1584,15 @@ void check_print_config (struct aqualinkdata *aqdata) if (aqdata->chiller_button == NULL) { LOG(AQUA_LOG,LOG_ERR, "Config error, `%s` is enabled, but no Virtual Button set for Heat Pump / Chiller! Creating vbutton.",CFG_N_force_chiller); aqkey *button = getVirtualButton(aqdata, 0); - setVirtualButtonLabel(button, cleanalloc("Heat Pump"));// Need to malloc this so it can be freed - setVirtualButtonAltLabel(button, cleanalloc("Chiller"));// Need to malloc this so it can be freed - aqdata->chiller_button = button; + if (button != NULL) { + setVirtualButtonLabel(button, cleanalloc("Heat Pump"));// Need to malloc this so it can be freed + setVirtualButtonAltLabel(button, cleanalloc("Chiller"));// Need to malloc this so it can be freed + aqdata->chiller_button = button; //aqdata->chiller_button->special_mask |= VIRTUAL_BUTTON_CHILLER; - setMASK(aqdata->chiller_button->special_mask, VIRTUAL_BUTTON_CHILLER); + setMASK(aqdata->chiller_button->special_mask, VIRTUAL_BUTTON_CHILLER); + } else { + LOG(AQUA_LOG,LOG_WARNING, "Error can't create Heat Pump / Chiller, total buttons=%d, config has %d already, ignoring!\n", TOTAL_BUTTONS, aqdata->total_buttons); + } } } else { LOG(AQUA_LOG,LOG_ERR, "Config error, `%s` can only be enabled, if using an iAqualink Touch ID for `%s`, Turning off\n",CFG_N_force_chiller, CFG_N_extended_device_id ); @@ -1637,6 +1641,18 @@ void check_print_config (struct aqualinkdata *aqdata) } else { aqdata->boost_linked_device = AQ_UNKNOWN; } + + // Check we have pump speed set + for (i=0; i < aqdata->num_pumps; i++) { + if (aqdata->pumps[i].maxSpeed <= 0) { + aqdata->pumps[i].maxSpeed = getPumpDefaultSpeed(&aqdata->pumps[i], true); + //aqdata.pumps[i].maxSpeed = (_aqualink_data.pumps[i].pumpType==VFPUMP?PUMP_GPM_MAX:PUMP_RPM_MAX); + } + if (aqdata->pumps[i].minSpeed <= 0) { + //aqdata.pumps[i].minSpeed = (_aqualink_data.pumps[i].pumpType==VFPUMP?PUMP_GPM_MIN:PUMP_RPM_MIN); + aqdata->pumps[i].minSpeed = getPumpDefaultSpeed(&aqdata->pumps[i], false); + } + } /* @@ -2103,6 +2119,21 @@ bool writeCfg (struct aqualinkdata *aqdata) if (((pump_detail *)aqdata->aqbuttons[i].special_mask_ptr)->pumpType != PT_UNKNOWN) { fprintf(fp,"%s_pumpType=%s\n", prefix, pumpType2String(((pump_detail *)aqdata->aqbuttons[i].special_mask_ptr)->pumpType)); } + + //if (((pump_detail *)aqdata->aqbuttons[i].special_mask_ptr)->minSpeed != PT_UNKNOWN) { + if (((pump_detail *)aqdata->aqbuttons[i].special_mask_ptr)->minSpeed != PT_UNKNOWN && + ((pump_detail *)aqdata->aqbuttons[i].special_mask_ptr)->minSpeed != getPumpDefaultSpeed((pump_detail *)aqdata->aqbuttons[i].special_mask_ptr, false) ) + { + fprintf(fp,"%s_pumpMinSpeed=%d\n", prefix, ((pump_detail *)aqdata->aqbuttons[i].special_mask_ptr)->minSpeed); + } + + //if (((pump_detail *)aqdata->aqbuttons[i].special_mask_ptr)->maxSpeed != PT_UNKNOWN) { + if (((pump_detail *)aqdata->aqbuttons[i].special_mask_ptr)->maxSpeed != PT_UNKNOWN && + ((pump_detail *)aqdata->aqbuttons[i].special_mask_ptr)->maxSpeed != getPumpDefaultSpeed((pump_detail *)aqdata->aqbuttons[i].special_mask_ptr, true) ) + { + fprintf(fp,"%s_pumpMaxSpeed=%d\n", prefix, ((pump_detail *)aqdata->aqbuttons[i].special_mask_ptr)->maxSpeed); + } + } else if (isPLIGHT(aqdata->aqbuttons[i].special_mask)) { //if (((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType > 0) { fprintf(fp,"%s_lightMode=%d\n", prefix, ((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType); diff --git a/source/json_messages.c b/source/json_messages.c index 9e052eb..317d55a 100644 --- a/source/json_messages.c +++ b/source/json_messages.c @@ -35,6 +35,7 @@ #include "rs_msg_utils.h" #include "color_lights.h" #include "iaqualink.h" +#include "aq_panel.h" //#define test_message "{\"type\": \"status\",\"version\": \"8157 REV MMM\",\"date\": \"09/01/16 THU\",\"time\": \"1:16 PM\",\"temp_units\": \"F\",\"air_temp\": \"96\",\"pool_temp\": \"86\",\"spa_temp\": \" \",\"battery\": \"ok\",\"pool_htr_set_pnt\": \"85\",\"spa_htr_set_pnt\": \"99\",\"freeze_protection\": \"off\",\"frz_protect_set_pnt\": \"0\",\"leds\": {\"pump\": \"on\",\"spa\": \"off\",\"aux1\": \"off\",\"aux2\": \"off\",\"aux3\": \"off\",\"aux4\": \"off\",\"aux5\": \"off\",\"aux6\": \"off\",\"aux7\": \"off\",\"pool_heater\": \"off\",\"spa_heater\": \"off\",\"solar_heater\": \"off\"}}" //#define test_labels "{\"type\": \"aux_labels\",\"aux1_label\": \"Cleaner\",\"aux2_label\": \"Waterfall\",\"aux3_label\": \"Spa Blower\",\"aux4_label\": \"Pool Light\",\"aux5_label\": \"Spa Light\",\"aux6_label\": \"Unassigned\",\"aux7_label\": \"Unassigned\"}" @@ -1456,6 +1457,33 @@ int build_aqualink_config_JSON(char* buffer, int size, struct aqualinkdata *aq_d } else length += result; } + + if (((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->minSpeed != PT_UNKNOWN && + ((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->minSpeed != getPumpDefaultSpeed((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr, false) ) + { + sprintf(buf,"%s_pumpMinSpeed", prefix); + stringptr = pumpType2String(((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->pumpType); + if ((result = json_cfg_element(buffer+length, size-length, buf, &((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->minSpeed, CFG_INT, 0, NULL, 0) ) <= 0) { + LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length); + return length; + } else + length += result; + } + + if (((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->maxSpeed != PT_UNKNOWN && + ((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->maxSpeed != getPumpDefaultSpeed((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr, true) ) + { + sprintf(buf,"%s_pumpMaxSpeed", prefix); + stringptr = pumpType2String(((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->pumpType); + if ((result = json_cfg_element(buffer+length, size-length, buf, &((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->maxSpeed, CFG_INT, 0, NULL, 0) ) <= 0) { + LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length); + return length; + } else + length += result; + } + + + } else if (isPLIGHT(aq_data->aqbuttons[i].special_mask)) { if (((clight_detail *)aq_data->aqbuttons[i].special_mask_ptr)->lightType > 0) { sprintf(buf,"%s_lightMode", prefix); diff --git a/source/net_services.c b/source/net_services.c index 252acac..b8094e8 100644 --- a/source/net_services.c +++ b/source/net_services.c @@ -180,7 +180,7 @@ void ws_send_logmsg(struct mg_connection *nc, char *msg) { } sd_journal *open_journal() { - sd_journal *journal; + sd_journal *journal; // should be static?????? char filter[51]; #ifndef AQ_CONTAINER @@ -192,14 +192,14 @@ sd_journal *open_journal() { #endif { LOGSystemError(errno, NET_LOG, "Failed to open journal"); - return journal; + return NULL; } snprintf(filter, 50, "SYSLOG_IDENTIFIER=%s",_aqualink_data->self ); if (sd_journal_add_match(journal, filter, 0) < 0) { LOGSystemError(errno, NET_LOG, "Failed to set journal syslog filter"); sd_journal_close(journal); - return journal; + return NULL; } /* Docker wll also have problem with this // Daemon will change PID after printing startup message, so don't filter on current PID @@ -282,11 +282,13 @@ bool _broadcast_systemd_logmessages(bool aqMgrActive, bool reOpenStaleConnection } // aqManager is active if (!active) { - if ( (journal = open_journal()) < 0) { + if ( (journal = open_journal()) == NULL) { + //printf("Open faied\n"); build_logmsg_JSON(msg, LOG_ERR, "Failed to open journal", WS_LOG_LENGTH,22); ws_send_logmsg(_mgr.active_connections, msg); return false; } + //printf("Open good %d\n",journal); if (sd_journal_seek_tail(journal) < 0) { build_logmsg_JSON(msg, LOG_ERR, "Failed to seek to journal end", WS_LOG_LENGTH,29); ws_send_logmsg(_mgr.active_connections, msg); @@ -373,7 +375,7 @@ bool write_systemd_logmessages_2file(char *fname, int lines) LOG(NET_LOG, LOG_WARNING, "Failed to open tmp log file '%s'\n",fname); return false; } - if ( (journal = open_journal()) < 0) { + if ( (journal = open_journal()) == NULL) { fclose (fp); return false; } @@ -2253,9 +2255,12 @@ bool _start_net_services(struct mg_mgr *mgr, struct aqualinkdata *aqdata) { //volatile bool _broadcast = false; // This is redundent when most the fully threadded rather than option. +#define JOURNAL_FAIL_RETRY 5 + void *net_services_thread( void *ptr ) { struct aqualinkdata *aqdata = (struct aqualinkdata *) ptr; + int journald_fail = 0; //struct mg_mgr mgr; if (!_start_net_services(&_mgr, aqdata)) { //LOG(NET_LOG,LOG_ERR, "Failed to start network services\n"); @@ -2279,9 +2284,28 @@ void *net_services_thread( void *ptr ) aqdata->updated = false; } #ifdef AQ_MANAGER +// NSF, need to stop and disable after 5 tries, this just keeps looping. +// USe something like below to notify user +// build_logmsg_JSON(msg, LOG_ERR, "Failed to open journal, giving up!", WS_LOG_LENGTH,29); +// set global variable so _broadcast_systemd_logmessages() also doesn't keep erroring. + + //if ( ! broadcast_systemd_logmessages(aqdata->aqManagerActive) && journald_fail < JOURNAL_FAIL_RETRY) { + if ( journald_fail < JOURNAL_FAIL_RETRY && ! broadcast_systemd_logmessages(aqdata->aqManagerActive) ) { + journald_fail++; + LOG(AQUA_LOG,LOG_ERR, "Couldn't open systemd journal log\n"); + } else if (journald_fail == JOURNAL_FAIL_RETRY) { + char msg[WS_LOG_LENGTH]; + build_logmsg_JSON(msg, LOG_ERR, "Giving up on journal, don't expect to see logs", WS_LOG_LENGTH,46); + ws_send_logmsg(_mgr.active_connections, msg); + journald_fail = JOURNAL_FAIL_RETRY+1; + } + // Reset failures when manager is not active. + if (!aqdata->aqManagerActive) {journald_fail=0;} +/* if ( ! broadcast_systemd_logmessages(aqdata->aqManagerActive)) { LOG(AQUA_LOG,LOG_ERR, "Couldn't open systemd journal log\n"); } +*/ #endif if (aqdata->simulator_active != SIM_NONE && aqdata->simulator_packet_updated == true ) { _broadcast_simulator_message(_mgr.active_connections); diff --git a/source/version.h b/source/version.h index d93bcc3..baeeb88 100644 --- a/source/version.h +++ b/source/version.h @@ -4,4 +4,4 @@ #define AQUALINKD_SHORT_NAME "AqualinkD" // Use Magor . Minor . Patch -#define AQUALINKD_VERSION "2.6.3" +#define AQUALINKD_VERSION "2.6.4" diff --git a/web/aqmanager.html b/web/aqmanager.html index b3fecdd..3a77a1e 100644 --- a/web/aqmanager.html +++ b/web/aqmanager.html @@ -311,6 +311,21 @@ opacity: 0.0; } + .config_option_deletebutton { + font-size: 10px !important; + font-weight: bold !important; + /*color: var(--body_text);*/ + /*background-color: #7f8385 !important;*/ + border: none !important; + color: rgb(0, 0, 0) !important; + padding: 2px 2px !important; + text-decoration: none !important; + margin: 2px 2px 2px 2px !important; + min-width: 18px !important; + border-radius: 5px !important; + height: 18px !important; + } + /* .helptxt { @@ -621,7 +636,7 @@ populateconfigtable(data); } - function addConfigRow(hideLineSeperator, data, obj, row=-1) { + function addConfigRow(hideLineSeperator, data, obj, row=-1, deletable=false) { const configtable = document.getElementById("config_table"); const newRow = configtable.insertRow(row); @@ -647,6 +662,14 @@ cell1.style.paddingLeft = "20px"; cell3.textContent = " "; + + // Add DELETE button deletable + + if (deletable) { + cell3.innerHTML = ''; + } + + if (data[obj]["valid values"] !== undefined) { //console.log(data[obj]["valid values"]); const input = document.createElement("select"); @@ -731,8 +754,8 @@ // key = 1 //} - const buttonTypelist = ["pumpIndex", "pumpID", "pumpType", "pumpName", "lightMode"]; - const virtButtonTypelist = ["pumpIndex", "pumpID", "pumpType", "pumpName", "onetouchID", "altLabel"]; + const buttonTypelist = ["pumpIndex", "pumpID", "pumpType", "pumpName", "pumpMaxSpeed", "pumpMinSpeed", "lightMode"]; + const virtButtonTypelist = ["pumpIndex", "pumpID", "pumpType", "pumpName", "pumpMaxSpeed", "pumpMinSpeed", "onetouchID", "altLabel"]; const configtable = document.getElementById("config_table"); const newRow = configtable.insertRow(); @@ -831,7 +854,7 @@ return; } - const virtButtonTypelist = ["pumpIndex", "pumpID", "pumpType", "pumpName", "onetouchID", "altLabel"]; + const virtButtonTypelist = ["pumpIndex", "pumpID", "pumpType", "pumpName", "pumpMaxSpeed", "pumpMinSpeed", "onetouchID", "altLabel"]; const configtable = document.getElementById("config_table"); @@ -919,6 +942,63 @@ console.log(event); } + function deleteCfgOption(event) { + + // Rebuild whole config table, or just delete single row. + // Rebuild table is better. + let rebuild = true; + + //var id = event.srcElement.getAttribute('id'); + var key = event.getAttribute('key'); + let deleted = false; + //var value = event.srcElement.value; + + //console.log(event.parentNode.parentNode); + //console.log("deleteCfgOption - "+key); + //console.log(_config[key]); + console.log(_config); + + if (!rebuild) { + const configtable = document.getElementById("config_table"); + for (let i = 0; i < configtable.rows.length; i++) { + //console.log(configtable.rows[i].cells[2]); + try{ + if(configtable.rows[i].cells[2].childNodes[0].getAttribute('key') == key) { + //configtable.deleteRow(i); + deleted = true; + } + } catch (e){} + } + } else { + deleted=true; + } + + //event.parentNode.parentNode.style.display = 'none'; + + if (deleted && key.startsWith("virtual_button") && key.endsWith("_label")) { + //console.log(key.slice(0, 17)); + delete _config[key.slice(0, 17)]; + // Delete the whole entity + } else if (deleted && key.startsWith("virtual_button")) { + delete _config[key.slice(0, 17)][key]; + } else if (deleted && key.startsWith("button")) { + delete _config[key.slice(0, 9)][key]; + //console.log(key.slice(0, 9)); + } else if (deleted && key.startsWith("sensor")) { + //console.log(key.slice(0, 9)); + delete _config[key.slice(0, 9)][key]; + } else if (deleted && key.startsWith("light_program_")) { + //console.log(key.slice(0, 9)); + delete _config[key]; + } + + if (rebuild) { + resetConfig(null); + } + + console.log(_config); + } + function addSensorRow(num=0, row=-1){ if ( num == 0 ) { if (_addedBlankSensor == true) { @@ -1011,7 +1091,6 @@ _addedBlankSensor = true; } - function cfgAddButtonOption(event) { var type = event.srcElement.value; @@ -1025,6 +1104,8 @@ case "pumpIndex": case "lightMode": case "onetouchID": + case "pumpMaxSpeed": + case "pumpMinSpeed": js.type = "int"; break; case "pumpID": @@ -1050,7 +1131,7 @@ for (let i = 0; i < configtable.rows.length; i++) { if(configtable.rows[i].cells[0].getAttribute('button_key') !== null) { if(configtable.rows[i].cells[0].getAttribute('button_key') == key) { - addConfigRow(true, _config[obj], key+"_"+type, i); + addConfigRow(true, _config[obj], key+"_"+type, i, true); break; } } @@ -1209,7 +1290,20 @@ } if (_config[obj].value !== undefined) { - addConfigRow(hideLineSeperator, _config, obj); + if (obj.toString().startsWith("light_program_") ) { + console.log(obj.toString()); + num = parseInt(lastKey.match(/[0-9]+/)); + num++; + console.log("check for light_program_"+String(num+1).padStart(2, '0')); + //console.log("check for light_program_"+num); + if ( !('light_program_'+String(num+1).padStart(2, '0') in _config)) { + addConfigRow(hideLineSeperator, _config, obj, -1, true); + } else { + addConfigRow(hideLineSeperator, _config, obj); + } + } else { + addConfigRow(hideLineSeperator, _config, obj); + } } else if (obj.toString().startsWith("button_") || obj.toString().startsWith("virtual_button_") ) { var hide=false; for (var obj1 in _config[obj]) { @@ -1223,7 +1317,11 @@ cell1.style.borderTop = "1px solid black"; hide=true; } else if (obj1.toString() != "advanced") { - addConfigRow(hide, _config[obj], obj1); + if ( obj1.toString().endsWith("_label") && !obj1.toString().startsWith("virtual_button")) { + addConfigRow(hide, _config[obj], obj1); + } else { + addConfigRow(hide, _config[obj], obj1, -1, true); + } hide=true; } } @@ -1232,7 +1330,7 @@ var hide=false; for (var obj1 in _config[obj]) { if (obj1.toString() != "advanced") { - addConfigRow(hide, _config[obj], obj1); + addConfigRow(hide, _config[obj], obj1, -1, true); hide=true; } }