mirror of https://github.com/sfeakes/AqualinkD.git
Merge branch 'master' into mqtt_state_class
commit
74b149afbc
20
Makefile
20
Makefile
|
@ -13,7 +13,7 @@ AQ_RS16 = true
|
|||
AQ_PDA = true
|
||||
AQ_ONETOUCH = true
|
||||
AQ_IAQTOUCH = true
|
||||
AQ_MANAGER =true
|
||||
AQ_MANAGER = true
|
||||
|
||||
#AQ_RS_EXTRA_OPTS = false
|
||||
#AQ_CONTAINER = false // this is for compiling for containers
|
||||
|
@ -31,7 +31,8 @@ CC_AMD64 = x86_64-linux-gnu-gcc
|
|||
#LIBS := -lpthread -lm
|
||||
#LIBS := -l pthread -l m
|
||||
#LIBS := -l pthread -l m -static # Take out -static, just for dev
|
||||
LIBS := -lpthread -lm
|
||||
# from documentation -lrt would be needed for glibc 2.17 & prior (debug clock realtime messages), but seems to be needed for armhf 2.24
|
||||
LIBS := -lpthread -lm -lrt
|
||||
|
||||
# Standard compile flags
|
||||
GCCFLAGS = -Wall -O3
|
||||
|
@ -98,7 +99,7 @@ ifeq ($(AQ_ONETOUCH), true)
|
|||
endif
|
||||
|
||||
ifeq ($(AQ_IAQTOUCH), true)
|
||||
SRCS := $(SRCS) iaqtouch.c iaqtouch_aq_programmer.c
|
||||
SRCS := $(SRCS) iaqtouch.c iaqtouch_aq_programmer.c iaqualink.c
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_IAQTOUCH
|
||||
endif
|
||||
|
||||
|
@ -213,14 +214,27 @@ SLOG_AMD64 = ./release/serial_logger-amd64
|
|||
|
||||
# Before the below works, you need to build the aqualinkd-releasebin docker for compiling.
|
||||
# sudo docker build -f Dockerfile.releaseBinaries -t aqualinkd-releasebin .
|
||||
# Something like below
|
||||
#releasebuilddocker:
|
||||
# sudo docker build -f ./docker/Dockerfile.releaseBinaries -t aqualinkd-releasebin .
|
||||
# $(info Docker for building release binaries has been created)
|
||||
|
||||
release:
|
||||
sudo docker run -it --mount type=bind,source=./,target=/build aqualinkd-releasebin make buildrelease
|
||||
$(info Binaries for release have been built)
|
||||
|
||||
quick:
|
||||
sudo docker run -it --mount type=bind,source=./,target=/build aqualinkd-releasebin make quickbuild
|
||||
$(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)
|
||||
|
||||
# This is run inside container Dockerfile.releaseBinariies (aqualinkd-releasebin)
|
||||
quickbuild: armhf arm64
|
||||
$(shell cd release && [ ! -f "./aqualinkd-armhf" ] && ln -s ./aqualinkd-armhf ./aqualinkd && ln -s ./serial_logger-armhf ./serial_logger)
|
||||
|
||||
|
||||
# Rules to pass to make.
|
||||
all: $(MAIN) $(SLOG)
|
||||
|
|
57
README.md
57
README.md
|
@ -87,6 +87,7 @@ Designed to mimic AqualinkRS devices, used to fully configure the master control
|
|||
* Create iAqualink Touch Simulator
|
||||
* Probably decoded enough protocols for AuqlinkD to self configure.
|
||||
|
||||
|
||||
<!--
|
||||
* NEED TO FIX for PDA and iAQT protocol.
|
||||
* Not always doing on/off
|
||||
|
@ -110,11 +111,61 @@ Designed to mimic AqualinkRS devices, used to fully configure the master control
|
|||
# Call for Help.
|
||||
* The only Jandy devices I have not decoded yet are LX heater & Chemical Feeder. If you have either of these devices and are willing to post some logs, please let me know, or post in the [Discussions area](https://github.com/sfeakes/AqualinkD/discussions)
|
||||
|
||||
# Updates in 2.3.8 (Dev)
|
||||
|
||||
<!--
|
||||
NEED TO FIX FOR THIS RELEASE.
|
||||
***** FIX NET_SERVICES.C action_uri() spa and spa_mode get confused. check EVERY strncmp
|
||||
* MQTT filter_pump/percent/set, maybe add max/min to pump config. / print protocol on startup
|
||||
* Pump by name and not ID. clean up code
|
||||
* DONE look at using 0x00 for no exit on serial errors / startup
|
||||
* DONE look at virtual button support
|
||||
* vbuton will need the PDA on iAQT protocol working.
|
||||
* change dimmer to % from steps. (will make HASIO & Homekit easier)
|
||||
* add config for homekit_f (panel in F homekin in C), F to F or C to C is fine.
|
||||
* deprecate (hide and default to yes) extended_device_id_programming
|
||||
* Move following to main and not config.c - show error is vbutton and no extended_device_id, vbutton w/ pump can be onetouch.
|
||||
* check panel version reported against config.
|
||||
# Updates in 2.4.1
|
||||
|
||||
# install.sh change spa_mode to spa in config.js
|
||||
# DONE change hassio.c to use rpm speed/percent
|
||||
# pickup speed faster on iaqualinktouch after change
|
||||
-->
|
||||
|
||||
# Updates in 2.5.0 (under development)
|
||||
* PDA panel Rev 6.0 or newer that do not have a Jandy iAqualink device attached can use the AqualinkTouch protocol rather than PDA protocol.
|
||||
* This is faster, more reliable and does not intefear with the physical PDA device (like existing implimentation)
|
||||
* Please consider this very much BETA at the moment.
|
||||
* use `device_id=0x33` in aqualinkd.conf.
|
||||
* PDA panel Rev 6.0 of newer WITH a Jandy iAqualink device attached can use `read_RS485_iAqualink = yes` to speed up device state change detection.
|
||||
* Added MQTT vsp_pump/speed/set for setting speed (RPM/GPM) by %, for automation hubs.
|
||||
* Added full dimmer range support for dimmable lights (not limited to 0,25,50,75,100 anymore)
|
||||
* Added vsp and dimmer to hassio and homebridge-aqualinkd plugin as full range dimmer controls.
|
||||
* Updated UI for support fullrange dimmer.
|
||||
* cleaned up code for spa_mode and spa for newer pannels.
|
||||
* Allow VSP to be asigned to virtual button.
|
||||
* Fixed bug with timer not starting.
|
||||
* Increase Speed of detecting device state changes.
|
||||
|
||||
# Updates in Release 2.4.0
|
||||
* <b>WARNING</b> Breaking change if you use dimmer (please change button_??_lightMode from 6 to 10)
|
||||
* Fixed bugs with particular Jandy panel versions and color lights.
|
||||
* Added support for more color lights, and sped up programming
|
||||
* Code & Repo refactor
|
||||
* Decoded more Pentair VSP pump status.
|
||||
* Changed VSP pump status handling (display more in web UI)
|
||||
* VSP Pump status & other attributes in HASSIO
|
||||
* Changed VSP pump status handling (display more in web UI).
|
||||
* VSP Pump status & other attributes in HASSIO.
|
||||
* Dual temperature sensors supported.
|
||||
* Updates to serial_logger.
|
||||
* Changes to aqmanager for adding more options for decoding protocols.
|
||||
* Support for packets changes from panels REV Yg
|
||||
* Support VSP by label (not pump number), REV Yg
|
||||
* Added support for One Touch Buttons & Virtual Buttons.
|
||||
* look at `virtual_button??_label` in aqualinkd.conf
|
||||
* have to use AqualinkTouch protocol for `extended_device_id` 0x31->0x33 in aqualinkd.conf
|
||||
|
||||
# Updates in Release 2.3.8
|
||||
* Release removed. Bug with light program 0.
|
||||
|
||||
# Updates in Release 2.3.7
|
||||
* Fix for Pentair VSP losing connection & bouncing SWG to 0 and back.
|
||||
|
|
|
@ -0,0 +1,286 @@
|
|||
|
||||
#####################################
|
||||
#
|
||||
# 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.releaseBinaries -t aqualinkd-releasebin .
|
||||
# docker run -it --mount type=bind,source=./build,target=/build aqualinkd-releasebin bash
|
||||
#
|
||||
# clean method
|
||||
# docker system prune
|
||||
#
|
||||
# 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 \
|
||||
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
|
||||
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
|
||||
|
|
@ -6,10 +6,11 @@
|
|||
# This file should be placed in the config aqualinkd directory defined
|
||||
# in your docker-compose.yml (or equiv)
|
||||
#
|
||||
# MAKE SURE TO CHAGE THE IP BELOW
|
||||
#
|
||||
# MAKE SURE TO CHAGE THE IP BELOW (1.1.1.1)
|
||||
# aqualinkd.cong should have serial_port=/dev/ttyEW11
|
||||
|
||||
echo "Starting SOCAT port binding....."
|
||||
socat -d -d pty,link=/dev/tty.Pool2,raw TCP:192.168.99.248:8899 &
|
||||
socat -d -d pty,link=/dev/ttyEW11,raw,ignoreeof TCP4:1.1.1.1:8899,ignoreeof &
|
||||
sudo docker compose up
|
||||
echo "Sleeping for SOCAT start....."
|
||||
sleep 2s
|
|
@ -58,7 +58,7 @@ if echo $DOCKER_TAGS | grep -q $VERSION; then
|
|||
fi
|
||||
|
||||
# Login first
|
||||
# cat ~sf/.docker.token | docker login --username sfeakes --password-stdin
|
||||
# cat ~/.docker.token | docker login --username sfeakes --password-stdin
|
||||
|
||||
echo "Building Docker container for $IMAGE using branch $VERSION"
|
||||
docker buildx build --platform=linux/amd64,linux/arm64 \
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Pass time between as #1 and #2 using 24 hour
|
||||
|
||||
# example crontab entry to start pump if system boots is between 6am and 11pm
|
||||
#
|
||||
# @reboot /path/start_pump_reboot 6 23
|
||||
#
|
||||
|
||||
startAfter=$1
|
||||
startBefore=$2
|
||||
|
||||
SLEEP_BETWEEN_TRIES=5 # 5 seconds
|
||||
TRIES=5 # 5 tries
|
||||
|
||||
# Wait for AqualinkD to come up and connect to panel
|
||||
sleep 30
|
||||
|
||||
hour=$(date +%H)
|
||||
|
||||
|
||||
function turn_on() {
|
||||
curl -s -S -o /dev/null http://localhost:80/api/Filter_Pump/set -d value=1 -X PUT --fail
|
||||
rtn=$?
|
||||
echo $rtn
|
||||
return $rtn
|
||||
}
|
||||
|
||||
#echo "Hour=$hour Ater=$startAfter Before=$startBefore"
|
||||
|
||||
# Remember 11:45 is 11, so don't use <= for startBefore
|
||||
if (($hour >= $startAfter && $hour < $startBefore )); then
|
||||
x=1
|
||||
while [ $x -le $TRIES ] && [ $(turn_on) -gt 0 ]; do
|
||||
sleep $SLEEP_BETWEEN_TRIES
|
||||
x=$(( $x + 1 ))
|
||||
done
|
||||
fi
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -28,6 +28,10 @@ display_warnings_in_web=true
|
|||
# If you change this from 80, remember to update aqualink.service.avahi
|
||||
socket_port=80
|
||||
|
||||
|
||||
# Note on serial port below. If you want aqualinkd to start and run without connecting to a panel or port
|
||||
# use 0x00 for device_id and a dummy serial_port like /dev/tty0.
|
||||
|
||||
# The serial port the daemon access to read the Aqualink RS8
|
||||
serial_port=/dev/ttyUSB0
|
||||
|
||||
|
@ -59,7 +63,7 @@ panel_type = RS-8 Combo
|
|||
# Working RS ID's are 0x0a 0x0b 0x09 0x08 <- 0x08 is usually taken
|
||||
# If your panel is a PDA only model, then PDA device ID's are 0x60, 0x61, 0x62, 0x63.
|
||||
# (These are NOT recomended to use unless you absolutly have no other option)
|
||||
device_id=0x0a
|
||||
device_id=0x00
|
||||
|
||||
|
||||
# The ID of Jandy SerialInterface device. These is only one usable ID, if serial_logger
|
||||
|
@ -87,12 +91,14 @@ device_id=0x0a
|
|||
# JXi = Jandy JXi heater (might also be LXi heaters)
|
||||
# LX = Jandy LX & LT heaters
|
||||
# Chem = Jandy Chemical Feeder
|
||||
# iAqualink = Read iAqualink2 (wifi device). Only relivent in PDA mode IF you have iAqualink2/3 device
|
||||
#read_RS485_swg = yes
|
||||
#read_RS485_ePump = yes
|
||||
#read_RS485_vsfPump = yes
|
||||
#read_RS485_JXi = yes
|
||||
#read_RS485_LX = yes
|
||||
#read_RS485_Chem = yes
|
||||
#read_RS485_iAqualink = yes
|
||||
|
||||
# Keep the panel time synced with systemtime. Make sure to set systemtime / NTP correctly.
|
||||
keep_paneltime_synced = yes
|
||||
|
@ -112,11 +118,9 @@ convert_dz_temp_to_c = yes
|
|||
# decide how to report.
|
||||
report_zero_spa_temp = yes
|
||||
|
||||
# default is to not report changes to pool temp when the filter pump is off or in spa mode
|
||||
# enable below to report 0 as the pool temp when the filter pump is off or when in spa mode.
|
||||
# This is for MQTT cnnections only, WEB socket and WEB API always report TEMP_UNKNOWN (-999) allowing the consumer to
|
||||
# decide how to report.
|
||||
report_zero_pool_temp = no
|
||||
# When pool or spa is off, report 0deg for water temp. If set to no, last known value will be used.
|
||||
report_zero_pool_temp = yes
|
||||
report_zero_spa_temp = yes
|
||||
|
||||
# mqtt stuff
|
||||
#mqtt_address = localhost:1883
|
||||
|
@ -144,15 +148,11 @@ report_zero_pool_temp = no
|
|||
# dead.
|
||||
# ~40 and we will be replying too slowley, so keep below that.
|
||||
# 10~20 is about what most device reply in. But 0-4 works well.
|
||||
rs485_frame_delay = 4
|
||||
rs485_frame_delay = 0
|
||||
|
||||
# Get rid of the startup warning message about no low latency. BETTER option is to buy a better adapter.
|
||||
#ftdi_low_latency = no
|
||||
|
||||
# Stop the SWG bounce from displaying when using VSP.
|
||||
#swg_zero_ignore_count = 20
|
||||
|
||||
|
||||
# Enable AqualinkD scheduler.
|
||||
# A version of cron that supports cron.d must be installed for the scheduler to work.
|
||||
# If you used the install script and didn;t receive any cron warnings, you should be good to go.
|
||||
|
@ -216,11 +216,12 @@ use_panel_aux_labels=no
|
|||
# These are all the button labels / options / pump and light configurations you want to use.
|
||||
# Simply change these to your setup, valid options for wach button are :-
|
||||
# None of these are mandatory unless you have PDA or RS16 panel, then _label is mandatory
|
||||
# button_??_label=Filter Pump <Label you want to see>
|
||||
# button_??_label=Filter Pump <Label you want to see>
|
||||
# button_??_dzidx=37 <Domoticz IDX>
|
||||
# button_??_pumpID=0x60 <RS485 ID of VSP>
|
||||
# button_??_pumpIndex=1 <Pump index Jandy panel is configured to use>
|
||||
# button_??_pumpType=Pentair VF <Pump Type, one of the folowing :- JANDY ePUMP, Pentair VF, Pentair VS>
|
||||
# button_??_pumpName=My Pump <Panel Rev Y supports renaming VSP, use the name here>
|
||||
# button_??_lightMode=4 <Color light mode>
|
||||
#
|
||||
# In most cases the label is just what you want to see in web UI/MQTT/API. ie you don't need to use Jandy's labeling. There are 2 exaeptions to the labeling listed below
|
||||
|
@ -230,28 +231,28 @@ use_panel_aux_labels=no
|
|||
#
|
||||
# Below is an example of how different Panels map into the buttons.
|
||||
#
|
||||
# | RS-6 Combo | RS-6 Only | RS-8 Combo | RS-2/6 Dual | RS-2/10 Dual | RS-16 Combo |
|
||||
# --------------------------------------------------------------------------------------------
|
||||
# Button_01 | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump |
|
||||
# Button_02 | Spa | Aux_1 | Spa | Spa | Spa | Spa |
|
||||
# Button_03 | Aux 1 | Aux 2 | Aux 1 | Aux 1 | Aux 1 | Aux 1 |
|
||||
# Button_04 | Aux 2 | Aux 3 | Aux 2 | Aux 2 | Aux 2 | Aux 2 |
|
||||
# Button_05 | Aux 3 | Aux 4 | Aux 3 | Aux 3 | Aux 3 | Aux 3 |
|
||||
# Button_06 | Aux 4 | Aux 5 | Aux 4 | Aux 4 | Aux 4 | Aux 4 |
|
||||
# Button_07 | Aux 5 | Temp 1 | Aux 5 | Aux 5 | Aux 5 | Aux 5 |
|
||||
# Button_08 | Pool Heater | Temp 2 | Aux 6 | Aux 6 | Aux 6 | Aux 6 |
|
||||
# Button_09 | Spa Heater | Solar Heater | Aux 7 | Pool Heater | Aux B1 | Aux 7 |
|
||||
# Button_10 | Solar Heater | | Pool Heater | Spa Heater | Aux B2 | Aux B1 |
|
||||
# Button_11 | | | Spa Heater | Solar Heater | Aux B3 | Aux B2 |
|
||||
# Button_12 | | | Solar Heater | | Aux B4 | Aux B3 |
|
||||
# Button_13 | | | | | Pool Heater | Aux B4 |
|
||||
# Button_14 | | | | | Spa Heater | Aux B5 |
|
||||
# Button_15 | | | | | Solar Heater | Aux B6 |
|
||||
# Button_16 | | | | | | Aux B7 |
|
||||
# Button_17 | | | | | | Aux B8 |
|
||||
# Button_18 | | | | | | Pool Heater |
|
||||
# Button_19 | | | | | | Spa Heater |
|
||||
# Button_20 | | | | | | Solar Heater |
|
||||
# | RS-4 Combo | RS-6 Combo | RS-6 Only | RS-8 Combo | RS-2/6 Dual | RS-2/10 Dual | RS-16 Combo |
|
||||
# ----------------------------------------------------------------------------------------------------------
|
||||
# Button_01 | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump |
|
||||
# Button_02 | Spa | Spa | Aux_1 | Spa | Spa | Spa | Spa |
|
||||
# Button_03 | Aux 1 | Aux 1 | Aux 2 | Aux 1 | Aux 1 | Aux 1 | Aux 1 |
|
||||
# Button_04 | Aux 2 | Aux 2 | Aux 3 | Aux 2 | Aux 2 | Aux 2 | Aux 2 |
|
||||
# Button_05 | Aux 3 | Aux 3 | Aux 4 | Aux 3 | Aux 3 | Aux 3 | Aux 3 |
|
||||
# Button_06 | Pool Heater | Aux 4 | Aux 5 | Aux 4 | Aux 4 | Aux 4 | Aux 4 |
|
||||
# Button_07 | Spa Heater | Aux 5 | Temp 1 | Aux 5 | Aux 5 | Aux 5 | Aux 5 |
|
||||
# Button_08 | Solar Heater | Pool Heater | Temp 2 | Aux 6 | Aux 6 | Aux 6 | Aux 6 |
|
||||
# Button_09 | | Spa Heater | Solar Heater | Aux 7 | Pool Heater | Aux B1 | Aux 7 |
|
||||
# Button_10 | | Solar Heater | | Pool Heater | Spa Heater | Aux B2 | Aux B1 |
|
||||
# Button_11 | | | | Spa Heater | Solar Heater | Aux B3 | Aux B2 |
|
||||
# Button_12 | | | | Solar Heater | | Aux B4 | Aux B3 |
|
||||
# Button_13 | | | | | | Pool Heater | Aux B4 |
|
||||
# Button_14 | | | | | | Spa Heater | Aux B5 |
|
||||
# Button_15 | | | | | | Solar Heater | Aux B6 |
|
||||
# Button_16 | | | | | | | Aux B7 |
|
||||
# Button_17 | | | | | | | Aux B8 |
|
||||
# Button_18 | | | | | | | Pool Heater |
|
||||
# Button_19 | | | | | | | Spa Heater |
|
||||
# Button_20 | | | | | | | Solar Heater |
|
||||
|
||||
#
|
||||
# Optional, ( button_01_pumpID & button_01_pumpIndex )
|
||||
|
@ -265,12 +266,12 @@ use_panel_aux_labels=no
|
|||
# button_01_pumpIndex=1
|
||||
# If you have assigned this pump an index number in your Aqualink control panel, (Between 1 & 4), put it here for VSP, RPM, Primp information to be captured.
|
||||
#
|
||||
# button_xx_lightMode = (0=Aqualink program, 1=Jandy, 2=Jandy LED, 3=SAm/SAL, 4=Color Logic, 5=Intellibrite, 6=Dimmer)
|
||||
#
|
||||
# button_xx_lightMode = (0=Aqualink program, 1=Jandy, 2=Jandy LED, 3=SAm/SAL, 4=Color Logic, 5=Intellibrite, 6=Hayw Univ Color, 7,8,9(future), 10=Dimmer, 11=Full Range Dimmer)
|
||||
#
|
||||
# Below are settings for standard buttons on RS-8 Combo panel used as example.
|
||||
button_01_label=Filter Pump
|
||||
|
||||
button_02_label=Spa Mode
|
||||
button_02_label=Spa
|
||||
|
||||
button_03_label=Cleaner
|
||||
|
||||
|
@ -294,3 +295,16 @@ button_11_label=Spa Heater
|
|||
|
||||
button_12_label=Solar Heater
|
||||
|
||||
# Virtual buttons.
|
||||
# To use these you must have extended_device_id set to AqualnkTouch protocol, ie 0x31, 0x31, 0x32, 0x33
|
||||
# These are the One Touch buttons. By default below are the labels
|
||||
# Panels rev Yg and newer support custom virtual buttons as well, simply add these here
|
||||
# Add the ones you would like to use below, making sure to
|
||||
# a) Sequential order of the button number starting 01
|
||||
# b) Label must be IDENTICAL to how it's displayed on a AqualinkTouch device (or web)
|
||||
#
|
||||
#virtual_button_01_label=Spa Mode
|
||||
#virtual_button_02_label=Clean Mode
|
||||
#virtual_button_03_label = OneTouch 4
|
||||
#virtual_button_04_label = OneTouch 5
|
||||
#virtual_button_05_label = OneTouch 6
|
||||
|
|
|
@ -57,8 +57,13 @@ if [ "$PARENT_COMMAND" != "make" ] && [ "$1" != "from-make" ] && [ "$1" != "igno
|
|||
BINEXT="-armhf"
|
||||
;;
|
||||
*)
|
||||
echo "Arch $ARCH is unknown, Default to using 32bit HF AqualinkD, you may need to manually try ./release/aqualnkd_arm64"
|
||||
BINEXT=""
|
||||
if [ -f $BUILD/$SOURCEBIN-$ARCH ]; then
|
||||
echo "Arch $ARCH is not officially supported, but we found a suitable binary"
|
||||
BINEXT="-$ARCH"
|
||||
else
|
||||
echo "Arch $ARCH is unknown, Default to using 32bit HF AqualinkD, you may need to manually try ./release/aqualnkd_arm64"
|
||||
BINEXT=""
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@ -124,6 +129,20 @@ else
|
|||
fi
|
||||
fi
|
||||
|
||||
# V2.3.9 has kind-a breaking change for config.js, so check existing and rename if needed
|
||||
# we added Aux_V? to the button list
|
||||
if [ -f "$WEBLocation/config.js" ]; then
|
||||
# Test is if has AUX_V1 in file AND "Spa" is in file (Spa_mode changed to Spa)
|
||||
if ! grep -q 'Aux_V1' $WEBLocation/$file || ! grep -q '"Spa"' $WEBLocation/$file; then
|
||||
dateext=`date +%Y%m%d_%H_%M_%S`
|
||||
echo "AqualinkD web config is old, making copy to $WEBLocation/config.js.$dateext"
|
||||
echo "Please make changes to new version $WEBLocation/config.js"
|
||||
mv $WEBLocation/config.js $WEBLocation/config.js.$dateext
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# copy files to locations, but only copy cfg if it doesn;t already exist
|
||||
|
||||
cp $BUILD/$SOURCEBIN $BINLocation/$BIN
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -9,13 +9,28 @@
|
|||
#include "devices_jandy.h"
|
||||
#include "allbutton_aq_programmer.h"
|
||||
|
||||
void processLEDstate(struct aqualinkdata *aq_data)
|
||||
/* Below can also be called from serialadapter.c */
|
||||
void processLEDstate(struct aqualinkdata *aq_data, unsigned char *packet, logmask_t from)
|
||||
{
|
||||
|
||||
int i = 0;
|
||||
int byte;
|
||||
int bit;
|
||||
|
||||
if (memcmp(aq_data->raw_status, packet + 4, AQ_PSTLEN) != 0) {
|
||||
aq_data->updated = true;
|
||||
LOG(from,LOG_DEBUG, "Processing LEDs status CHANGED\n");
|
||||
} else {
|
||||
LOG(from,LOG_DEBUG, "Processing LEDs status\n");
|
||||
// Their is no point in continuing here, so we could return if wanted.
|
||||
// But for the moment, we don't need to speed up anything.
|
||||
}
|
||||
|
||||
memcpy(aq_data->raw_status, packet + 4, AQ_PSTLEN);
|
||||
|
||||
//debuglogPacket(ALLB_LOG, );
|
||||
|
||||
|
||||
for (byte = 0; byte < 5; byte++)
|
||||
{
|
||||
for (bit = 0; bit < 8; bit += 2)
|
||||
|
@ -27,7 +42,7 @@ void processLEDstate(struct aqualinkdata *aq_data)
|
|||
else
|
||||
aq_data->aqualinkleds[i].state = OFF;
|
||||
|
||||
//LOG(ALLB_LOG,LOG_DEBUG,"Led %d state %d",i+1,aq_data->aqualinkleds[i].state);
|
||||
//LOG(from,LOG_DEBUG,"Led %d state %d",i+1,aq_data->aqualinkleds[i].state);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -42,9 +57,17 @@ void processLEDstate(struct aqualinkdata *aq_data)
|
|||
aq_data->aqualinkleds[SOLAR_HTR_LED_INDEX - 1].state = ENABLE;
|
||||
/*
|
||||
for (i=0; i < TOTAL_BUTTONS; i++) {
|
||||
LOG(ALLB_LOG,LOG_NOTICE, "%s = %d", aq_data->aqbuttons[i].name, aq_data->aqualinkleds[i].state);
|
||||
LOG(from,LOG_NOTICE, "%s = %d", aq_data->aqbuttons[i].name, aq_data->aqualinkleds[i].state);
|
||||
}
|
||||
*/
|
||||
#ifdef CLIGHT_PANEL_FIX // Use state from RSSD protocol for color light if it's on.
|
||||
for (int i=0; i < aq_data->num_lights; i++) {
|
||||
if ( aq_data->lights[i].RSSDstate == ON && aq_data->lights[i].button->led->state != ON ) {
|
||||
aq_data->lights[i].button->led->state = aq_data->lights[i].RSSDstate;
|
||||
//LOG(from,LOG_WARNING,"Fix Jandy bug, color light '%s' is on, setting status to match!\n", aq_data->lights[i].button->label);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void setUnits(char *msg, struct aqualinkdata *aq_data)
|
||||
|
@ -78,6 +101,8 @@ void setUnits(char *msg, struct aqualinkdata *aq_data)
|
|||
#define MSG_RS16BUTTON (1 << 8)
|
||||
#define MSG_BATTERY_LOW (1 << 9)
|
||||
#define MSG_SWG_DEVICE (1 << 10)
|
||||
#define MSG_LOOP_POOL_TEMP (1 << 11)
|
||||
#define MSG_LOOP_SPA_TEMP (1 << 12)
|
||||
|
||||
#ifdef AQ_RS16
|
||||
int16_t RS16_endswithLEDstate(char *msg, struct aqualinkdata *aq_data)
|
||||
|
@ -224,6 +249,14 @@ void _processMessage(char *message, struct aqualinkdata *aq_data, bool reset)
|
|||
// NSF Need something to catch startup when SWG=0 so we set it to enabeled.
|
||||
// when other ways/protocols to detect SWG=0 are turned off.
|
||||
}
|
||||
|
||||
if ((msg_loop & MSG_LOOP_POOL_TEMP) != MSG_LOOP_POOL_TEMP && aq_data->pool_temp != TEMP_UNKNOWN ) {
|
||||
aq_data->pool_temp = TEMP_UNKNOWN;
|
||||
}
|
||||
if ((msg_loop & MSG_LOOP_SPA_TEMP) != MSG_LOOP_SPA_TEMP && aq_data->spa_temp != TEMP_UNKNOWN ) {
|
||||
aq_data->spa_temp = TEMP_UNKNOWN;
|
||||
}
|
||||
|
||||
/*
|
||||
// AQUAPURE=0 we never get that message on ALLBUTTON so don't turn off unless filter pump if off
|
||||
if ((msg_loop & MSG_SWG) != MSG_SWG && aq_data->aqbuttons[PUMP_INDEX].led->state == OFF ) {
|
||||
|
@ -302,6 +335,7 @@ void _processMessage(char *message, struct aqualinkdata *aq_data, bool reset)
|
|||
}
|
||||
else if (strncasecmp(msg, MSG_POOL_TEMP, MSG_POOL_TEMP_LEN) == 0)
|
||||
{
|
||||
msg_loop |= MSG_LOOP_POOL_TEMP;
|
||||
aq_data->pool_temp = atoi(msg + MSG_POOL_TEMP_LEN);
|
||||
|
||||
if (aq_data->temp_units == UNKNOWN)
|
||||
|
@ -309,6 +343,7 @@ void _processMessage(char *message, struct aqualinkdata *aq_data, bool reset)
|
|||
}
|
||||
else if (strncasecmp(msg, MSG_SPA_TEMP, MSG_SPA_TEMP_LEN) == 0)
|
||||
{
|
||||
msg_loop |= MSG_LOOP_SPA_TEMP;
|
||||
aq_data->spa_temp = atoi(msg + MSG_SPA_TEMP_LEN);
|
||||
|
||||
if (aq_data->temp_units == UNKNOWN)
|
||||
|
@ -617,9 +652,16 @@ bool process_allbutton_packet(unsigned char *packet, int length, struct aqualink
|
|||
//LOG(ALLB_LOG,LOG_DEBUG_SERIAL, "RS Received ACK length %d.\n", length);
|
||||
break;
|
||||
case CMD_STATUS:
|
||||
//LOG(ALLB_LOG,LOG_DEBUG_SERIAL, "RS Received STATUS length %d.\n", length);
|
||||
memcpy(aq_data->raw_status, packet + 4, AQ_PSTLEN);
|
||||
processLEDstate(aq_data);
|
||||
//LOG(ALLB_LOG,LOG_DEBUG, "RS Received STATUS length %d.\n", length);
|
||||
//debuglogPacket(ALLB_LOG, packet, length, true, true);
|
||||
|
||||
//memcpy(aq_data->raw_status, packet + 4, AQ_PSTLEN);
|
||||
//processLEDstate(aq_data);
|
||||
processLEDstate(aq_data, packet, ALLB_LOG);
|
||||
|
||||
/* NSF Take this out, and use the ALLButton loop cycle to determin if we get spa/pool temp
|
||||
messages. Works better for dual equiptment when both pool & spa pumps and dual temp sensors */
|
||||
/*
|
||||
if (aq_data->aqbuttons[PUMP_INDEX].led->state == OFF)
|
||||
{
|
||||
aq_data->pool_temp = TEMP_UNKNOWN;
|
||||
|
@ -635,6 +677,7 @@ bool process_allbutton_packet(unsigned char *packet, int length, struct aqualink
|
|||
{
|
||||
aq_data->pool_temp = TEMP_UNKNOWN;
|
||||
}
|
||||
*/
|
||||
|
||||
// COLOR MODE programming relies on state changes, so let any threads know
|
||||
//if (aq_data->active_thread.ptype == AQ_SET_LIGHTPROGRAM_MODE) {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define ALLBUTTON_H_
|
||||
|
||||
|
||||
|
||||
void processLEDstate(struct aqualinkdata *aq_data, unsigned char *packet, logmask_t from);
|
||||
bool process_allbutton_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data);
|
||||
|
||||
#endif //ALLBUTTON_H_
|
|
@ -536,6 +536,9 @@ void *set_allbutton_light_colormode( void *ptr )
|
|||
|
||||
if (i == LIGHT_COLOR_OPTIONS) {
|
||||
LOG(ALLB_LOG, LOG_ERR, "Light Programming didn't receive color light mode message for '%s'\n",use_current_mode?"light program":mode_name);
|
||||
} else {
|
||||
// Set before we are called.
|
||||
//updateButtonLightProgram(aq_data, val, btn);
|
||||
}
|
||||
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
@ -624,6 +627,9 @@ void *set_allbutton_light_programmode( void *ptr )
|
|||
}
|
||||
//waitForButtonState(aq_data, &aq_data->aqbuttons[btn], ON, 2);
|
||||
|
||||
// set before we are called
|
||||
//updateButtonLightProgram(aq_data, val, btn);
|
||||
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
||||
// just stop compiler error, ptr is not valid as it's just been freed
|
||||
|
|
|
@ -53,6 +53,11 @@
|
|||
#define PUMP_MODE_TOPIC "/Mode"
|
||||
#define PUMP_STATUS_TOPIC "/Status"
|
||||
#define PUMP_PPC_TOPIC "/PPC"
|
||||
#define PUMP_SPEED_TOPIC "/Speed"
|
||||
|
||||
#define LIGHT_PROGRAM_TOPIC "/program"
|
||||
#define LIGHT_DIMMER_VALUE_TOPIC "/brightness"
|
||||
|
||||
/*
|
||||
#define AIR_TEMPERATURE "Air"
|
||||
#define POOL_TEMPERATURE "Pool_Water"
|
||||
|
|
|
@ -24,10 +24,13 @@
|
|||
#include "serialadapter.h"
|
||||
#include "aq_timer.h"
|
||||
#include "allbutton_aq_programmer.h"
|
||||
#include "rs_msg_utils.h"
|
||||
#include "iaqualink.h"
|
||||
|
||||
void initPanelButtons(struct aqualinkdata *aqdata, bool rspda, int size, bool combo, bool dual);
|
||||
void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button);
|
||||
|
||||
|
||||
char *name2label(char *str)
|
||||
{
|
||||
int len = strlen(str);
|
||||
|
@ -46,6 +49,76 @@ char *name2label(char *str)
|
|||
return newst;
|
||||
}
|
||||
|
||||
// This has NOT been tested.
|
||||
uint16_t getPanelSupport( char *rev_string, int rev_len)
|
||||
{
|
||||
uint16_t supported = 0;
|
||||
|
||||
char REV[5];
|
||||
|
||||
if (! rsm_get_revision(REV, rev_string, rev_len) ) {
|
||||
LOG(PANL_LOG,LOG_ERR, "Couldn't get panel revision from '%s'\n",rev_string);
|
||||
return 0; // No point in continue
|
||||
} else if (REV[0] > 90 || REV[0] < 65) { // > Z or < A
|
||||
LOG(PANL_LOG,LOG_WARNING, "Panel revision is not understood '%s', please report this issue");
|
||||
}
|
||||
|
||||
|
||||
// Get the actual rev letter
|
||||
//if ( rsm_get_revision(REV, rev_string, rev_len) ) {
|
||||
// Rev >=I == one touch protocol
|
||||
// Rev >=O == VSP
|
||||
// Rev >=Q == iaqualink touch protocol.
|
||||
// REv >= P == chemlink
|
||||
// Rev >= I serial adapter.
|
||||
// Rev >= F == Dommer. But need serial protocol so set to I
|
||||
// Rev >= L == JandyColors Smart Light Control
|
||||
// Rev >= MMM = 12V JandyColor Lights (also light dimmer)
|
||||
// Rev >= N Hayward ColorLogic LED Light
|
||||
// Rev >= O.1== Jandy WaterColors LED ( 9 colors )
|
||||
// Rev >= T.0.1 == limited color light
|
||||
// Rec >= T.2 == more color lights
|
||||
// Rev >= Q Aqualink Touch protocol
|
||||
// Rev >= R iAqualink (wifi adapter) protocol
|
||||
// Rev >= L PC Dock
|
||||
// Rev >= W pump label (not number)
|
||||
// Rev >= Yg Virtual Device called Label Auxiliraries
|
||||
|
||||
if (REV[0] > 89 || ( REV[0] == 89 && REV[1] >= 103))
|
||||
supported |= RSP_SUP_VBTN;
|
||||
|
||||
if (REV[0] >= 81) // Q in ascii
|
||||
supported |= RSP_SUP_AQLT;
|
||||
|
||||
if (REV[0] >= 82) // R
|
||||
supported |= RSP_SUP_IAQL;
|
||||
|
||||
if (REV[0] >= 80) // P in ascii
|
||||
supported |= RSP_SUP_CHEM;
|
||||
|
||||
if (REV[0] >= 79) // O in ascii
|
||||
supported |= RSP_SUP_VSP;
|
||||
|
||||
if (REV[0] >= 73){ // I in ascii
|
||||
supported |= RSP_SUP_ONET;
|
||||
supported |= RSP_SUP_RSSA;
|
||||
supported |= RSP_SUP_SWG;
|
||||
}
|
||||
|
||||
if (REV[0] >= 76) // L in ascii
|
||||
supported |= RSP_SUP_CLIT;
|
||||
|
||||
if (REV[0] >= 73) // I in ascii, dimmer came out in F, but we use the serial adapter to set, so use that as support
|
||||
supported |= RSP_SUP_DLIT;
|
||||
|
||||
//if (REV[0] > 84 || (REV[0] == 84 && REV[1] == 64 && REV[2] >= 50) ) // T in ascii (or T and . and 2 )
|
||||
// supported |= RSP_SUP_CLIT4;
|
||||
|
||||
//}
|
||||
|
||||
return supported;
|
||||
}
|
||||
|
||||
void changePanelToMode_Only() {
|
||||
_aqconfig_.paneltype_mask |= RSP_SINGLE;
|
||||
_aqconfig_.paneltype_mask &= ~RSP_COMBO;
|
||||
|
@ -109,7 +182,6 @@ setPanel("RS-8 Combo");
|
|||
}
|
||||
*/
|
||||
|
||||
|
||||
char _panelString[60];
|
||||
void setPanelString()
|
||||
{
|
||||
|
@ -254,6 +326,80 @@ void setPanelByName(struct aqualinkdata *aqdata, const char *str)
|
|||
setPanel(aqdata, rs, size, combo, dual);
|
||||
}
|
||||
|
||||
aqkey *addVirtualButton(struct aqualinkdata *aqdata, char *label, int vindex) {
|
||||
if (aqdata->total_buttons + 1 >= TOTAL_BUTTONS) {
|
||||
return NULL;
|
||||
}
|
||||
if (aqdata->virtual_button_start <= 0) {
|
||||
aqdata->virtual_button_start = aqdata->total_buttons;
|
||||
}
|
||||
aqkey *button = &aqdata->aqbuttons[aqdata->total_buttons++];
|
||||
|
||||
//aqdata->aqbuttons[index].led = ;
|
||||
//aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
//aqdata->aqbuttons[index].label = // copy label;
|
||||
//aqdata->aqbuttons[index].name = // aux_v?; ? is vindex
|
||||
//aqdata->aqbuttons[index].code = NUL;
|
||||
//aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
//aqdata->aqbuttons[index].special_mask = 0;
|
||||
|
||||
aqled *led = malloc(sizeof(aqled));
|
||||
button->led = led;
|
||||
|
||||
char *name = malloc(sizeof(char*) * 10);
|
||||
snprintf(name, 9, "%s%d", BTN_VAUX, vindex);
|
||||
button->name = name;
|
||||
|
||||
if (strlen(label) <= 0) {
|
||||
button->label = name;
|
||||
} else {
|
||||
button->label = label;
|
||||
}
|
||||
// These 3 vbuttons have a button code on iaqualink protocol, so use that for rssd_code.
|
||||
if (strncasecmp (button->label, "ALL OFF", 7) == 0) {
|
||||
button->rssd_code = IAQ_ALL_OFF;
|
||||
} else if (strncasecmp (button->label, "Spa Mode", 8) == 0) {
|
||||
button->rssd_code = IAQ_SPA_MODE;
|
||||
} else if (strncasecmp (button->label, "Clean Mode", 10) == 0) {
|
||||
button->rssd_code = IAQ_CLEAN_MODE;
|
||||
} else {
|
||||
button->rssd_code = NUL;
|
||||
}
|
||||
|
||||
button->code = NUL;
|
||||
button->dz_idx = DZ_NULL_IDX;
|
||||
button->special_mask |= VIRTUAL_BUTTON; // Could change to special mask vbutton
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
//{{ (((value | float(0) - %d) / %d) * 100) | int }} - minspeed, (maxspeed - minspeed),
|
||||
//{{ ((value | float(0) / 100) * %d) + %d | int }} - (maxspeed - minspeed), minspeed)
|
||||
|
||||
int getPumpSpeedAsPercent(pump_detail *pump) {
|
||||
int pValue = pump->pumpType==VFPUMP?pump->gpm:pump->rpm;
|
||||
|
||||
if (pValue < pump->minSpeed) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Below will return 0% if pump is at min, so return max (caculation, 1)
|
||||
return AQ_MAX( (int)((float)(pValue - pump->minSpeed) / (float)(pump->maxSpeed - pump->minSpeed) * 100) + 0.5, 1);
|
||||
}
|
||||
|
||||
int convertPumpPercentToSpeed(pump_detail *pump, int pValue) {
|
||||
if (pValue >= 100)
|
||||
return pump->maxSpeed;
|
||||
else if (pValue <= 0)
|
||||
return pump->minSpeed;
|
||||
|
||||
return ( ((float)(pValue / (float)100) * (pump->maxSpeed - pump->minSpeed) + pump->minSpeed)) + 0.5;
|
||||
}
|
||||
|
||||
// 4,6,8,10,12,14
|
||||
void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo, bool dual) {
|
||||
|
||||
|
@ -265,6 +411,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_PUMP;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_PUMP;
|
||||
index++;
|
||||
|
||||
if (combo) {
|
||||
|
@ -275,6 +422,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_SPA;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_SPA;
|
||||
index++;
|
||||
}
|
||||
|
||||
|
@ -285,6 +433,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUX1;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX1;
|
||||
index++;
|
||||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[4-1];
|
||||
|
@ -294,6 +443,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUX2;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX2;
|
||||
index++;
|
||||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[3-1];
|
||||
|
@ -303,6 +453,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUX3;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX3;
|
||||
index++;
|
||||
|
||||
|
||||
|
@ -314,6 +465,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUX4;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX4;
|
||||
index++;
|
||||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[8-1];
|
||||
|
@ -323,6 +475,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUX5;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX5;
|
||||
index++;
|
||||
}
|
||||
|
||||
|
@ -334,6 +487,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUX6;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX6;
|
||||
index++;
|
||||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[1-1];
|
||||
|
@ -343,6 +497,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUX7;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX7;
|
||||
index++;
|
||||
}
|
||||
#ifdef AQ_RS16
|
||||
|
@ -364,6 +519,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUXB1;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX8;
|
||||
index++;
|
||||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[12-1];
|
||||
|
@ -373,6 +529,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUXB2;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX9;
|
||||
index++;
|
||||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[1-1];
|
||||
|
@ -382,6 +539,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUXB3;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX10;
|
||||
index++;
|
||||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[13-1];
|
||||
|
@ -391,6 +549,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUXB4;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX11;
|
||||
index++;
|
||||
}
|
||||
|
||||
|
@ -402,6 +561,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUXB5;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX12;
|
||||
index++;
|
||||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[22-1]; // doesn't actually exist
|
||||
|
@ -411,6 +571,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUXB6;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX13;
|
||||
index++;
|
||||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[23-1]; // doesn't actually exist
|
||||
|
@ -419,6 +580,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].name = BTN_AUXB7;
|
||||
aqdata->aqbuttons[index].code = KEY_AUXB7;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX14;
|
||||
index++;
|
||||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[24-1]; // doesn't actually exist
|
||||
|
@ -428,6 +590,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUXB8;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX15;
|
||||
index++;
|
||||
}
|
||||
#endif // AQ_RS16
|
||||
|
@ -442,6 +605,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_AUX6;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_AUX6;
|
||||
index++;
|
||||
}
|
||||
//Dual panels (2/10 & 2/14) have no AUX7, they go from AUX6 to AUXB1, but the keycodes are the same as other panels
|
||||
|
@ -463,6 +627,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_POOL_HTR;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_POOLHT;
|
||||
index++;
|
||||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[17-1];
|
||||
|
@ -472,20 +637,21 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
aqdata->aqbuttons[index].code = KEY_SPA_HTR;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
aqdata->aqbuttons[index].rssd_code = RS_SA_SPAHT;
|
||||
index++;
|
||||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[19-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_SOLAR_HTR):BTN_PDA_SOLAR_HTR;
|
||||
aqdata->aqbuttons[index].name = BTN_SOLAR_HTR;
|
||||
aqdata->aqbuttons[index].code = KEY_SOLAR_HTR;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_EXT_AUX):BTN_PDA_EXT_AUX;
|
||||
aqdata->aqbuttons[index].name = BTN_EXT_AUX;
|
||||
aqdata->aqbuttons[index].code = KEY_EXT_AUX;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
aqdata->aqbuttons[index].special_mask = 0;
|
||||
index++;
|
||||
|
||||
// Set the sizes for button index
|
||||
aqdata->total_buttons = index;
|
||||
|
||||
//aqdata->single_device = !combo;
|
||||
aqdata->virtual_button_start = 0;
|
||||
|
||||
#ifdef AQ_RS16
|
||||
aqdata->rs16_vbutton_start = 13 - (combo?0:1);
|
||||
|
@ -522,6 +688,9 @@ const char* getRequestName(request_source source)
|
|||
case NET_TIMER:
|
||||
return "Timer";
|
||||
break;
|
||||
case UNACTION_TIMER:
|
||||
return "UnactionTimer";
|
||||
break;
|
||||
}
|
||||
|
||||
static char buf[25];
|
||||
|
@ -575,6 +744,9 @@ const char* getActionName(action_type type)
|
|||
case DATE_TIME:
|
||||
return "Date Time";
|
||||
break;
|
||||
case LIGHT_BRIGHTNESS:
|
||||
return "Light Brightness";
|
||||
break;
|
||||
}
|
||||
|
||||
static char buf[25];
|
||||
|
@ -592,6 +764,14 @@ bool setDeviceState(struct aqualinkdata *aqdata, int deviceIndex, bool isON, req
|
|||
{
|
||||
aqkey *button = &aqdata->aqbuttons[deviceIndex];
|
||||
|
||||
//if ( button->special_mask & VIRTUAL_BUTTON && button->special_mask & VS_PUMP) {
|
||||
if ( isVS_PUMP(button->special_mask) && isVBUTTON(button->special_mask)) {
|
||||
// Virtual Button with VSP is always on.
|
||||
LOG(PANL_LOG, LOG_INFO, "received '%s' for '%s', virtual pump is always on, ignoring", (isON == false ? "OFF" : "ON"), button->name);
|
||||
button->led->state = ON;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((button->led->state == OFF && isON == false) ||
|
||||
(isON > 0 && (button->led->state == ON || button->led->state == FLASH ||
|
||||
button->led->state == ENABLE))) {
|
||||
|
@ -605,9 +785,14 @@ bool setDeviceState(struct aqualinkdata *aqdata, int deviceIndex, bool isON, req
|
|||
// AqualinkTouch in PDA mode, we can program light. (if turing off, use standard AQ_PDA_DEVICE_ON_OFF below)
|
||||
programDeviceLightMode(aqdata, (isON?0:-1), deviceIndex); // -1 means off 0 means use current light mode
|
||||
} else {
|
||||
char msg[PTHREAD_ARG];
|
||||
sprintf(msg, "%-5d%-5d", deviceIndex, (isON == false ? OFF : ON));
|
||||
aq_programmer(AQ_PDA_DEVICE_ON_OFF, msg, aqdata);
|
||||
// If we are using AqualinkTouch with iAqualink enabled, we can send button on/off much faster using that.
|
||||
if ( isPDA_IAQT && isIAQL_ACTIVE) {
|
||||
set_iaqualink_aux_state(button, isON);
|
||||
} else {
|
||||
char msg[PTHREAD_ARG];
|
||||
sprintf(msg, "%-5d%-5d", deviceIndex, (isON == false ? OFF : ON));
|
||||
aq_programmer(AQ_PDA_DEVICE_ON_OFF, msg, aqdata);
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
|
@ -618,23 +803,52 @@ bool setDeviceState(struct aqualinkdata *aqdata, int deviceIndex, bool isON, req
|
|||
// OK Programable light, and no light mode selected. Now let's work out best way to turn it on. serial_adapter protocol will to it without questions,
|
||||
// all other will require programmig.
|
||||
if (isRSSA_ENABLED) {
|
||||
set_aqualink_rssadapter_aux_state(deviceIndex, true);
|
||||
set_aqualink_rssadapter_aux_state(button, true);
|
||||
} else {
|
||||
//set_light_mode("0", deviceIndex); // 0 means use current light mode
|
||||
programDeviceLightMode(aqdata, 0, deviceIndex); // 0 means use current light mode
|
||||
}
|
||||
} else if (isVBUTTON(button->special_mask)) {
|
||||
// Virtual buttons only supported with Aqualink Touch
|
||||
LOG(PANL_LOG, LOG_NOTICE, "********** %s code=0x%02hhx iaq enabled=%s *****\n",button->name, button->rssd_code, isIAQT_ENABLED?"Yes":"No");
|
||||
if (isIAQT_ENABLED) {
|
||||
// If it's one of the pre-defined onces & iaqualink is enabled, we can set it easile with button.
|
||||
if ( isIAQL_ACTIVE && button->rssd_code != NUL)
|
||||
{
|
||||
set_iaqualink_aux_state(button, isON);
|
||||
} else {
|
||||
char msg[PTHREAD_ARG];
|
||||
sprintf(msg, "%-5d%-5d", deviceIndex, (isON == false ? OFF : ON));
|
||||
aq_programmer(AQ_SET_IAQTOUCH_DEVICE_ON_OFF, msg, aqdata);
|
||||
}
|
||||
} else {
|
||||
LOG(PANL_LOG, LOG_ERR, "Can only use Aqualink Touch protocol for Virtual Buttons");
|
||||
}
|
||||
} else if ( source == NET_DZMQTT && isRSSA_ENABLED ) {
|
||||
// Domoticz has a bad habbit of resending the same state back to us, when we use the PRESTATE_ONOFF option
|
||||
// since allbutton (default) is stateless, and rssaadapter is statefull, use rssaadapter for any domoricz requests
|
||||
set_aqualink_rssadapter_aux_state(deviceIndex, isON);
|
||||
set_aqualink_rssadapter_aux_state(button, isON);
|
||||
//} else if ( source == NET_TIMER && isRSSA_ENABLED ) {
|
||||
// Timer will sometimes send duplicate, so use RSSA since that protocol has on/off rather than toggle
|
||||
// set_aqualink_rssadapter_aux_state(button, isON);
|
||||
} else if (button->special_mask & PROGRAM_LIGHT && isRSSA_ENABLED) {
|
||||
// If off and program light, use the RS serial adapter since that is overiding the state now.
|
||||
set_aqualink_rssadapter_aux_state(button, isON);
|
||||
} else {
|
||||
//set_iaqualink_aux_state(button, isON);
|
||||
//set_aqualink_rssadapter_aux_state(button, isON);
|
||||
aq_send_allb_cmd(button->code);
|
||||
}
|
||||
|
||||
#ifdef CLIGHT_PANEL_FIX
|
||||
if (isRSSA_ENABLED) {get_aqualink_rssadapter_colorlight_statuses(aqdata);}
|
||||
#endif
|
||||
|
||||
// Pre set device to state, next status will correct if state didn't take, but this will stop multiple ON messages setting on/off
|
||||
//#ifdef PRESTATE_ONOFF
|
||||
if (_aqconfig_.device_pre_state) {
|
||||
if ((button->code == KEY_POOL_HTR || button->code == KEY_SPA_HTR ||
|
||||
button->code == KEY_SOLAR_HTR) &&
|
||||
button->code == KEY_EXT_AUX) &&
|
||||
isON > 0) {
|
||||
button->led->state = ENABLE; // if heater and set to on, set pre-status to enable.
|
||||
//_aqualink_data->updated = true;
|
||||
|
@ -679,24 +893,62 @@ bool programDeviceValue(struct aqualinkdata *aqdata, action_type type, int value
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
void programDeviceLightBrightness(struct aqualinkdata *aqdata, int value, int button, bool expectMultiple)
|
||||
{
|
||||
clight_detail *light = getProgramableLight(aqdata, button);
|
||||
|
||||
if (!isRSSA_ENABLED) {
|
||||
LOG(PANL_LOG,LOG_ERR, "Light mode brightness is only supported with `rssa_device_id` set\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (light == NULL) {
|
||||
LOG(PANL_LOG,LOG_ERR, "Light mode control not configured for button %d\n",button);
|
||||
return;
|
||||
}
|
||||
|
||||
// DIMMER is 0,25,50,100 DIMMER2 is range
|
||||
if (light->lightType == LC_DIMMER) {
|
||||
value = round(value / 25);
|
||||
}
|
||||
|
||||
if (!expectMultiple) {
|
||||
programDeviceLightMode(aqdata, value, button);
|
||||
return;
|
||||
}
|
||||
|
||||
time(&aqdata->unactioned.requested);
|
||||
aqdata->unactioned.value = value;
|
||||
aqdata->unactioned.type = LIGHT_MODE;
|
||||
aqdata->unactioned.id = button;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//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)
|
||||
{
|
||||
int i;
|
||||
clight_detail *light = NULL;
|
||||
#ifdef AQ_PDA
|
||||
if (isPDA_PANEL && !isPDA_IAQT) {
|
||||
LOG(PANL_LOG,LOG_ERR, "Light mode control not supported in PDA mode\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
int i;
|
||||
clight_detail *light = NULL;
|
||||
for (i=0; i < aqdata->num_lights; i++) {
|
||||
if (&aqdata->aqbuttons[button] == aqdata->lights[i].button) {
|
||||
// Found the programmable light
|
||||
light = &aqdata->lights[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
clight_detail *light = getProgramableLight(aqdata, button);
|
||||
|
||||
if (light == NULL) {
|
||||
LOG(PANL_LOG,LOG_ERR, "Light mode control not configured for button %d\n",button);
|
||||
|
@ -713,11 +965,33 @@ void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button)
|
|||
_aqconfig_.light_programming_initial_off,
|
||||
_aqconfig_.light_programming_mode );
|
||||
aq_programmer(AQ_SET_LIGHTPROGRAM_MODE, buf, aqdata);
|
||||
} else if (isRSSA_ENABLED && light->lightType == LC_DIMMER2) {
|
||||
// Dimmer needs to be turned on before you set dimmer level
|
||||
if (light->button->led->state != ON) {
|
||||
set_aqualink_rssadapter_aux_extended_state(light->button, RS_SA_ON);
|
||||
}
|
||||
set_aqualink_rssadapter_aux_extended_state(light->button, value);
|
||||
} else if (isRSSA_ENABLED && light->lightType == LC_DIMMER) {
|
||||
// Dimmer needs to be turned on first
|
||||
if (light->button->led->state != ON) {
|
||||
set_aqualink_rssadapter_aux_extended_state(light->button, RS_SA_ON);
|
||||
}
|
||||
// Value 1 = 25, 2 = 50, 3 = 75, 4 = 100 (need to convert value into binary)
|
||||
if (value >= 1 && value <= 4) {
|
||||
// If value is not on of those vales, then ignore
|
||||
unsigned char rssd_value = value * 25;
|
||||
set_aqualink_rssadapter_aux_extended_state(light->button, rssd_value);
|
||||
} else {
|
||||
LOG(PANL_LOG,LOG_ERR, "Light mode %d is not valid for '%s'\n",value, light->button->label);
|
||||
}
|
||||
} else {
|
||||
//sprintf(buf, "%-5s%-5d%-5d",value, button, light->lightType);
|
||||
sprintf(buf, "%-5d%-5d%-5d",value, button, 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -759,8 +1033,16 @@ bool panel_device_request(struct aqualinkdata *aqdata, action_type type, int dev
|
|||
//start_timer(aqdata, &aqdata->aqbuttons[deviceIndex], deviceIndex, value);
|
||||
start_timer(aqdata, deviceIndex, value);
|
||||
break;
|
||||
case LIGHT_BRIGHTNESS:
|
||||
programDeviceLightBrightness(aqdata, value, deviceIndex, (source==NET_MQTT?true:false));
|
||||
break;
|
||||
case LIGHT_MODE:
|
||||
programDeviceLightMode(aqdata, value, deviceIndex);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case POOL_HTR_SETOINT:
|
||||
case SPA_HTR_SETOINT:
|
||||
|
@ -785,9 +1067,46 @@ bool panel_device_request(struct aqualinkdata *aqdata, action_type type, int dev
|
|||
}
|
||||
|
||||
|
||||
// Programmable light has been updated, so update the status in AqualinkD
|
||||
void updateButtonLightProgram(struct aqualinkdata *aqdata, int value, int button)
|
||||
{
|
||||
/*
|
||||
int i;
|
||||
clight_detail *light = NULL;
|
||||
|
||||
for (i=0; i < aqdata->num_lights; i++) {
|
||||
if (&aqdata->aqbuttons[button] == aqdata->lights[i].button) {
|
||||
// Found the programmable light
|
||||
light = &aqdata->lights[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
clight_detail *light = getProgramableLight(aqdata, button);
|
||||
|
||||
if (light == NULL) {
|
||||
LOG(PANL_LOG,LOG_ERR, "Button not found for light button index=%d\n",button);
|
||||
return;
|
||||
}
|
||||
|
||||
light->currentValue = value;
|
||||
}
|
||||
|
||||
clight_detail *getProgramableLight(struct aqualinkdata *aqdata, int button)
|
||||
{
|
||||
if ( isPLIGHT(aqdata->aqbuttons[button].special_mask) ) {
|
||||
return (clight_detail *)aqdata->aqbuttons[button].special_mask_ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pump_detail *getPumpDetail(struct aqualinkdata *aqdata, int button)
|
||||
{
|
||||
if ( isVS_PUMP(aqdata->aqbuttons[button].special_mask) ) {
|
||||
return (pump_detail *)aqdata->aqbuttons[button].special_mask_ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef DO_NOT_COMPILE
|
||||
|
||||
|
@ -1227,4 +1546,4 @@ void initButtons_OLD_RS16(struct aqualinkdata *aqdata)
|
|||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,23 @@
|
|||
#define RSP_RSSA (1 << 14) // 128
|
||||
#define RSP_EXT_PROG (1 << 15) // 128
|
||||
|
||||
|
||||
// Bitmask for pannel support against board rev
|
||||
// used in getPanelSupport()
|
||||
#define RSP_SUP_ONET (1 << 0)
|
||||
#define RSP_SUP_AQLT (1 << 1) // Aqualink Touch
|
||||
#define RSP_SUP_IAQL (1 << 2 ) // iAqualink Wifi
|
||||
#define RSP_SUP_RSSA (1 << 3 ) // RS Serial Adapter
|
||||
#define RSP_SUP_VSP (1 << 4)
|
||||
#define RSP_SUP_CHEM (1 << 5) // chem feeder
|
||||
#define RSP_SUP_TSCHEM (1 << 6 ) // true sense chem reader
|
||||
#define RSP_SUP_SWG (1 << 7) // Salt water generator
|
||||
#define RSP_SUP_CLIT (1 << 8) // color lights
|
||||
#define RSP_SUP_DLIT (1 << 9) // dimmer lights
|
||||
#define RSP_SUP_VBTN (1 << 10) // Virtual button
|
||||
#define RSP_SUP_PLAB (1 << 11) // Pump VSP by Label and not number
|
||||
|
||||
|
||||
//void initButtons(struct aqualinkdata *aqdata);
|
||||
void setPanelByName(struct aqualinkdata *aqdata, const char *str);
|
||||
void setPanel(struct aqualinkdata *aqdata, bool rs, int size, bool combo, bool dual);
|
||||
|
@ -37,11 +54,24 @@ const char* getPanelString();
|
|||
|
||||
bool panel_device_request(struct aqualinkdata *aqdata, action_type type, int deviceIndex, int value, request_source source);
|
||||
|
||||
void updateButtonLightProgram(struct aqualinkdata *aqdata, int value, int button);
|
||||
|
||||
void changePanelToMode_Only();
|
||||
void addPanelOneTouchInterface();
|
||||
void addPanelIAQTouchInterface();
|
||||
void addPanelRSserialAdapterInterface();
|
||||
void changePanelToExtendedIDProgramming();
|
||||
|
||||
int getPumpSpeedAsPercent(pump_detail *pump);
|
||||
int convertPumpPercentToSpeed(pump_detail *pump, int value); // This is probable only needed internally
|
||||
|
||||
uint16_t getPanelSupport( char *rev_string, int rev_len);
|
||||
|
||||
aqkey *addVirtualButton(struct aqualinkdata *aqdata, char *label, int vindex);
|
||||
|
||||
clight_detail *getProgramableLight(struct aqualinkdata *aqdata, int button);
|
||||
pump_detail *getPumpDetail(struct aqualinkdata *aqdata, int button);
|
||||
|
||||
//void panneltest();
|
||||
|
||||
#define isPDA_PANEL ((_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA)
|
||||
|
@ -53,6 +83,13 @@ void changePanelToExtendedIDProgramming();
|
|||
#define isIAQT_ENABLED ((_aqconfig_.paneltype_mask & RSP_IAQT) == RSP_IAQT)
|
||||
#define isRSSA_ENABLED ((_aqconfig_.paneltype_mask & RSP_RSSA) == RSP_RSSA)
|
||||
#define isEXTP_ENABLED ((_aqconfig_.paneltype_mask & RSP_EXT_PROG) == RSP_EXT_PROG)
|
||||
|
||||
#define isIAQL_ACTIVE ((_aqconfig_.extended_device_id2 != NUL))
|
||||
|
||||
#define isVS_PUMP(mask) ((mask & VS_PUMP) == VS_PUMP)
|
||||
#define isVBUTTON(mask) ((mask & VIRTUAL_BUTTON) == VIRTUAL_BUTTON)
|
||||
#define isPLIGHT(mask) ((mask & PROGRAM_LIGHT) == PROGRAM_LIGHT)
|
||||
|
||||
int PANEL_SIZE();
|
||||
//
|
||||
//#define PANEL_SIZE PANEL_SIZE()
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "color_lights.h"
|
||||
#include "config.h"
|
||||
#include "devices_jandy.h"
|
||||
#include "iaqualink.h"
|
||||
|
||||
#ifdef AQ_DEBUG
|
||||
#include <time.h>
|
||||
|
@ -585,8 +586,16 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat
|
|||
return;
|
||||
}
|
||||
pda_reset_sleep();
|
||||
} else if (isPDA_PANEL && isPDA_IAQT)
|
||||
}
|
||||
else if (isPDA_PANEL && isPDA_IAQT)
|
||||
{
|
||||
if (isIAQL_ACTIVE) { // if we have iAqualink and AqualinkTouch active on PDA, use iAqualink for setpoints.
|
||||
if (r_type == AQ_SET_POOL_HEATER_TEMP) {
|
||||
type = AQ_SET_IAQLINK_POOL_HEATER_TEMP;
|
||||
} else if (r_type == AQ_SET_SPA_HEATER_TEMP) {
|
||||
type = AQ_SET_IAQLINK_SPA_HEATER_TEMP;
|
||||
}
|
||||
}
|
||||
if ( get_programming_mode(type) != IAQTOUCH) {
|
||||
LOG(PROG_LOG, LOG_ERR, "Selected Programming mode '%s' '%d' not supported with PDA control panel in iAqualinkTouch mode\n",ptypeName(type),type);
|
||||
return;
|
||||
|
@ -629,6 +638,14 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat
|
|||
increase_aqualink_rssadapter_spa_setpoint(args, aq_data);
|
||||
return; // No need to create this as thread.
|
||||
break;
|
||||
case AQ_SET_IAQLINK_POOL_HEATER_TEMP:
|
||||
set_iaqualink_heater_setpoint(atoi(args), true);
|
||||
return; // No need to create this as thread.
|
||||
break;
|
||||
case AQ_SET_IAQLINK_SPA_HEATER_TEMP:
|
||||
set_iaqualink_heater_setpoint(atoi(args), false);
|
||||
return; // No need to create this as thread.
|
||||
break;
|
||||
default:
|
||||
// Should check that _prog_functions[type] is valid.
|
||||
if( pthread_create( &programmingthread->thread_id , NULL , _prog_functions[type], (void*)programmingthread) < 0) {
|
||||
|
@ -821,43 +838,50 @@ const char *ptypeName(program_type type)
|
|||
#endif
|
||||
#ifdef AQ_IAQTOUCH
|
||||
case AQ_SET_IAQTOUCH_PUMP_VS_PROGRAM:
|
||||
return "Set iAqualink Touch Pump VS Program";
|
||||
return "Set AqualinkTouch Touch Pump VS Program";
|
||||
break;
|
||||
case AQ_SET_IAQTOUCH_PUMP_RPM:
|
||||
return "Set iAqualink Touch Pump RPM";
|
||||
return "Set AqualinkTouch Touch Pump RPM";
|
||||
break;
|
||||
case AQ_GET_IAQTOUCH_VSP_ASSIGNMENT:
|
||||
return "Get iAqualink Touch Pump Assignment";
|
||||
return "Get AqualinkTouch Touch Pump Assignment";
|
||||
break;
|
||||
case AQ_GET_IAQTOUCH_SETPOINTS:
|
||||
return "Get iAqualink Touch Setpoints";
|
||||
return "Get AqualinkTouch Touch Setpoints";
|
||||
break;
|
||||
case AQ_GET_IAQTOUCH_FREEZEPROTECT:
|
||||
return "Get iAqualink Touch Freezeprotect";
|
||||
return "Get AqualinkTouch Touch Freezeprotect";
|
||||
break;
|
||||
case AQ_GET_IAQTOUCH_AUX_LABELS:
|
||||
return "Get iAqualink AUX Labels";
|
||||
return "Get AqualinkTouch AUX Labels";
|
||||
break;
|
||||
case AQ_SET_IAQTOUCH_SWG_PERCENT:
|
||||
return "Set iAqualink SWG Percent";
|
||||
break;
|
||||
case AQ_SET_IAQTOUCH_SWG_BOOST:
|
||||
return "Set iAqualink Boost";
|
||||
break;
|
||||
case AQ_SET_IAQTOUCH_SPA_HEATER_TEMP:
|
||||
return "Set iAqualink Spa Heater";
|
||||
return "Set AqualinkTouch SWG Percent";
|
||||
break;
|
||||
case AQ_SET_IAQTOUCH_POOL_HEATER_TEMP:
|
||||
return "Set iAqualink Pool Heater";
|
||||
return "Set AqualinkTouch Pool Heater";
|
||||
break;
|
||||
case AQ_SET_IAQTOUCH_SET_TIME:
|
||||
return "Set iAqualink Set Time";
|
||||
return "Set AqualinkTouch Set Time";
|
||||
break;
|
||||
case AQ_SET_IAQTOUCH_DEVICE_ON_OFF:
|
||||
return "Set iAqualink Device On/Off";
|
||||
return "Set AqualinkTouch Device On/Off";
|
||||
break;
|
||||
case AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE:
|
||||
return "Set iAqualink Light Color (using panel)";
|
||||
return "Set AqualinkTouch Light Color (using panel)";
|
||||
break;
|
||||
case AQ_SET_IAQTOUCH_SWG_BOOST:
|
||||
return "Set AqualinkTouch Boost";
|
||||
break;
|
||||
case AQ_SET_IAQTOUCH_SPA_HEATER_TEMP:
|
||||
return "Set AqualinkTouch Spa Heater";
|
||||
break;
|
||||
// These to same as above, but on the iAqualink protocol, not AqualinkTouch protocol
|
||||
case AQ_SET_IAQLINK_POOL_HEATER_TEMP:
|
||||
return "Set iAqualink Pool Heater";
|
||||
break;
|
||||
case AQ_SET_IAQLINK_SPA_HEATER_TEMP:
|
||||
return "Set iAqualink Pool Heater";
|
||||
break;
|
||||
#endif
|
||||
#ifdef AQ_PDA
|
||||
|
|
|
@ -35,6 +35,7 @@ typedef enum emulation_type{
|
|||
ONETOUCH,
|
||||
IAQTOUCH,
|
||||
AQUAPDA, // AQUAPALM and PDA are taken as specific type.
|
||||
IAQUALNK, // iAqualink (wifi extra ID)
|
||||
JANDY_DEVICE, // Very rarley used.
|
||||
SIMULATOR
|
||||
} emulation_type;
|
||||
|
@ -93,10 +94,12 @@ typedef enum {
|
|||
AQ_GET_IAQTOUCH_AUX_LABELS,
|
||||
AQ_SET_IAQTOUCH_SWG_PERCENT,
|
||||
AQ_SET_IAQTOUCH_SWG_BOOST,
|
||||
AQ_SET_IAQTOUCH_POOL_HEATER_TEMP,
|
||||
AQ_SET_IAQTOUCH_SPA_HEATER_TEMP,
|
||||
AQ_SET_IAQTOUCH_SET_TIME,
|
||||
AQ_SET_IAQTOUCH_DEVICE_ON_OFF,
|
||||
AQ_SET_IAQTOUCH_POOL_HEATER_TEMP,
|
||||
AQ_SET_IAQTOUCH_SPA_HEATER_TEMP,
|
||||
AQ_SET_IAQLINK_POOL_HEATER_TEMP, // Same as above but using iAqualink not AqualinkTouch
|
||||
AQ_SET_IAQLINK_SPA_HEATER_TEMP, // Same as above but using iAqualink not AqualinkTouch
|
||||
AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE,
|
||||
// ******** RS Serial Adapter Delimiter make sure to change MAX/MIN below
|
||||
AQ_GET_RSSADAPTER_SETPOINTS,
|
||||
|
|
|
@ -56,7 +56,7 @@ int _blocking_fds = -1;
|
|||
|
||||
static struct termios _oldtio;
|
||||
|
||||
static struct timespec last_serial_read_time;
|
||||
static struct timespec _last_serial_read_time;
|
||||
|
||||
void send_packet(int fd, unsigned char *packet, int length);
|
||||
//unsigned char getProtocolType(unsigned char* packet);
|
||||
|
@ -76,6 +76,8 @@ emulation_type getJandyDeviceType(unsigned char ID) {
|
|||
return AQUAPDA;
|
||||
if (ID >= 0x30 && ID <= 0x33)
|
||||
return IAQTOUCH;
|
||||
if (ID >= 0xa0 && ID <= 0xa3)
|
||||
return IAQUALNK;
|
||||
|
||||
/*
|
||||
if (ID >= 0x00 && ID <= 0x03)
|
||||
|
@ -222,7 +224,10 @@ const char* get_jandy_packet_type(unsigned char* packet , int length)
|
|||
return "iAq pMessage";
|
||||
break;
|
||||
case CMD_IAQ_PAGE_BUTTON:
|
||||
return "iAq pButton";
|
||||
if (packet[PKT_DEST] == 0x00) // To master is iAqualink2 send command
|
||||
return "iAqualnk sendCmd";
|
||||
else
|
||||
return "iAq pButton";
|
||||
break;
|
||||
case CMD_IAQ_POLL:
|
||||
return "iAq Poll";
|
||||
|
@ -248,6 +253,15 @@ const char* get_jandy_packet_type(unsigned char* packet , int length)
|
|||
case CMD_IAQ_MSG_LONG:
|
||||
return "iAq Popup message";
|
||||
break;
|
||||
case CMD_IAQ_MAIN_STATUS:
|
||||
return "iAq Main status";
|
||||
break;
|
||||
case CMD_IAQ_1TOUCH_STATUS:
|
||||
return "iAq 1Tch status";
|
||||
break;
|
||||
case CMD_IAQ_AUX_STATUS:
|
||||
return "iAq AUX status";
|
||||
break;
|
||||
case RSSA_DEV_STATUS:
|
||||
// This is a fail reply 0x10|0x02|0x48|0x13|0x02|0x00|0x10|0x00|0x7f|0x10|0x03|
|
||||
// Rather than check all, just check 0x02 and checksum sin't I'm not sure 0x10 means faiure without 0x00 around it.
|
||||
|
@ -286,6 +300,10 @@ const char* get_jandy_packet_type(unsigned char* packet , int length)
|
|||
return "LXi status";
|
||||
break;
|
||||
|
||||
case 0x53:
|
||||
return "iAqalnk Poll";
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf(buf, "Unknown '0x%02hhx'", packet[PKT_CMD]);
|
||||
return buf;
|
||||
|
@ -329,7 +347,7 @@ bool check_jandy_checksum(unsigned char* packet, int length)
|
|||
LOG(RSSD_LOG,LOG_INFO, "Ignoring bad checksum, seems to be bug in Jandy protocol\n");
|
||||
if (getLogLevel(RSSD_LOG) >= LOG_DEBUG) {
|
||||
static char buf[1000];
|
||||
beautifyPacket(buf,packet,length,true);
|
||||
beautifyPacket(buf,1000, packet,length,true);
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Packetin question %s\n",buf);
|
||||
}
|
||||
return true;
|
||||
|
@ -826,13 +844,14 @@ void send_packet(int fd, unsigned char *packet, int length)
|
|||
struct timespec min_frame_wait_time;
|
||||
struct timespec frame_wait_time;
|
||||
struct timespec remainder_time;
|
||||
//struct timespec diff;
|
||||
|
||||
min_frame_wait_time.tv_sec = 0;
|
||||
min_frame_wait_time.tv_nsec = _aqconfig_.frame_delay * 1000000;
|
||||
|
||||
do {
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
timespec_subtract(&elapsed_time, &now, &last_serial_read_time);
|
||||
timespec_subtract(&elapsed_time, &now, &_last_serial_read_time);
|
||||
if (timespec_subtract(&frame_wait_time, &min_frame_wait_time, &elapsed_time)) {
|
||||
break;
|
||||
}
|
||||
|
@ -869,10 +888,10 @@ void send_packet(int fd, unsigned char *packet, int length)
|
|||
*/
|
||||
|
||||
// MAYBE Change this back to debug serial
|
||||
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial write %d bytes\n",length-2);
|
||||
//LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial write %d bytes\n",length-2);
|
||||
//LOG(RSSD_LOG,LOG_DEBUG, "Serial write %d bytes, type 0x%02hhx cmd 0x%02hhx\n",length-2,packet[5],packet[6]);
|
||||
if (_aqconfig_.log_protocol_packets || getLogLevel(RSSD_LOG) >= LOG_DEBUG_SERIAL)
|
||||
logPacketWrite(&packet[1], length-2);
|
||||
logPacketWrite(&packet[1], length-1);
|
||||
/*
|
||||
if (getLogLevel(PDA_LOG) == LOG_DEBUG) {
|
||||
char buff[1024];
|
||||
|
@ -895,7 +914,7 @@ void send_packet(int fd, unsigned char *packet, int length)
|
|||
//if (_aqconfig_.frame_delay > 0) {
|
||||
#ifndef SERIAL_LOGGER
|
||||
if (_aqconfig_.frame_delay > 0) {
|
||||
timespec_subtract(&elapsed_time, &now, &last_serial_read_time);
|
||||
timespec_subtract(&elapsed_time, &now, &_last_serial_read_time);
|
||||
LOG(RSTM_LOG, LOG_DEBUG, "Time from recv to %s send is %.3f sec\n",
|
||||
(_blocking_mode?"blocking":"non-blocking"),
|
||||
roundf3(timespec2float(&elapsed_time)));
|
||||
|
@ -985,6 +1004,8 @@ int get_packet_lograw(int fd, unsigned char* packet)
|
|||
}
|
||||
int _get_packet(int fd, unsigned char* packet, bool rawlog)
|
||||
*/
|
||||
|
||||
|
||||
int get_packet(int fd, unsigned char* packet)
|
||||
{
|
||||
unsigned char byte = 0x00;
|
||||
|
@ -1128,7 +1149,7 @@ int get_packet(int fd, unsigned char* packet)
|
|||
// Break out of the loop if we exceed maximum packet
|
||||
// length.
|
||||
if (index >= AQ_MAXPKTLEN) {
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial packet too large\n");
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial packet too large for buffer, stopped reading\n");
|
||||
logPacketError(packet, index);
|
||||
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
return AQSERR_2LARGE;
|
||||
|
@ -1136,9 +1157,15 @@ int get_packet(int fd, unsigned char* packet)
|
|||
}
|
||||
}
|
||||
|
||||
// Clean out rest of buffer, make sure their is nothing else
|
||||
/* Doesn't work for shit due to probe message speed, need to come back and re-think
|
||||
*/
|
||||
|
||||
// Report any unusual size packets.
|
||||
if (index >= AQ_MAXPKTLEN_WARNING) {
|
||||
// Aqualink2 packets 0x72 and 0x71 can be very large, so supress if it one of those.
|
||||
if (packet[PKT_CMD] != CMD_IAQ_AUX_STATUS && packet[PKT_CMD] != CMD_IAQ_1TOUCH_STATUS) {
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial packet seems too large at length %d\n", index);
|
||||
logPacketError(packet, index);
|
||||
}
|
||||
}
|
||||
|
||||
//LOG(RSSD_LOG,LOG_DEBUG, "Serial checksum, length %d got 0x%02hhx expected 0x%02hhx\n", index, packet[index-3], generate_checksum(packet, index));
|
||||
if (jandyPacketStarted) {
|
||||
|
@ -1156,6 +1183,8 @@ int get_packet(int fd, unsigned char* packet)
|
|||
return AQSERR_CHKSUM;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
if (generate_checksum(packet, index) != packet[index-3]){
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad checksum, ignoring\n");
|
||||
|
@ -1169,28 +1198,35 @@ int get_packet(int fd, unsigned char* packet)
|
|||
return AQSERR_2SMALL;
|
||||
}
|
||||
|
||||
//if (_aqconfig_.frame_delay > 0) {
|
||||
|
||||
if (_aqconfig_.frame_delay > 0 || getLogLevel(RSTM_LOG) >= LOG_DEBUG) {
|
||||
clock_gettime(CLOCK_REALTIME, &packet_end_time);
|
||||
if (getLogLevel(RSTM_LOG) >= LOG_DEBUG) {
|
||||
timespec_subtract(&packet_elapsed, &packet_end_time, &last_serial_read_time);
|
||||
timespec_subtract(&packet_elapsed, &packet_end_time, &_last_serial_read_time);
|
||||
/*
|
||||
LOG(RSTM_LOG, LOG_NOTICE, "Start sec=%ld nsec=%ld\n",_last_serial_read_time.tv_sec,_last_serial_read_time.tv_nsec);
|
||||
LOG(RSTM_LOG, LOG_NOTICE, "End sec=%ld nsec=%ld\n",packet_end_time.tv_sec,packet_end_time.tv_nsec);
|
||||
LOG(RSTM_LOG, LOG_NOTICE, "Elapsed sec=%ld nsec=%ld Time between packets (%.3f sec)\n",packet_elapsed.tv_sec,packet_elapsed.tv_nsec, roundf3(timespec2float(&packet_elapsed)) );
|
||||
*/
|
||||
LOG(RSTM_LOG, LOG_DEBUG, "Time between packets (%.3f sec)\n", roundf3(timespec2float(&packet_elapsed)) );
|
||||
|
||||
}
|
||||
if (_aqconfig_.frame_delay > 0) {
|
||||
memcpy(&last_serial_read_time, &packet_end_time, sizeof(struct timespec));
|
||||
}
|
||||
//if (_aqconfig_.frame_delay > 0) {
|
||||
memcpy(&_last_serial_read_time, &packet_end_time, sizeof(struct timespec));
|
||||
//}
|
||||
}
|
||||
|
||||
//clock_gettime(CLOCK_REALTIME, &last_serial_read_time);
|
||||
//clock_gettime(CLOCK_REALTIME, &_last_serial_read_time);
|
||||
//}
|
||||
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
|
||||
//LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
|
||||
if (_aqconfig_.log_protocol_packets || getLogLevel(RSSD_LOG) >= LOG_DEBUG_SERIAL)
|
||||
logPacketRead(packet, index);
|
||||
// Return the packet length.
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else // PLAYBACKMODE
|
||||
|
||||
// Need to re-write this if we ever use playback mode again. Pull info from aq_serial.old.c
|
||||
|
|
|
@ -46,6 +46,10 @@ const char *getJandyDeviceName(emulation_type etype);
|
|||
#define JANDY_DEC_SWG_MAX 83 // 0x53
|
||||
#define JANDY_DEC_PUMP_MIN 120 // 0x78
|
||||
#define JANDY_DEC_PUMP_MAX 123 // 0x7b
|
||||
// Have also seen epump at 0xe0 with panel rev W that supports more pumps
|
||||
#define JANDY_DEC_PUMP2_MIN 224 // 0xe0
|
||||
#define JANDY_DEC_PUMP2_MAX 228 // 0xe3 // Their are probably more, but this is a guess
|
||||
|
||||
#define JANDY_DEC_JXI_MIN 104 // 0x68
|
||||
#define JANDY_DEC_JXI_MAX 107 // 0x6B
|
||||
#define JANDY_DEC_LX_MIN 56 // 0x38
|
||||
|
@ -53,6 +57,38 @@ const char *getJandyDeviceName(emulation_type etype);
|
|||
#define JANDY_DEC_CHEM_MIN 128 // 0x80
|
||||
#define JANDY_DEC_CHEM_MAX 131 // 0x83
|
||||
|
||||
#define JANDY_DEV_IAQLN_MIN 0xa0 //
|
||||
#define JANDY_DEV_IAQLN_MAX 0xa3 // 0
|
||||
|
||||
#define JANDY_DEV_AQLNK_MIN 0x30 //
|
||||
#define JANDY_DEV_AQLNK_MAX 0x33 // 0
|
||||
|
||||
/*
|
||||
//===== Device ID's =====//
|
||||
//=========================================================================//
|
||||
DEV_MASTER_MASK = 0x00; // MASTER(S???0 00-03 0b0 0000 0XX //
|
||||
DEV_CTL_MASK = 0x08; // HOME CONTROLLER (RS-8?) 08-0b 0b0 0001 0XX //
|
||||
// 0x10; // XXXXX DEVICE 10-13 0b0 0010 0XX //
|
||||
// 0x18; // XXXXX DEVICE 18-1b 0b0 0011 0XX //
|
||||
DEV_SPA_MASK = 0x20; // SPA DEVICE 20-23 0b0 0100 0XX //
|
||||
DEV_RPC_MASK = 0x28; // REMOTE POWER CENTER DEVICE 28-2b 0b0 0101 0XX //
|
||||
DEV_AQUALINK_MASK = 0x30; // AQUALINK DEVICE 30-33 0b0 0110 0XX //
|
||||
DEV_LX_HTR_MASK = 0x38; // LX HEATER 38-3b 0b0 0111 0XX //
|
||||
DEV_ONETOUCH_MASK = 0x40; // XXXXX ONE TOUCH DEVICE 40-43 0b0 1000 0XX //
|
||||
// 0x48; // XXXXX DEVICE 48-4b 0b0 1001 0XX //
|
||||
DEV_AQUARITE_MASK = 0x50; // AQUARITE DEVICE 50-53 0b0 1010 0XX //
|
||||
DEV_PCDOCK_MASK = 0x58; // PCDOCK DEVICE 58-5b 0b0 1011 0XX //
|
||||
DEV_PDA_JDA_MASK = 0x60; // AQUAPALM DEVICE 60-63 0b0 1100 0XX //
|
||||
DEV_LXI_LRZE_MASK = 0x68; // LXi/LZRE DEVICE 68-6b 0b0 1101 0XX //
|
||||
DEV_HEATPUMP_MASK = 0x70; // HEAT PUMP DEVICE 70-73 0b0 1110 0XX //
|
||||
JANDY_EPUMP_MASK = 0x78; // EPUMP DEVICE 78-7b 0b0 1111 0XX //
|
||||
DEV_CHEMLINK_MASK = 0x80; // CHEMLINK DEVICE 80-83 0b1 0000 0XX //
|
||||
Heater 0x88; // XXXXX DEVICE 88-8b 0b1 0001 0XX //
|
||||
// 0x90; // XXXXX DEVICE 90-93 0b1 0010 0XX //
|
||||
// 0x98; // XXXXX DEVICE 98-9b 0b1 0011 0XX //
|
||||
DEV_AQUALINK_2_MASK = 0xA0; // AQUALINK 2 A0-A3 0b1 0100 0XX //
|
||||
DEV_UNKNOWN_MASK = 0xF8; // Unknown mask, used to reset values
|
||||
*/
|
||||
|
||||
// PACKET DEFINES Jandy
|
||||
#define NUL 0x00
|
||||
|
@ -94,12 +130,20 @@ const char *getJandyDeviceName(emulation_type etype);
|
|||
|
||||
#define AQ_MINPKTLEN 5
|
||||
//#define AQ_MAXPKTLEN 64
|
||||
#define AQ_MAXPKTLEN 128 // Max 79 bytes so far, so 128 is a guess at the moment, just seen large packets from iAqualink
|
||||
//#define AQ_MAXPKTLEN 128 // Max 79 bytes so far, so 128 is a guess at the moment, just seen large packets from iAqualink
|
||||
//#define AQ_MAXPKTLEN 256 // Still getting this at 128, so temp increase to 256 and print message over 128 in aq_serial.c
|
||||
#define AQ_MAXPKTLEN 512 // Still getting this at 128, so temp increase to 256 and print message over 128 in aq_serial.c
|
||||
#define AQ_MAXPKTLEN_SEND 32 // Out biggest send buffer
|
||||
#define AQ_PSTLEN 5
|
||||
#define AQ_MSGLEN 16
|
||||
#define AQ_MSGLONGLEN 128
|
||||
#define AQ_TADLEN 13
|
||||
|
||||
// For printing warning & debug messages for packets.
|
||||
// The below are related to AQ_MAXPKTLEN
|
||||
#define AQ_MAXPKTLEN_WARNING 128 // Print warning message if over this
|
||||
//#define AQ_PACKET_PRINT_BUFFER 1400 // Must be at least AQ_MAXPKTLEN * 5 + 100
|
||||
|
||||
/* COMMANDS */
|
||||
#define CMD_PROBE 0x00
|
||||
#define CMD_ACK 0x01
|
||||
|
@ -171,7 +215,8 @@ const char *getJandyDeviceName(emulation_type etype);
|
|||
#define KEY_AUX7 0x15
|
||||
#define KEY_POOL_HTR 0x12
|
||||
#define KEY_SPA_HTR 0x17
|
||||
#define KEY_SOLAR_HTR 0x1c
|
||||
//#define KEY_SOLAR_HTR 0x1c
|
||||
#define KEY_EXT_AUX 0x1c
|
||||
#define KEY_MENU 0x09
|
||||
#define KEY_CANCEL 0x0e
|
||||
#define KEY_LEFT 0x13
|
||||
|
@ -199,7 +244,7 @@ const char *getJandyDeviceName(emulation_type etype);
|
|||
#endif
|
||||
|
||||
#define BTN_PUMP "Filter_Pump"
|
||||
#define BTN_SPA "Spa_Mode"
|
||||
#define BTN_SPA "Spa"
|
||||
#define BTN_AUX1 "Aux_1"
|
||||
#define BTN_AUX2 "Aux_2"
|
||||
#define BTN_AUX3 "Aux_3"
|
||||
|
@ -209,11 +254,14 @@ const char *getJandyDeviceName(emulation_type etype);
|
|||
#define BTN_AUX7 "Aux_7"
|
||||
#define BTN_POOL_HTR "Pool_Heater"
|
||||
#define BTN_SPA_HTR "Spa_Heater"
|
||||
#define BTN_SOLAR_HTR "Solar_Heater"
|
||||
//#define BTN_SOLAR_HTR "Solar_Heater"
|
||||
#define BTN_EXT_AUX "Extra_Aux"
|
||||
|
||||
#define BTN_TEMP1_HTR "Temp1_Heater"
|
||||
#define BTN_TEMP2_HTR "Temp2_Heater"
|
||||
|
||||
#define BTN_VAUX "Aux_V" // A number will be appended
|
||||
|
||||
#ifdef AQ_RS16
|
||||
#define BTN_AUXB1 "Aux_B1"
|
||||
#define BTN_AUXB2 "Aux_B2"
|
||||
|
@ -236,7 +284,8 @@ const char *getJandyDeviceName(emulation_type etype);
|
|||
#define BTN_PDA_AUX7 "AUX7"
|
||||
#define BTN_PDA_POOL_HTR "POOL HEAT"
|
||||
#define BTN_PDA_SPA_HTR "SPA HEAT"
|
||||
#define BTN_PDA_SOLAR_HTR "EXTRA AUX"
|
||||
//#define BTN_PDA_SOLAR_HTR "EXTRA AUX"
|
||||
#define BTN_PDA_EXT_AUX "EXTRA AUX"
|
||||
|
||||
#define BUTTON_LABEL_LENGTH 20
|
||||
|
||||
|
@ -367,6 +416,11 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
#define CMD_IAQ_TITLE_MESSAGE 0x2d // This is what the product name is set to (Jandy RS) usually
|
||||
//#define CMD_IAQ_VSP_ERROR 0x2c // Error when setting speed too high
|
||||
#define CMD_IAQ_MSG_LONG 0x2c // This this is display popup message. Next 2 bytes 0x00|0x01 = wait and then 0x00|0x00 clear
|
||||
|
||||
// If
|
||||
#define CMD_IAQ_MAIN_STATUS 0x70
|
||||
#define CMD_IAQ_1TOUCH_STATUS 0x71
|
||||
#define CMD_IAQ_AUX_STATUS 0x72 // Get this on AqualinkTouch protocol when iAqualink protocol sends 0x18 (get aux status I assume)
|
||||
/*
|
||||
#define CMD_IAQ_MSG_3 0x2d // Equiptment status message??
|
||||
#define CMD_IAQ_0x31 0x31 // Some pump speed info
|
||||
|
@ -439,6 +493,10 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
#define IAQ_PAGE_FREEZE_PROTECT 0x11
|
||||
#define IAQ_PAGE_LABEL_AUX 0x32
|
||||
#define IAQ_PAGE_HELP 0x0c
|
||||
#define IAQ_PAGE_SERVICEMODE 0x5e // Also Timeout
|
||||
|
||||
#define IAQ_PAGE_DEVICES_REV_Yg 0x0a // Panel rev Yg (and maybe others use this)
|
||||
|
||||
//#define IAQ_PAGE_START_BOOST 0x3f
|
||||
//#define IAQ_PAGE_DEGREES 0xFF // Added this as never want to actually select the page, just go to it.
|
||||
|
||||
|
@ -546,4 +604,4 @@ bool onetouch_mode();
|
|||
//void send_test_cmd(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3);
|
||||
//void send_command(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3);
|
||||
//void send_messaged(int fd, unsigned char destination, char *message);
|
||||
#endif // AQ_SERIAL_H_
|
||||
#endif // AQ_SERIAL_H_
|
||||
|
|
|
@ -88,6 +88,7 @@ void start_timer(struct aqualinkdata *aq_data, /*aqkey *button,*/ int deviceInde
|
|||
tmthread->thread_id = 0;
|
||||
tmthread->duration_min = duration;
|
||||
tmthread->next = NULL;
|
||||
tmthread->started_at = time(0); // This will get reset once we actually start. But need it here incase someone calls get_timer_left() before we start
|
||||
|
||||
if( pthread_create( &tmthread->thread_id , NULL , timer_worker, (void*)tmthread) < 0) {
|
||||
LOG(TIMR_LOG, LOG_ERR, "could not create timer thread for button '%s'\n",button->name);
|
||||
|
@ -113,19 +114,22 @@ void start_timer(struct aqualinkdata *aq_data, /*aqkey *button,*/ int deviceInde
|
|||
}
|
||||
}
|
||||
|
||||
#define WAIT_TIME_BEFORE_ON_CHECK 1000 // 1 second
|
||||
#define WAIT_TIME_BEFORE_ON_CHECK 1000
|
||||
//#define WAIT_TIME_BEFORE_ON_CHECK 1000000 // 1 second
|
||||
|
||||
void *timer_worker( void *ptr )
|
||||
{
|
||||
struct timerthread *tmthread;
|
||||
tmthread = (struct timerthread *) ptr;
|
||||
int retval = 0;
|
||||
int cnt=0;
|
||||
|
||||
LOG(TIMR_LOG, LOG_NOTICE, "Start timer for '%s'\n",tmthread->button->name);
|
||||
|
||||
// Add mask so we know timer is active
|
||||
tmthread->button->special_mask |= TIMER_ACTIVE;
|
||||
|
||||
/*
|
||||
#ifndef PRESTATE_ONOFF
|
||||
delay(WAIT_TIME_BEFORE_ON_CHECK);
|
||||
LOG(TIMR_LOG, LOG_DEBUG, "wait finished for button state '%s'\n",tmthread->button->name);
|
||||
|
@ -140,6 +144,19 @@ void *timer_worker( void *ptr )
|
|||
panel_device_request(tmthread->aq_data, ON_OFF, tmthread->deviceIndex, false, NET_TIMER);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
while (tmthread->button->led->state == OFF) {
|
||||
LOG(TIMR_LOG, LOG_DEBUG, "waiting for button state '%s' to change\n",tmthread->button->name);
|
||||
delay(WAIT_TIME_BEFORE_ON_CHECK);
|
||||
if (cnt++ == 5 && !isPDA_PANEL) {
|
||||
LOG(TIMR_LOG, LOG_NOTICE, "turning on '%s'\n",tmthread->button->name);
|
||||
panel_device_request(tmthread->aq_data, ON_OFF, tmthread->deviceIndex, true, NET_TIMER);
|
||||
} else if (cnt == 10) {
|
||||
LOG(TIMR_LOG, LOG_ERR, "button state never turned on'%s'\n",tmthread->button->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&tmthread->thread_mutex);
|
||||
|
||||
|
@ -162,12 +179,24 @@ void *timer_worker( void *ptr )
|
|||
|
||||
LOG(TIMR_LOG, LOG_NOTICE, "End timer for '%s'\n",tmthread->button->name);
|
||||
|
||||
if (tmthread->button->led->state != OFF) {
|
||||
// We need to detect if we ended on time or were killed.
|
||||
// If killed the device is probable off (or being set to off), so we should probably poll a few times before turning off.
|
||||
// Either that of change ap_panel to not turn off device if timer is set.
|
||||
|
||||
//LOG(TIMR_LOG, LOG_NOTICE, "End timer duration '%d'\n",tmthread->duration_min);
|
||||
|
||||
// if duration_min is 0 we were killed, if not we got here on timeout, so turn off device.
|
||||
|
||||
if (tmthread->duration_min != 0 && tmthread->button->led->state != OFF) {
|
||||
LOG(TIMR_LOG, LOG_INFO, "Timer waking turning '%s' off\n",tmthread->button->name);
|
||||
panel_device_request(tmthread->aq_data, ON_OFF, tmthread->deviceIndex, false, NET_TIMER);
|
||||
} else {
|
||||
} else if (tmthread->button->led->state == OFF) {
|
||||
LOG(TIMR_LOG, LOG_INFO, "Timer waking '%s' is already off\n",tmthread->button->name);
|
||||
}
|
||||
|
||||
if (tmthread->button->led->state != OFF) {
|
||||
// Need to wait
|
||||
}
|
||||
|
||||
// remove mask so we know timer is dead
|
||||
tmthread->button->special_mask &= ~ TIMER_ACTIVE;
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#endif
|
||||
|
||||
|
||||
#define CLIGHT_PANEL_FIX // Overcome bug in some jandy panels where color light status of on is not in LED status
|
||||
|
||||
#define TIME_CHECK_INTERVAL 3600
|
||||
//#define TIME_CHECK_INTERVAL 100 // DEBUG ONLY
|
||||
#define ACCEPTABLE_TIME_DIFF 120
|
||||
|
@ -64,6 +66,14 @@ bool checkAqualinkTime(); // Only need to externalise this for PDA
|
|||
#define MAX_PUMPS 4
|
||||
#define MAX_LIGHTS 4
|
||||
|
||||
bool isVirtualButtonEnabled();
|
||||
|
||||
#define PUMP_RPM_MAX 3450
|
||||
#define PUMP_RPM_MIN 600
|
||||
#define PUMP_GPM_MAX 130
|
||||
#define PUMP_GPM_MIN 15
|
||||
|
||||
|
||||
enum {
|
||||
FAHRENHEIT,
|
||||
CELSIUS,
|
||||
|
@ -81,16 +91,18 @@ typedef struct aqualinkkey
|
|||
// char *pda_label;
|
||||
//#endif
|
||||
unsigned char code;
|
||||
unsigned char rssd_code;
|
||||
int dz_idx;
|
||||
uint8_t special_mask;
|
||||
void *special_mask_ptr;
|
||||
} aqkey;
|
||||
|
||||
// special_mask for above aqualinkkey structure.
|
||||
#define VS_PUMP (1 << 0)
|
||||
#define PROGRAM_LIGHT (1 << 1)
|
||||
#define TIMER_ACTIVE (1 << 2)
|
||||
//#define DIMMER_LIGHT (1 << 3) // NOT USED YET
|
||||
|
||||
//#define DIMMER_LIGHT (1 << 3) // NOT USED (Use PROGRAM_LIGHT or type LC_DIMMER)
|
||||
#define VIRTUAL_BUTTON (1 << 4)
|
||||
//typedef struct ProgramThread ProgramThread; // Definition is later
|
||||
|
||||
struct programmingthread {
|
||||
|
@ -117,6 +129,7 @@ typedef enum action_type {
|
|||
ON_OFF,
|
||||
TIMER,
|
||||
LIGHT_MODE,
|
||||
LIGHT_BRIGHTNESS,
|
||||
DATE_TIME
|
||||
} action_type;
|
||||
|
||||
|
@ -167,14 +180,19 @@ typedef enum panel_vsp_status
|
|||
PS_ERROR = -4
|
||||
} panel_vsp_status;
|
||||
|
||||
#define PUMP_NAME_LENGTH 30
|
||||
|
||||
typedef struct pumpd
|
||||
{
|
||||
int rpm;
|
||||
int gpm;
|
||||
int watts;
|
||||
int maxSpeed; // Max rpm or gpm depending on pump
|
||||
int minSpeed;
|
||||
unsigned char pumpID;
|
||||
int pumpIndex;
|
||||
char pumpName[PUMP_NAME_LENGTH];
|
||||
//char *pumpName;
|
||||
pump_type pumpType;
|
||||
//int buttonID;
|
||||
protocolType prclType;
|
||||
|
@ -196,7 +214,12 @@ typedef enum clight_type {
|
|||
LC_SAL,
|
||||
LC_CLOGIG,
|
||||
LC_INTELLIB,
|
||||
LC_DIMMER,
|
||||
LC_HAYWCL,
|
||||
LC_SPARE_1,
|
||||
LC_SPARE_2,
|
||||
LC_SPARE_3,
|
||||
LC_DIMMER, // use 0, 25, 50, 100
|
||||
LC_DIMMER2, // use range 0 to 100
|
||||
NUMBER_LIGHT_COLOR_TYPES // This is used to size and count so add more prior to this
|
||||
} clight_type;
|
||||
|
||||
|
@ -205,13 +228,16 @@ typedef enum {
|
|||
NET_API,
|
||||
NET_WS,
|
||||
NET_DZMQTT,
|
||||
NET_TIMER // Not used yet, need to change aq_timer.c
|
||||
NET_TIMER, // Not used yet, need to change aq_timer.c
|
||||
UNACTION_TIMER
|
||||
} request_source;
|
||||
|
||||
typedef struct clightd
|
||||
{
|
||||
clight_type lightType;
|
||||
aqkey *button;
|
||||
int currentValue;
|
||||
aqledstate RSSDstate; // state from rs serial adapter
|
||||
} clight_detail;
|
||||
|
||||
|
||||
|
@ -230,6 +256,7 @@ struct aqualinkdata
|
|||
aqled aqualinkleds[TOTAL_LEDS];
|
||||
aqkey aqbuttons[TOTAL_BUTTONS];
|
||||
unsigned short total_buttons;
|
||||
unsigned short virtual_button_start;
|
||||
int air_temp;
|
||||
int pool_temp;
|
||||
int spa_temp;
|
||||
|
@ -282,6 +309,9 @@ struct aqualinkdata
|
|||
|
||||
#ifdef AQ_MANAGER
|
||||
volatile bool run_slogger;
|
||||
int slogger_packets;
|
||||
bool slogger_debug;
|
||||
char slogger_ids[20];
|
||||
#endif
|
||||
|
||||
#ifdef AQ_RS16
|
||||
|
@ -298,6 +328,9 @@ struct aqualinkdata
|
|||
struct timespec last_active_time;
|
||||
struct timespec start_active_time;
|
||||
#endif
|
||||
|
||||
// Overcome color light bug, by reconnecting allbutton panel.
|
||||
//bool reconnectAllButton;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "onetouch_aq_programmer.h"
|
||||
#include "iaqtouch.h"
|
||||
#include "iaqtouch_aq_programmer.h"
|
||||
#include "iaqualink.h"
|
||||
#include "version.h"
|
||||
#include "rs_msg_utils.h"
|
||||
#include "serialadapter.h"
|
||||
|
@ -78,6 +79,7 @@ char *_cfgFile;
|
|||
int _cmdln_loglevel = -1;
|
||||
bool _cmdln_debugRS485 = false;
|
||||
bool _cmdln_lograwRS485 = false;
|
||||
bool _cmdln_nostartupcheck = false;
|
||||
|
||||
#ifdef AQ_TM_DEBUG
|
||||
//struct timespec _rs_packet_readitme;
|
||||
|
@ -127,6 +129,10 @@ void intHandler(int sig_num)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool isVirtualButtonEnabled() {
|
||||
return _aqualink_data.virtual_button_start>0?true:false;
|
||||
}
|
||||
|
||||
// Should move to panel.
|
||||
bool checkAqualinkTime()
|
||||
{
|
||||
|
@ -349,6 +355,9 @@ void action_delayed_request()
|
|||
LOG(AQUA_LOG,LOG_NOTICE, "Changing spa heater setpoint by %d\n", _aqualink_data.unactioned.value);
|
||||
aq_programmer(AQ_ADD_RSSADAPTER_SPA_HEATER_TEMP, sval, &_aqualink_data);
|
||||
}
|
||||
else if (_aqualink_data.unactioned.type == LIGHT_MODE) {
|
||||
panel_device_request(&_aqualink_data, LIGHT_MODE, _aqualink_data.unactioned.id, _aqualink_data.unactioned.value, UNACTION_TIMER);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_ERR, "Unknown request of type %d\n", _aqualink_data.unactioned.type);
|
||||
|
@ -455,6 +464,10 @@ int main(int argc, char *argv[])
|
|||
else if (strcmp(argv[i], "-rsrd") == 0)
|
||||
{
|
||||
_cmdln_lograwRS485 = true;
|
||||
}
|
||||
else if (strcmp(argv[i], "-nc") == 0)
|
||||
{
|
||||
_cmdln_nostartupcheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,7 +491,7 @@ int startup(char *self, char *cfgFile)
|
|||
|
||||
// Sanity check on Device ID's against panel type
|
||||
if (isRS_PANEL) {
|
||||
if (_aqconfig_.device_id >= 0x08 && _aqconfig_.device_id <= 0x0B) {
|
||||
if ( (_aqconfig_.device_id >= 0x08 && _aqconfig_.device_id <= 0x0B) || _aqconfig_.device_id == 0x00) {
|
||||
// We are good
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Device ID 0x%02hhx does not match RS panel, please check config!\n", _aqconfig_.device_id);
|
||||
|
@ -486,6 +499,10 @@ int startup(char *self, char *cfgFile)
|
|||
}
|
||||
} else if (isPDA_PANEL) {
|
||||
if ( (_aqconfig_.device_id >= 0x60 && _aqconfig_.device_id <= 0x63) || _aqconfig_.device_id == 0x33 ) {
|
||||
if ( _aqconfig_.device_id == 0x33 ) {
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Enabeling iAqualink protocol.\n");
|
||||
_aqconfig_.enable_iaqualink = true;
|
||||
}
|
||||
// We are good
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Device ID 0x%02hhx does not match PDA panel, please check config!\n", _aqconfig_.device_id);
|
||||
|
@ -527,7 +544,6 @@ int startup(char *self, char *cfgFile)
|
|||
_aqualink_data.total_buttons = 12;
|
||||
*/
|
||||
|
||||
|
||||
if (_cmdln_loglevel != -1)
|
||||
_aqconfig_.log_level = _cmdln_loglevel;
|
||||
|
||||
|
@ -563,6 +579,9 @@ int startup(char *self, char *cfgFile)
|
|||
LOG(AQUA_LOG,LOG_NOTICE, "Config rssa_device_id = 0x%02hhx\n", _aqconfig_.rssa_device_id);
|
||||
#if defined AQ_ONETOUCH || defined AQ_IAQTOUCH
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config extra_device_id = 0x%02hhx\n", _aqconfig_.extended_device_id);
|
||||
if (_aqconfig_.enable_iaqualink) {
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config enable_iaqualink = %s\n", bool2text(_aqconfig_.enable_iaqualink));
|
||||
}
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config extra_device_prog = %s\n", bool2text(_aqconfig_.extended_device_id_programming));
|
||||
#endif
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config serial_port = %s\n", _aqconfig_.serial_port);
|
||||
|
@ -621,8 +640,7 @@ int startup(char *self, char *cfgFile)
|
|||
LOG(AQUA_LOG,LOG_NOTICE, "Config light_pgm_mode = %.2f\n", _aqconfig_.light_programming_mode);
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Debug RS485 protocol = %s\n", bool2text(_aqconfig_.log_protocol_packets));
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Debug RS485 protocol raw = %s\n", bool2text(_aqconfig_.log_raw_bytes));
|
||||
if ( _aqconfig_.RSSD_LOG_filter != NUL)
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Log RS485 packets from = 0x%02hhx\n", _aqconfig_.RSSD_LOG_filter);
|
||||
|
||||
//LOG(AQUA_LOG,LOG_NOTICE, "Use PDA 4 auxiliary info = %s\n", bool2text(_aqconfig_.use_PDA_auxiliary));
|
||||
//LOG(AQUA_LOG,LOG_NOTICE, "Read Pentair Packets = %s\n", bool2text(_aqconfig_.read_pentair_packets));
|
||||
// logMessage (LOG_NOTICE, "Config serial_port = %s\n", config_parameters->serial_port);
|
||||
|
@ -635,10 +653,10 @@ int startup(char *self, char *cfgFile)
|
|||
LOG(AQUA_LOG,LOG_NOTICE, "Read JXi heater direct = %s\n", bool2text(READ_RSDEV_JXI));
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Read LX heater direct = %s\n", bool2text(READ_RSDEV_LX));
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Read Chem Feeder direct = %s\n", bool2text(READ_RSDEV_CHEM));
|
||||
|
||||
/*
|
||||
if (READ_RSDEV_SWG && _aqconfig_.swg_zero_ignore != DEFAULT_SWG_ZERO_IGNORE_COUNT)
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Ignore SWG 0 msg count = %d\n", _aqconfig_.swg_zero_ignore);
|
||||
|
||||
*/
|
||||
if (_aqconfig_.ftdi_low_latency == true)
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Serial FTDI low latency = %s\n", bool2text(_aqconfig_.ftdi_low_latency));
|
||||
|
||||
|
@ -668,7 +686,10 @@ int startup(char *self, char *cfgFile)
|
|||
ext[0] = '\0';
|
||||
for (j = 0; j < _aqualink_data.num_pumps; j++) {
|
||||
if (_aqualink_data.pumps[j].button == &_aqualink_data.aqbuttons[i]) {
|
||||
sprintf(ext, "VSP ID 0x%02hhx | PumpID %-1d |",_aqualink_data.pumps[j].pumpID, _aqualink_data.pumps[j].pumpIndex);
|
||||
sprintf(ext, "VSP ID 0x%02hhx | PumpID %-1d | %s",
|
||||
_aqualink_data.pumps[j].pumpID,
|
||||
_aqualink_data.pumps[j].pumpIndex,
|
||||
_aqualink_data.pumps[j].pumpName[0]=='\0'?"":_aqualink_data.pumps[j].pumpName);
|
||||
}
|
||||
}
|
||||
for (j = 0; j < _aqualink_data.num_lights; j++) {
|
||||
|
@ -691,7 +712,23 @@ int startup(char *self, char *cfgFile)
|
|||
LOG(AQUA_LOG,LOG_NOTICE, "Config BTN %-13s = label %-15s | %s\n",
|
||||
_aqualink_data.aqbuttons[i].name, _aqualink_data.aqbuttons[i].label, ext);
|
||||
}
|
||||
|
||||
if ( ((_aqualink_data.aqbuttons[i].special_mask & VIRTUAL_BUTTON) == VIRTUAL_BUTTON) &&
|
||||
((_aqualink_data.aqbuttons[i].special_mask & VS_PUMP ) != VS_PUMP) &&
|
||||
(_aqconfig_.extended_device_id < 0x30 || _aqconfig_.extended_device_id > 0x33 ) ){
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, extended_device_id must be on of the folowing (0x30,0x31,0x32,0x33) to use virtual button : '%s'",_aqualink_data.aqbuttons[i].label);
|
||||
}
|
||||
}
|
||||
/*
|
||||
for (i=0; i < _aqualink_data.total_buttons; i++)
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Button index=%d, label=%s, code=0x%02hhx, rssd code=0x%02hhx\n",
|
||||
i,
|
||||
_aqualink_data.aqbuttons[i].label,
|
||||
_aqualink_data.aqbuttons[i].code,
|
||||
_aqualink_data.aqbuttons[i].rssd_code);
|
||||
}
|
||||
*/
|
||||
|
||||
if (_aqconfig_.deamonize == true)
|
||||
{
|
||||
|
@ -718,6 +755,9 @@ int startup(char *self, char *cfgFile)
|
|||
/* Point of this is to sent ack as quickly as possible, all checks should be done prior to calling this.*/
|
||||
void caculate_ack_packet(int rs_fd, unsigned char *packet_buffer, emulation_type source)
|
||||
{
|
||||
unsigned char *cmd;
|
||||
int size;
|
||||
|
||||
switch (source) {
|
||||
case ALLBUTTON:
|
||||
send_extended_ack(rs_fd, (packet_buffer[PKT_CMD]==CMD_MSG_LONG?ACK_SCREEN_BUSY_SCROLL:ACK_NORMAL), pop_allb_cmd(&_aqualink_data));
|
||||
|
@ -743,13 +783,22 @@ void caculate_ack_packet(int rs_fd, unsigned char *packet_buffer, emulation_type
|
|||
if (packet_buffer[PKT_CMD] != CMD_IAQ_CTRL_READY)
|
||||
send_extended_ack(rs_fd, ACK_IAQ_TOUCH, pop_iaqt_cmd(packet_buffer[PKT_CMD]));
|
||||
else {
|
||||
unsigned char *cmd;
|
||||
int size = ref_iaqt_control_cmd(&cmd);
|
||||
size = ref_iaqt_control_cmd(&cmd);
|
||||
send_jandy_command(rs_fd, cmd, size);
|
||||
rem_iaqt_control_cmd(cmd);
|
||||
}
|
||||
//DEBUG_TIMER_STOP(_rs_packet_timer,AQUA_LOG,"AquaTouch Emulation type Processed packet in");
|
||||
break;
|
||||
case IAQUALNK:
|
||||
//send_iaqualink_ack(rs_fd, packet_buffer);
|
||||
size = get_iaqualink_cmd(packet_buffer[PKT_CMD], &cmd);
|
||||
if (size == 2){
|
||||
send_extended_ack(rs_fd, cmd[0], cmd[1]);
|
||||
} else {
|
||||
send_jandy_command(rs_fd, cmd, size);
|
||||
}
|
||||
remove_iaqualink_cmd();
|
||||
break;
|
||||
#endif
|
||||
#ifdef AQ_PDA
|
||||
case AQUAPDA:
|
||||
|
@ -863,7 +912,8 @@ void main_loop()
|
|||
pthread_mutex_init(&_aqualink_data.active_thread.thread_mutex, NULL);
|
||||
pthread_cond_init(&_aqualink_data.active_thread.thread_cond, NULL);
|
||||
|
||||
for (i=0; i < MAX_PUMPS; i++) {
|
||||
//for (i=0; i < MAX_PUMPS; i++) {
|
||||
for (i=0; i < _aqualink_data.num_pumps; i++) {
|
||||
_aqualink_data.pumps[i].rpm = TEMP_UNKNOWN;
|
||||
_aqualink_data.pumps[i].gpm = TEMP_UNKNOWN;
|
||||
_aqualink_data.pumps[i].watts = TEMP_UNKNOWN;
|
||||
|
@ -872,6 +922,20 @@ void main_loop()
|
|||
_aqualink_data.pumps[i].status = TEMP_UNKNOWN;
|
||||
_aqualink_data.pumps[i].pStatus = PS_OFF;
|
||||
_aqualink_data.pumps[i].pressureCurve = TEMP_UNKNOWN;
|
||||
|
||||
if (_aqualink_data.pumps[i].maxSpeed <= 0) {
|
||||
_aqualink_data.pumps[i].maxSpeed = (_aqualink_data.pumps[i].pumpType==VFPUMP?PUMP_GPM_MAX:PUMP_RPM_MAX);
|
||||
}
|
||||
if (_aqualink_data.pumps[i].minSpeed <= 0) {
|
||||
_aqualink_data.pumps[i].minSpeed = (_aqualink_data.pumps[i].pumpType==VFPUMP?PUMP_GPM_MIN:PUMP_RPM_MIN);
|
||||
}
|
||||
|
||||
//printf("arrayindex=%d, pump=%d, min=%d, max=%d\n",i,_aqualink_data.pumps[i].pumpIndex, _aqualink_data.pumps[i].minSpeed ,_aqualink_data.pumps[i].maxSpeed);
|
||||
}
|
||||
|
||||
for (i=0; i < MAX_LIGHTS; i++) {
|
||||
_aqualink_data.lights[i].currentValue = TEMP_UNKNOWN;
|
||||
_aqualink_data.lights[i].RSSDstate = OFF;
|
||||
}
|
||||
|
||||
if (_aqconfig_.force_swg == true) {
|
||||
|
@ -971,22 +1035,26 @@ void main_loop()
|
|||
got_probe_rssa = true;
|
||||
|
||||
if (_aqconfig_.device_id == 0x00) {
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Searching for valid ID, please configure one for faster startup\n");
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Searching for valid ID, please configure `device_id` for faster startup\n");
|
||||
}
|
||||
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Waiting for Control Panel probe\n");
|
||||
i=0;
|
||||
|
||||
// Loop until we get the probe messages, that means we didn;t start too soon after last shutdown.
|
||||
while ( (got_probe == false || got_probe_rssa == false || got_probe_extended == false ) && _keepRunning == true)
|
||||
while ( (got_probe == false || got_probe_rssa == false || got_probe_extended == false ) && _keepRunning == true && _cmdln_nostartupcheck == false)
|
||||
{
|
||||
if (blank_read == blank_read_reconnect) {
|
||||
if (blank_read == blank_read_reconnect / 2) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Nothing read on '%s', are you sure that's right?\n",_aqconfig_.serial_port);
|
||||
#ifdef AQ_CONTAINER
|
||||
// Reset blank reads here, we want to ignore TTY errors in container to keep it running
|
||||
blank_read = 1;
|
||||
#endif
|
||||
} else if (blank_read == blank_read_reconnect*2) {
|
||||
if (_aqconfig_.device_id == 0x00) {
|
||||
blank_read = 1; // if device id=0x00 it's code for don't exit
|
||||
}
|
||||
_aqualink_data.updated = true; // Make sure to show erros if ui is up
|
||||
} else if (blank_read == blank_read_reconnect*2 ) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "I'm done, exiting, please check '%s'\n",_aqconfig_.serial_port);
|
||||
stopPacketLogger();
|
||||
close_serial_port(rs_fd);
|
||||
|
@ -1137,8 +1205,15 @@ void main_loop()
|
|||
if (_aqualink_data.run_slogger) {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Starting serial_logger, this will take some time!\n");
|
||||
broadcast_aqualinkstate_error(CONNECTION_RUNNING_SLOG);
|
||||
serial_logger(rs_fd, _aqconfig_.serial_port, getSystemLogLevel());
|
||||
|
||||
if (_aqualink_data.slogger_debug)
|
||||
addDebugLogMask(SLOG_LOG);
|
||||
|
||||
serial_logger(rs_fd, _aqconfig_.serial_port, _aqualink_data.slogger_debug?LOG_DEBUG:getSystemLogLevel(), _aqualink_data.slogger_packets, _aqualink_data.slogger_ids);
|
||||
_aqualink_data.run_slogger = false;
|
||||
|
||||
if (_aqualink_data.slogger_debug)
|
||||
removeDebugLogMask(SLOG_LOG);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1209,10 +1284,14 @@ void main_loop()
|
|||
}
|
||||
|
||||
// Process and packets of devices we are acting as
|
||||
if (packet_length > 0 && getProtocolType(packet_buffer) == JANDY &&
|
||||
if (packet_length > 0 && getProtocolType(packet_buffer) == JANDY && packet_buffer[PKT_DEST] != 0x00 &&
|
||||
(packet_buffer[PKT_DEST] == _aqconfig_.device_id ||
|
||||
packet_buffer[PKT_DEST] == _aqconfig_.rssa_device_id ||
|
||||
packet_buffer[PKT_DEST] == _aqconfig_.extended_device_id ))
|
||||
#if defined AQ_ONETOUCH || defined AQ_IAQTOUCH
|
||||
packet_buffer[PKT_DEST] == _aqconfig_.extended_device_id ||
|
||||
packet_buffer[PKT_DEST] == _aqconfig_.extended_device_id2
|
||||
#endif
|
||||
))
|
||||
{
|
||||
switch(getJandyDeviceType(packet_buffer[PKT_DEST])){
|
||||
case ALLBUTTON:
|
||||
|
@ -1235,6 +1314,10 @@ void main_loop()
|
|||
_aqualink_data.updated = process_pda_packet(packet_buffer, packet_length);
|
||||
caculate_ack_packet(rs_fd, packet_buffer, AQUAPDA);
|
||||
break;
|
||||
case IAQUALNK:
|
||||
_aqualink_data.updated = process_iaqualink_packet(packet_buffer, packet_length, &_aqualink_data);
|
||||
caculate_ack_packet(rs_fd, packet_buffer, IAQUALNK);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -7,13 +7,25 @@
|
|||
#include "color_lights.h"
|
||||
|
||||
|
||||
/*
|
||||
Jandy Colors
|
||||
Jandy LED Light
|
||||
Sam/SL
|
||||
Color Logic
|
||||
Intelibright
|
||||
Haywood Universal Color
|
||||
|
||||
*/
|
||||
|
||||
/****** This list MUST be in order of clight_type enum *******/
|
||||
const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] =
|
||||
//char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] =
|
||||
{
|
||||
// AqualnkD Colors ignored as no names in control panel.
|
||||
{ "bogus" },
|
||||
{ "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18" },
|
||||
{ // Jandy Color
|
||||
"Alpine White",
|
||||
"",
|
||||
"Alpine White", // 0x41
|
||||
"Sky Blue",
|
||||
"Cobalt Blue",
|
||||
"Caribbean Blue",
|
||||
|
@ -21,10 +33,12 @@ const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS]
|
|||
"Emerald Green",
|
||||
"Emerald Rose",
|
||||
"Magenta",
|
||||
"Garnet Red",
|
||||
"Violet",
|
||||
"Color Splash"
|
||||
},
|
||||
{ // Jandy LED
|
||||
"",
|
||||
"Alpine White",
|
||||
"Sky Blue",
|
||||
"Cobalt Blue",
|
||||
|
@ -41,6 +55,7 @@ const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS]
|
|||
"Disco Tech"
|
||||
},
|
||||
{ // SAm/SAL
|
||||
"",
|
||||
"White",
|
||||
"Light Green",
|
||||
"Green",
|
||||
|
@ -49,27 +64,23 @@ const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS]
|
|||
"Lavender",
|
||||
"Magenta"
|
||||
},
|
||||
{ // Color Logic
|
||||
"Voodoo Lounge",
|
||||
"Deep Blue Sea",
|
||||
//"Royal Blue",
|
||||
"Afternoon Skies", // 'Afternoon Sky' on allbutton, Skies on iaqtouch
|
||||
//"Aqua Green",
|
||||
"Emerald",
|
||||
{ // Color Logic
|
||||
"",
|
||||
"Voodoo Lounge", // 0x41 (both home and sim)
|
||||
"Deep Blue Sea", // 0x42 (both gome and sim)
|
||||
"Afternoon Skies", // 0x44 home // 0x43 sim // 'Afternoon Sky' on allbutton, Skies on iaqtouch
|
||||
"Emerald", // 0x44
|
||||
"Sangria",
|
||||
"Cloud White",
|
||||
//"Warm Red",
|
||||
//"Flamingo",
|
||||
//"Vivid Violet",
|
||||
//"Sangria",
|
||||
"Twilight",
|
||||
"Tranquility",
|
||||
"Gemstone",
|
||||
"USA",
|
||||
"Mardi Gras",
|
||||
"Cool Cabaret"
|
||||
},
|
||||
"Cloud White", // 0x46
|
||||
"Twilight", // 0x4c (home panel) // 0x47
|
||||
"Tranquility", // 0x4d (home panel) // 0x48
|
||||
"Gemstone", // 0x4e (home panel) // 0x49 (simulator)
|
||||
"USA", // 0x4f (home panel) // 0x4a (simulator)
|
||||
"Mardi Gras", // 0x50 (home panel) // 0x4b (simulator)
|
||||
"Cool Cabaret" // 0x51 (home panel) // 0x4c
|
||||
},
|
||||
{ // IntelliBrite
|
||||
"",
|
||||
"SAm",
|
||||
"Party",
|
||||
"Romance",
|
||||
|
@ -83,17 +94,76 @@ const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS]
|
|||
"White",
|
||||
"Magenta"
|
||||
},
|
||||
{ // Dimmer
|
||||
"25%",
|
||||
"50%",
|
||||
"75%",
|
||||
"100%"
|
||||
}
|
||||
{ // Haywood Universal Color
|
||||
"",
|
||||
"Voodoo Lounge", // 0x41 (both home and sim) // Looks like 28 + <value or index> = 0x41 = 1st index
|
||||
"Deep Blue Sea", // 0x42 (both gome and sim)
|
||||
"Royal Blue", // // 0x43 home // non
|
||||
"Afternoon Skies", // 0x44 home // 0x43 sim // 'Afternoon Sky' on allbutton, Skies on iaqtouch
|
||||
"Aqua Green", //
|
||||
"Emerald", // 0x44
|
||||
"Cloud White", // 0x46
|
||||
"Warm Red", //
|
||||
"Flamingo", //
|
||||
"Vivid Violet", //
|
||||
"Sangria", // 0x4b (home panel) // Non existant
|
||||
"Twilight", // 0x4c (home panel) // 0x47
|
||||
"Tranquility", // 0x4d (home panel) // 0x48
|
||||
"Gemstone", // 0x4e (home panel) // 0x49 (simulator)
|
||||
"USA", // 0x4f (home panel) // 0x4a (simulator)
|
||||
"Mardi Gras", // 0x50 (home panel) // 0x4b (simulator)
|
||||
"Cool Cabaret" // 0x51 (home panel) // 0x4c
|
||||
},
|
||||
{/*Spare 1*/},
|
||||
{/*Spare 2*/},
|
||||
{/*Spare 3*/},
|
||||
{ // Dimmer // From manual this is 0 for off, 128+<value%> so 153 = 25% = 0x99
|
||||
"",
|
||||
"25%", // 0x99 (simulator) = 153 dec
|
||||
"50%", // 0xb2 (simulator) = 178 dec same as (0x99 + 25)
|
||||
"75%", // 0xcb (simulator) = 203 dec
|
||||
"100%" // 0xe4 = 228 dec
|
||||
},
|
||||
{/* Dimmer with full range */}
|
||||
};
|
||||
|
||||
// DON'T FORGET TO CHANGE #define DIMMER_LIGHT_INDEX 10 in color_lights.h
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void deleteLightOption(int type, int index)
|
||||
{
|
||||
int arrlen = LIGHT_COLOR_OPTIONS;
|
||||
memmove(_color_light_options[type]+index, _color_light_options[type]+index+1, (--arrlen - index) * sizeof *_color_light_options[type]);
|
||||
}
|
||||
|
||||
void setColorLightsPanelVersion(uint8_t supported)
|
||||
{
|
||||
static bool set = false;
|
||||
if (set)
|
||||
return;
|
||||
|
||||
if ((supported & REP_SUP_CLIT4) == REP_SUP_CLIT4)
|
||||
return; // Full panel support, no need to delete anything
|
||||
|
||||
//deleteLightOption(4, 11); // Color Logic "Sangria"
|
||||
deleteLightOption(4, 9); // Color Logic "Vivid Violet",
|
||||
deleteLightOption(4, 8); // Color Logic "Flamingo"
|
||||
deleteLightOption(4, 7); // Color Logic "Warm Red",
|
||||
deleteLightOption(4, 4); // Color Logic "Aqua Green"
|
||||
deleteLightOption(4, 2); // Color Logic "Royal Blue"
|
||||
|
||||
set = true;
|
||||
}
|
||||
*/
|
||||
|
||||
const char *light_mode_name(clight_type type, int index, emulation_type protocol)
|
||||
{
|
||||
if (index <= 0 || index > LIGHT_COLOR_OPTIONS ){
|
||||
return "";
|
||||
}
|
||||
|
||||
// Rename any modes depending on emulation type
|
||||
if (protocol == ALLBUTTON) {
|
||||
if (strcmp(_color_light_options[type][index],"Afternoon Skies") == 0) {
|
||||
|
@ -129,6 +199,23 @@ bool isShowMode(const char *mode)
|
|||
return false;
|
||||
}
|
||||
|
||||
void set_currentlight_value(clight_detail *light, int index)
|
||||
{
|
||||
// Dimmer 2 has different values (range 1 to 100)
|
||||
if (light->lightType == LC_DIMMER2) {
|
||||
if (index < 0 || index > 100)
|
||||
light->currentValue = 0;
|
||||
else
|
||||
light->currentValue = index;
|
||||
} else {
|
||||
// We want to leave the last color, so if 0 don't do anything, but set to 0 if bad value
|
||||
if (index < 0 || index > LIGHT_COLOR_OPTIONS)
|
||||
light->currentValue = 0;
|
||||
else if (index > 0 && index < LIGHT_COLOR_OPTIONS)
|
||||
light->currentValue = index;
|
||||
}
|
||||
}
|
||||
|
||||
int build_color_lights_js(struct aqualinkdata *aqdata, char* buffer, int size)
|
||||
{
|
||||
memset(&buffer[0], 0, size);
|
||||
|
@ -139,8 +226,8 @@ int build_color_lights_js(struct aqualinkdata *aqdata, char* buffer, int size)
|
|||
length += sprintf(buffer+length, "_light_program[0] = light_program;\n");
|
||||
|
||||
for (i=1; i < NUMBER_LIGHT_COLOR_TYPES; i++) {
|
||||
length += sprintf(buffer+length, "_light_program[%d] = [", i);
|
||||
for (j=0; j < LIGHT_COLOR_OPTIONS; j++) {
|
||||
length += sprintf(buffer+length, "_light_program[%d] = [ ", i);
|
||||
for (j=1; j < LIGHT_COLOR_OPTIONS; j++) { // Start a 1 since index 0 is blank
|
||||
if (_color_light_options[i][j] != NULL)
|
||||
length += sprintf(buffer+length, "\"%s%s\",", _color_light_options[i][j], (isShowMode(_color_light_options[i][j])?" - Show":"") );
|
||||
}
|
||||
|
|
|
@ -6,9 +6,15 @@
|
|||
#include "aq_programmer.h"
|
||||
|
||||
#define LIGHT_COLOR_NAME 16
|
||||
#define LIGHT_COLOR_OPTIONS 17
|
||||
#define LIGHT_COLOR_OPTIONS 19
|
||||
//#define LIGHT_COLOR_TYPES LC_DIMMER+1
|
||||
|
||||
// The status returned from RS Serial Adapter has this added as a base.
|
||||
#define RSSD_COLOR_LIGHT_OFFSET 64
|
||||
#define RSSD_DIMMER_LIGHT_OFFSET 128
|
||||
|
||||
//#define DIMMER_LIGHT_TYPE_INDEX 10
|
||||
|
||||
/*
|
||||
// color light modes (Aqualink program, Jandy, Jandy LED, SAm/SAL, Color Logic, Intellibrite)
|
||||
typedef enum clight_type {
|
||||
|
@ -23,13 +29,22 @@ typedef enum clight_type {
|
|||
//const char *light_mode_name(clight_type type, int index);
|
||||
const char *light_mode_name(clight_type type, int index, emulation_type protocol);
|
||||
int build_color_lights_js(struct aqualinkdata *aqdata, char* buffer, int size);
|
||||
|
||||
void set_currentlight_value(clight_detail *light, int index);
|
||||
|
||||
|
||||
//char *_color_light_options_[LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS][LIGHT_COLOR_NAME];
|
||||
|
||||
#endif //COLOR_LIGHTS_H_
|
||||
/*
|
||||
|
||||
Rev T.2 has the below
|
||||
Jandy colors <- Same
|
||||
Jandy LED <- Same
|
||||
SAm/Sal <- Same
|
||||
IntelliBrite <- Same
|
||||
Hayw Univ Col <- Color Logic
|
||||
|
||||
*/
|
||||
/*
|
||||
Color Name Jandy Colors Jandy LED SAm/SAL Color Logic IntelliBrite dimmer
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
|
219
source/config.c
219
source/config.c
|
@ -47,6 +47,8 @@
|
|||
|
||||
char *generate_mqtt_id(char *buf, int len);
|
||||
pump_detail *getpump(struct aqualinkdata *aqdata, int button);
|
||||
bool populatePumpData(struct aqualinkdata *aqdata, char *pumpcfg ,aqkey *button, char *value);
|
||||
pump_detail *getPumpFromButtonID(struct aqualinkdata *aqdata, aqkey *button);
|
||||
|
||||
struct tmpPanelInfo {
|
||||
int size;
|
||||
|
@ -81,7 +83,10 @@ void init_parameters (struct aqconfig * parms)
|
|||
//parms->device_id = strtoul(DEFAULT_DEVICE_ID, &p, 16);
|
||||
parms->device_id = strtoul(DEFAULT_DEVICE_ID, NULL, 16);
|
||||
parms->rssa_device_id = NUL;
|
||||
parms->RSSD_LOG_filter = NUL;
|
||||
|
||||
for (int i=0; i < MAX_RSSD_LOG_FILTERS; i++) {
|
||||
parms->RSSD_LOG_filter[i] = NUL;
|
||||
}
|
||||
parms->paneltype_mask = 0;
|
||||
#if defined AQ_ONETOUCH || defined AQ_IAQTOUCH
|
||||
parms->extended_device_id = NUL;
|
||||
|
@ -120,8 +125,8 @@ void init_parameters (struct aqconfig * parms)
|
|||
//parms->onetouch_mode = false;
|
||||
parms->convert_mqtt_temp = true;
|
||||
parms->convert_dz_temp = true;
|
||||
parms->report_zero_pool_temp = false;
|
||||
parms->report_zero_spa_temp = false;
|
||||
parms->report_zero_pool_temp = true;
|
||||
parms->report_zero_spa_temp = true;
|
||||
//parms->read_all_devices = true;
|
||||
//parms->read_pentair_packets = false;
|
||||
parms->read_RS485_devmask = 0;
|
||||
|
@ -132,7 +137,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
parms->force_frzprotect_setpoints = false;
|
||||
parms->force_chem_feeder = false;
|
||||
//parms->swg_pool_and_spa = false;
|
||||
parms->swg_zero_ignore = DEFAULT_SWG_ZERO_IGNORE_COUNT;
|
||||
//parms->swg_zero_ignore = DEFAULT_SWG_ZERO_IGNORE_COUNT;
|
||||
parms->display_warnings_web = false;
|
||||
|
||||
parms->log_protocol_packets = false; // Read & Write as packets write to file
|
||||
|
@ -244,6 +249,8 @@ char *generate_mqtt_id(char *buf, int len) {
|
|||
strncpy(buf, basename(__progname), len);
|
||||
i = strlen(buf);
|
||||
|
||||
if ( i > 9) { i=9; } // cut down to 9 characters (aqualinkd)
|
||||
|
||||
if (i < len) {
|
||||
buf[i++] = '_';
|
||||
// If we can't get MAC to pad mqtt id then use PID
|
||||
|
@ -394,16 +401,24 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
|
|||
_aqconfig_.rssa_device_id = strtoul(cleanalloc(value), NULL, 16);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "RSSD_LOG_filter", 15) == 0) {
|
||||
_aqconfig_.RSSD_LOG_filter = strtoul(cleanalloc(value), NULL, 16);
|
||||
for (int i=0; i < MAX_RSSD_LOG_FILTERS; i++) {
|
||||
if (_aqconfig_.RSSD_LOG_filter[i] == NUL) {
|
||||
_aqconfig_.RSSD_LOG_filter[i] = strtoul(cleanalloc(value), NULL, 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
rtn=true;
|
||||
#if defined AQ_ONETOUCH || defined AQ_IAQTOUCH
|
||||
} else if (strncasecmp (param, "extended_device_id_programming", 30) == 0) {
|
||||
// Has to be before the below.
|
||||
_aqconfig_.extended_device_id_programming = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "extended_device_id", 9) == 0) {
|
||||
} else if (strncasecmp(param, "extended_device_id", 18) == 0) {
|
||||
_aqconfig_.extended_device_id = strtoul(cleanalloc(value), NULL, 16);
|
||||
//_config_parameters.onetouch_device_id != 0x00
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "enable_iaqualink", 16) == 0) {
|
||||
_aqconfig_.enable_iaqualink = text2bool(value);
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_IAQUALNK; // This should not be set if we are reading dieectly so turn off mask
|
||||
rtn=true;
|
||||
#endif
|
||||
} else if (strncasecmp(param, "panel_type_size", 15) == 0) {
|
||||
|
@ -582,6 +597,17 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
|
|||
else
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_JAN_CHEM;
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "read_RS485_iAqualink", 20) == 0) {
|
||||
/* This should not be used with enable_iaqualink */
|
||||
if (text2bool(value)) {
|
||||
if (_aqconfig_.enable_iaqualink)
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'read_RS485_iAqualink' is not valid when 'enable_iaqualink=yes', ignoring read_RS485_iAqualink!\n");
|
||||
else
|
||||
_aqconfig_.read_RS485_devmask |= READ_RS485_IAQUALNK;
|
||||
} else {
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_IAQUALNK;
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "use_panel_aux_labels", 20) == 0) {
|
||||
_aqconfig_.use_panel_aux_labels = text2bool(value);
|
||||
rtn=true;
|
||||
|
@ -603,9 +629,11 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
|
|||
} else if (strncasecmp (param, "debug_RSProtocol_packets", 24) == 0) {
|
||||
_aqconfig_.log_protocol_packets = text2bool(value);
|
||||
rtn=true;
|
||||
/*
|
||||
} else if (strncasecmp (param, "swg_zero_ignore_count", 21) == 0) {
|
||||
_aqconfig_.swg_zero_ignore = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
*/
|
||||
} else if (strncasecmp (param, "display_warnings_in_web", 23) == 0) {
|
||||
_aqconfig_.display_warnings_web = text2bool(value);
|
||||
rtn=true;
|
||||
|
@ -670,79 +698,139 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
|
|||
LOG(AQUA_LOG,LOG_ERR, "Config error, unknown light mode '%s'\n",type);
|
||||
} else {
|
||||
aqdata->lights[aqdata->num_lights].button = &aqdata->aqbuttons[num];
|
||||
aqdata->lights[aqdata->num_lights].lightType = type;
|
||||
aqdata->num_lights++;
|
||||
aqdata->lights[aqdata->num_lights].lightType = type;
|
||||
aqdata->aqbuttons[num].special_mask |= PROGRAM_LIGHT;
|
||||
aqdata->aqbuttons[num].special_mask_ptr = &aqdata->lights[aqdata->num_lights];
|
||||
|
||||
aqdata->num_lights++;
|
||||
}
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, (colored|programmable) Lights limited to %d, ignoring %s'\n",MAX_LIGHTS,param);
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 9, "_pumpID", 7) == 0) {
|
||||
pump_detail *pump = getpump(aqdata, num);
|
||||
if (pump != NULL) {
|
||||
pump->pumpID = strtoul(cleanalloc(value), NULL, 16);
|
||||
if ( (int)pump->pumpID <= PENTAIR_DEC_PUMP_MAX) {
|
||||
pump->prclType = PENTAIR;
|
||||
} else {
|
||||
pump->prclType = JANDY;
|
||||
//pump->pumpType = EPUMP; // For testing let the interface set this
|
||||
} else if (strncasecmp(param + 9, "_pump", 5) == 0) {
|
||||
|
||||
if ( ! populatePumpData(aqdata, param + 10, &aqdata->aqbuttons[num], value) )
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring : %s",MAX_PUMPS,param);
|
||||
}
|
||||
|
||||
rtn=true;
|
||||
}
|
||||
//#if defined AQ_IAQTOUCH
|
||||
} else if (strncasecmp(param, "virtual_button_", 15) == 0) {
|
||||
rtn=true;
|
||||
int num = strtoul(param + 15, NULL, 10);
|
||||
if (_aqconfig_.paneltype_mask == 0) {
|
||||
// ERROR the vbutton will be irnored.
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, Panel type must be definied before adding a virtual_button, ignored setting : %s",param);
|
||||
//} else if (_aqconfig_.extended_device_id < 0x30 || _aqconfig_.extended_device_id > 0x33 ) {
|
||||
// LOG(AQUA_LOG,LOG_WARNING, "Config error, extended_device_id must on of the folowing (0x30,0x31,0x32,0x33), ignored setting : %s",param);
|
||||
} else if (strncasecmp(param + 17, "_label", 6) == 0) {
|
||||
char *label = cleanalloc(value);
|
||||
aqkey *button = addVirtualButton(aqdata, label, num);
|
||||
if (button != NULL) {
|
||||
button->special_mask |= VIRTUAL_BUTTON;
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Error with '%s', total buttons=%d, config has %d already, ignoring!\n",param, TOTAL_BUTTONS, aqdata->total_buttons+1);
|
||||
}
|
||||
} else if (strncasecmp(param + 17, "_pump", 5) == 0) {
|
||||
char *vbname = malloc(sizeof(char*) * 10);
|
||||
snprintf(vbname, 9, "%s%d", BTN_VAUX, num);
|
||||
aqkey *vbutton = NULL;
|
||||
for (int i = aqdata->virtual_button_start; i < aqdata->total_buttons; i++) {
|
||||
//printf("Checking %s agasinsdt %s\n",aqdata->aqbuttons[i].name, vbname);
|
||||
if ( strcmp( aqdata->aqbuttons[i].name, vbname) == 0 ) {
|
||||
vbutton = &aqdata->aqbuttons[i];
|
||||
vbutton->led->state = ON; //Virtual pump is always on
|
||||
if ( ! populatePumpData(aqdata, param + 18, vbutton, value) )
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring : %s",MAX_PUMPS,param);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 9, "_pumpIndex", 10) == 0) { //button_01_pumpIndex=1
|
||||
pump_detail *pump = getpump(aqdata, num);
|
||||
if (pump != NULL) {
|
||||
pump->pumpIndex = strtoul(value, NULL, 10);
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
|
||||
if (vbutton == NULL) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, could not find vitrual button for `%s`",param);
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 9, "_pumpType", 9) == 0) {
|
||||
// This is not documented, as it's prefered for AqualinkD to find the pump type.
|
||||
pump_detail *pump = getpump(aqdata, num);
|
||||
if (pump != NULL) {
|
||||
if ( stristr(value, "Pentair VS") != 0)
|
||||
pump->pumpType = VSPUMP;
|
||||
else if ( stristr(value, "Pentair VF") != 0)
|
||||
pump->pumpType = VFPUMP;
|
||||
else if ( stristr(value, "Jandy ePump") != 0)
|
||||
pump->pumpType = EPUMP;
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
|
||||
}
|
||||
rtn=true;
|
||||
}
|
||||
/*
|
||||
} else if (strncasecmp(param + 9, "_pumpID", 7) == 0) {
|
||||
//aqdata->aqbuttons[num].pda_label = cleanalloc(value);
|
||||
//96 to 111 = Pentair, 120 to 123 = Jandy
|
||||
if (pi < MAX_PUMPS) {
|
||||
aqdata->pumps[pi].button = &aqdata->aqbuttons[num];
|
||||
aqdata->pumps[pi].pumpID = strtoul(cleanalloc(value), NULL, 16);
|
||||
aqdata->pumps[pi].pumpIndex = pi+1;
|
||||
//aqdata->pumps[pi].buttonID = num;
|
||||
if (aqdata->pumps[pi].pumpID < 119)
|
||||
aqdata->pumps[pi].ptype = PENTAIR;
|
||||
else
|
||||
aqdata->pumps[pi].ptype = JANDY;
|
||||
pi++;
|
||||
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 9, "_pumpIndex", 10) == 0) { //button_01_pumpIndex=1
|
||||
}*/
|
||||
}
|
||||
//#endif
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
// pumpcfg is pointer to pumpIndex, pumpName, pumpType pumpID, (ie pull off button_??_ or vurtual_button_??_)
|
||||
bool populatePumpData(struct aqualinkdata *aqdata, char *pumpcfg ,aqkey *button, char *value)
|
||||
{
|
||||
|
||||
pump_detail *pump = getPumpFromButtonID(aqdata, button);
|
||||
if (pump == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strncasecmp(pumpcfg, "pumpIndex", 9) == 0) {
|
||||
pump->pumpIndex = strtoul(value, NULL, 10);
|
||||
} else if (strncasecmp(pumpcfg, "pumpType", 8) == 0) {
|
||||
if ( stristr(value, "Pentair VS") != 0)
|
||||
pump->pumpType = VSPUMP;
|
||||
else if ( stristr(value, "Pentair VF") != 0)
|
||||
pump->pumpType = VFPUMP;
|
||||
else if ( stristr(value, "Jandy ePump") != 0)
|
||||
pump->pumpType = EPUMP;
|
||||
} else if (strncasecmp(pumpcfg, "pumpName", 8) == 0) {
|
||||
strncpy(pump->pumpName ,cleanwhitespace(value), PUMP_NAME_LENGTH-1);
|
||||
} else if (strncasecmp(pumpcfg, "pumpID", 6) == 0) {
|
||||
pump->pumpID = strtoul(cleanalloc(value), NULL, 16);
|
||||
if ( (int)pump->pumpID >= PENTAIR_DEC_PUMP_MIN && (int)pump->pumpID <= PENTAIR_DEC_PUMP_MAX) {
|
||||
pump->prclType = PENTAIR;
|
||||
} else {
|
||||
pump->prclType = JANDY;
|
||||
}
|
||||
} else if (strncasecmp(pumpcfg, "pumpMaxSpeed", 12) == 0) {
|
||||
pump->maxSpeed = strtoul(value, NULL, 10);
|
||||
} else if (strncasecmp(pumpcfg, "pumpMinSpeed", 12) == 0) {
|
||||
pump->minSpeed = strtoul(value, NULL, 10);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pump_detail *getPumpFromButtonID(struct aqualinkdata *aqdata, aqkey *button)
|
||||
{
|
||||
int pi;
|
||||
|
||||
// Does it exist
|
||||
for (pi=0; pi < aqdata->num_pumps; pi++) {
|
||||
if (aqdata->pumps[pi].button == button) {
|
||||
return &aqdata->pumps[pi];
|
||||
}
|
||||
}
|
||||
|
||||
// Create new entry
|
||||
if (aqdata->num_pumps < MAX_PUMPS) {
|
||||
//printf ("Creating pump %d\n",button);
|
||||
button->special_mask |= VS_PUMP;
|
||||
button->special_mask_ptr = (void*)&aqdata->pumps[aqdata->num_pumps];
|
||||
aqdata->pumps[aqdata->num_pumps].button = button;
|
||||
aqdata->pumps[aqdata->num_pumps].pumpType = PT_UNKNOWN;
|
||||
aqdata->pumps[aqdata->num_pumps].rpm = TEMP_UNKNOWN;
|
||||
aqdata->pumps[aqdata->num_pumps].watts = TEMP_UNKNOWN;
|
||||
aqdata->pumps[aqdata->num_pumps].gpm = TEMP_UNKNOWN;
|
||||
aqdata->pumps[aqdata->num_pumps].pStatus = PS_OFF;
|
||||
aqdata->pumps[aqdata->num_pumps].pumpIndex = 0;
|
||||
aqdata->pumps[aqdata->num_pumps].maxSpeed = TEMP_UNKNOWN;
|
||||
aqdata->pumps[aqdata->num_pumps].minSpeed = TEMP_UNKNOWN;
|
||||
//pumpType
|
||||
aqdata->pumps[aqdata->num_pumps].pumpName[0] = '\0';
|
||||
aqdata->num_pumps++;
|
||||
return &aqdata->pumps[aqdata->num_pumps-1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
pump_detail *getpump(struct aqualinkdata *aqdata, int button)
|
||||
{
|
||||
//static int _pumpindex = 0;
|
||||
|
@ -767,13 +855,16 @@ pump_detail *getpump(struct aqualinkdata *aqdata, int button)
|
|||
aqdata->pumps[aqdata->num_pumps].watts = TEMP_UNKNOWN;
|
||||
aqdata->pumps[aqdata->num_pumps].gpm = TEMP_UNKNOWN;
|
||||
aqdata->pumps[aqdata->num_pumps].pStatus = PS_OFF;
|
||||
aqdata->pumps[aqdata->num_pumps].pumpIndex = 0;
|
||||
//pumpType
|
||||
aqdata->pumps[aqdata->num_pumps].pumpName[0] = '\0';
|
||||
aqdata->num_pumps++;
|
||||
return &aqdata->pumps[aqdata->num_pumps-1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
void init_config()
|
||||
{
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#define DEFAULT_MQTT_SERVER NULL
|
||||
#define DEFAULT_MQTT_USER NULL
|
||||
#define DEFAULT_MQTT_PASSWD NULL
|
||||
#define DEFAULT_SWG_ZERO_IGNORE_COUNT 0
|
||||
//#define DEFAULT_SWG_ZERO_IGNORE_COUNT 0
|
||||
|
||||
#define MQTT_ID_LEN 18 // 20 seems to kill mosquitto 1.6
|
||||
|
||||
|
@ -31,6 +31,9 @@
|
|||
#define READ_RS485_JAN_JXI (1 << 3) // Jandy JX & LXi heater
|
||||
#define READ_RS485_JAN_LX (1 << 4) // Jandy LX heater
|
||||
#define READ_RS485_JAN_CHEM (1 << 5) // Jandy Chemical Feeder
|
||||
#define READ_RS485_IAQUALNK (1 << 6) // Read iAqualink messages
|
||||
|
||||
#define MAX_RSSD_LOG_FILTERS 4
|
||||
|
||||
struct aqconfig
|
||||
{
|
||||
|
@ -44,7 +47,10 @@ struct aqconfig
|
|||
int16_t paneltype_mask;
|
||||
#if defined AQ_ONETOUCH || defined AQ_IAQTOUCH
|
||||
unsigned char extended_device_id;
|
||||
unsigned char extended_device_id2;
|
||||
bool extended_device_id_programming;
|
||||
bool enable_iaqualink;
|
||||
//bool enable_RS_device_value_print;
|
||||
#endif
|
||||
bool deamonize;
|
||||
#ifndef AQ_MANAGER // Need to uncomment and clean up referances in future.
|
||||
|
@ -83,11 +89,11 @@ struct aqconfig
|
|||
bool force_ps_setpoints;
|
||||
bool force_frzprotect_setpoints;
|
||||
bool force_chem_feeder;
|
||||
int swg_zero_ignore;
|
||||
//int swg_zero_ignore; // This can be removed since this was due to VSP that's been fixed.
|
||||
bool display_warnings_web;
|
||||
bool log_protocol_packets; // Read & Write as packets
|
||||
bool log_raw_bytes; // Read as bytes
|
||||
unsigned char RSSD_LOG_filter;
|
||||
unsigned char RSSD_LOG_filter[MAX_RSSD_LOG_FILTERS];
|
||||
//bool log_raw_RS_bytes;
|
||||
/*
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
|
@ -120,6 +126,7 @@ struct aqconfig _aqconfig_;
|
|||
#define READ_RSDEV_JXI ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_JXI) == READ_RS485_JAN_JXI)
|
||||
#define READ_RSDEV_LX ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_LX) == READ_RS485_JAN_LX)
|
||||
#define READ_RSDEV_CHEM ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_CHEM) == READ_RS485_JAN_CHEM)
|
||||
#define READ_RSDEV_iAQLNK ((_aqconfig_.read_RS485_devmask & READ_RS485_IAQUALNK) == READ_RS485_IAQUALNK)
|
||||
|
||||
#define isPDA_IAQT (_aqconfig_.device_id == 0x33)
|
||||
//#define isPDA ((_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA)
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "utils.h"
|
||||
#include "aq_mqtt.h"
|
||||
#include "packetLogger.h"
|
||||
#include "iaqualink.h"
|
||||
|
||||
/*
|
||||
All button errors
|
||||
|
@ -83,10 +84,11 @@ bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct
|
|||
else if (READ_RSDEV_SWG && packet_buffer[PKT_DEST] >= JANDY_DEC_SWG_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_SWG_MAX)
|
||||
{
|
||||
interestedInNextAck = DRS_SWG;
|
||||
rtn = processPacketToSWG(packet_buffer, packet_length, aqdata, _aqconfig_.swg_zero_ignore);
|
||||
rtn = processPacketToSWG(packet_buffer, packet_length, aqdata/*, _aqconfig_.swg_zero_ignore*/);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
else if (READ_RSDEV_ePUMP && packet_buffer[PKT_DEST] >= JANDY_DEC_PUMP_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_PUMP_MAX)
|
||||
else if (READ_RSDEV_ePUMP && ( (packet_buffer[PKT_DEST] >= JANDY_DEC_PUMP_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_PUMP_MAX)
|
||||
|| (packet_buffer[PKT_DEST] >= JANDY_DEC_PUMP2_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_PUMP2_MAX) ) )
|
||||
{
|
||||
interestedInNextAck = DRS_EPUMP;
|
||||
rtn = processPacketToJandyPump(packet_buffer, packet_length, aqdata);
|
||||
|
@ -110,6 +112,11 @@ bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct
|
|||
rtn = processPacketToJandyChemFeeder(packet_buffer, packet_length, aqdata);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
else if (READ_RSDEV_iAQLNK && packet_buffer[PKT_DEST] >= JANDY_DEV_AQLNK_MIN && packet_buffer[PKT_DEST] <= JANDY_DEV_AQLNK_MAX
|
||||
&& packet_buffer[PKT_DEST] != _aqconfig_.extended_device_id) // We would have already read extended_device_id frame
|
||||
{
|
||||
process_iAqualinkStatusPacket(packet_buffer, packet_length, aqdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
interestedInNextAck = DRS_NONE;
|
||||
|
@ -125,14 +132,14 @@ bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct
|
|||
return rtn;
|
||||
}
|
||||
|
||||
bool processPacketToSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata, int swg_zero_ignore) {
|
||||
static int swg_zero_cnt = 0;
|
||||
bool processPacketToSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata /*, int swg_zero_ignore*/) {
|
||||
//static int swg_zero_cnt = 0;
|
||||
bool changedAnything = false;
|
||||
|
||||
// Only log if we are jandy debug move and not serial (otherwise it'll print twice)
|
||||
// Only log if we are jandy debug move and not serial (otherwise it'll print twice)
|
||||
if (getLogLevel(DJAN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
|
||||
char buff[1024];
|
||||
beautifyPacket(buff, packet, packet_length, true);
|
||||
beautifyPacket(buff, 1024, packet, packet_length, true);
|
||||
LOG(DJAN_LOG,LOG_DEBUG, "To SWG: %s", buff);
|
||||
}
|
||||
|
||||
|
@ -142,32 +149,34 @@ bool processPacketToSWG(unsigned char *packet, int packet_length, struct aqualin
|
|||
// Not really sure what to do with this, just ignore 0xff / 255 for the moment. (if statment above)
|
||||
|
||||
// SWG can get ~10 messages to set to 0 then go back again for some reason, so don't go to 0 until 10 messages are received
|
||||
if (swg_zero_cnt <= swg_zero_ignore && packet[4] == 0x00) {
|
||||
/*
|
||||
if (swg_zero_cnt < swg_zero_ignore && packet[4] == 0x00) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Ignoring SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n", (int)packet[4],
|
||||
swg_zero_cnt, swg_zero_ignore, packet[4], packet[5]);
|
||||
swg_zero_cnt++;
|
||||
} else if (swg_zero_cnt > swg_zero_ignore && packet[4] == 0x00) {
|
||||
} else if (swg_zero_cnt >= swg_zero_ignore && packet[4] == 0x00) {
|
||||
if (aqdata->swg_percent != (int)packet[4]) {
|
||||
//aqdata->swg_percent = (int)packet[4];
|
||||
setSWGpercent(aqdata, (int)packet[4]);
|
||||
changedAnything = true;
|
||||
aqdata->updated = true;
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG %% to %d from reading control panel packet sent to SWG (received %d messages)\n", aqdata->swg_percent, swg_zero_cnt);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG %% to %d from reading control panel RS485 packet sent to SWG\n", aqdata->swg_percent);
|
||||
}
|
||||
// LOG(DJAN_LOG, LOG_DEBUG, "SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n",
|
||||
// (int)packet[4],swg_zero_cnt,SWG_ZERO_IGNORE_COUNT,packet[4],packet[5]); swg_zero_cnt++;
|
||||
} else {
|
||||
swg_zero_cnt = 0;
|
||||
} else {*/
|
||||
//swg_zero_cnt = 0;
|
||||
if (aqdata->swg_percent != (int)packet[4]) {
|
||||
//aqdata->swg_percent = (int)packet[4];
|
||||
setSWGpercent(aqdata, (int)packet[4]);
|
||||
changedAnything = true;
|
||||
aqdata->updated = true;
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG %% to %d from control panel packet to SWG\n", aqdata->swg_percent);
|
||||
LOG(DJAN_LOG, LOG_INFO, "Set SWG %% to %d from control panel to SWG\n", aqdata->swg_percent);
|
||||
}
|
||||
|
||||
// LOG(DJAN_LOG, LOG_DEBUG, "SWG set to %d due to packet from control panel to SWG 0x%02hhx 0x%02hhx\n",
|
||||
// aqdata.swg_percent,packet[4],packet[5]);
|
||||
}
|
||||
/*}*/
|
||||
|
||||
if (aqdata->swg_percent > 100)
|
||||
aqdata->boost = true;
|
||||
|
@ -194,7 +203,7 @@ bool processPacketFromSWG(unsigned char *packet, int packet_length, struct aqual
|
|||
// Only log if we are jandy debug move and not serial (otherwise it'll print twice)
|
||||
if (getLogLevel(DJAN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
|
||||
char buff[1024];
|
||||
beautifyPacket(buff, packet, packet_length, true);
|
||||
beautifyPacket(buff, 1024, packet, packet_length, true);
|
||||
LOG(DJAN_LOG,LOG_DEBUG, "From SWG: %s", buff);
|
||||
}
|
||||
|
||||
|
@ -211,7 +220,7 @@ bool processPacketFromSWG(unsigned char *packet, int packet_length, struct aqual
|
|||
|
||||
if ( (packet[4] * 100) != aqdata->swg_ppm ) {
|
||||
aqdata->swg_ppm = packet[4] * 100;
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG PPM to %d from SWG packet\n", aqdata->swg_ppm);
|
||||
LOG(DJAN_LOG, LOG_INFO, "Received SWG PPM %d from SWG packet\n", aqdata->swg_ppm);
|
||||
changedAnything = true;
|
||||
aqdata->updated = true;
|
||||
}
|
||||
|
@ -562,17 +571,17 @@ bool processPacketToJandyPump(unsigned char *packet_buffer, int packet_length, s
|
|||
*/
|
||||
// Only log if we are jandy debug move and not serial (otherwise it'll print twice)
|
||||
if (getLogLevel(DJAN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
|
||||
char msg[1000];
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
char msg[1024];
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "To ePump: %s\n", msg);
|
||||
}
|
||||
|
||||
// If type 0x45 and 0x44 set to interested in next command.
|
||||
if (packet_buffer[3] == CMD_EPUMP_RPM) {
|
||||
// All we need to do is set we are interested in next packet, but ca lling function already did this.
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "ControlPanel request Pump ID 0x%02hhx set RPM to %d\n",packet_buffer[PKT_DEST], ( (packet_buffer[EP_HI_B_RPM-1] * 256) + packet_buffer[EP_LO_B_RPM-1]) / 4 );
|
||||
LOG(DJAN_LOG, LOG_INFO, "ControlPanel request Pump ID 0x%02hhx set RPM to %d\n",packet_buffer[PKT_DEST], ( (packet_buffer[EP_HI_B_RPM-1] * 256) + packet_buffer[EP_LO_B_RPM-1]) / 4 );
|
||||
} else if (packet_buffer[3] == CMD_EPUMP_WATTS) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "ControlPanel request Pump ID 0x%02hhx get watts\n",packet_buffer[PKT_DEST]);
|
||||
LOG(DJAN_LOG, LOG_INFO, "ControlPanel request Pump ID 0x%02hhx get watts\n",packet_buffer[PKT_DEST]);
|
||||
}
|
||||
|
||||
if (getLogLevel(DJAN_LOG) == LOG_DEBUG) {
|
||||
|
@ -594,9 +603,9 @@ bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length,
|
|||
|
||||
// Only log if we are jandy debug move and not serial (otherwise it'll print twice)
|
||||
if (getLogLevel(DJAN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
|
||||
char msg[1000];
|
||||
char msg[1024];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "From ePump: %s\n", msg);
|
||||
}
|
||||
|
||||
|
@ -659,9 +668,9 @@ bool processPacketToJandyJXiHeater(unsigned char *packet_buffer, int packet_leng
|
|||
{
|
||||
|
||||
if (getLogLevel(DJAN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
|
||||
char msg[1000];
|
||||
char msg[1024];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "To JXi: %s\n", msg);
|
||||
}
|
||||
|
||||
|
@ -684,24 +693,24 @@ bool processPacketToJandyJXiHeater(unsigned char *packet_buffer, int packet_leng
|
|||
*/
|
||||
|
||||
if (packet_buffer[5] != aqdata->pool_htr_set_point) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "JXi pool setpoint %d, Pool heater sp %d (changing to LXi)\n", packet_buffer[5], aqdata->pool_htr_set_point);
|
||||
LOG(DJAN_LOG, LOG_INFO, "JXi pool setpoint %d, Pool heater sp %d (changing to LXi)\n", packet_buffer[5], aqdata->pool_htr_set_point);
|
||||
aqdata->pool_htr_set_point = packet_buffer[5];
|
||||
}
|
||||
|
||||
if (packet_buffer[6] != aqdata->spa_htr_set_point) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "JXi spa setpoint %d, Spa heater sp %d (changing to LXi)\n", packet_buffer[6], aqdata->spa_htr_set_point);
|
||||
LOG(DJAN_LOG, LOG_INFO, "JXi spa setpoint %d, Spa heater sp %d (changing to LXi)\n", packet_buffer[6], aqdata->spa_htr_set_point);
|
||||
aqdata->spa_htr_set_point = packet_buffer[6];
|
||||
}
|
||||
|
||||
if (packet_buffer[7] != 0xff && packet_buffer[4] != 0x00) {
|
||||
if (packet_buffer[4] == 0x11 || packet_buffer[4] == 0x19) {
|
||||
if (aqdata->pool_temp != packet_buffer[7]) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "JXi pool water temp %d, pool water temp %d (changing to LXi)\n", packet_buffer[7], aqdata->pool_temp);
|
||||
LOG(DJAN_LOG, LOG_INFO, "JXi pool water temp %d, pool water temp %d (changing to LXi)\n", packet_buffer[7], aqdata->pool_temp);
|
||||
aqdata->pool_temp = packet_buffer[7];
|
||||
}
|
||||
} else if (packet_buffer[4] == 0x12 || packet_buffer[4] == 0x1a) {
|
||||
if (aqdata->spa_temp != packet_buffer[7]) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "JXi spa water temp %d, spa water temp %d (changing to LXi)\n", packet_buffer[7], aqdata->spa_temp);
|
||||
LOG(DJAN_LOG, LOG_INFO, "JXi spa water temp %d, spa water temp %d (changing to LXi)\n", packet_buffer[7], aqdata->spa_temp);
|
||||
aqdata->spa_temp = packet_buffer[7];
|
||||
}
|
||||
}
|
||||
|
@ -792,9 +801,9 @@ void getJandyHeaterErrorMQTT(struct aqualinkdata *aqdata, char *message)
|
|||
bool processPacketFromJandyJXiHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to)
|
||||
{
|
||||
if (getLogLevel(DJAN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
|
||||
char msg[1000];
|
||||
char msg[1024];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "From JXi: %s\n", msg);
|
||||
}
|
||||
|
||||
|
@ -848,10 +857,10 @@ bool processPacketFromJandyJXiHeater(unsigned char *packet_buffer, int packet_le
|
|||
bool processPacketToJandyLXHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
|
||||
char msg[1000];
|
||||
char msg[1024];
|
||||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "To LX: %s\n", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
@ -877,10 +886,10 @@ bool processPacketToJandyLXHeater(unsigned char *packet_buffer, int packet_lengt
|
|||
|
||||
bool processPacketFromJandyLXHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to)
|
||||
{
|
||||
char msg[1000];
|
||||
char msg[1024];
|
||||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "From LX: %s\n", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
@ -906,10 +915,10 @@ bool processPacketFromJandyLXHeater(unsigned char *packet_buffer, int packet_len
|
|||
|
||||
bool processPacketToJandyChemFeeder(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
char msg[1000];
|
||||
char msg[1024];
|
||||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "To Chem: %s\n", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
@ -922,10 +931,10 @@ bool processPacketToJandyChemFeeder(unsigned char *packet_buffer, int packet_len
|
|||
}
|
||||
|
||||
bool processPacketFromJandyChemFeeder(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to){
|
||||
char msg[1000];
|
||||
char msg[1024];
|
||||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "From Chem: %s\n", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
@ -934,12 +943,18 @@ bool processPacketFromJandyChemFeeder(unsigned char *packet_buffer, int packet_l
|
|||
|
||||
LOG(DJAN_LOG, LOG_INFO, "%s\n", msg);
|
||||
|
||||
/*
|
||||
ph_setpoint = float(raw_data[8]) / 10
|
||||
acl_setpoint = raw_data[9] * 10
|
||||
ph_current = float(raw_data[10]) / 10
|
||||
acl_current = raw_data[11] * 10
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
// JXi Heater
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
|
||||
bool processPacketToSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata, int swg_zero_ignore);
|
||||
bool processPacketToSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata/*, int swg_zero_ignore*/);
|
||||
bool processPacketFromSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to);
|
||||
bool processPacketToJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to);
|
||||
|
|
|
@ -34,7 +34,7 @@ bool processPentairPacket(unsigned char *packet, int packet_length, struct aqual
|
|||
// Only log if we are pentair debug move and not serial (otherwise it'll print twice)
|
||||
if (getLogLevel(DPEN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
|
||||
char buff[1024];
|
||||
beautifyPacket(buff, packet, packet_length, true);
|
||||
beautifyPacket(buff, 1024, packet, packet_length, true);
|
||||
LOG(DPEN_LOG,LOG_DEBUG, "%s", buff);
|
||||
}
|
||||
|
||||
|
@ -103,9 +103,9 @@ bool processPentairPacket(unsigned char *packet, int packet_length, struct aqual
|
|||
// Set power to pump
|
||||
else if (packet[PEN_PKT_CMD] == PEN_CMD_POWER && packet[PEN_PKT_DEST] >= PENTAIR_DEC_PUMP_MIN && packet[PEN_PKT_DEST] <= PENTAIR_DEC_PUMP_MAX) {
|
||||
if (packet[9] == 0x0A) {
|
||||
LOG(DPEN_LOG, LOG_INFO,"Pentair Pump 0x%02hhx request set power ON\n");
|
||||
LOG(DPEN_LOG, LOG_INFO,"Pentair Pump 0x%02hhx request set power ON\n",packet[PEN_PKT_DEST]);
|
||||
} else {
|
||||
LOG(DPEN_LOG, LOG_INFO,"Pentair Pump 0x%02hhx request set power OFF\n");
|
||||
LOG(DPEN_LOG, LOG_INFO,"Pentair Pump 0x%02hhx request set power OFF\n",packet[PEN_PKT_DEST]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -123,15 +123,34 @@ const char *HASSIO_VSP_DISCOVER = "{"
|
|||
"\"payload_off\": \"0\","
|
||||
"\"percentage_command_topic\": \"%s/%s/%s/set\"," // aqualinkd,filter_pump , RPM|GPM
|
||||
"\"percentage_state_topic\": \"%s/%s/%s\"," // aqualinkd,filter_pump , RPM|GPM
|
||||
// "\"percentage_value_template\": \"{{ (((value | float(0) - %d) / %d) * 100) | int }}\"," // 600, (3450-600)
|
||||
"\"percentage_value_template\": \"{%% if value | float(0) > %d %%} {{ (((value | float(0) - %d) / %d) * 100) | int }}{%% else %%} 1{%% endif %%}\"," // min,min,(max-min)
|
||||
"\"percentage_command_template\": \"{{ ((value | float(0) / 100) * %d) + %d | int }}\"," // (3450-130), 600
|
||||
//"\"percentage_value_template\": \"{%% if value | float(0) > %d %%} {{ (((value | float(0) - %d) / %d) * 100) | int }}{%% else %%} 1{%% endif %%}\"," // min,min,(max-min)
|
||||
//"\"percentage_command_template\": \"{{ ((value | float(0) / 100) * %d) + %d | int }}\"," // (3450-130), 600
|
||||
"\"speed_range_max\": 100,"
|
||||
"\"speed_range_min\": 1," // 18|12 600rpm|15gpm
|
||||
"\"qos\": 1,"
|
||||
"\"retain\": false"
|
||||
"}";
|
||||
|
||||
|
||||
const char *HASSIO_DIMMER_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"light\","
|
||||
"\"unique_id\": \"aqualinkd_%s\"," // Aux_5
|
||||
"\"name\": \"%s\"," // Dimmer_name
|
||||
"\"state_topic\": \"%s/%s\"," // aqualinkd,Aux_5
|
||||
"\"command_topic\": \"%s/%s/set\"," // aqualinkd,Aux_5
|
||||
"\"json_attributes_topic\": \"%s/%s/delay\"," // aqualinkd,Aux_5
|
||||
"\"json_attributes_template\": \"{{ {'delay': value|int} | tojson }}\","
|
||||
"\"payload_on\": \"1\","
|
||||
"\"payload_off\": \"0\","
|
||||
"\"brightness_command_topic\": \"%s/%s%s/set\"," // aqualinkd,Aux_5,/brightness
|
||||
"\"brightness_state_topic\": \"%s/%s%s\"," // aqualinkd/Aux_5,/brightness
|
||||
"\"brightness_scale\": 100,"
|
||||
"\"qos\": 1,"
|
||||
"\"retain\": false"
|
||||
"}";
|
||||
|
||||
// Need to add timer attributes to the switches, once figure out how to use in homeassistant
|
||||
// ie aqualinkd/Filter_Pump/timer/duration
|
||||
|
||||
|
@ -371,7 +390,20 @@ void publish_mqtt_hassio_discover(struct aqualinkdata *aqdata, struct mg_connect
|
|||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
(_aqconfig_.convert_mqtt_temp?HASSIO_CONVERT_CLIMATE_TOF:HASSIO_NO_CONVERT_CLIMATE));
|
||||
sprintf(topic, "%s/climate/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->aqbuttons[i].name);
|
||||
send_mqtt(nc, topic, msg);
|
||||
send_mqtt(nc, topic, msg);
|
||||
} else if ( isPLIGHT(aqdata->aqbuttons[i].special_mask) && ((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType == LC_DIMMER2 ) {
|
||||
// Dimmer
|
||||
sprintf(msg,HASSIO_DIMMER_DISCOVER,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
aqdata->aqbuttons[i].name,
|
||||
aqdata->aqbuttons[i].label,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,LIGHT_DIMMER_VALUE_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,LIGHT_DIMMER_VALUE_TOPIC);
|
||||
sprintf(topic, "%s/light/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->aqbuttons[i].name);
|
||||
send_mqtt(nc, topic, msg);
|
||||
} else {
|
||||
// Switches
|
||||
//sprintf(msg,"{\"type\": \"switch\",\"unique_id\": \"%s\",\"name\": \"%s\",\"state_topic\": \"aqualinkd/%s\",\"command_topic\": \"aqualinkd/%s/set\",\"json_attributes_topic\": \"aqualinkd/%s/delay\",\"json_attributes_topic\": \"aqualinkd/%s/delay\",\"json_attributes_template\": \"{{ {'delay': value|int} | tojson }}\",\"payload_on\": \"1\",\"payload_off\": \"0\",\"qos\": 1,\"retain\": false}" ,
|
||||
|
@ -461,20 +493,9 @@ void publish_mqtt_hassio_discover(struct aqualinkdata *aqdata, struct mg_connect
|
|||
|
||||
// VSP Pumps
|
||||
for (i=0; i < aqdata->num_pumps; i++) {
|
||||
int maxspeed=3450; // Min is 600
|
||||
int minspeed=600; // 600 as % of max
|
||||
char units[4];
|
||||
sprintf(units, "RPM");
|
||||
|
||||
if ( aqdata->pumps[i].pumpType == VFPUMP ) {
|
||||
maxspeed=130; // Min is 15
|
||||
minspeed=15; // 15 as % of max
|
||||
sprintf(units, "GPM");
|
||||
}
|
||||
char units[] = "Speed";
|
||||
// Create a FAN for pump against the button it' assigned to
|
||||
// In the future maybe change this to the pump# or change the sensors to button???
|
||||
// Need to change the max / min. These do NOT lomit the slider in hassio, only the MQTT limits.
|
||||
// So the 0-100% should be 600-3450 RPM and 15-130 GPM (ie 1% would = 600 & 0%=off)
|
||||
sprintf(msg, HASSIO_VSP_DISCOVER,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
aqdata->pumps[i].button->name,units,
|
||||
|
@ -483,9 +504,7 @@ void publish_mqtt_hassio_discover(struct aqualinkdata *aqdata, struct mg_connect
|
|||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name,units,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name,units,
|
||||
minspeed, minspeed, (maxspeed - minspeed),
|
||||
(maxspeed - minspeed), minspeed);
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name,units);
|
||||
|
||||
sprintf(topic, "%s/fan/aqualinkd/aqualinkd_%s_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->pumps[i].button->name, units);
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
|
|
@ -24,10 +24,14 @@
|
|||
#include "packetLogger.h"
|
||||
#include "iaqtouch.h"
|
||||
#include "iaqtouch_aq_programmer.h"
|
||||
#include "iaqualink.h"
|
||||
#include "aq_programmer.h"
|
||||
#include "rs_msg_utils.h"
|
||||
#include "devices_jandy.h"
|
||||
|
||||
|
||||
#define NEW_POLL_CYCLE
|
||||
|
||||
void temp_debugprintExtraInfo(unsigned char *pk, int length);
|
||||
|
||||
|
||||
|
@ -136,7 +140,7 @@ struct iaqt_page_button *iaqtFindButtonByIndex(int index) {
|
|||
struct iaqt_page_button *buttons;
|
||||
|
||||
// NSF Need to merge this from iaqtFindButtonByLabel function
|
||||
if (_currentPage == IAQ_PAGE_DEVICES)
|
||||
if (_currentPage == IAQ_PAGE_DEVICES || _currentPage == IAQ_PAGE_DEVICES_REV_Yg)
|
||||
buttons = _devicePageButtons[0];
|
||||
else if (_currentPage == IAQ_PAGE_DEVICES2)
|
||||
buttons = _devicePageButtons[1];
|
||||
|
@ -164,7 +168,7 @@ struct iaqt_page_button *iaqtFindButtonByLabel(const char *label) {
|
|||
int i;
|
||||
struct iaqt_page_button *buttons;
|
||||
|
||||
if (_currentPage == IAQ_PAGE_DEVICES)
|
||||
if (_currentPage == IAQ_PAGE_DEVICES || _currentPage == IAQ_PAGE_DEVICES_REV_Yg)
|
||||
buttons = _devicePageButtons[0];
|
||||
else if (_currentPage == IAQ_PAGE_DEVICES2)
|
||||
buttons = _devicePageButtons[1];
|
||||
|
@ -234,9 +238,9 @@ int char2iaqtRSset(unsigned char* packetbuffer, char *msg, int msg_len)
|
|||
return ++bcnt;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void createDeviceUpdatePacket() {
|
||||
unsigned char packets[AQ_MAXPKTLEN];
|
||||
unsigned char packets[AQ_MAXPKTLEN_SEND];
|
||||
int cnt;
|
||||
|
||||
packets[0] = DEV_MASTER;
|
||||
|
@ -253,6 +257,7 @@ void createDeviceUpdatePacket() {
|
|||
|
||||
//send_jandy_command(NULL, packets, cnt);
|
||||
}
|
||||
*/
|
||||
|
||||
void processPageMessage(unsigned char *message, int length)
|
||||
{
|
||||
|
@ -284,12 +289,73 @@ void processTableMessage(unsigned char *message, int length)
|
|||
LOG(IAQT_LOG,LOG_ERR, "Run out of IAQT table buffer, need %d have %d\n",(int)message[5],IAQ_MSG_TABLE_LINES);
|
||||
}
|
||||
|
||||
// aqualinkd button found and updated, AQstart & AQend are index of aqualinkd button array
|
||||
void updateAQButtonFromPageButton(struct aqualinkdata *aq_data, struct iaqt_page_button *pageButton, int AQstartIndex, int AQendIndex)
|
||||
{
|
||||
|
||||
for (int i = AQstartIndex; i < AQendIndex; i++)
|
||||
{
|
||||
//LOG(IAQT_LOG,LOG_DEBUG, "Button compare '%s' to '%s'\n",pageButton->name, aq_data->aqbuttons[i].label);
|
||||
|
||||
int rtn = -1;
|
||||
// If we are loading HOME page then simply button name is the label ie "Aux3"
|
||||
// If loading DEVICES? page then button name + status is "Aux3 OFF "
|
||||
if (_currentPageLoading == IAQ_PAGE_HOME)
|
||||
rtn = rsm_strmatch((const char *)pageButton->name, aq_data->aqbuttons[i].label);
|
||||
else
|
||||
rtn = rsm_strmatch_ignore((const char *)pageButton->name, aq_data->aqbuttons[i].label, 5); // 5 = 3 chars and 2 spaces ' OFF '
|
||||
|
||||
if (rtn == 0)
|
||||
{
|
||||
if (rtn == 0)
|
||||
{
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "*** Found Status for %s state 0x%02hhx\n", aq_data->aqbuttons[i].label, pageButton->state);
|
||||
switch(pageButton->state) {
|
||||
case 0x00:
|
||||
if (aq_data->aqbuttons[i].led->state != OFF) {
|
||||
aq_data->aqbuttons[i].led->state = OFF;
|
||||
aq_data->updated = true;
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
if (aq_data->aqbuttons[i].led->state != ON) {
|
||||
aq_data->aqbuttons[i].led->state = ON;
|
||||
aq_data->updated = true;
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
if (aq_data->aqbuttons[i].led->state != FLASH) {
|
||||
aq_data->aqbuttons[i].led->state = FLASH;
|
||||
aq_data->updated = true;
|
||||
}
|
||||
break;
|
||||
case 0x03:
|
||||
if (aq_data->aqbuttons[i].led->state != ENABLE) {
|
||||
aq_data->aqbuttons[i].led->state = ENABLE;
|
||||
aq_data->updated = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Dimmer light will have the % as the state. so 0x32=50% 0x4B=75%
|
||||
// So anything greater than 0 use as on
|
||||
if (pageButton->state > 0x00) {
|
||||
aq_data->aqbuttons[i].led->state = ON;
|
||||
aq_data->updated = true;
|
||||
}
|
||||
//LOG(IAQT_LOG,LOG_NOTICE, "Unknown state 0x%02hhx for button %s\n",pageButton->state,pageButton->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processPageButton(unsigned char *message, int length, struct aqualinkdata *aq_data)
|
||||
{
|
||||
struct iaqt_page_button *button;
|
||||
int index = (int)message[PKT_IAQT_BUTINDX];
|
||||
|
||||
if (_currentPageLoading == IAQ_PAGE_DEVICES)
|
||||
if (_currentPageLoading == IAQ_PAGE_DEVICES || _currentPageLoading == IAQ_PAGE_DEVICES_REV_Yg)
|
||||
button = &_devicePageButtons[0][index];
|
||||
else if (_currentPageLoading == IAQ_PAGE_DEVICES2)
|
||||
button = &_devicePageButtons[1][index];
|
||||
|
@ -328,8 +394,22 @@ void processPageButton(unsigned char *message, int length, struct aqualinkdata *
|
|||
|
||||
// This get's called or every device state change in PDA mode, since we page over all the devices.
|
||||
// So capture and update the device state
|
||||
if (isPDA_PANEL) {
|
||||
updateAQButtonFromPageButton(aq_data,button,0,aq_data->total_buttons);
|
||||
} else {
|
||||
#ifdef AQ_RS16
|
||||
if ( PANEL_SIZE() >= 16) {
|
||||
updateAQButtonFromPageButton(aq_data,button,aq_data->rs16_vbutton_start,aq_data->rs16_vbutton_end + 1);
|
||||
}
|
||||
#endif
|
||||
if ( isVirtualButtonEnabled() ) {
|
||||
updateAQButtonFromPageButton(aq_data,button,aq_data->virtual_button_start,aq_data->total_buttons);
|
||||
}
|
||||
}
|
||||
|
||||
if (isPDA_PANEL || PANEL_SIZE() >= 16 ) {
|
||||
/*
|
||||
// NSF Add virtual button support below. ( || aq_data->virtual_button_start > 0 )
|
||||
if (isPDA_PANEL || PANEL_SIZE() >= 16) {
|
||||
int start = 0;
|
||||
int end = aq_data->total_buttons;
|
||||
|
||||
|
@ -347,7 +427,7 @@ void processPageButton(unsigned char *message, int length, struct aqualinkdata *
|
|||
int rtn=-1;
|
||||
//LOG(IAQT_LOG,LOG_DEBUG, "Button compare '%s' to '%s'\n",button->name, aq_data->aqbuttons[i].label);
|
||||
// If we are loading HOME page then simply button name is the label ie "Aux3"
|
||||
// If loading DEVICES? page then button name + statusis "Aux3 OFF "
|
||||
// If loading DEVICES? page then button name + status is "Aux3 OFF "
|
||||
|
||||
if (_currentPageLoading == IAQ_PAGE_HOME)
|
||||
rtn = rsm_strmatch((const char *)button->name, aq_data->aqbuttons[i].label);
|
||||
|
@ -388,7 +468,7 @@ void processPageButton(unsigned char *message, int length, struct aqualinkdata *
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
|
||||
|
@ -417,15 +497,87 @@ void iaqt_pump_update(struct aqualinkdata *aq_data, int updated) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* Some newer revisions support pump by name and not number.
|
||||
Seen this is rev Yg
|
||||
|
||||
Info: iAQ Touch: Page: Status (diff ID) | 0x2a\
|
||||
Info: iAQ Touch: Status page 00| Filter Pump\
|
||||
Info: iAQ Touch: Status page 01| Spa Light\
|
||||
Info: iAQ Touch: Status page 02| Pool Light\
|
||||
Info: iAQ Touch: Status page 03| Pump 2248\ <--- This is the pump name.
|
||||
Info: iAQ Touch: Status page 04| RPM: 1350\
|
||||
Info: iAQ Touch: Status page 05| Watts: 176\
|
||||
Info: iAQ Touch: Status page 06| #1 AquaPure\
|
||||
|
||||
*/
|
||||
|
||||
pump_detail *matchPump(const logmask_t from, struct aqualinkdata *aq_data, char *name, int *pump_index)
|
||||
{
|
||||
int i;
|
||||
pump_detail *pump = NULL;
|
||||
int pi = 0;
|
||||
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Finding pump for message '%s'\n",name);
|
||||
|
||||
if (rsm_strcmp(name, "Intelliflo VS") == 0 ||
|
||||
rsm_strcmp(name, "Intelliflo VF") == 0 ||
|
||||
rsm_strcmp(name, "Jandy ePUMP") == 0 ||
|
||||
rsm_strcmp(name, "ePump AC") == 0)
|
||||
{
|
||||
pi = rsm_atoi(&name[14]);
|
||||
if (pi <= 0)
|
||||
pi = rsm_atoi(&name[10]); // ePump AC seems to display index in different position
|
||||
}
|
||||
|
||||
// Now loop over all the VSP pumps and check the name.
|
||||
for (i = 0; i < aq_data->num_pumps; i++)
|
||||
{
|
||||
if ((pi > 0 && aq_data->pumps[i].pumpIndex == pi) ||
|
||||
(rsm_strcmp(name, aq_data->pumps[i].pumpName) == 0))
|
||||
{
|
||||
*pump_index = i;
|
||||
pump = &aq_data->pumps[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Log a warning
|
||||
if (pi > 0)
|
||||
{
|
||||
if (pump == NULL)
|
||||
{
|
||||
LOG(from, LOG_WARNING, "Got pump message '%s' but can't find pump # %d, please update aqualinkd.conf\n", name, pi);
|
||||
}
|
||||
else if (pump->pumpType == PT_UNKNOWN)
|
||||
{
|
||||
if (rsm_strcmp(name, "Intelliflo VS") == 0)
|
||||
pump->pumpType = VSPUMP;
|
||||
else if (rsm_strcmp(name, "Intelliflo VF") == 0)
|
||||
pump->pumpType = VFPUMP;
|
||||
else if (rsm_strcmp(name, "Jandy ePUMP") == 0 ||
|
||||
rsm_strcmp(name, "ePump AC") == 0)
|
||||
pump->pumpType = EPUMP;
|
||||
}
|
||||
}
|
||||
|
||||
if (pump == NULL)
|
||||
LOG(from, LOG_DEBUG, "Did not find pump config for '%s'\n", name);
|
||||
else
|
||||
LOG(from, LOG_DEBUG, "Found pump '%s', Name='%s', 'Index='%d'\n", name, pump->pumpName, pump->pumpIndex);
|
||||
|
||||
return pump;
|
||||
}
|
||||
|
||||
void passDeviceStatusPage(struct aqualinkdata *aq_data)
|
||||
{
|
||||
int i;
|
||||
int pi;
|
||||
int pi = -2;
|
||||
pump_detail *pump = NULL;
|
||||
//bool found_swg = false;
|
||||
//int pump_index = 0;
|
||||
|
||||
for (i=0; i <IAQ_STATUS_PAGE_LINES; i++ ) {
|
||||
/*
|
||||
//LOG(IAQT_LOG,LOG_NOTICE, "Passing message %.2d| %s\n",i,_deviceStatus[i]);
|
||||
if (rsm_strcmp(_deviceStatus[i],"Intelliflo VS") == 0 ||
|
||||
rsm_strcmp(_deviceStatus[i],"Intelliflo VF") == 0 ||
|
||||
|
@ -458,8 +610,10 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data)
|
|||
|
||||
continue;
|
||||
|
||||
} else if (rsm_strcmp(_deviceStatus[i],"RPM:") == 0) {
|
||||
} else*/ if (rsm_strcmp(_deviceStatus[i],"RPM:") == 0) {
|
||||
pump = matchPump(IAQT_LOG, aq_data, _deviceStatus[i-1], &pi);
|
||||
if (pump != NULL) {
|
||||
iaqt_pump_update(aq_data, pi); // Log that we saw a pump
|
||||
pump->rpm = rsm_atoi(&_deviceStatus[i][9]);
|
||||
pump->pStatus = PS_OK;
|
||||
aq_data->updated = true;
|
||||
|
@ -483,7 +637,9 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data)
|
|||
LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
|
||||
continue;
|
||||
} else if (rsm_strcmp(_deviceStatus[i],"*** Priming ***") == 0) {
|
||||
pump = matchPump(IAQT_LOG, aq_data, _deviceStatus[i-1], &pi);
|
||||
if (pump != NULL) {
|
||||
iaqt_pump_update(aq_data, pi); // Log that we saw a pump
|
||||
//pump->rpm = PUMP_PRIMING; // NSF need to remove future
|
||||
pump->pStatus = PS_PRIMING;
|
||||
aq_data->updated = true;
|
||||
|
@ -491,7 +647,9 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data)
|
|||
LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
|
||||
continue;
|
||||
} else if (rsm_strcmp(_deviceStatus[i],"(Offline)") == 0) {
|
||||
pump = matchPump(IAQT_LOG, aq_data, _deviceStatus[i-1], &pi);
|
||||
if (pump != NULL) {
|
||||
iaqt_pump_update(aq_data, pi); // Log that we saw a pump
|
||||
//pump->rpm = PUMP_OFFLINE; // NSF need to remove future
|
||||
pump->pStatus = PS_OFFLINE;
|
||||
aq_data->updated = true;
|
||||
|
@ -499,7 +657,9 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data)
|
|||
LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
|
||||
continue;
|
||||
} else if (rsm_strcmp(_deviceStatus[i],"(Priming Error)") == 0) {
|
||||
pump = matchPump(IAQT_LOG, aq_data, _deviceStatus[i-1], &pi);
|
||||
if (pump != NULL) {
|
||||
iaqt_pump_update(aq_data, pi); // Log that we saw a pump
|
||||
//pump->rpm = PUMP_ERROR; // NSF need to remove future
|
||||
pump->pStatus = PS_ERROR;
|
||||
aq_data->updated = true;
|
||||
|
@ -556,7 +716,7 @@ void debugPrintButtons(struct iaqt_page_button buttons[])
|
|||
int i;
|
||||
for (i=0; i < IAQ_PAGE_BUTTONS; i++) {
|
||||
if (buttons[i].state != 0 || buttons[i].type != 0 || buttons[i].unknownByte != 0 || buttons[i].keycode != 0)
|
||||
LOG(IAQT_LOG,LOG_INFO, "Button %.2d| %21.21s | type=0x%02hhx | state=0x%02hhx | unknown=0x%02hhx | keycode=0x%02hhx\n",i,buttons[i].name,buttons[i].type,buttons[i].state,buttons[i].unknownByte,buttons[i].keycode);
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Button %.2d| %21.21s | type=0x%02hhx | state=0x%02hhx | unknown=0x%02hhx | keycode=0x%02hhx\n",i,buttons[i].name,buttons[i].type,buttons[i].state,buttons[i].unknownByte,buttons[i].keycode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -593,24 +753,28 @@ void processPage(struct aqualinkdata *aq_data)
|
|||
case IAQ_PAGE_DEVICES:
|
||||
case IAQ_PAGE_DEVICES2:
|
||||
case IAQ_PAGE_DEVICES3:
|
||||
case IAQ_PAGE_DEVICES_REV_Yg:
|
||||
if (_currentPage == IAQ_PAGE_DEVICES)
|
||||
dp = 0;
|
||||
else if (_currentPage == IAQ_PAGE_DEVICES_REV_Yg)
|
||||
dp = 0;
|
||||
else if (_currentPage == IAQ_PAGE_DEVICES2)
|
||||
dp = 1;
|
||||
else if (_currentPage == IAQ_PAGE_DEVICES3)
|
||||
dp = 2;
|
||||
//LOG(IAQT_LOG,LOG_INFO, "Devices Page #1:-\n");
|
||||
debugPrintButtons(_devicePageButtons[dp]);
|
||||
|
||||
#ifndef NEW_POLL_CYCLE
|
||||
// If Button 15 has type 0x02 then we have previous, if 0x00 nothing (previous send code KEY_IAQTCH_PREV_PAGE)
|
||||
// If Button 16 has type 0x03 then we have next, if 0x00 nothing (next send code KEY_IAQTCH_NEXT_PAGE)
|
||||
if ( (isPDA_PANEL || PANEL_SIZE() >= 16) && !in_iaqt_programming_mode(aq_data) ) {
|
||||
if ( (isPDA_PANEL || isVirtualButtonEnabled() || PANEL_SIZE() >= 16) && !in_iaqt_programming_mode(aq_data) ) {
|
||||
if (_devicePageButtons[dp][16].type == 0x03) {
|
||||
iaqt_queue_cmd(KEY_IAQTCH_NEXT_PAGE);
|
||||
} else {
|
||||
iaqt_queue_cmd(KEY_IAQTCH_STATUS);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case IAQ_PAGE_COLOR_LIGHT:
|
||||
//LOG(IAQT_LOG,LOG_INFO, "Color Light Page :-\n");
|
||||
|
@ -630,6 +794,15 @@ void processPage(struct aqualinkdata *aq_data)
|
|||
//Info: iAQ Touch: Home Status page 01| 72
|
||||
//Info: iAQ Touch: Home Status page 04| Spa Temp
|
||||
//Info: iAQ Touch: Home Status page 05| Air Temp
|
||||
// IF WE HAVE A PANEL WITH EXTRA PUMP & TEMP SENSOR, THEN WE GET DIFFERENT INFO.
|
||||
// We Need to code for both cases.
|
||||
//Info: iAQ Touch: Home Status page 00| 96 <- pool
|
||||
//Info: iAQ Touch: Home Status page 01| 96 <- air
|
||||
//Info: iAQ Touch: Home Status page 02| Spa Temp
|
||||
//Info: iAQ Touch: Home Status page 03| 95 <- spa temp
|
||||
//Info: iAQ Touch: Home Status page 04| Pool Temp
|
||||
//Info: iAQ Touch: Home Status page 05| Air Temp
|
||||
|
||||
if (isPDA_PANEL) { // Set temp if PDA panel
|
||||
if (rsm_strcmp(_homeStatus[5],"Air Temp") == 0) {
|
||||
aq_data->air_temp = atoi(_homeStatus[1]);
|
||||
|
@ -701,27 +874,64 @@ void processPage(struct aqualinkdata *aq_data)
|
|||
}
|
||||
}
|
||||
|
||||
#define REQUEST_STATUS_POLL_COUNT 50
|
||||
#define REQUEST_STATUS_POLL_COUNT 10
|
||||
|
||||
bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data)
|
||||
{
|
||||
static bool gotInit = false;
|
||||
static int cnt = 0;
|
||||
static int probesSinceLastPageCMD=0;
|
||||
static bool gotStatus = true;
|
||||
static char message[AQ_MSGLONGLEN + 1];
|
||||
bool fake_pageend = false;
|
||||
//char buff[1024];
|
||||
// NSF Take this out
|
||||
|
||||
/*
|
||||
if ( packet[3] != CMD_IAQ_POLL && getLogLevel(IAQT_LOG) >= LOG_DEBUG ) {
|
||||
//if ( getLogLevel(IAQT_LOG) >= LOG_DEBUG ) {
|
||||
char buff[1000];
|
||||
beautifyPacket(buff, packet, length, false);
|
||||
char buff[1024];
|
||||
beautifyPacket(buff, 1024, packet, length, true);
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Received message : %s", buff);
|
||||
}
|
||||
|
||||
|
||||
if (packet[PKT_CMD] == CMD_IAQ_PAGE_START) {
|
||||
}*/
|
||||
|
||||
// DEBUG for iAqualink
|
||||
/*
|
||||
if (_aqconfig_.enable_iaqualink) {
|
||||
if (packet[PKT_CMD] == CMD_IAQ_AUX_STATUS) {
|
||||
// Look at notes in iaqualink.c for how this packet is made up
|
||||
int start=packet[4];
|
||||
start = start + 5;
|
||||
for (int i = start; i < length-3; i=i) {
|
||||
int status=i;
|
||||
int labelstart=status+5;
|
||||
int labellen=packet[status+4];
|
||||
if (labelstart+labellen < length) {
|
||||
LOG(IAQT_LOG,LOG_NOTICE, "Label %.*s = %s, bit1=0x%02hhx bit2=0x%02hhx bit3=0x%02hhx bit4=0x%02hhx\n", labellen, &packet[labelstart], (packet[status]==0x00?"Off":"On "), packet[status],packet[status+1],packet[status+2],packet[status+3]);
|
||||
}
|
||||
i = labelstart + labellen;
|
||||
}
|
||||
|
||||
LOG(IAQT_LOG,LOG_NOTICE, "Pump %s, Spa %s, SWG %d, PumpRPM %d, PoolSP=%d, SpaSP=%d\n",
|
||||
aq_data->aqbuttons[0].led->state==OFF?"Off":"On ",
|
||||
aq_data->aqbuttons[1].led->state==OFF?"Off":"On ",
|
||||
aq_data->swg_percent,
|
||||
aq_data->pumps[0].rpm,
|
||||
aq_data->pool_htr_set_point,
|
||||
aq_data->spa_htr_set_point);
|
||||
} else if (packet[PKT_CMD] == 0x70){
|
||||
debuglogPacket(IAQT_LOG, packet, length, true, true);
|
||||
} else if (packet[PKT_CMD] == 0x71){
|
||||
debuglogPacket(IAQT_LOG, packet, length, true, true);
|
||||
}
|
||||
}*/
|
||||
if (packet[PKT_CMD] == CMD_IAQ_MAIN_STATUS ||
|
||||
packet[PKT_CMD] == CMD_IAQ_1TOUCH_STATUS ||
|
||||
packet[PKT_CMD] == CMD_IAQ_AUX_STATUS) {
|
||||
process_iaqualink_packet(packet, length, aq_data);
|
||||
}
|
||||
else if (packet[PKT_CMD] == CMD_IAQ_PAGE_START)
|
||||
{
|
||||
// Reset and messages on new page
|
||||
aq_data->last_display_message[0] = ' ';
|
||||
aq_data->last_display_message[1] = '\0';
|
||||
|
@ -738,7 +948,9 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd
|
|||
if (gotStatus == false)
|
||||
gotStatus = true;
|
||||
//[IAQ_STATUS_PAGE_LINES][AQ_MSGLEN+1];
|
||||
} else if (packet[PKT_CMD] == CMD_IAQ_PAGE_END) {
|
||||
}
|
||||
else if (packet[PKT_CMD] == CMD_IAQ_PAGE_END)
|
||||
{
|
||||
set_iaq_cansend(true);
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Turning IAQ SEND on\n");
|
||||
if (_currentPageLoading != NUL) {
|
||||
|
@ -828,6 +1040,18 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd
|
|||
//printf("***** iAqualink Touch STARTUP Message ******* \n");
|
||||
if (gotInit == false) {
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "STARTUP Message\n");
|
||||
|
||||
if (_aqconfig_.enable_iaqualink) {
|
||||
|
||||
// Below will not send 0x29 since queueGetProgramData takes presidance,
|
||||
//iaqt_queue_cmd(0x29);
|
||||
if (isPDA_PANEL) {
|
||||
_aqconfig_.extended_device_id2 = _aqconfig_.device_id + 112;
|
||||
} else {
|
||||
_aqconfig_.extended_device_id2 = _aqconfig_.extended_device_id + 112; // 0x70 in dec
|
||||
}
|
||||
LOG(IAQT_LOG,LOG_NOTICE, "Enabling iAqualink Protocol on 0x%02hhx\n",_aqconfig_.extended_device_id2);
|
||||
}
|
||||
//LOG(IAQT_LOG,LOG_ERR, "STARTUP REMOVED GET PANEL DATA FOR TESTING\n");
|
||||
queueGetProgramData(IAQTOUCH, aq_data);
|
||||
gotInit = true;
|
||||
|
@ -838,8 +1062,81 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd
|
|||
/*
|
||||
NEED TO ALTERNATE SEND KEY_IAQTCH_HOMEP_KEY08 KEY and KEY_IAQTCH_STATUS BELOW FOR PDA
|
||||
*/
|
||||
|
||||
// Standard ack/poll
|
||||
if (packet[3] == CMD_IAQ_POLL) {
|
||||
probesSinceLastPageCMD++;
|
||||
|
||||
#ifdef NEW_POLL_CYCLE
|
||||
/*
|
||||
// loop device/<pause>device1/device2/device3/status/home/<repeat>
|
||||
----------
|
||||
if not programming && poll packet {
|
||||
if home page end loaded {
|
||||
reset counter
|
||||
goto device page.
|
||||
}
|
||||
|
||||
if (counter 5 ) {
|
||||
if device goto device 1
|
||||
else if device1 goto device2
|
||||
else if device2 goto device3
|
||||
else if device3 goto status
|
||||
else if status goto Home
|
||||
}
|
||||
increase counter
|
||||
}*/
|
||||
if (in_programming_mode(aq_data) == false) {
|
||||
if (_currentPage == IAQ_PAGE_HOME) {
|
||||
iaqt_queue_cmd(KEY_IAQTCH_HOMEP_KEY08); // This is "other devices on/off" page
|
||||
cnt = 0;
|
||||
}
|
||||
//if ( (isPDA_PANEL || isVirtualButtonEnabled() || PANEL_SIZE() >= 16) && !in_iaqt_programming_mode(aq_data) ) {
|
||||
// Just sent Status Page request if none of the above are active
|
||||
//}
|
||||
// After we send devices page in above if statment, kick us through a loop of
|
||||
// devices devices1 devices2 devices2 status.
|
||||
uint8_t nextPageRequestKey = KEY_IAQTCH_HOME;
|
||||
|
||||
if (cnt++ > REQUEST_STATUS_POLL_COUNT) {
|
||||
switch(_currentPage) {
|
||||
case IAQ_PAGE_DEVICES:
|
||||
case IAQ_PAGE_DEVICES_REV_Yg:
|
||||
if (_devicePageButtons[0][16].type == 0x03)
|
||||
nextPageRequestKey = KEY_IAQTCH_NEXT_PAGE;
|
||||
else
|
||||
nextPageRequestKey = KEY_IAQTCH_STATUS;
|
||||
break;
|
||||
case IAQ_PAGE_DEVICES2:
|
||||
if (_devicePageButtons[1][16].type == 0x03)
|
||||
nextPageRequestKey = KEY_IAQTCH_NEXT_PAGE;
|
||||
else
|
||||
nextPageRequestKey = KEY_IAQTCH_STATUS;
|
||||
break;
|
||||
case IAQ_PAGE_DEVICES3:
|
||||
if (_devicePageButtons[1][16].type == 0x03)
|
||||
nextPageRequestKey = KEY_IAQTCH_NEXT_PAGE;
|
||||
else
|
||||
nextPageRequestKey = KEY_IAQTCH_STATUS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (probesSinceLastPageCMD > 3) {
|
||||
// Seems to be a bug with wifi device ghosting command on/off, kind-a looks like our page commands don;t take sometimes so wait.
|
||||
// This didn;t fix issue, but see
|
||||
iaqt_queue_cmd(nextPageRequestKey);
|
||||
probesSinceLastPageCMD=0;
|
||||
} else {
|
||||
LOG(IAQT_LOG, LOG_INFO, "Waiting to send next page cnt %d\n",probesSinceLastPageCMD);
|
||||
}
|
||||
}
|
||||
} else if (in_programming_mode(aq_data) == true) {
|
||||
// Set count to something close to max, so we will pull latest info once programming has finished.
|
||||
// This is good for VSP GPM programming as it takes number of seconds to register once finished programming.
|
||||
// -5 seems to be too quick for VSP/GPM so using 10
|
||||
cnt = REQUEST_STATUS_POLL_COUNT - 10;
|
||||
}
|
||||
#else
|
||||
//LOG(IAQT_LOG,LOG_DEBUG, "poll count %d\n",cnt);
|
||||
// Load status page every 50 messages
|
||||
if (cnt++ > REQUEST_STATUS_POLL_COUNT && in_programming_mode(aq_data) == false ) {
|
||||
|
@ -863,14 +1160,18 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd
|
|||
iaqt_queue_cmd(KEY_IAQTCH_STATUS);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
} else if (in_programming_mode(aq_data) == true) {
|
||||
// Set count to something close to above, so we will pull latest info once programming has finished.
|
||||
// This is goot for VSP GPM programming as it takes number of seconds to register once finished programming.
|
||||
// Set count to something close to max, so we will pull latest info once programming has finished.
|
||||
// This is good for VSP GPM programming as it takes number of seconds to register once finished programming.
|
||||
// -5 seems to be too quick for VSP/GPM so using 10
|
||||
cnt = REQUEST_STATUS_POLL_COUNT - 10;
|
||||
}
|
||||
|
||||
// On poll no need to kick programming threads
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
//debuglogPacket(IAQT_LOG ,packet, length);
|
||||
|
@ -968,6 +1269,15 @@ const char *iaqt_page_name(const unsigned char page)
|
|||
case IAQ_PAGE_HELP:
|
||||
return "Help Page";
|
||||
break;
|
||||
case IAQ_PAGE_SERVICEMODE:
|
||||
return "Service Mode";
|
||||
break;
|
||||
|
||||
// New stuff
|
||||
case IAQ_PAGE_DEVICES_REV_Yg:
|
||||
return "Devices (rev Yg)";
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf (_namebuf,"** Unknown 0x%02hhx **",page);
|
||||
return _namebuf;
|
||||
|
@ -1046,6 +1356,8 @@ void temp_debugprintExtraInfo(unsigned char *pk, int length)
|
|||
printf(" New Page | Other Devices\n");
|
||||
else if (pk[4] == IAQ_PAGE_DEVICES2)
|
||||
printf(" New Page | Other Devices page 2\n");
|
||||
else if (pk[4] == IAQ_PAGE_DEVICES_REV_Yg)
|
||||
printf(" New Page | Devices Panel REV Yg\n");
|
||||
else if (pk[4] == IAQ_PAGE_SET_TEMP)
|
||||
printf(" New Page | Set Temp\n");
|
||||
else if (pk[4] == IAQ_PAGE_MENU)
|
||||
|
|
|
@ -132,7 +132,7 @@ void send_aqt_cmd(unsigned char cmd)
|
|||
*
|
||||
*/
|
||||
|
||||
unsigned char _iaqt_control_cmd[AQ_MAXPKTLEN];
|
||||
unsigned char _iaqt_control_cmd[AQ_MAXPKTLEN_SEND];
|
||||
int _iaqt_control_cmd_len;
|
||||
|
||||
|
||||
|
@ -142,9 +142,9 @@ int ref_iaqt_control_cmd(unsigned char **cmd)
|
|||
*cmd = _iaqt_control_cmd;
|
||||
|
||||
if ( getLogLevel(IAQT_LOG) >= LOG_DEBUG ) {
|
||||
char buff[1000];
|
||||
char buff[1024];
|
||||
//sprintf("Sending control command:")
|
||||
beautifyPacket(buff, _iaqt_control_cmd, _iaqt_control_cmd_len, false);
|
||||
beautifyPacket(buff, 1024, _iaqt_control_cmd, _iaqt_control_cmd_len, false);
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Sending commandsed : %s\n", buff);
|
||||
}
|
||||
|
||||
|
@ -153,7 +153,7 @@ int ref_iaqt_control_cmd(unsigned char **cmd)
|
|||
|
||||
void rem_iaqt_control_cmd(unsigned char *cmd)
|
||||
{
|
||||
memset(_iaqt_control_cmd, 0, AQ_MAXPKTLEN * sizeof(unsigned char));
|
||||
memset(_iaqt_control_cmd, 0, AQ_MAXPKTLEN_SEND * sizeof(unsigned char));
|
||||
_iaqt_control_cmd_len = 0;
|
||||
}
|
||||
|
||||
|
@ -285,7 +285,7 @@ typedef enum {icct_setrpm, icct_settime, icct_setdate} iaqtControlCmdYype;
|
|||
|
||||
// Type is always 0 at the moment, haven't found any
|
||||
void queue_iaqt_control_command(iaqtControlCmdYype type, int num) {
|
||||
//unsigned char packets[AQ_MAXPKTLEN];
|
||||
//unsigned char packets[AQ_MAXPKTLEN_SEND];
|
||||
//int cnt;
|
||||
|
||||
if (waitfor_iaqt_ctrl_queue2empty() == false)
|
||||
|
@ -372,7 +372,8 @@ bool goto_iaqt_page(const unsigned char pageID, struct aqualinkdata *aq_data) {
|
|||
|
||||
if (pageID == IAQ_PAGE_DEVICES) {
|
||||
send_aqt_cmd(KEY_IAQTCH_HOMEP_KEY08);
|
||||
if (waitfor_iaqt_nextPage(aq_data) != IAQ_PAGE_DEVICES) {
|
||||
unsigned char page = waitfor_iaqt_nextPage(aq_data);
|
||||
if (page != IAQ_PAGE_DEVICES && page != IAQ_PAGE_DEVICES_REV_Yg) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find Device page\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -686,6 +687,7 @@ void *set_aqualink_iaqtouch_pump_rpm( void *ptr )
|
|||
char VSPstr[20];
|
||||
int structIndex;
|
||||
struct iaqt_page_button *button;
|
||||
char *pumpName = NULL;
|
||||
|
||||
//printf("**** program string '%s'\n",buf);
|
||||
|
||||
|
@ -694,6 +696,7 @@ void *set_aqualink_iaqtouch_pump_rpm( void *ptr )
|
|||
//int pumpRPM = atoi(&buf[2]);
|
||||
for (structIndex=0; structIndex < aq_data->num_pumps; structIndex++) {
|
||||
if (aq_data->pumps[structIndex].pumpIndex == pumpIndex) {
|
||||
pumpName = aq_data->pumps[structIndex].pumpName;
|
||||
if (aq_data->pumps[structIndex].pumpType == PT_UNKNOWN) {
|
||||
LOG(IAQT_LOG,LOG_ERR, "Can't set Pump RPM/GPM until type is known\n");
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
@ -707,8 +710,8 @@ void *set_aqualink_iaqtouch_pump_rpm( void *ptr )
|
|||
//int pumpRPM = atoi(&buf[2]);
|
||||
//int pumpIndex = 1;
|
||||
|
||||
// Just force to pump 1 for testing
|
||||
sprintf(VSPstr, "VSP%1d Spd ADJ",pumpIndex);
|
||||
|
||||
|
||||
// NSF Should probably check pumpRPM is not -1 here
|
||||
|
||||
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_IAQTOUCH_PUMP_RPM);
|
||||
|
@ -718,10 +721,17 @@ void *set_aqualink_iaqtouch_pump_rpm( void *ptr )
|
|||
if ( goto_iaqt_page(IAQ_PAGE_DEVICES, aq_data) == false )
|
||||
goto f_end;
|
||||
|
||||
sprintf(VSPstr, "VSP%1d Spd ADJ",pumpIndex);
|
||||
button = iaqtFindButtonByLabel(VSPstr);
|
||||
if (button == NULL && pumpName[0] != '\0') {
|
||||
// Try by name
|
||||
sprintf(VSPstr, "%s ADJ",pumpName);
|
||||
button = iaqtFindButtonByLabel(VSPstr);
|
||||
}
|
||||
|
||||
if (button == NULL) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find '%s' button on page setup\n", VSPstr);
|
||||
goto f_end;
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not Pump by index 'VSP%1d Spd ADJ' or by name '%s' button on page setup\n", pumpIndex, VSPstr);
|
||||
goto f_end;
|
||||
}
|
||||
|
||||
send_aqt_cmd(button->keycode);
|
||||
|
|
|
@ -0,0 +1,632 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "aq_serial.h"
|
||||
#include "aqualink.h"
|
||||
#include "iaqualink.h"
|
||||
#include "packetLogger.h"
|
||||
#include "aq_serial.h"
|
||||
#include "serialadapter.h"
|
||||
#include "rs_msg_utils.h"
|
||||
|
||||
#define IAQUA_QLEN 20
|
||||
|
||||
typedef struct iaqulnkcmd
|
||||
{
|
||||
unsigned char command[20];
|
||||
int length;
|
||||
} iaqualink_cmd;
|
||||
|
||||
iaqualink_cmd _iqaua_queue[IAQUA_QLEN];
|
||||
unsigned char _std_cmd[2];
|
||||
int _iaqua_q_length = 0;
|
||||
bool _aqua_last_cmdfrom_queue = false;
|
||||
|
||||
|
||||
unsigned char _cmd_readyCommand[] = {0x3f, 0x20};
|
||||
unsigned char _fullcmd[] = {0x00, 0x24, 0x73, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
|
||||
bool push_iaqualink_cmd(unsigned char *cmd, int length) {
|
||||
if (_iaqua_q_length >= IAQUA_QLEN ) {
|
||||
LOG(IAQL_LOG,LOG_ERR, "Queue overflow, last command ignored!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(_iqaua_queue[_iaqua_q_length].command, cmd, length);
|
||||
_iqaua_queue[_iaqua_q_length].length = length;
|
||||
_iaqua_q_length++;
|
||||
|
||||
LOG(IAQL_LOG, LOG_INFO, "Queue cmd, size %d, queu length=%d\n",length, _iaqua_q_length);
|
||||
|
||||
//LOG(IAQL_LOG,LOG_DEBUG, "Added to message queue, position %d 0x%02hhx|0x%02hhx|0x%02hhx|0x%02hhx\n",_rssa_q_length-1,_rssa_queue[_rssa_q_length-1][0],_rssa_queue[_rssa_q_length-1][1],_rssa_queue[_rssa_q_length-1][2],_rssa_queue[_rssa_q_length-1][3]);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//unsigned char *get_iaqualink_cmd(unsigned char source_message_type, unsigned char *dest_message, int *len) {
|
||||
int get_iaqualink_cmd(unsigned char source_message_type, unsigned char **dest_message) {
|
||||
|
||||
//LOG(IAQL_LOG, LOG_INFO, "Caculating cmd\n");
|
||||
|
||||
_aqua_last_cmdfrom_queue = false;
|
||||
|
||||
_std_cmd[0] = source_message_type;
|
||||
_std_cmd[1] = 0x00;
|
||||
*dest_message = _std_cmd;
|
||||
int len = 2;
|
||||
|
||||
if (source_message_type == 0x73 && _iaqua_q_length > 0)
|
||||
{ // Send big/long message
|
||||
if ( _iqaua_queue[0].length >= 19 ) {
|
||||
*dest_message = _iqaua_queue[0].command;
|
||||
len = _iqaua_queue[0].length;
|
||||
_aqua_last_cmdfrom_queue = true;
|
||||
} else {
|
||||
LOG(IAQL_LOG,LOG_WARNING,"Next command in queue is not full command, ignoring\n");
|
||||
}
|
||||
}
|
||||
else if (source_message_type == 0x53 && _iaqua_q_length > 0)
|
||||
{ // Send small command
|
||||
if ( _iqaua_queue[0].length <= 2 ) {
|
||||
*dest_message = _iqaua_queue[0].command;
|
||||
len = _iqaua_queue[0].length;
|
||||
_aqua_last_cmdfrom_queue = true;
|
||||
} else {
|
||||
LOG(IAQL_LOG,LOG_WARNING,"Next command in queue is too large, ignoring\n");
|
||||
LOG(IAQL_LOG,LOG_ERR,"Re sending get prepare frame\n");
|
||||
*dest_message = _cmd_readyCommand;
|
||||
}
|
||||
}
|
||||
|
||||
//LOG(IAQL_LOG, LOG_INFO, "Return cmd size %d\n",len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void remove_iaqualink_cmd() {
|
||||
if (_iaqua_q_length > 0 && _aqua_last_cmdfrom_queue == true) {
|
||||
LOG(IAQL_LOG,LOG_DEBUG, "Remove from message queue, length %d\n",_iaqua_q_length-1);
|
||||
memmove(&_iqaua_queue[0], &_iqaua_queue[1], (sizeof(iaqualink_cmd)) * _iaqua_q_length);
|
||||
_iaqua_q_length--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned char iAqalnkDevID(aqkey *button) {
|
||||
|
||||
// For the 3 actual vbuttons that exist, we have already set their codes so just return it with no conversion
|
||||
if ( ((button->special_mask & VIRTUAL_BUTTON) == VIRTUAL_BUTTON) && button->rssd_code != NUL ) {
|
||||
return button->rssd_code;
|
||||
}
|
||||
|
||||
switch (button->rssd_code) {
|
||||
case RS_SA_PUMP:
|
||||
return IAQ_PUMP;
|
||||
break;
|
||||
case RS_SA_SPA:
|
||||
return IAQ_SPA;
|
||||
break;
|
||||
case RS_SA_POOLHT:
|
||||
return IAQ_POOL_HTR;
|
||||
break;
|
||||
case RS_SA_SPAHT:
|
||||
return IAQ_SPA_HTR;
|
||||
break;
|
||||
case RS_SA_AUX1:
|
||||
return IAQ_AUX1;
|
||||
break;
|
||||
case RS_SA_AUX2:
|
||||
return IAQ_AUX2;
|
||||
break;
|
||||
case RS_SA_AUX3:
|
||||
return IAQ_AUX3;
|
||||
break;
|
||||
case RS_SA_AUX4:
|
||||
return IAQ_AUX4;
|
||||
break;
|
||||
case RS_SA_AUX5:
|
||||
return IAQ_AUX5;
|
||||
break;
|
||||
case RS_SA_AUX6:
|
||||
return IAQ_AUX6;
|
||||
break;
|
||||
case RS_SA_AUX7:
|
||||
return IAQ_AUX7;
|
||||
break;
|
||||
case RS_SA_AUX8:
|
||||
return IAQ_AUXB1;
|
||||
break;
|
||||
case RS_SA_AUX9:
|
||||
return IAQ_AUXB2;
|
||||
break;
|
||||
case RS_SA_AUX10:
|
||||
return IAQ_AUXB3;
|
||||
break;
|
||||
case RS_SA_AUX11:
|
||||
return IAQ_AUXB4;
|
||||
break;
|
||||
case RS_SA_AUX12:
|
||||
return IAQ_AUXB5;
|
||||
break;
|
||||
case RS_SA_AUX13:
|
||||
return IAQ_AUXB6;
|
||||
break;
|
||||
case RS_SA_AUX14:
|
||||
return IAQ_AUXB7;
|
||||
break;
|
||||
case RS_SA_AUX15:
|
||||
return IAQ_AUXB8;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
|
||||
void lastchecksum(unsigned char *packet, int length){
|
||||
static unsigned char last70checksum = 0x00;
|
||||
static unsigned char last71checksum = 0x00;
|
||||
static unsigned char last72checksum = 0x00;
|
||||
|
||||
switch (packet[PKT_CMD]){
|
||||
case 0x70:
|
||||
if (last70checksum != packet[length-3] && last70checksum != 0x00) {
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
LOG(IAQL_LOG, LOG_INFO,"******* CHECKSUM CHANGED for 0x70 *******\n");
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
}
|
||||
last70checksum = packet[length-3];
|
||||
break;
|
||||
case 0x71:
|
||||
if (last71checksum != packet[length-3] && last71checksum != 0x00) {
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
LOG(IAQL_LOG, LOG_INFO,"******* CHECKSUM CHANGED for 0x71 *******\n");
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
}
|
||||
last71checksum = packet[length-3];
|
||||
break;
|
||||
case 0x72:
|
||||
if (last72checksum != packet[length-3] && last72checksum != 0x00) {
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
LOG(IAQL_LOG, LOG_INFO,"******* CHECKSUM CHANGED for 0x72 *******\n");
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
}
|
||||
last72checksum = packet[length-3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
All taken from panel Yg, but only heater setpoints seem to work.
|
||||
Only setpoints seem to work,
|
||||
|
||||
Can't get to work on T2 panel
|
||||
RPM to 2750
|
||||
Bit 6 = 0x5e
|
||||
Bit 10 * 256 + Bit 11
|
||||
Bit 7 or 9 probably pump index.
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x0a|0xbe|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xd5|0x10|0x03|
|
||||
|
||||
RPM to 2995
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x0b|0xb3|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xcb|0x10|0x03|
|
||||
|
||||
|
||||
Can't get to work on T2 panel
|
||||
SWG 50%
|
||||
Byte 6 = 0x19
|
||||
Byte 7 = 50%
|
||||
Byte 9 & 10 ????
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x32|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x0e|0x10|0x03|
|
||||
|
||||
SWG 51%
|
||||
Byte 7 = 51%
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x33|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x0f|0x10|0x03|
|
||||
|
||||
Works on T2
|
||||
Spa Setpoint 102
|
||||
Byte 6 = 0x06
|
||||
Byte 8 = 0x66=102
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x06|0x00|0x66|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x16|0x10|0x03|
|
||||
|
||||
Works on T2
|
||||
Pool Setpoint 72
|
||||
Byte 6 = 0x05
|
||||
Byte 8 = 0x48=72
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x05|0x00|0x48|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xf7|0x10|0x03|
|
||||
|
||||
*/
|
||||
|
||||
|
||||
void set_iaqualink_aux_state(aqkey *button, bool isON) {
|
||||
|
||||
_fullcmd[4] = iAqalnkDevID(button);
|
||||
|
||||
if (_fullcmd[4] != 0xFF) {
|
||||
push_iaqualink_cmd(_cmd_readyCommand, 2);
|
||||
push_iaqualink_cmd(_fullcmd, 19);
|
||||
} else {
|
||||
LOG(IAQL_LOG, LOG_ERR, "Couldn't find iaqualink keycode for button %s\n",button->label);
|
||||
}
|
||||
|
||||
// reset
|
||||
_fullcmd[4] = 0x00;
|
||||
}
|
||||
|
||||
void set_iaqualink_heater_setpoint(int value, bool isPool) {
|
||||
|
||||
|
||||
if (isPool) {
|
||||
_fullcmd[4] = 0x05;
|
||||
} else {
|
||||
_fullcmd[4] = 0x06;
|
||||
}
|
||||
|
||||
// Should check value is valid here.
|
||||
_fullcmd[6] = value;
|
||||
|
||||
push_iaqualink_cmd(_cmd_readyCommand, 2);
|
||||
push_iaqualink_cmd(_fullcmd, 19);
|
||||
|
||||
// reset
|
||||
_fullcmd[4] = 0x00;
|
||||
_fullcmd[6] = 0x00;
|
||||
}
|
||||
|
||||
void iAqSetButtonState(struct aqualinkdata *aq_data, int index, const unsigned char byte)
|
||||
{
|
||||
if ( aq_data->aqbuttons[index].led->state != OFF && byte == 0x00) {
|
||||
aq_data->aqbuttons[index].led->state = OFF;
|
||||
LOG(IAQL_LOG, LOG_INFO, "Set %s off\n",aq_data->aqbuttons[index].label);
|
||||
} else if ( aq_data->aqbuttons[index].led->state != ON && byte == 0x01) {
|
||||
aq_data->aqbuttons[index].led->state = ON;
|
||||
LOG(IAQL_LOG, LOG_INFO, "Set %s on\n",aq_data->aqbuttons[index].label);
|
||||
} else if ( aq_data->aqbuttons[index].led->state != ENABLE && byte == 0x03) {
|
||||
aq_data->aqbuttons[index].led->state = ENABLE;
|
||||
LOG(IAQL_LOG, LOG_INFO, "Set %s enabled\n",aq_data->aqbuttons[index].label);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Status packets are requested on iAqualink ID 0xA? but received on AqualinkTouch ID 0x3?
|
||||
They are also sent when iAqualink is connected and a device changes.
|
||||
So good to catch in PDA mode when a physical iAqualink device is connected to PDA panel.
|
||||
packet has cmd of 0x70, 0x71, 0x72
|
||||
*/
|
||||
bool process_iAqualinkStatusPacket(unsigned char *packet, int length, struct aqualinkdata *aq_data)
|
||||
{
|
||||
if (packet[PKT_CMD] == CMD_IAQ_MAIN_STATUS)
|
||||
{
|
||||
logPacket(IAQL_LOG, LOG_INFO, packet, length, true);
|
||||
int startIndex = 4 + 1;
|
||||
int numberBytes = packet[4];
|
||||
int offsetIndex = startIndex + numberBytes;
|
||||
bool foundSpaSP = false;
|
||||
bool foundWaterTemp = false;
|
||||
bool foundAirTemp = false;
|
||||
|
||||
for (int i = 0; i <= numberBytes; i++)
|
||||
{
|
||||
int byteType = packet[5 + i];
|
||||
int byte = packet[offsetIndex + i];
|
||||
char *label;
|
||||
|
||||
// Some panels have blanks for the last 3 buys, the first of which is "water temp" (not sure on others 0x20, 0x21)
|
||||
// So if we saw 0x1d break loop if not force next as water temp.
|
||||
if (foundWaterTemp && i == numberBytes)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (i == numberBytes)
|
||||
{
|
||||
byteType = 0x1d;
|
||||
}
|
||||
|
||||
if (byteType == 0) {
|
||||
label = "Filter Pump ";
|
||||
if (isPDA_PANEL) { iAqSetButtonState(aq_data, 0, byte); }
|
||||
} else if (byteType == 1) {
|
||||
label = "Pool Heater "; // 0x00 off 0x01=on&heating, 0x03=enabled
|
||||
if (isPDA_PANEL) { iAqSetButtonState(aq_data, aq_data->pool_heater_index , byte); }
|
||||
} else if (byteType == 2) {
|
||||
label = "Spa ";
|
||||
} else if (byteType == 3) {
|
||||
label = "Spa Heater "; // 0x01=on&heating, 0x03=ena
|
||||
if (isPDA_PANEL) { iAqSetButtonState(aq_data, aq_data->spa_heater_index , byte); }
|
||||
} else if (byteType == 6) {
|
||||
label = "Pool Htr setpoint";
|
||||
} else if (byteType == 8 || byteType == 9) {// 8 usually, also get 9 & 14 (different spa/heater modes not sorted out yet. 14 sometimes blank as well)
|
||||
label = "Spa Htr setpoint ";
|
||||
foundSpaSP=true;
|
||||
} else if ( (/*byteType == 14 ||*/ byteType == 12) && foundSpaSP==false && byte != 0) {
|
||||
label = "Spa Htr setpoint ";
|
||||
} else if ( (byteType == 14 || byteType == 15 || byteType == 26) && byte != 0 && byte != 255 && foundAirTemp == false ) {// 0x0f
|
||||
label = "Air Temp "; // we also see this as 14 (RS16) ONLY
|
||||
foundAirTemp = true;
|
||||
} else if ( (byteType == 27 || byteType == 28 || byteType == 29) && byte != 0 && byte != 255 && foundWaterTemp == false) {
|
||||
// Last 3 bytes don't have type on some panels
|
||||
label = "Water Temp ";
|
||||
foundWaterTemp = true;
|
||||
}
|
||||
else
|
||||
label = " ";
|
||||
|
||||
LOG(IAQL_LOG, LOG_INFO, "%-17s = %3d | index=%d type=(%0.2d 0x%02hhx) value=0x%02hhx offset=%d\n", label, byte, i, byteType, byteType, byte, (offsetIndex + i));
|
||||
}
|
||||
LOG(IAQL_LOG, LOG_INFO, "Status from other protocols Pump %s, Spa %s, SWG %d, PumpRPM %d, PoolSP=%d, SpaSP=%d, WaterTemp=%d, AirTemp=%d\n",
|
||||
aq_data->aqbuttons[0].led->state == OFF ? "Off" : "On ",
|
||||
aq_data->aqbuttons[1].led->state == OFF ? "Off" : "On ",
|
||||
aq_data->swg_percent,
|
||||
aq_data->pumps[0].rpm,
|
||||
aq_data->pool_htr_set_point,
|
||||
aq_data->spa_htr_set_point,
|
||||
(aq_data->aqbuttons[1].led->state == OFF ? aq_data->pool_temp : aq_data->spa_temp),
|
||||
aq_data->air_temp);
|
||||
}
|
||||
else if (packet[PKT_CMD] == CMD_IAQ_1TOUCH_STATUS)
|
||||
{
|
||||
logPacket(IAQL_LOG, LOG_INFO, packet, length, true);
|
||||
int numLabels = packet[4];
|
||||
int start = numLabels + 4 + 1;
|
||||
|
||||
if (numLabels == 1)
|
||||
{
|
||||
// This just seem to list a ton of pump (names)
|
||||
LOG(IAQL_LOG, LOG_INFO, "**** !!! haven't decoded above packet yet !!! *****\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numLabels; i++)
|
||||
{
|
||||
int status = packet[start];
|
||||
int length = packet[start + 1];
|
||||
int byteType = packet[5 + i];
|
||||
LOG(IAQL_LOG, LOG_INFO, "%-15.*s = %s | index %d type=(%0.2d 0x%02hhx) status=0x%02hhx start=%d length=%d\n", length, &packet[start + 2], (status == 0x00 ? "Off" : "On "), i, byteType, byteType, status, start, length);
|
||||
// Check against virtual onetouch buttons.
|
||||
for (int bi=aq_data->virtual_button_start ; bi < aq_data->total_buttons ; bi++) {
|
||||
if (rsm_strcmp((char *)&packet[start + 2], aq_data->aqbuttons[bi].label) == 0) {
|
||||
//LOG(IAQL_LOG, LOG_INFO, "Status for %s is %s\n",aq_data->aqbuttons[bi].label,(status == 0x00 ? "Off" : "On "));
|
||||
// == means doesn;t match, RS 1=on 0=off / LED enum 1=off 0=on
|
||||
if (aq_data->aqbuttons[bi].led->state == status) {
|
||||
LOG(IAQL_LOG, LOG_INFO, "Updated Status for %s is %s\n",aq_data->aqbuttons[bi].label,(status == 0x00 ? "Off" : "On "));
|
||||
aq_data->aqbuttons[bi].led->state = (status == 0x00 ? OFF:ON);
|
||||
aq_data->updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
start = start + packet[start + 1] + 2;
|
||||
}
|
||||
}
|
||||
else if (packet[PKT_CMD] == CMD_IAQ_AUX_STATUS)
|
||||
{
|
||||
logPacket(IAQL_LOG, LOG_INFO, packet, length, true);
|
||||
// Look at notes in iaqualink.c for how this packet is made up
|
||||
// Since this is so similar to above CMD_IAQ_1TOUCH_STATUS, we should look at using same logic for both.
|
||||
int start = packet[4];
|
||||
start = start + 5;
|
||||
for (int i = start; i < length - 3; i = i)
|
||||
{
|
||||
int status = i;
|
||||
int labelstart = status + 5;
|
||||
int labellen = packet[status + 4];
|
||||
if (labelstart + labellen < length)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "%-15.*s = %s | bit1=0x%02hhx bit2=0x%02hhx bit3=0x%02hhx bit4=0x%02hhx\n", labellen, &packet[labelstart], (packet[status] == 0x00 ? "Off" : "On "), packet[status], packet[status + 1], packet[status + 2], packet[status + 3]);
|
||||
}
|
||||
if (isPDA_PANEL) {
|
||||
for (int bi=2 ; bi < aq_data->total_buttons ; bi++) {
|
||||
if (rsm_strcmp((char *)&packet[labelstart], aq_data->aqbuttons[bi].label) == 0) {
|
||||
if (aq_data->aqbuttons[bi].led->state == packet[status]) {
|
||||
LOG(IAQL_LOG, LOG_INFO, "Updated Status for %s is %s\n",aq_data->aqbuttons[bi].label,(packet[status] == 0x00 ? "Off" : "On "));
|
||||
aq_data->aqbuttons[bi].led->state = (packet[status] == 0x00 ? OFF:ON);
|
||||
aq_data->updated = true;
|
||||
}
|
||||
//LOG(IAQL_LOG, LOG_INFO, "Match %s to %.*s state(aqd=%d pnl=%d)\n",aq_data->aqbuttons[bi].label, labellen, (char *)&packet[labelstart], aq_data->aqbuttons[bi].led->state, packet[status]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = labelstart + labellen;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool process_iaqualink_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data)
|
||||
{
|
||||
|
||||
lastchecksum(packet, length);
|
||||
|
||||
unsigned char cmd_getMainstatus[] = {0x3f, 0x08};
|
||||
unsigned char cmd_getTouchstatus[] = {0x3f, 0x10};
|
||||
unsigned char cmd_getAuxstatus[] = {0x3f, 0x18};
|
||||
//unsigned char cmd_readyCommand[] = {0x3f, 0x20};
|
||||
//unsigned char fullcmd[] = {0x00, 0x24, 0x73, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
// byte 4 is ID. 0x00 pump, 0x02 spa etc
|
||||
|
||||
|
||||
if (packet[PKT_DEST] == _aqconfig_.extended_device_id2)
|
||||
{
|
||||
static int cnt = 0;
|
||||
//static unsigned char ID = 0;
|
||||
//static cur_swg = 0;
|
||||
static unsigned char sendid = 0x00;
|
||||
|
||||
if (packet[PKT_CMD] == 0x53)
|
||||
{
|
||||
cnt++;
|
||||
if (cnt == 20) {
|
||||
cnt=0;
|
||||
/*
|
||||
sendid=sendid==0x18?0x60:0x18;
|
||||
_fullcmd[4] = sendid;
|
||||
push_iaqualink_cmd(_cmd_readyCommand, 2);
|
||||
push_iaqualink_cmd(_fullcmd, 19);
|
||||
_fullcmd[4] = 0x00;
|
||||
*/
|
||||
push_iaqualink_cmd(cmd_getMainstatus, 2);
|
||||
push_iaqualink_cmd(cmd_getTouchstatus, 2);
|
||||
push_iaqualink_cmd(cmd_getAuxstatus, 2);
|
||||
/*
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
LOG(IAQL_LOG, LOG_INFO,"********** Send %d 0x%02hhx ************\n",ID,ID);
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
|
||||
_fullcmd[4] = ID++;
|
||||
push_iaqualink_cmd(_cmd_readyCommand, 2);
|
||||
push_iaqualink_cmd(_fullcmd, 19);
|
||||
|
||||
push_iaqualink_cmd(cmd_getMainstatus, 2);
|
||||
push_iaqualink_cmd(cmd_getTouchstatus, 2);
|
||||
push_iaqualink_cmd(cmd_getAuxstatus, 2);
|
||||
|
||||
push_iaqualink_cmd(_cmd_readyCommand, 2);
|
||||
push_iaqualink_cmd(_fullcmd, 19);
|
||||
*/
|
||||
|
||||
//fullcmd[4] = ID;
|
||||
//fullcmd[4] = ID;
|
||||
//fullcmd[5] = 0x32;
|
||||
|
||||
//fullcmd[7] = ID;
|
||||
//fullcmd[8] = 0x01;
|
||||
|
||||
|
||||
//set_iaqualink_heater_setpoint(50, true);
|
||||
|
||||
//push_iaqualink_cmd(cmd_getMainstatus, 2);
|
||||
//push_iaqualink_cmd(cmd_getTouchstatus, 2);
|
||||
//push_iaqualink_cmd(cmd_getAuxstatus, 2);
|
||||
/*
|
||||
if (aq_data->swg_percent != cur_swg && cur_swg != 0) {
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
LOG(IAQL_LOG, LOG_INFO,"********** SWG Changed to %d ************\n",aq_data->swg_percent);
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
exit(0);
|
||||
}
|
||||
cur_swg = aq_data->swg_percent;
|
||||
LOG(IAQL_LOG, LOG_INFO,"******* QUEUE SWG Comand of %d | 0x%02hhx *************\n",ID,ID);
|
||||
ID++;*/
|
||||
|
||||
}
|
||||
}
|
||||
// Packets sent to iAqualink protocol
|
||||
// debuglogPacket(IAQL_LOG, packet, length, true, true);
|
||||
}
|
||||
else if (packet[PKT_DEST] == _aqconfig_.extended_device_id || (isPDA_PANEL && packet[PKT_DEST] == _aqconfig_.device_id) )
|
||||
{
|
||||
process_iAqualinkStatusPacket(packet, length, aq_data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DONOTCOMPILE
|
||||
|
||||
// This is onle here temporarly until we figure out the protocol.
|
||||
void send_iaqualink_ack(int rs_fd, unsigned char *packet_buffer)
|
||||
{
|
||||
/*
|
||||
Probe | HEX: 0x10|0x02|0xa3|0x00|0xb5|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
Unknown '0x61' | HEX: 0x10|0x02|0xa3|0x61|0x00|0x00|0x00|0x04|0x00|0x27|0x41|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x61|0x00|0x74|0x10|0x03|
|
||||
Unknown '0x50' | HEX: 0x10|0x02|0xa3|0x50|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x00|0x25|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x50|0x00|0x63|0x10|0x03|
|
||||
Unknown '0x51' | HEX: 0x10|0x02|0xa3|0x51|0x00|0x06|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x51|0x00|0x64|0x10|0x03|
|
||||
Unknown '0x59' | HEX: 0x10|0x02|0xa3|0x59|0x00|0x0e|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x59|0x00|0x6c|0x10|0x03|
|
||||
Unknown '0x52' | HEX: 0x10|0x02|0xa3|0x52|0x00|0x07|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x52|0x00|0x65|0x10|0x03|
|
||||
Unknown '0x53' | HEX: 0x10|0x02|0xa3|0x53|0x08|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x3f|0x00|0x52|0x10|0x03|
|
||||
Use byte 3 as return ack, except for 0x53=0x3f
|
||||
*/
|
||||
if (packet_buffer[PKT_CMD] == CMD_PROBE)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "Got probe on '0x%02hhx' 2nd iAqualink Protocol\n", packet_buffer[PKT_DEST]);
|
||||
send_extended_ack(rs_fd, packet_buffer[PKT_CMD], 0x00);
|
||||
}
|
||||
else if (packet_buffer[PKT_CMD] == 0x53)
|
||||
{
|
||||
static int cnt = 0;
|
||||
cnt++;
|
||||
if (cnt == 10)
|
||||
{
|
||||
//cnt = 5;
|
||||
LOG(IAQL_LOG, LOG_INFO, "Sent accept next packet Comand\n");
|
||||
send_extended_ack(rs_fd, 0x3f, 0x20);
|
||||
}
|
||||
if (cnt == 20)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "Sending get status\n");
|
||||
send_extended_ack(rs_fd, 0x3f, 0x08);
|
||||
}
|
||||
else if (cnt == 22)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "Sending get other status\n");
|
||||
send_extended_ack(rs_fd, 0x3f, 0x10);
|
||||
}
|
||||
else if (cnt == 24)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "Sending get aux button status\n");
|
||||
send_extended_ack(rs_fd, 0x3f, 0x18);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use 0x3f
|
||||
if (cnt > 24)
|
||||
{
|
||||
cnt = 0;
|
||||
}
|
||||
send_extended_ack(rs_fd, 0x3f, 0x00);
|
||||
}
|
||||
// send_jandy_command(rs_fd, get_rssa_cmd(packet_buffer[PKT_CMD]), 4);
|
||||
}
|
||||
else if (packet_buffer[PKT_CMD] == 0x73)
|
||||
{
|
||||
static int id = 10;
|
||||
// unsigned char pb1[] = {PCOL_JANDY,0x10,0x02,0x00,0x24,0x73,0x01,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0x10,0x03,0x00};
|
||||
// unsigned char pb2[] = {PCOL_JANDY,0x10,0x02,0x00,0x24,0x73,0x01,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcb,0x10,0x03,0x00};
|
||||
// 0x21 turns on filter_pump and aux 1
|
||||
//unsigned char pb3[] = {0x00, 0x24, 0x73, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
unsigned char swg[] = {0x00, 0x24, 0x73, 0x01, 0x19, 0x32, 0x00, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
//unsigned char swg[] = {0x00, 0x24, 0x73, 0x01, 0x19, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
unsigned char rpm[] = {0x00,0x24,0x73,0x01,0x5e,0x04,0x00,0x01,0x0a,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd5,0x10,0x03};
|
||||
//pb3[4] = id++;
|
||||
//swg[5] = ++id;
|
||||
|
||||
LOG(IAQL_LOG, LOG_INFO, "*** Sending SWG dec=%d hex=0x%02hhx\n", swg[5], swg[5]);
|
||||
// send_packet(rs_fd, pb2, 25);
|
||||
send_jandy_command(rs_fd, swg, 19);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use packet_buffer[PKT_CMD]
|
||||
send_extended_ack(rs_fd, packet_buffer[PKT_CMD], 0x00);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,378 @@
|
|||
|
||||
#ifndef AQ_IAQUALINK_H_
|
||||
#define AQ_IAQUALINK_H_
|
||||
|
||||
//void send_iaqualink_ack(int rs_fd, unsigned char *packet_buffer);
|
||||
|
||||
int get_iaqualink_cmd(unsigned char source_message_type, unsigned char **dest_message);
|
||||
void remove_iaqualink_cmd();
|
||||
|
||||
bool process_iaqualink_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data);
|
||||
bool process_iAqualinkStatusPacket(unsigned char *packet, int length, struct aqualinkdata *aq_data);
|
||||
|
||||
void set_iaqualink_aux_state(aqkey *button, bool isON);
|
||||
void set_iaqualink_heater_setpoint(int value, bool isPool);
|
||||
|
||||
// Send the below commands to turn on/off (toggle)
|
||||
// This is the button in pButton. (byte 6 in below)
|
||||
// iAq pButton | HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x21|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xcb|0x10|0x03|
|
||||
|
||||
#define IAQ_PUMP 0x00
|
||||
#define IAQ_POOL_HTR 0x01
|
||||
#define IAQ_SPA 0x02
|
||||
#define IAQ_SPA_HTR 0x03
|
||||
//....... some missing ....
|
||||
#define IAQ_ALL_OFF 0x10 // Not sure on this
|
||||
#define IAQ_SPA_MODE 0x11
|
||||
#define IAQ_CLEAN_MODE 0x12
|
||||
|
||||
#define IAD_SWG 0x19
|
||||
//....... some missing ....
|
||||
#define IAQ_AUX1 0x21 //0x25 RS16 & 12 // AUX5
|
||||
#define IAQ_AUX2 0x22 //0x26 RS16
|
||||
#define IAQ_AUX3 0x23 //0x27 RS16
|
||||
#define IAQ_AUX4 0x24 //0x28 RS16
|
||||
#define IAQ_AUX5 0x25 //0x29 RS16
|
||||
#define IAQ_AUX6 0x26 //0x2a RS16
|
||||
#define IAQ_AUX7 0x27 //0x2b RS16
|
||||
#define IAQ_AUXB1 0x28 //0x2c RS16
|
||||
#define IAQ_AUXB2 0x29 //0x2d RS16
|
||||
#define IAQ_AUXB3 0x2a //0x2e RS16
|
||||
#define IAQ_AUXB4 0x2b //0x2f RS16
|
||||
#define IAQ_AUXB5 0x2c //0x30 RS16
|
||||
#define IAQ_AUXB6 0x2d //0x31 RS16
|
||||
#define IAQ_AUXB7 0x2e //0x32 RS16
|
||||
#define IAQ_AUXB8 0x2f //0x33 RS16
|
||||
/*
|
||||
#define IAQ_AUX1 0x25 //0x25 RS16 & 12 // AUX5
|
||||
#define IAQ_AUX2 0x26 //0x26 RS16
|
||||
#define IAQ_AUX3 0x27 //0x27 RS16
|
||||
#define IAQ_AUX4 0x28 //0x28 RS16
|
||||
#define IAQ_AUX5 0x29 //0x29 RS16
|
||||
#define IAQ_AUX6 0x2a //0x2a RS16
|
||||
#define IAQ_AUX7 0x2b //0x2b RS16
|
||||
#define IAQ_AUXB1 0x2c //0x2c RS16
|
||||
#define IAQ_AUXB2 0x2d //0x2d RS16
|
||||
#define IAQ_AUXB3 0x2e //0x2e RS16
|
||||
#define IAQ_AUXB4 0x2f //0x2f RS16
|
||||
#define IAQ_AUXB5 0x30 //0x30 RS16
|
||||
#define IAQ_AUXB6 0x31 //0x31 RS16
|
||||
#define IAQ_AUXB7 0x32 //0x32 RS16
|
||||
#define IAQ_AUXB8 0x33 //0x33 RS16
|
||||
*/
|
||||
//... Looks like there are C & D buttons
|
||||
/* I got this when sending dec=53 hex=0x35 as the button, all of a sudden got extra buttons in the aux status message send to AqualinkTouch protocol
|
||||
Not sure on ordering BUT dec=57 hex=0x39 = button D2 / dec=58 hex=0x3a = D3
|
||||
Notice: iAQ Touch: Label Aux C1 = On
|
||||
Notice: iAQ Touch: Label Aux C2 = Off
|
||||
Notice: iAQ Touch: Label Aux C3 = Off
|
||||
Notice: iAQ Touch: Label Aux C4 = Off
|
||||
Notice: iAQ Touch: Label Aux C5 = Off
|
||||
Notice: iAQ Touch: Label Aux C6 = On
|
||||
Notice: iAQ Touch: Label Aux C7 = On
|
||||
Notice: iAQ Touch: Label Aux C8 = On
|
||||
Notice: iAQ Touch: Label Aux D1 = On
|
||||
Notice: iAQ Touch: Label Aux D2 = On
|
||||
Notice: iAQ Touch: Label Aux D3 = On
|
||||
Notice: iAQ Touch: Label Aux D4 = On
|
||||
Notice: iAQ Touch: Label Aux D5 = On
|
||||
Notice: iAQ Touch: Label Aux D6 = On
|
||||
Notice: iAQ Touch: Label Aux D7 = On
|
||||
Notice: iAQ Touch: Label Aux D8 = On
|
||||
*/
|
||||
#define IAQ_AUXD2 0x39
|
||||
#define IAQ_AUXD3 0x3a // 58 in dec
|
||||
#define IAQ_AUXD4 // 59 in dec
|
||||
#define IAQ_AUXD5 // 60 in dec
|
||||
#define IAQ_AUXD6 // 61 in dec
|
||||
#define IAQ_AUXD7 // 62 in dec
|
||||
#define IAQ_AUXD8 // 63 in dec (but this is VAUX1)
|
||||
//... Need to add Vitrual buttons...
|
||||
#define IAQ_VAUX1 0x3f
|
||||
|
||||
#define IAQ_PUMP_RPM 0x5e
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Read Jandy packet To 0xa3 of type Unknown '0x53' | HEX: 0x10|0x02|0xa3|0x53|0x08|0x10|0x03|
|
||||
Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x3f|0x00|0x52|0x10|0x03|
|
||||
|
||||
|
||||
Below get's sent to AqualinkTouch with iAqualink is enabled.
|
||||
End of message is board cpu and panel type.
|
||||
Read Jandy packet To 0x33 of type Unknown '0x70' | HEX: 0x10|0x02|0x33|0x70|0x0d|0x00|0x01|0x02|0x03|0x05|0x06|0x07|0x0e|0x0f|0x1a|0x1d|0x20|0x21|0x00|0x00|0x00|0x00|0x00|0x48|0x00|0x66|0x00|0x50|0x00|0x00|0x00|0xff|0x42|0x30|0x33|0x31|0x36|0x38|0x32|0x33|0x20|0x52|0x53|0x2d|0x34|0x20|0x43|0x6f|0x6d|0x62|0x6f|0x00|0x00|0x4b|0x10|0x03|
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
----
|
||||
Retrieve poll 0x53
|
||||
Reply ack w/ command 0x01|0x3f|0x20. (0x20 command)
|
||||
Retrieve 0x73 command Same ID iAqualink
|
||||
Reply iAQ pButton ( turn something on / set something)
|
||||
|
||||
Retrieve poll 0x53
|
||||
Reply ack w/ command 0x01|0x3f|0x08. (0x08 command)
|
||||
Retrieve 0x70 command on AqualinkTouch ID
|
||||
Reply iAQ pButton (status / last part of frame is board cpu)
|
||||
-- Byte 4 = offset.
|
||||
-- Byte 21 look like spa heat 0x00=off, 0x03=enabled
|
||||
-- offest+ 8 spa setpoint
|
||||
-- offset+ 10 air temp
|
||||
-- offest+ 13 pool temp
|
||||
-- offset+ 14 SWG% ?????
|
||||
-- Byte 27 looks like air temp
|
||||
-- Byte 28 air temp????
|
||||
-- Byte 30 pool temp
|
||||
-- Byte 34 looks like SWG%
|
||||
-- after byte 0xff is board
|
||||
|
||||
Retrieve poll 0x53
|
||||
Reply ack w/ command 0x01|0x3f|0x10. (0x10 command)
|
||||
Retrieve 0x71 command on AqualinkTouch ID
|
||||
Reply iAQ pButton (not sure)
|
||||
Byte 4 & 5 seems to indicate a different sub type
|
||||
0x71|0x01|0x19 = status about pool / spa / speed 1,2,3,4 / pool & spa heat
|
||||
0x71|0x01|0x1a = no idea
|
||||
0x71|0x01|0x17 = Pump numbers (doesn't seem to have any status, just pump names)
|
||||
|
||||
0x71|0x06|0x01 = Touch like spa mode / all off
|
||||
0x71|0x07|0x01 = Same as above. but more trailing packets.
|
||||
|
||||
Retrieve poll 0x53
|
||||
Reply ack w/ command 0x3f 0x18. (0x18 is command)
|
||||
Retrieve 0x72 command on AqualinkTouch ID
|
||||
Get a massive packet Aux status
|
||||
|
||||
----
|
||||
|
||||
Retrieve poll 0x53
|
||||
Reply ack w/ command 0x01|0x3f|0x20. (0x20 command)
|
||||
Retrieve 0x72 command
|
||||
Reply iAQ pButton (turn something on / set something). Below are examples.
|
||||
|
||||
RPM to 2750
|
||||
Bit 10 * 256 + Bit 11
|
||||
Bit 6 & 7 probably pump index.
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x0a|0xbe|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xd5|0x10|0x03|
|
||||
|
||||
RPM to 2995
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x0b|0xb3|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xcb|0x10|0x03|
|
||||
|
||||
SWG 50%
|
||||
Byte 7 = 50%
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x32|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x0e|0x10|0x03|
|
||||
|
||||
SWG 51%
|
||||
Byte 7 = 51%
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x33|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x0f|0x10|0x03|
|
||||
|
||||
---------
|
||||
|
||||
Send command 0x18 to 0xa1 returns below to 0x31. Looks like status of aux devices.
|
||||
Retrieve poll 0x53
|
||||
Reply ack w/ command 0x3f 0x18. (0x18 is command)
|
||||
Get a massive packet back, of aux status
|
||||
|
||||
Filter pump does not effect the below.
|
||||
Heater on/off does not effect below.
|
||||
HEater setpoints does not effect.
|
||||
Only Aux on/off seem to effect the status.
|
||||
|
||||
4th bit tells you where to start,
|
||||
after start 4 bits are status
|
||||
last bit of status tell you chars in label.
|
||||
after label repeat start 4 bits.
|
||||
|
||||
For Aux1 10th bit 0=off 1=on 11 to 14 15 to 19=name
|
||||
Aux2 19th
|
||||
Aux3 28
|
||||
Aux4 37
|
||||
|
||||
In Below Aux 3 color light / Aux 4 dimmer / Aux 5 color light (different type to aux3)
|
||||
|
||||
Aux 1 off / Aux 3 on
|
||||
HEX: 0x10|0x02|0x31|0x72|0x05|0x01|0x02|0x03|0x04|0x05|0x00|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x31|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x32|0x01|0x07|0x02|0x03|0x04|0x41|0x75|0x78|0x33|0x00|0x01|0x01|0x00|0x04|0x41|0x75|0x78|0x34|0x00|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x35|0xd5|0x10|0x03|
|
||||
Dec | 16| 2| 49| 114| 5| 1| 2| 3| 4| 5| 0| 1| 0| 0| 4| 65| 117| 120| 49| 1| 1| 0| 0| 4| 65| 117| 120| 50| 1| 7| 2| 3| 4| 65| 117| 120| 51| 0| 1| 1| 0| 4| 65| 117| 120| 52| 0| 1| 0| 0| 4| 65| 117| 120| 53| 213| 16| 3
|
||||
Ascii | | | 1| r| | | | | | | | | | | | A| u| x| 1| | | | | | A| u| x| 2| | | | | | A| u| x| 3| | | | | | A| u| x| 4| | | | | | A| u| x| 5| | |
|
||||
|
||||
Aux 1 on / Aux 3 on
|
||||
| HEX: 0x10|0x02|0x31|0x72|0x05|0x01|0x02|0x03|0x04|0x05|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x31|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x32|0x01|0x07|0x02|0x03|0x04|0x41|0x75|0x78|0x33|0x00|0x01|0x01|0x00|0x04|0x41|0x75|0x78|0x34|0x00|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x35|0xd6|0x10|0x03|
|
||||
Dec | 16| 2| 49| 114| 5| 1| 2| 3| 4| 5| 1| 1| 0| 0| 4| 65| 117| 120| 49| 1| 1| 0| 0| 4| 65| 117| 120| 50| 1| 7| 2| 3| 4| 65| 117| 120| 51| 0| 1| 1| 0| 4| 65| 117| 120| 52| 0| 1| 0| 0| 4| 65| 117| 120| 53| 214| 16| 3
|
||||
Ascii | | | 1| r| | | | | | | | | | | | A| u| x| 1| | | | | | A| u| x| 2| | | | | | A| u| x| 3| | | | | | A| u| x| 4| | | | | | A| u| x| 5| | |
|
||||
|
||||
Aux 1 off Aux3 to different light color
|
||||
Hex |0x10|0x02|0x31|0x72|0x05|0x01|0x02|0x03|0x04|0x05|0x00|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x31|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x32|0x00|0x07|0x02|0x03|0x04|0x41|0x75|0x78|0x33|0x00|0x01|0x01|0x00|0x04|0x41|0x75|0x78|0x34|0x00|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x35|0xd4|0x10|0x03|
|
||||
Dec | 16| 2| 49| 114| 5| 1| 2| 3| 4| 5| 0| 1| 0| 0| 4| 65| 117| 120| 49| 1| 1| 0| 0| 4| 65| 117| 120| 50| 0| 7| 2| 3| 4| 65| 117| 120| 51| 0| 1| 1| 0| 4| 65| 117| 120| 52| 0| 1| 0| 0| 4| 65| 117| 120| 53| 212| 16| 3
|
||||
Ascii | | | 1| r| | | | | | | | | | | | A| u| x| 1| | | | | | A| u| x| 2| | | | | | A| u| x| 3| | | | | | A| u| x| 4| | | | | | A| u| x| 5| | |
|
||||
|
||||
|
||||
|
||||
RS16 panel.
|
||||
HEX: 0x10|0x02|0x31|0x72|0x0f|0x01|0x02|0x03|0x04|0x05|0x06|0x07|0x08|0x09|0x0a|0x0b|0x0c|0x0d|0x0e|0x0f|0x00|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x31|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x32|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x33|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x34|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x35|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x36|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x37|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x31|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x32|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x33|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x34|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x35|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x36|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x37|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x38|0x77|0x10|0x03|
|
||||
Dec | 16| 2| 49| 114| 15| 1| 2| 3| 4| 5| 6| 7| 8| 9| 10| 11| 12| 13| 14| 15| 0| 1| 0| 0| 4| 65| 117| 120| 49| 1| 1| 0| 0| 4| 65| 117| 120| 50| 1| 1| 0| 0| 4| 65| 117| 120| 51| 1| 1| 0| 0| 4| 65| 117| 120| 52| 1| 1| 0| 0| 4| 65| 117| 120| 53| 1| 1| 0| 0| 4| 65| 117| 120| 54| 1| 1| 0| 0| 4| 65| 117| 120| 55| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 49| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 50| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 51| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 52| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 53| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 54| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 55| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 56| 119| 16| 3
|
||||
Ascii | | | 1| r| | | | | | | | | | | | | | | | | | | | | | A| u| x| 1| | | | | | A| u| x| 2| | | | | | A| u| x| 3| | | | | | A| u| x| 4| | | | | | A| u| x| 5| | | | | | A| u| x| 6| | | | | | A| u| x| 7| | | | | | A| u| x| | B| 1| | | | | | A| u| x| | B| 2| | | | | | A| u| x| | B| 3| | | | | | A| u| x| | B| 4| | | | | | A| u| x| | B| 5| | | | | | A| u| x| | B| 6| | | | | | A| u| x| | B| 7| | | | | | A| u| x| | B| 8| w| |
|
||||
|
||||
Hex |0x10|0x02|0x31|0x72|
|
||||
|
||||
*/
|
||||
|
||||
/* Startup sequences
|
||||
|
||||
RS16 combo
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Probe | HEX: 0x10|0x02|0xa1|0x00|0xb3|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x61' | HEX: 0x10|0x02|0xa1|0x61|0x00|0x00|0x00|0x01|0x00|0x1d|0x32|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x61|0x00|0x74|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x50' | HEX: 0x10|0x02|0xa1|0x50|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x00|0x23|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x50|0x00|0x63|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x51' | HEX: 0x10|0x02|0xa1|0x51|0x31|0x42|0x41|0x36|0x32|0x38|0x32|0x35|0x42|0x37|0x43|0x36|0x39|0x41|0x34|0x43|0x00|0xa2|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x51|0x00|0x64|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x59' | HEX: 0x10|0x02|0xa1|0x59|0x00|0x0c|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x59|0x00|0x6c|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x52' | HEX: 0x10|0x02|0xa1|0x52|0x00|0x05|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x52|0x00|0x65|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type iAqalnk Poll | HEX: 0x10|0x02|0xa1|0x53|0x06|0x10|0x03|
|
||||
|
||||
RS8 Combo rev T.2
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Probe | HEX: 0x10|0x02|0xa1|0x00|0xb3|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x61' | HEX: 0x10|0x02|0xa1|0x61|0x00|0x00|0x00|0x01|0x00|0x1d|0x32|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x61|0x00|0x74|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x50' | HEX: 0x10|0x02|0xa1|0x50|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x00|0x23|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x50|0x00|0x63|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x51' | HEX: 0x10|0x02|0xa1|0x51|0x31|0x42|0x41|0x36|0x32|0x38|0x32|0x35|0x42|0x37|0x43|0x36|0x39|0x41|0x34|0x43|0x00|0xa2|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x51|0x00|0x64|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x59' | HEX: 0x10|0x02|0xa1|0x59|0x00|0x0c|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x59|0x00|0x6c|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x52' | HEX: 0x10|0x02|0xa1|0x52|0x00|0x05|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x52|0x00|0x65|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type iAqalnk Poll | HEX: 0x10|0x02|0xa1|0x53|0x06|0x10|0x03|
|
||||
|
||||
RS4 rev Yg
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Probe | HEX: 0x10|0x02|0xa3|0x00|0xb5|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Unknown '0x61' | HEX: 0x10|0x02|0xa3|0x61|0x00|0x00|0x00|0x04|0x00|0x27|0x41|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x61|0x00|0x74|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Unknown '0x50' | HEX: 0x10|0x02|0xa3|0x50|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x00|0x25|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x50|0x00|0x63|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Unknown '0x51' | HEX: 0x10|0x02|0xa3|0x51|0x00|0x06|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x51|0x00|0x64|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Unknown '0x59' | HEX: 0x10|0x02|0xa3|0x59|0x00|0x0e|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x59|0x00|0x6c|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Unknown '0x52' | HEX: 0x10|0x02|0xa3|0x52|0x00|0x07|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x52|0x00|0x65|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Unknown '0x53' | HEX: 0x10|0x02|0xa3|0x53|0x08|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x3f|0x00|0x52|0x10|0x03|
|
||||
|
||||
RS6 rev T2 RS8 (home)
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Probe | HEX: 0x10|0x02|0xa1|0x00|0xb3|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x61' | HEX: 0x10|0x02|0xa1|0x61|0x00|0x00|0x00|0x01|0x00|0x1d|0x32|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x61|0x00|0x74|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x50' | HEX: 0x10|0x02|0xa1|0x50|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x00|0x23|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x50|0x00|0x63|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x51' | HEX: 0x10|0x02|0xa1|0x51|0x31|0x42|0x41|0x36|0x32|0x38|0x32|0x35|0x42|0x37|0x43|0x36|0x39|0x41|0x34|0x43|0x00|0xa2|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x51|0x00|0x64|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x59' | HEX: 0x10|0x02|0xa1|0x59|0x01|0x0d|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x59|0x00|0x6c|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x52' | HEX: 0x10|0x02|0xa1|0x52|0x03|0x08|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x52|0x00|0x65|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type iAqalnk Poll | HEX: 0x10|0x02|0xa1|0x53|0x06|0x10|0x03|
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
0x10|0x02|0x31|0x72|0x0f|0x01|0x02|0x03|0x04|0x05|0x06|0x07|0x08|0x09|0x0a|0x0b|0x0c|0x0d|0x0e|0x0f|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x31|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x32|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x33|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x34|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x35|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x36|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x37|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x31|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x32|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x33|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x34|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x35|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x36|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x37|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x38|0x70|0x10|0x03|
|
||||
|
||||
|
||||
Only panel (RS8)
|
||||
Air index 3 type 15 (pump off)
|
||||
Air index 3 type 14 (pump off)
|
||||
Air index 3 type 8 (pump on)
|
||||
Water index 5 type 15 (pump on)
|
||||
Temp2 ndex 8 type 20
|
||||
always 1 | index=4 type=(15 0x0f)
|
||||
|
||||
Comb0
|
||||
Spa setpoint index 8 type 14
|
||||
Air index 8 type 26
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Pump RPM
|
||||
|
||||
All taken from panel Yg, but only heater setpoints seem to work.
|
||||
Only setpoints seem to work,
|
||||
|
||||
RPM to 2750
|
||||
Bit 6 = 0x5e
|
||||
Bit 10 * 256 + Bit 11
|
||||
Bit 7 or 9 probably pump index.
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x0a|0xbe|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xd5|0x10|0x03|
|
||||
|
||||
RPM to 2995
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x0b|0xb3|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xcb|0x10|0x03|
|
||||
|
||||
|
||||
Below is setting RPM to 2505
|
||||
|
||||
packet To 0xa3 of type iAqalnk Poll | HEX: 0x10|0x02|0xa3|0x53|0x08|0x10|0x03|
|
||||
packet To 0x00 of type Ack w/ Command | HEX: 0x10|0x02|0x00|0x01|0x3f|0x20|0x72|0x10|0x03|
|
||||
packet To 0x33 of type iAq Poll | HEX: 0x10|0x02|0x33|0x30|0x75|0x10|0x03|
|
||||
packet To 0xa3 of type Unknown '0x73' | HEX: 0x10|0x02|0xa3|0x73|0x28|0x10|0x03|
|
||||
packet To 0x00 of type iAqualnk sendCmd | HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x09|0xc9|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xdf|0x10|0x03|
|
||||
packet To 0x33 of type iAq Poll | HEX: 0x10|0x02|0x33|0x30|0x75|0x10|0x03|
|
||||
packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
packet To 0x33 of type iAq 1Tch status | HEX: 0x10|0x02|0x33|0x71|0x07|0x01|0x02|0x03|0x04|0x05|0x0f|0x12|0x00|0x07|0x41|0x6c|0x6c|0x20|0x4f|0x46|0x46|0x00|0x08|0x53|0x70|0x61|0x20|0x4d|0x6f|0x64|0x65|0x00|0x0a|0x43|0x6c|0x65|0x61|0x6e|0x20|0x4d|0x6f|0x64|0x65|0x00|0x08|0x42|0x75|0x62|0x62|0x6c|0x65|0x72|0x73|0x00|0x0a|0x57|0x61|0x74|0x65|0x72|0x66|0x61|0x6c|0x6c|0x31|0x04|0x09|0xc9|0x0d|0x7a|0x06|0xa4|0x0a|0xbe|0x08|0xca|0x08|0xca|0x0a|0xbe|0x0a|0xbe|0x05|0xdc|0x04|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x6a|0x10|0x03|
|
||||
All OFF = Off | index 0 type=(01 0x01) status=0x00 start=12 length=7
|
||||
Spa Mode = Off | index 1 type=(02 0x02) status=0x00 start=21 length=8
|
||||
Clean Mode = Off | index 2 type=(03 0x03) status=0x00 start=31 length=10
|
||||
Bubblers = Off | index 3 type=(04 0x04) status=0x00 start=43 length=8
|
||||
Waterfall1 = Off | index 4 type=(05 0x05) status=0x00 start=53 length=10
|
||||
*** RPM is in the next bytes from iAq 1Tch status. But can't tell how to pull them since SWG is also here as well. ****
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
SWG
|
||||
|
||||
SWG 50%
|
||||
Byte 6 = 0x19
|
||||
Byte 7 = 50%
|
||||
Byte 9 & 10 ????
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x32|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x0e|0x10|0x03|
|
||||
|
||||
SWG 51%
|
||||
Byte 7 = 51%
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x33|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x0f|0x10|0x03|
|
||||
|
||||
|
||||
Below is set SWG to 35
|
||||
|
||||
packet To 0xa3 of type iAqalnk Poll | HEX: 0x10|0x02|0xa3|0x53|0x08|0x10|0x03|
|
||||
packet To 0x00 of type Ack w/ Command | HEX: 0x10|0x02|0x00|0x01|0x3f|0x20|0x72|0x10|0x03|
|
||||
packet To 0x33 of type iAq Poll | HEX: 0x10|0x02|0x33|0x30|0x75|0x10|0x03|
|
||||
packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
packet To 0xa3 of type Unknown '0x73' | HEX: 0x10|0x02|0xa3|0x73|0x28|0x10|0x03|
|
||||
packet To 0x00 of type iAqualnk sendCmd | HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x23|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xff|0x10|0x03|
|
||||
packet To 0x33 of type iAq Poll | HEX: 0x10|0x02|0x33|0x30|0x75|0x10|0x03|
|
||||
packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
packet To 0x33 of type iAq 1Tch status | HEX: 0x10|0x02|0x33|0x71|0x07|0x01|0x02|0x03|0x04|0x05|0x12|0x20|0x00|0x07|0x41|0x6c|0x6c|0x20|0x4f|0x46|0x46|0x00|0x08|0x53|0x70|0x61|0x20|0x4d|0x6f|0x64|0x65|0x00|0x0a|0x43|0x6c|0x65|0x61|0x6e|0x20|0x4d|0x6f|0x64|0x65|0x00|0x08|0x42|0x75|0x62|0x62|0x6c|0x65|0x72|0x73|0x00|0x0a|0x57|0x61|0x74|0x65|0x72|0x66|0x61|0x6c|0x6c|0x31|0x04|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x23|0x00|0x00|0x18|0x00|0x00|0x01|0x00|0xd3|0x10|0x03|
|
||||
All OFF = Off | index 0 type=(01 0x01) status=0x00 start=12 length=7
|
||||
Spa Mode = Off | index 1 type=(02 0x02) status=0x00 start=21 length=8
|
||||
Clean Mode = Off | index 2 type=(03 0x03) status=0x00 start=31 length=10
|
||||
Bubblers = Off | index 3 type=(04 0x04) status=0x00 start=43 length=8
|
||||
Waterfall1 = Off | index 4 type=(05 0x05) status=0x00 start=53 length=10
|
||||
*** SWG is in the next bytes from iAq 1Tch status. But can't tell how to pull them since RPM is also here as well. ****
|
||||
|
||||
*/
|
|
@ -33,6 +33,7 @@
|
|||
#include "aq_timer.h"
|
||||
#include "aq_programmer.h"
|
||||
#include "rs_msg_utils.h"
|
||||
#include "color_lights.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\"}"
|
||||
|
@ -44,19 +45,33 @@
|
|||
//SPA WILL TURN OFF AFTER COOL DOWN CYCLE
|
||||
|
||||
|
||||
bool printableChar(char ch)
|
||||
{
|
||||
if ( (ch < 32 || ch > 126) ||
|
||||
ch == 123 || // {
|
||||
ch == 125 || // }
|
||||
ch == 34 || // "
|
||||
ch == 92 // backslash
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
int json_chars(char *dest, const char *src, int dest_len, int src_len)
|
||||
{
|
||||
int i;
|
||||
int end = dest_len < src_len ? dest_len:src_len;
|
||||
for(i=0; i < end; i++) {
|
||||
/*
|
||||
if ( (src[i] < 32 || src[i] > 126) ||
|
||||
src[i] == 123 || // {
|
||||
src[i] == 125 || // }
|
||||
src[i] == 34 || // "
|
||||
src[i] == 92 // backslash
|
||||
) // only printable chars
|
||||
src[i] == 92 // backslash
|
||||
) // only printable chars*/
|
||||
if (! printableChar(src[i]))
|
||||
dest[i] = ' ';
|
||||
else
|
||||
dest[i] = src[i];
|
||||
|
@ -98,6 +113,14 @@ const char* _getStatus(struct aqualinkdata *aqdata, const char *blankmsg)
|
|||
return programtypeDisplayName(aqdata->active_thread.ptype);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
printf("**** Programming=%s, length=%ld, empty=%s, Message=%s \n",
|
||||
aqdata->active_thread.thread_id==0?"no":"yes",
|
||||
strlen(aqdata->last_display_message),
|
||||
rsm_isempy(aqdata->last_display_message,strlen(aqdata->last_display_message))==true?"yes":"no",
|
||||
aqdata->last_display_message);
|
||||
*/
|
||||
if (aqdata->active_thread.thread_id != 0) {
|
||||
if (!aqdata->is_display_message_programming || rsm_isempy(aqdata->last_display_message,strlen(aqdata->last_display_message))){
|
||||
return programtypeDisplayName(aqdata->active_thread.ptype);
|
||||
|
@ -111,24 +134,11 @@ const char* _getStatus(struct aqualinkdata *aqdata, const char *blankmsg)
|
|||
return JSON_TIMEOUT;
|
||||
}
|
||||
|
||||
// NSF should probably use json_chars here.
|
||||
if (aqdata->last_display_message[0] != '\0') {
|
||||
int i;
|
||||
for(i=0; i < strlen(aqdata->last_display_message); i++ ) {
|
||||
if (aqdata->last_display_message[i] <= 31 || aqdata->last_display_message[i] >= 127) {
|
||||
if (! printableChar(aqdata->last_display_message[i])) {
|
||||
aqdata->last_display_message[i] = ' ';
|
||||
} else {
|
||||
switch (aqdata->last_display_message[i]) {
|
||||
case '"':
|
||||
case '/':
|
||||
case '\n':
|
||||
case '\t':
|
||||
case '\f':
|
||||
case '\r':
|
||||
case '\b':
|
||||
aqdata->last_display_message[i] = ' ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf("JSON Sending '%s'\n",aqdata->last_display_message);
|
||||
|
@ -242,12 +252,13 @@ char *get_aux_information(aqkey *button, struct aqualinkdata *aqdata, char *buff
|
|||
//printf("Button %s is VSP\n", button->name);
|
||||
for (i=0; i < aqdata->num_pumps; i++) {
|
||||
if (button == aqdata->pumps[i].button) {
|
||||
length += sprintf(buffer, ",\"type_ext\":\"switch_vsp\",\"Pump_RPM\":\"%d\",\"Pump_GPM\":\"%d\",\"Pump_Watts\":\"%d\",\"Pump_Type\":\"%s\",\"Pump_Status\":\"%d\"",
|
||||
length += sprintf(buffer, ",\"type_ext\":\"switch_vsp\",\"Pump_RPM\":\"%d\",\"Pump_GPM\":\"%d\",\"Pump_Watts\":\"%d\",\"Pump_Type\":\"%s\",\"Pump_Status\":\"%d\",\"Pump_Speed\":\"%d\"",
|
||||
aqdata->pumps[i].rpm,
|
||||
aqdata->pumps[i].gpm,
|
||||
aqdata->pumps[i].watts,
|
||||
(aqdata->pumps[i].pumpType==VFPUMP?"vfPump":(aqdata->pumps[i].pumpType==VSPUMP?"vsPump":"ePump")),
|
||||
getPumpStatus(i, aqdata));
|
||||
getPumpStatus(i, aqdata),
|
||||
getPumpSpeedAsPercent(&aqdata->pumps[i]));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
@ -258,7 +269,17 @@ char *get_aux_information(aqkey *button, struct aqualinkdata *aqdata, char *buff
|
|||
//printf("Button %s is ProgramableLight\n", button->name);
|
||||
for (i=0; i < aqdata->num_lights; i++) {
|
||||
if (button == aqdata->lights[i].button) {
|
||||
length += sprintf(buffer, ",\"type_ext\": \"switch_program\", \"Light_Type\":\"%d\"", aqdata->lights[i].lightType);
|
||||
if (aqdata->lights[i].lightType == LC_DIMMER2) {
|
||||
length += sprintf(buffer, ",\"type_ext\": \"light_dimmer\", \"Light_Type\":\"%d\", \"Light_Program\":\"%d\", \"Program_Name\":\"%d%%\" ",
|
||||
aqdata->lights[i].lightType,
|
||||
aqdata->lights[i].currentValue,
|
||||
aqdata->lights[i].currentValue);
|
||||
} else {
|
||||
length += sprintf(buffer, ",\"type_ext\": \"switch_program\", \"Light_Type\":\"%d\", \"Light_Program\":\"%d\", \"Program_Name\":\"%s\" ",
|
||||
aqdata->lights[i].lightType,
|
||||
aqdata->lights[i].currentValue,
|
||||
light_mode_name(aqdata->lights[i].lightType, aqdata->lights[i].currentValue, ALLBUTTON));
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
@ -284,6 +305,7 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
bool homekit_f = (homekit && ( aqdata->temp_units==FAHRENHEIT || aqdata->temp_units == UNKNOWN) );
|
||||
|
||||
length += sprintf(buffer+length, "{\"type\": \"devices\"");
|
||||
length += sprintf(buffer+length, ",\"aqualinkd_version\":\"%s\"",AQUALINKD_VERSION);//"09/01/16 THU",
|
||||
length += sprintf(buffer+length, ",\"date\":\"%s\"",aqdata->date );//"09/01/16 THU",
|
||||
length += sprintf(buffer+length, ",\"time\":\"%s\"",aqdata->time );//"1:16 PM",
|
||||
if ( aqdata->temp_units == FAHRENHEIT )
|
||||
|
@ -488,9 +510,20 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
//return length;
|
||||
}
|
||||
|
||||
int logmaskjsonobject(int16_t flag, char* buffer)
|
||||
int logmaskjsonobject(logmask_t flag, char* buffer)
|
||||
{
|
||||
int length = sprintf(buffer, "{\"name\":\"%s\",\"id\":\"%d\",\"set\":\"%s\"},", logmask2name(flag), flag,(isDebugLogMaskSet(flag)?JSON_ON:JSON_OFF));
|
||||
|
||||
if (flag == RSSD_LOG) {
|
||||
//length = sprintf(buffer, "{\"name\":\"%s\",\"id\":\"%d\",\"set\":\"%s\",\"filter\":\"0x%02hhx\"},", logmask2name(flag), flag,(isDebugLogMaskSet(flag)?JSON_ON:JSON_OFF), _aqconfig_.RSSD_LOG_filter[0]);
|
||||
length = sprintf(buffer, "{\"name\":\"%s\",\"id\":\"%d\",\"set\":\"%s\",\"filters\":[", logmask2name(flag), flag,(isDebugLogMaskSet(flag)?JSON_ON:JSON_OFF));
|
||||
for (int i=0; i < MAX_RSSD_LOG_FILTERS; i++) {
|
||||
length += sprintf(buffer+length, "\"0x%02hhx\",", _aqconfig_.RSSD_LOG_filter[i]);
|
||||
}
|
||||
//"]},"
|
||||
length += sprintf(buffer+length-1, "]},");
|
||||
length--;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
int logleveljsonobject(int level, char* buffer)
|
||||
|
@ -523,11 +556,12 @@ int build_aqualink_aqmanager_JSON(struct aqualinkdata *aqdata, char* buffer, int
|
|||
length += logmaskjsonobject(RSSA_LOG, buffer+length);
|
||||
length += logmaskjsonobject(DJAN_LOG, buffer+length);
|
||||
length += logmaskjsonobject(DPEN_LOG, buffer+length);
|
||||
length += logmaskjsonobject(RSSD_LOG, buffer+length);
|
||||
length += logmaskjsonobject(PROG_LOG, buffer+length);
|
||||
length += logmaskjsonobject(SCHD_LOG, buffer+length);
|
||||
length += logmaskjsonobject(RSTM_LOG, buffer+length);
|
||||
length += logmaskjsonobject(SIM_LOG, buffer+length);
|
||||
|
||||
length += logmaskjsonobject(RSSD_LOG, buffer+length); // Make sure the last one.
|
||||
// DBGT_LOG is a compile time only, so don;t include
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
|
@ -693,7 +727,35 @@ printf("Pump Type %d\n",aqdata->pumps[i].pumpType);
|
|||
length--;
|
||||
length += sprintf(buffer+length, "}");
|
||||
|
||||
length += sprintf(buffer+length, ",\"light_program\":{" );
|
||||
for (i=0; i < aqdata->num_lights; i++)
|
||||
{
|
||||
if (aqdata->lights[i].lightType == LC_DIMMER2) {
|
||||
length += sprintf(buffer+length, "\"%s\": \"%d%%\",", aqdata->lights[i].button->name, aqdata->lights[i].currentValue );
|
||||
} else {
|
||||
length += sprintf(buffer+length, "\"%s\": \"%s\",", aqdata->lights[i].button->name, light_mode_name(aqdata->lights[i].lightType, aqdata->lights[i].currentValue, RSSADAPTER) );
|
||||
}
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
length += sprintf(buffer+length, "}");
|
||||
|
||||
/*
|
||||
for (i=0; i < aqdata->num_lights; i++)
|
||||
{
|
||||
length += sprintf(buffer+length, ",\"Plight_%d\":{\"name\":\"%s\",\"id\":\"%s\", \"type\":\"%d\", \"value\":\"%d\", \"state\":\"%s\"}",
|
||||
i+1,
|
||||
aqdata->lights[i].button->label,
|
||||
aqdata->lights[i].button->name,
|
||||
aqdata->lights[i].lightType,
|
||||
aqdata->lights[i].currentValue,
|
||||
LED2text(aqdata->lights[i].RSSDstate)
|
||||
);
|
||||
}
|
||||
*/
|
||||
//if (buffer[length-1] == ',')
|
||||
// length--;
|
||||
//length += sprintf(buffer+length, "}");
|
||||
|
||||
|
||||
length += sprintf(buffer+length, "}" );
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "simulator.h"
|
||||
#include "hassio.h"
|
||||
#include "version.h"
|
||||
#include "color_lights.h"
|
||||
|
||||
#ifdef AQ_PDA
|
||||
#include "pda.h"
|
||||
|
@ -74,6 +75,7 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc);
|
|||
#endif
|
||||
|
||||
void reset_last_mqtt_status();
|
||||
bool uri_strcmp(const char *uri, const char *string);
|
||||
|
||||
//static const char *s_http_port = "8080";
|
||||
static struct mg_serve_http_opts _http_server_opts;
|
||||
|
@ -913,11 +915,17 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
|
|||
_last_mqtt_aqualinkdata.pumps[i].rpm = _aqualink_data->pumps[i].rpm;
|
||||
//send_mqtt_aux_msg(nc, PUMP_TOPIC, i+1, PUMP_RPM_TOPIC, _aqualink_data->pumps[i].rpm);
|
||||
send_mqtt_aux_msg(nc, _aqualink_data->pumps[i].button->name, PUMP_RPM_TOPIC, _aqualink_data->pumps[i].rpm);
|
||||
if (_aqualink_data->pumps[i].pumpType == EPUMP || _aqualink_data->pumps[i].pumpType == VSPUMP) {
|
||||
send_mqtt_aux_msg(nc, _aqualink_data->pumps[i].button->name, PUMP_SPEED_TOPIC, getPumpSpeedAsPercent(&_aqualink_data->pumps[i]));
|
||||
}
|
||||
}
|
||||
if (_aqualink_data->pumps[i].gpm != TEMP_UNKNOWN && _aqualink_data->pumps[i].gpm != _last_mqtt_aqualinkdata.pumps[i].gpm) {
|
||||
_last_mqtt_aqualinkdata.pumps[i].gpm = _aqualink_data->pumps[i].gpm;
|
||||
//send_mqtt_aux_msg(nc, PUMP_TOPIC, i+1, PUMP_GPH_TOPIC, _aqualink_data->pumps[i].gph);
|
||||
send_mqtt_aux_msg(nc, _aqualink_data->pumps[i].button->name, PUMP_GPM_TOPIC, _aqualink_data->pumps[i].gpm);
|
||||
if (_aqualink_data->pumps[i].pumpType == VFPUMP) {
|
||||
send_mqtt_aux_msg(nc, _aqualink_data->pumps[i].button->name, PUMP_SPEED_TOPIC, getPumpSpeedAsPercent(&_aqualink_data->pumps[i]));
|
||||
}
|
||||
}
|
||||
if (_aqualink_data->pumps[i].watts != TEMP_UNKNOWN && _aqualink_data->pumps[i].watts != _last_mqtt_aqualinkdata.pumps[i].watts) {
|
||||
_last_mqtt_aqualinkdata.pumps[i].watts = _aqualink_data->pumps[i].watts;
|
||||
|
@ -939,6 +947,32 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
|
|||
send_mqtt_aux_msg(nc, _aqualink_data->pumps[i].button->name, PUMP_STATUS_TOPIC, pumpStatus);
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over programmable lights
|
||||
for (i=0; i < _aqualink_data->num_lights; i++) {
|
||||
char topic[50];
|
||||
if ( _aqualink_data->lights[i].currentValue != TEMP_UNKNOWN && _aqualink_data->lights[i].currentValue != _last_mqtt_aqualinkdata.lights[i].currentValue ) {
|
||||
_last_mqtt_aqualinkdata.lights[i].currentValue = _aqualink_data->lights[i].currentValue;
|
||||
send_mqtt_aux_msg(nc, _aqualink_data->lights[i].button->name, LIGHT_PROGRAM_TOPIC, _aqualink_data->lights[i].currentValue);
|
||||
|
||||
sprintf(topic, "%s%s/name", _aqualink_data->lights[i].button->name, LIGHT_PROGRAM_TOPIC);
|
||||
if (_aqualink_data->lights[i].lightType == LC_DIMMER2) {
|
||||
char message[30];
|
||||
sprintf(message, "%d%%", _aqualink_data->lights[i].currentValue);
|
||||
send_mqtt_string_msg(nc, topic, message);
|
||||
} else {
|
||||
send_mqtt_string_msg(nc, topic, light_mode_name(_aqualink_data->lights[i].lightType, _aqualink_data->lights[i].currentValue, ALLBUTTON));
|
||||
}
|
||||
/*
|
||||
if (_aqualink_data->lights[i].lightType == LC_DIMMER) {
|
||||
sprintf(topic, "%s%s", _aqualink_data->lights[i].button->name, LIGHT_DIMMER_VALUE_TOPIC);
|
||||
send_mqtt_int_msg(nc, topic, _aqualink_data->lights[i].currentValue * 25);
|
||||
} else*/ if (_aqualink_data->lights[i].lightType == LC_DIMMER2) {
|
||||
sprintf(topic, "%s%s", _aqualink_data->lights[i].button->name, LIGHT_DIMMER_VALUE_TOPIC);
|
||||
send_mqtt_int_msg(nc, topic, _aqualink_data->lights[i].currentValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1054,10 +1088,33 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
setSystemLogLevel(round(value));
|
||||
return uAQmanager; // Want to resent updated status
|
||||
} else if (strncmp(ri1, "addlogmask", 10) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
if ( round(value) == RSSD_LOG ) {
|
||||
// Check for filter on RSSD LOG
|
||||
if (ri2 != NULL) {
|
||||
unsigned int n;
|
||||
// ri will be /addlogmask/0x01 0x02 0x03 0x04/
|
||||
for (int i=0; i < MAX_RSSD_LOG_FILTERS; i++) {
|
||||
int index=i*5;
|
||||
if (ri2[index]=='0' && ri2[index+1]=='x') {
|
||||
sscanf(&ri2[index], "0x%2x", &n);
|
||||
_aqconfig_.RSSD_LOG_filter[i] = n;
|
||||
//_aqconfig_.RSSD_LOG_filter_OLD = strtoul(cleanalloc(ri2), NULL, 16);
|
||||
LOG(NET_LOG,LOG_NOTICE, "Adding RSSD LOG filter 0x%02hhx", _aqconfig_.RSSD_LOG_filter[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
addDebugLogMask(round(value));
|
||||
return uAQmanager; // Want to resent updated status
|
||||
} else if (strncmp(ri1, "removelogmask", 13) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
removeDebugLogMask(round(value));
|
||||
if ( round(value) == RSSD_LOG ) {
|
||||
for (int i=0; i < MAX_RSSD_LOG_FILTERS; i++) {
|
||||
_aqconfig_.RSSD_LOG_filter[i] = NUL;
|
||||
}
|
||||
//_aqconfig_.RSSD_LOG_filter_OLD = NUL;
|
||||
//LOG(NET_LOG,LOG_NOTICE, "Removed RSSD LOG filter");
|
||||
}
|
||||
return uAQmanager; // Want to resent updated status
|
||||
} else if (strncmp(ri1, "logfile", 7) == 0) {
|
||||
/*
|
||||
|
@ -1077,8 +1134,25 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
return uActioned;
|
||||
} else if (strncmp(ri1, "seriallogger", 12) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
LOG(NET_LOG,LOG_NOTICE, "Received request to run serial_logger!\n");
|
||||
//LOG(NET_LOG,LOG_NOTICE, "Received request ri1=%s, ri2=%s, ri3=%s value=%f\n",ri1,ri2,ri3,value);
|
||||
_aqualink_data->slogger_packets = round(value);
|
||||
if (ri2 != NULL) {
|
||||
//MIN( 19, (ri3 - ri2));
|
||||
snprintf(_aqualink_data->slogger_ids, MIN( 19, (ri3 - ri2)+1 ), ri2); // 0x01 0x02 0x03 0x04
|
||||
} else {
|
||||
_aqualink_data->slogger_ids[0] = '\0';
|
||||
}
|
||||
if (ri3 != NULL && strncmp(ri3, "true", 4) == 0) {
|
||||
_aqualink_data->slogger_debug = true;
|
||||
} else {
|
||||
_aqualink_data->slogger_debug = false;
|
||||
}
|
||||
//LOG(NET_LOG,LOG_NOTICE, "Received request to run serial_logger (%d,%s,%s)!\n",
|
||||
// _aqualink_data->slogger_packets,
|
||||
// _aqualink_data->slogger_ids[0]!='\0'?_aqualink_data->slogger_ids:" ",
|
||||
// _aqualink_data->slogger_debug?"debug":"" );
|
||||
_aqualink_data->run_slogger = true;
|
||||
return uActioned;
|
||||
return uActioned;
|
||||
#else // AQ_MANAGER
|
||||
} else if (strncmp(ri1, "aqmanager", 9) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
return uNotAvailable;
|
||||
|
@ -1212,8 +1286,24 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
LOG(NET_LOG,LOG_WARNING, "%s: Didn't find device that matched URI '%.*s'\n",actionName[from], uri_length, URI);
|
||||
rtn = uBad;
|
||||
}
|
||||
} else if ((ri3 != NULL && (strncasecmp(ri2, "brightness", 10) == 0) && (strncasecmp(ri3, "set", 3) == 0))) {
|
||||
found = false;
|
||||
for (i=0; i < _aqualink_data->total_buttons; i++) {
|
||||
if (strncmp(ri1, _aqualink_data->aqbuttons[i].name, strlen(_aqualink_data->aqbuttons[i].name)) == 0 ||
|
||||
strncmp(ri1, _aqualink_data->aqbuttons[i].label, strlen(_aqualink_data->aqbuttons[i].label)) == 0)
|
||||
{
|
||||
found = true;
|
||||
panel_device_request(_aqualink_data, LIGHT_BRIGHTNESS, i, value, from);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
*rtnmsg = NO_PLIGHT_DEVICE;
|
||||
LOG(NET_LOG,LOG_WARNING, "%s: Didn't find device that matched URI '%.*s'\n",actionName[from], uri_length, URI);
|
||||
rtn = uBad;
|
||||
}
|
||||
// Action a pump RPM/GPM message
|
||||
} else if ((ri3 != NULL && ((strncasecmp(ri2, "RPM", 3) == 0) || (strncasecmp(ri2, "GPM", 3) == 0) || (strncasecmp(ri2, "VSP", 3) == 0)) && (strncasecmp(ri3, "set", 3) == 0))) {
|
||||
} else if ((ri3 != NULL && ((strncasecmp(ri2, "RPM", 3) == 0) || (strncasecmp(ri2, "GPM", 3) == 0) || (strncasecmp(ri2, "Speed", 5) == 0) || (strncasecmp(ri2, "VSP", 3) == 0)) && (strncasecmp(ri3, "set", 3) == 0))) {
|
||||
found = false;
|
||||
// Is it a pump index or pump name
|
||||
if (strncmp(ri1, "Pump_", 5) == 0) { // Pump by number
|
||||
|
@ -1233,9 +1323,15 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
return uBad;
|
||||
}
|
||||
} else {
|
||||
LOG(NET_LOG,LOG_NOTICE, "%s: request to change pump %d %s to %d\n",actionName[from],pumpIndex+1, (strncasecmp(ri2, "GPM", 3) == 0)?"GPM":"RPM", round(value));
|
||||
if (strncasecmp(ri2, "Speed", 5) == 0) {
|
||||
int val = convertPumpPercentToSpeed(&_aqualink_data->pumps[i], round(value));
|
||||
LOG(NET_LOG,LOG_NOTICE, "%s: request to change pump %d Speed to %d%%, using %s of %d\n",actionName[from],pumpIndex+1, round(value), (_aqualink_data->pumps[i].pumpType==VFPUMP?"GPM":"RPM" ) ,val);
|
||||
panel_device_request(_aqualink_data, PUMP_RPM, pumpIndex, val, from);
|
||||
} else {
|
||||
LOG(NET_LOG,LOG_NOTICE, "%s: request to change pump %d %s to %d\n",actionName[from],pumpIndex+1, (strncasecmp(ri2, "GPM", 3) == 0)?"GPM":"RPM", round(value));
|
||||
//create_program_request(from, PUMP_RPM, round(value), pumpIndex);
|
||||
panel_device_request(_aqualink_data, PUMP_RPM, pumpIndex, round(value), from);
|
||||
panel_device_request(_aqualink_data, PUMP_RPM, pumpIndex, round(value), from);
|
||||
}
|
||||
}
|
||||
//_aqualink_data->unactioned.type = PUMP_RPM;
|
||||
//_aqualink_data->unactioned.value = round(value);
|
||||
|
@ -1246,7 +1342,8 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
}
|
||||
} else { // Pump by button name
|
||||
for (i=0; i < _aqualink_data->total_buttons ; i++) {
|
||||
if (strncmp(ri1, _aqualink_data->aqbuttons[i].name, strlen(_aqualink_data->aqbuttons[i].name)) == 0 ){
|
||||
//if (strncmp(ri1, _aqualink_data->aqbuttons[i].name, strlen(_aqualink_data->aqbuttons[i].name)) == 0 ){
|
||||
if ( uri_strcmp(ri1, _aqualink_data->aqbuttons[i].name)) {
|
||||
int pi;
|
||||
for (pi=0; pi < _aqualink_data->num_pumps; pi++) {
|
||||
if (_aqualink_data->pumps[pi].button == &_aqualink_data->aqbuttons[i]) {
|
||||
|
@ -1263,9 +1360,15 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
return uBad;
|
||||
}
|
||||
} else {
|
||||
LOG(NET_LOG,LOG_NOTICE, "%s: request to change pump %d %s to %d\n",actionName[from], pi+1, (strncasecmp(ri2, "GPM", 3) == 0)?"GPM":"RPM", round(value));
|
||||
if (strncasecmp(ri2, "Speed", 5) == 0) {
|
||||
int val = convertPumpPercentToSpeed(&_aqualink_data->pumps[pi], round(value));
|
||||
LOG(NET_LOG,LOG_NOTICE, "%s: request to change pump %d Speed to %d%%, using %s of %d\n",actionName[from],_aqualink_data->pumps[pi].pumpIndex, round(value), (_aqualink_data->pumps[i].pumpType==VFPUMP?"GPM":"RPM" ) ,val);
|
||||
panel_device_request(_aqualink_data, PUMP_RPM, _aqualink_data->pumps[pi].pumpIndex, val, from);
|
||||
} else {
|
||||
LOG(NET_LOG,LOG_NOTICE, "%s: request to change pump %d %s to %d\n",actionName[from], pi+1, (strncasecmp(ri2, "GPM", 3) == 0)?"GPM":"RPM", round(value));
|
||||
//create_program_request(from, PUMP_RPM, round(value), _aqualink_data->pumps[pi].pumpIndex);
|
||||
panel_device_request(_aqualink_data, PUMP_RPM, _aqualink_data->pumps[pi].pumpIndex, round(value), from);
|
||||
panel_device_request(_aqualink_data, PUMP_RPM, _aqualink_data->pumps[pi].pumpIndex, round(value), from);
|
||||
}
|
||||
}
|
||||
//_aqualink_data->unactioned.type = PUMP_RPM;
|
||||
//_aqualink_data->unactioned.value = round(value);
|
||||
|
@ -1322,13 +1425,15 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
|
||||
for (i=0; i < _aqualink_data->total_buttons && found==false; i++) {
|
||||
// If Label = "Spa", "Spa_Heater" will turn on "Spa", so need to check '/' on label as next character
|
||||
if (strncmp(ri1, _aqualink_data->aqbuttons[i].name, strlen(_aqualink_data->aqbuttons[i].name)) == 0 ||
|
||||
(strncmp(ri1, _aqualink_data->aqbuttons[i].label, strlen(_aqualink_data->aqbuttons[i].label)) == 0 && ri1[strlen(_aqualink_data->aqbuttons[i].label)] == '/'))
|
||||
//if (strncmp(ri1, _aqualink_data->aqbuttons[i].name, strlen(_aqualink_data->aqbuttons[i].name)) == 0 ||
|
||||
// (strncmp(ri1, _aqualink_data->aqbuttons[i].label, strlen(_aqualink_data->aqbuttons[i].label)) == 0 && ri1[strlen(_aqualink_data->aqbuttons[i].label)] == '/'))
|
||||
if ( uri_strcmp(ri1, _aqualink_data->aqbuttons[i].name) || uri_strcmp(ri1, _aqualink_data->aqbuttons[i].label) )
|
||||
{
|
||||
found = true;
|
||||
//create_panel_request(from, i, value, istimer);
|
||||
LOG(NET_LOG,LOG_INFO, "%d: MATCH %s to topic %.*s\n",from,_aqualink_data->aqbuttons[i].name,uri_length, URI);
|
||||
LOG(NET_LOG,LOG_INFO, "ri1=%s, length=%d char at len=%c\n",ri1,strlen(_aqualink_data->aqbuttons[i].label),ri1[strlen(_aqualink_data->aqbuttons[i].label)] );
|
||||
panel_device_request(_aqualink_data, atype, i, value, from);
|
||||
//LOG(NET_LOG,LOG_INFO, "%s: MATCH %s to topic %.*s\n",from,_aqualink_data->aqbuttons[i].name,uri_length, URI);
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
|
@ -1346,6 +1451,28 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
return rtn;
|
||||
}
|
||||
|
||||
/*
|
||||
Quicker and more accurate for us than normal strncmp, since we check for the trailing / at right position
|
||||
check Spa against uri /Spa/set /Spa_mode/set / Spa_heater/set
|
||||
*/
|
||||
bool uri_strcmp(const char *uri, const char *string) {
|
||||
int i;
|
||||
int len = strlen(string);
|
||||
|
||||
// Check the trailing / on length first.
|
||||
if (uri[len] != '/') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now check all characters
|
||||
for (i=0; i < len; i++) {
|
||||
if ( uri[i] != string[i] ){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg) {
|
||||
char *rtnmsg;
|
||||
|
@ -1947,6 +2074,10 @@ void reset_last_mqtt_status()
|
|||
//_last_mqtt_aqualinkdata.pumps[i].driveState = TEMP_UNKNOWN;
|
||||
}
|
||||
|
||||
for (i=0; i < _aqualink_data->num_lights; i++) {
|
||||
_last_mqtt_aqualinkdata.lights[i].currentValue = TEMP_UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void start_mqtt(struct mg_mgr *mgr) {
|
||||
|
|
|
@ -13,10 +13,10 @@ static FILE *_byteLogFile = NULL;
|
|||
static bool _logfile_raw = false;
|
||||
static bool _logfile_packets = false;
|
||||
//static bool _includePentair = false;
|
||||
static unsigned char _lastReadFrom = NUL;
|
||||
//static unsigned char _lastReadFrom = NUL;
|
||||
|
||||
void _logPacket(int16_t from, unsigned char *packet_buffer, int packet_length, bool error, bool force, bool is_read);
|
||||
int _beautifyPacket(char *buff, unsigned char *packet_buffer, int packet_length, bool error, bool is_read);
|
||||
void _logPacket(logmask_t from, unsigned char *packet_buffer, int packet_length, bool error, bool force, bool is_read);
|
||||
int _beautifyPacket(char *buff, int buff_size, unsigned char *packet_buffer, int packet_length, bool error, bool is_read);
|
||||
|
||||
//void startPacketLogger(bool debug_RSProtocol_packets) {
|
||||
void startPacketLogger() {
|
||||
|
@ -88,13 +88,30 @@ void logPacketError(unsigned char *packet_buffer, int packet_length) {
|
|||
_logPacket(RSSD_LOG, packet_buffer, packet_length, true, false, true);
|
||||
}
|
||||
|
||||
void debuglogPacket(int16_t from, unsigned char *packet_buffer, int packet_length, bool is_read) {
|
||||
if ( getLogLevel(from) >= LOG_DEBUG )
|
||||
_logPacket(from, packet_buffer, packet_length, false, true, is_read);
|
||||
/* This should never be used in production */
|
||||
void debuglogPacket(logmask_t from, unsigned char *packet_buffer, int packet_length, bool is_read, bool forcelog) {
|
||||
if ( forcelog == true || getLogLevel(from) >= LOG_DEBUG )
|
||||
_logPacket(from, packet_buffer, packet_length, false, forcelog, is_read);
|
||||
}
|
||||
|
||||
void _logPacket(int16_t from, unsigned char *packet_buffer, int packet_length, bool error, bool force, bool is_read)
|
||||
void logPacket(logmask_t from, int level, unsigned char *packet_buffer, int packet_length, bool is_read) {
|
||||
if ( getLogLevel(from) >= level )
|
||||
_logPacket(from, packet_buffer, packet_length, false, false, is_read);
|
||||
}
|
||||
|
||||
bool RSSD_LOG_filter_match(unsigned char ID) {
|
||||
for (int i=0; i < MAX_RSSD_LOG_FILTERS; i++) {
|
||||
if (_aqconfig_.RSSD_LOG_filter[i] != NUL && _aqconfig_.RSSD_LOG_filter[i] == ID) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void _logPacket(logmask_t from, unsigned char *packet_buffer, int packet_length, bool error, bool force, bool is_read)
|
||||
{
|
||||
static unsigned char lastPacketTo = NUL;
|
||||
|
||||
// No point in continuing if loglevel is < debug_serial and not writing to file
|
||||
if ( force == false &&
|
||||
error == false &&
|
||||
|
@ -104,46 +121,53 @@ void _logPacket(int16_t from, unsigned char *packet_buffer, int packet_length, b
|
|||
return;
|
||||
}
|
||||
|
||||
if ( _aqconfig_.RSSD_LOG_filter != NUL ) {
|
||||
if (is_read) {
|
||||
_lastReadFrom = packet_buffer[PKT_DEST];
|
||||
if ( is_read && _aqconfig_.RSSD_LOG_filter != packet_buffer[PKT_DEST]) {
|
||||
return;
|
||||
}
|
||||
} else if (!is_read && _lastReadFrom != _aqconfig_.RSSD_LOG_filter) { // Must be write
|
||||
|
||||
if ( _aqconfig_.RSSD_LOG_filter[0] != NUL ) {
|
||||
// NOTE Whole IF statment is reversed
|
||||
//if ( ! ( (_aqconfig_.RSSD_LOG_filter_OLD == packet_buffer[PKT_DEST]) ||
|
||||
// ( packet_buffer[PKT_DEST] == 0x00 && lastPacketTo == _aqconfig_.RSSD_LOG_filter_OLD)) )
|
||||
if ( ! ( (RSSD_LOG_filter_match(packet_buffer[PKT_DEST])) ||
|
||||
( packet_buffer[PKT_DEST] == 0x00 && RSSD_LOG_filter_match(lastPacketTo) )) )
|
||||
{
|
||||
lastPacketTo = packet_buffer[PKT_DEST];
|
||||
return;
|
||||
}
|
||||
/*
|
||||
if ( is_read && _aqconfig_.RSSD_LOG_filter != packet_buffer[PKT_DEST]) {
|
||||
return;
|
||||
}
|
||||
*/
|
||||
lastPacketTo = packet_buffer[PKT_DEST];
|
||||
}
|
||||
|
||||
char buff[1000];
|
||||
if (is_read)
|
||||
LOG(from,LOG_DEBUG_SERIAL, "Serial read %d bytes\n",packet_length);
|
||||
else
|
||||
LOG(from,LOG_DEBUG_SERIAL, "Serial write %d bytes\n",packet_length);
|
||||
|
||||
_beautifyPacket(buff, packet_buffer, packet_length, error, is_read);
|
||||
//char buff[1000];
|
||||
char buff[LARGELOGBUFFER];
|
||||
|
||||
int len = _beautifyPacket(buff, LARGELOGBUFFER, packet_buffer, packet_length, error, is_read);
|
||||
|
||||
if (_logfile_packets)
|
||||
writePacketLog(buff);
|
||||
|
||||
if (error == true)
|
||||
LOG(from,LOG_WARNING, "%s", buff);
|
||||
LOG_LARGEMSG(from,LOG_WARNING, buff, len);
|
||||
else {
|
||||
if (force)
|
||||
LOG(from,LOG_DEBUG, "%s", buff);
|
||||
if (force) {
|
||||
LOG_LARGEMSG(from, getSystemLogLevel()<LOG_DEBUG?getSystemLogLevel():LOG_DEBUG, buff, len);
|
||||
//LOG_LARGEMSG(from, LOG_DEBUG, buff, len);
|
||||
}
|
||||
//else if (is_read && _aqconfig_.serial_debug_filter != NUL && _aqconfig_.serial_debug_filter == packet_buffer[PKT_DEST])
|
||||
// LOG(from,LOG_NOTICE, "%s", buff);
|
||||
else
|
||||
LOG(from,LOG_DEBUG_SERIAL, "%s", buff);
|
||||
else {
|
||||
LOG_LARGEMSG(from,LOG_DEBUG_SERIAL, buff, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int beautifyPacket(char *buff, unsigned char *packet_buffer, int packet_length, bool is_read)
|
||||
int beautifyPacket(char *buff, int buff_size, unsigned char *packet_buffer, int packet_length, bool is_read)
|
||||
{
|
||||
return _beautifyPacket(buff, packet_buffer, packet_length, false, is_read);
|
||||
return _beautifyPacket(buff, buff_size, packet_buffer, packet_length, false, is_read);
|
||||
}
|
||||
int _beautifyPacket(char *buff, unsigned char *packet_buffer, int packet_length, bool error, bool is_read)
|
||||
int _beautifyPacket(char *buff, int buff_size, unsigned char *packet_buffer, int packet_length, bool error, bool is_read)
|
||||
{
|
||||
int i = 0;
|
||||
int cnt = 0;
|
||||
|
@ -163,8 +187,13 @@ int _beautifyPacket(char *buff, unsigned char *packet_buffer, int packet_length,
|
|||
cnt = sprintf(buff, "%5.5s %sTo 0x%02hhx of type %16.16s | HEX: ",(is_read?"Read":"Write"),(error?"BAD PACKET ":""), packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length));
|
||||
}
|
||||
*/
|
||||
for (i = 0; i < packet_length; i++)
|
||||
for (i = 0; i < packet_length; i++) {
|
||||
// Check we have enough space for next set of chars
|
||||
if ( (cnt + 6) > buff_size)
|
||||
break;
|
||||
|
||||
cnt += sprintf(buff + cnt, "0x%02hhx|", packet_buffer[i]);
|
||||
}
|
||||
|
||||
cnt += sprintf(buff + cnt, "\n");
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define RS485LOGFILE "/tmp/RS485.log"
|
||||
#define RS485BYTELOGFILE "/tmp/RS485raw.log"
|
||||
|
||||
|
@ -18,10 +20,11 @@ void logPacketRead(unsigned char *packet_buffer, int packet_length);
|
|||
void logPacketWrite(unsigned char *packet_buffer, int packet_length);
|
||||
void logPacketError(unsigned char *packet_buffer, int packet_length);
|
||||
void logPacketByte(unsigned char *byte);
|
||||
void logPacket(logmask_t from, int level, unsigned char *packet_buffer, int packet_length, bool is_read) ;
|
||||
int beautifyPacket(char *buff, int buff_size, unsigned char *packet_buffer, int packet_length, bool is_read);
|
||||
|
||||
// Only use for manual debugging
|
||||
//void debuglogPacket(unsigned char *packet_buffer, int packet_length);
|
||||
void debuglogPacket(int16_t from, unsigned char *packet_buffer, int packet_length, bool is_read);
|
||||
int beautifyPacket(char *buff, unsigned char *packet_buffer, int packet_length, bool is_read);
|
||||
void debuglogPacket(logmask_t from, unsigned char *packet_buffer, int packet_length, bool is_read, bool forcelog);
|
||||
|
||||
|
||||
#endif //PACKETLOGGER_H_
|
28
source/pda.c
28
source/pda.c
|
@ -152,13 +152,21 @@ void equiptment_update_cycle(int eqID) {
|
|||
LOG(PDA_LOG,LOG_DEBUG, "Start new equipment cycle bitmask 0x%04x\n",
|
||||
update_equiptment_bitmask);
|
||||
|
||||
for (i=0; i < _aqualink_data->total_buttons - 2 ; i++) { // total_buttons - 2 because we don't get heaters in this cycle
|
||||
if (pda_m_type() == PM_EQUIPTMENT_STATUS) {
|
||||
LOG(PDA_LOG,LOG_DEBUG, "Full equiptment update\n");
|
||||
} else {
|
||||
LOG(PDA_LOG,LOG_DEBUG, "Main menu equiptment update (4 devices)\n");
|
||||
}
|
||||
|
||||
for (i=0; i < _aqualink_data->total_buttons - 3 ; i++) { // total_buttons - 3 because we don't get heaters in this cycle
|
||||
//for (i=0; i < _aqualink_data->total_buttons; i++) { // total_buttons - 2 because we don't get heaters in this cycle
|
||||
if ((update_equiptment_bitmask & (1 << (i))) != (1 << (i))) {
|
||||
if (_aqualink_data->aqbuttons[i].led->state != OFF) {
|
||||
_aqualink_data->aqbuttons[i].led->state = OFF;
|
||||
_aqualink_data->updated = true;
|
||||
LOG(PDA_LOG,LOG_DEBUG, "Turn off equipment id %d %s not seen in last cycle\n", i, _aqualink_data->aqbuttons[i].name);
|
||||
}
|
||||
//LOG(PDA_LOG,LOG_DEBUG, "Thick id %d %s total = %d\n", i, _aqualink_data->aqbuttons[i].name, _aqualink_data->total_buttons);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -812,6 +820,7 @@ bool process_pda_packet(unsigned char *packet, int length)
|
|||
int index = -1;
|
||||
static bool equiptment_update_loop = false;
|
||||
static bool read_equiptment_menu = false;
|
||||
static int time_msg_cnt = 0;
|
||||
|
||||
_aqualink_data->last_packet_type = packet[PKT_CMD];
|
||||
|
||||
|
@ -829,6 +838,7 @@ bool process_pda_packet(unsigned char *packet, int length)
|
|||
break;
|
||||
|
||||
case CMD_STATUS:
|
||||
//LOG(PDA_LOG,LOG_DEBUG, "**** PDA Menu type %d ****\n", pda_m_type());
|
||||
_aqualink_data->last_display_message[0] = '\0';
|
||||
if (equiptment_update_loop == false && pda_m_type() == PM_EQUIPTMENT_STATUS)
|
||||
{
|
||||
|
@ -866,6 +876,21 @@ bool process_pda_packet(unsigned char *packet, int length)
|
|||
case CMD_MSG_LONG:
|
||||
msg = (char *)packet + PKT_DATA + 1;
|
||||
index = packet[PKT_DATA] & 0xF;
|
||||
|
||||
// When nothing is on, all we see it time updated, so count them and if we get 2 in a row, everyting is off.
|
||||
if (packet[PKT_DATA] == 0x40) { // 0x40 is ID for time.
|
||||
time_msg_cnt++;
|
||||
LOG(PDA_LOG,LOG_DEBUG, "**** Time message count %d ****\n",time_msg_cnt);
|
||||
if ( time_msg_cnt >= 2) {
|
||||
equiptment_update_cycle(-1);
|
||||
}
|
||||
if (time_msg_cnt >= (INT8_MAX -10)){
|
||||
time_msg_cnt=2;
|
||||
}
|
||||
} else {
|
||||
time_msg_cnt = 0;
|
||||
}
|
||||
|
||||
if (packet[PKT_DATA] == 0x82)
|
||||
{ // Air & Water temp is always this ID
|
||||
process_pda_packet_msg_long_temp(msg);
|
||||
|
@ -873,6 +898,7 @@ bool process_pda_packet(unsigned char *packet, int length)
|
|||
else if (packet[PKT_DATA] == 0x40)
|
||||
{ // Time is always on this ID
|
||||
process_pda_packet_msg_long_time(msg);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -54,6 +54,9 @@ Pull revision from string examples
|
|||
' REV. O.2 '
|
||||
'B0029221 REV T.0.1'
|
||||
' REV T.0.1'
|
||||
|
||||
AllButton: Control Panel version B0316823 REV Yg
|
||||
|
||||
*/
|
||||
bool rsm_get_revision(char *dest, const char *src, int src_len)
|
||||
{
|
||||
|
@ -156,9 +159,9 @@ bool rsm_isempy(const char *src, int length)
|
|||
int i;
|
||||
for(i=0; i < length; i++) {
|
||||
if (src[i] > 32 && src[i] < 127) // 32 is space
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
Can probably replace this with rsm_strncasestr in all code.
|
||||
|
@ -493,4 +496,4 @@ int rsm_HHMM2min(char *message) {
|
|||
int min = strtoul(message+3, &ptr, 10);
|
||||
|
||||
return (hour*60)+min;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,9 +39,9 @@
|
|||
#include "config.h"
|
||||
|
||||
#define SLOG_MAX 80
|
||||
#define PACKET_MAX 600
|
||||
#define PACKET_MAX 800
|
||||
|
||||
#define VERSION "serial_logger V2.3"
|
||||
#define VERSION "serial_logger V2.6"
|
||||
|
||||
/*
|
||||
typedef enum used {
|
||||
|
@ -65,6 +65,7 @@ struct aqconfig _aqconfig_;
|
|||
char _panelType[AQ_MSGLEN];
|
||||
char _panelRev[AQ_MSGLEN];
|
||||
bool _panelPDA = false;
|
||||
int _panelRevInt = 0;
|
||||
|
||||
typedef struct serial_id_log {
|
||||
unsigned char ID;
|
||||
|
@ -98,14 +99,46 @@ void broadcast_log(char *msg){
|
|||
}
|
||||
void intHandler(int dummy) {
|
||||
_keepRunning = false;
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "Stopping!\n");
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Stopping!\n");
|
||||
if (_playback_file) // If we are reading file, loop is irevelent
|
||||
exit(0);
|
||||
}
|
||||
#else
|
||||
int serial_logger (int rs_fd, char *port_name, int logLevel) {
|
||||
return _serial_logger(rs_fd, port_name, PACKET_MAX, (logLevel>=LOG_NOTICE?logLevel:LOG_NOTICE), true, false, false, false, false);
|
||||
int serial_logger (int rs_fd, char *port_name, int logLevel, int slogger_packets, char *slogger_ids)
|
||||
{
|
||||
int packets=PACKET_MAX;
|
||||
unsigned int n;
|
||||
int i=0;
|
||||
|
||||
// Reset some globals so we run.
|
||||
_filters=0;
|
||||
_pfilters=0;
|
||||
_keepRunning = true;
|
||||
|
||||
if (slogger_packets > 0)
|
||||
packets = slogger_packets;
|
||||
|
||||
int id_len = strlen(slogger_ids)-4;
|
||||
|
||||
//LOG(SLOG_LOG, LOG_NOTICE, "Jandy filter len=%d\n",id_len);
|
||||
for (i=0; i <= id_len; i=i+5) {
|
||||
//LOG(SLOG_LOG, LOG_NOTICE, "Jandy filter loop i=%d\n",i);
|
||||
if (slogger_ids[i] == '0' && slogger_ids[i+1] == 'x') {
|
||||
//LOG(SLOG_LOG, LOG_NOTICE, "Jandy filter loop %d %d\n",slogger_ids[i],slogger_ids[i+1]);
|
||||
sscanf(&slogger_ids[i], "0x%2x", &n);
|
||||
if (n != 0) {
|
||||
_filter[_filters] = n;
|
||||
_filters++;
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Add Jandy filter %i 0x%02hhx\n",_filters, _filter[_filters-1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Running serial logger with %d pakets, loglevel %s\n",packets,elevel2text(logLevel>=LOG_NOTICE?logLevel:LOG_NOTICE) );
|
||||
|
||||
return _serial_logger(rs_fd, port_name, packets, (logLevel>=LOG_NOTICE?logLevel:LOG_NOTICE), true, false, false, false, false);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define MASTER " <-- Master control panel"
|
||||
|
@ -122,6 +155,10 @@ int serial_logger (int rs_fd, char *port_name, int logLevel) {
|
|||
#define CHEM " <-- Chemlink"
|
||||
#define JXI_HEATER " <-- LXi / LRZ Heater"
|
||||
|
||||
#define IAQLNK2 " <-- iAqualink 2.0"
|
||||
#define HEAT_PUMP " <-- Heat Pump"
|
||||
#define REM_PWR_CENT " <-- Remote Power Center"
|
||||
|
||||
#define UNKNOWN " <-- Unknown Device"
|
||||
|
||||
#define P_VSP " <-- Pentair VSP"
|
||||
|
@ -135,31 +172,53 @@ int serial_logger (int rs_fd, char *port_name, int logLevel) {
|
|||
const char *getDevice(unsigned char ID) {
|
||||
if (ID >= 0x00 && ID <= 0x03)
|
||||
return MASTER;
|
||||
|
||||
if (ID >= 0x08 && ID <= 0x0B)
|
||||
return KEYPAD;
|
||||
|
||||
if (ID >= 0x50 && ID <= 0x53)
|
||||
return SWG;
|
||||
|
||||
if (ID >= 0x20 && ID <= 0x23)
|
||||
return SPA_R;
|
||||
|
||||
if (ID >= 0x30 && ID <= 0x33)
|
||||
return AQUA;
|
||||
|
||||
if (ID >= 0x38 && ID <= 0x3B)
|
||||
return LX_HEATER;
|
||||
|
||||
if (ID >= 0x40 && ID <= 0x43)
|
||||
return ONE_T;
|
||||
|
||||
if (ID >= 0x48 && ID <= 0x4B)
|
||||
return RS_SERL;
|
||||
|
||||
if (ID >= 0x58 && ID <= 0x5B)
|
||||
return PC_DOCK;
|
||||
|
||||
if (ID >= 0x60 && ID <= 0x63)
|
||||
return PDA;
|
||||
|
||||
if (ID >= 0x68 && ID <= 0x6B)
|
||||
return JXI_HEATER;
|
||||
//if (ID >= 0x70 && ID <= 0x73)
|
||||
|
||||
if (ID >= 0x70 && ID <= 0x73)
|
||||
return HEAT_PUMP;
|
||||
|
||||
// Looks like 0xe0 is also a Jandy ePump
|
||||
if (ID >= 0x78 && ID <= 0x7B)
|
||||
return EPUMP;
|
||||
|
||||
if (ID >= 0x80 && ID <= 0x83)
|
||||
return CHEM;
|
||||
|
||||
if (ID >= 0xA0 && ID <= 0xA3)
|
||||
return IAQLNK2;
|
||||
|
||||
if (ID >= 0x28 && ID <= 0x2B)
|
||||
return REM_PWR_CENT;
|
||||
|
||||
//if (ID == 0x08)
|
||||
// return KEYPAD;
|
||||
|
||||
|
@ -301,6 +360,51 @@ void getPanelInfo(int rs_fd, unsigned char *packet_buffer, int packet_length)
|
|||
if (_panelType[1] == 'P' && _panelType[2] == 'D') { // PDA Panel
|
||||
_panelPDA = true;
|
||||
}
|
||||
|
||||
char REV[5];
|
||||
if ( rsm_get_revision(REV, _panelRev, AQ_MSGLEN) ) {
|
||||
_panelRevInt = REV[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool filterMatch(unsigned char ID, unsigned char *packet_buffer, bool failNoFilters) {
|
||||
int i;
|
||||
|
||||
//printf("Check 0x%02hhx & 0x%02hhx - ",ID,packet_buffer[PKT_DEST]);
|
||||
|
||||
if (_filters != 0 || _pfilters != 0)
|
||||
{
|
||||
bool dest_match = false;
|
||||
bool src_match = false;
|
||||
bool pent_match = false;
|
||||
|
||||
if (_filters != 0) {
|
||||
for (i=0; i < _filters; i++) {
|
||||
if ( packet_buffer[PKT_DEST] == _filter[i])
|
||||
dest_match = true;
|
||||
if ( ID == _filter[i] && packet_buffer[PKT_DEST] == 0x00 )
|
||||
src_match = true;
|
||||
}
|
||||
}
|
||||
if (_pfilters != 0) {
|
||||
for (i=0; i < _pfilters; i++) {
|
||||
if ( packet_buffer[PEN_PKT_FROM] == _pfilter[i] ||
|
||||
packet_buffer[PEN_PKT_DEST] == _pfilter[i] )
|
||||
pent_match = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(dest_match == false && src_match == false && pent_match == false) {
|
||||
//printf("don't print\n");
|
||||
return false;
|
||||
}
|
||||
} else if (failNoFilters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//printf("print\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef SERIAL_LOGGER
|
||||
|
@ -325,6 +429,10 @@ void printPacket(unsigned char ID, unsigned char *packet_buffer, int packet_leng
|
|||
return;
|
||||
}
|
||||
|
||||
if ( filterMatch(ID, packet_buffer, false) == false ) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
// if filter is set and not match, then return without printing.
|
||||
if (_filters != 0 || _pfilters != 0)
|
||||
{
|
||||
|
@ -351,7 +459,7 @@ void printPacket(unsigned char ID, unsigned char *packet_buffer, int packet_leng
|
|||
if(dest_match == false && src_match == false && pent_match == false)
|
||||
return;
|
||||
}
|
||||
|
||||
*/
|
||||
if (message != NULL)
|
||||
printf("%s",message);
|
||||
|
||||
|
@ -484,7 +592,7 @@ int main(int argc, char *argv[]) {
|
|||
if (_playback_file) {
|
||||
rs_fd = open(argv[1], O_RDONLY | O_NOCTTY | O_NONBLOCK | O_NDELAY);
|
||||
if (rs_fd < 0) {
|
||||
LOG(RSSD_LOG, LOG_ERR, "Unable to open file: %s\n", argv[1]);
|
||||
LOG(SLOG_LOG, LOG_ERR, "Unable to open file: %s\n", argv[1]);
|
||||
displayLastSystemError(argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
@ -495,7 +603,7 @@ int main(int argc, char *argv[]) {
|
|||
rs_fd = init_blocking_serial_port(argv[1]);
|
||||
|
||||
if (rs_fd < 0) {
|
||||
LOG(RSSD_LOG, LOG_ERR, "Unable to open port: %s\n", argv[1]);
|
||||
LOG(SLOG_LOG, LOG_ERR, "Unable to open port: %s\n", argv[1]);
|
||||
displayLastSystemError(argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
@ -505,14 +613,14 @@ int main(int argc, char *argv[]) {
|
|||
signal(SIGTERM, intHandler);
|
||||
|
||||
if (!errorMonitor) {
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "Logging serial information!\n");
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Logging serial information!\n");
|
||||
} else {
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "Logging serial errors!\n");
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Logging serial errors!\n");
|
||||
}
|
||||
if (_aqconfig_.log_protocol_packets)
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "Logging packets to %s!\n",RS485LOGFILE);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Logging packets to %s!\n",RS485LOGFILE);
|
||||
if (_aqconfig_.log_raw_bytes)
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "Logging raw bytes to %s!\n",RS485BYTELOGFILE);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Logging raw bytes to %s!\n",RS485BYTELOGFILE);
|
||||
|
||||
if (logLevel < LOG_DEBUG && errorMonitor==false )
|
||||
printf("Please wait.");
|
||||
|
@ -554,6 +662,13 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
int blankReads = 0;
|
||||
bool returnError = false;
|
||||
|
||||
bool found_swg =false;
|
||||
bool found_vsp =false;
|
||||
bool found_jxi =false;
|
||||
bool found_lx =false;
|
||||
bool found_chem =false;
|
||||
bool found_pent_vsp =false;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &start_time);
|
||||
if (timePackets) {
|
||||
clock_gettime(CLOCK_REALTIME, &packet_start_time);
|
||||
|
@ -561,7 +676,7 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
|
||||
while (_keepRunning == true) {
|
||||
if (rs_fd < 0) {
|
||||
LOG(RSSD_LOG, LOG_ERR, "ERROR, serial port disconnect\n");
|
||||
LOG(SLOG_LOG, LOG_ERR, "ERROR, serial port disconnect\n");
|
||||
}
|
||||
|
||||
packet_length = get_packet(rs_fd, packet_buffer);
|
||||
|
@ -575,27 +690,27 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
|
||||
if (packet_length == AQSERR_READ) {
|
||||
// Unrecoverable read error. Force an attempt to reconnect.
|
||||
LOG(RSSD_LOG, LOG_ERR, "ERROR, on serial port! Please check %s\n",port_name);
|
||||
LOG(SLOG_LOG, LOG_ERR, "ERROR, on serial port! Please check %s\n",port_name);
|
||||
_keepRunning = false;
|
||||
returnError = true;
|
||||
} else if (packet_length == AQSERR_TIMEOUT) {
|
||||
// Unrecoverable read error. Force an attempt to reconnect.
|
||||
LOG(RSSD_LOG, LOG_ERR, "ERROR, Timeout on serial port, nothing read! Please check %s\n",port_name);
|
||||
LOG(SLOG_LOG, LOG_ERR, "ERROR, Timeout on serial port, nothing read! Please check %s\n",port_name);
|
||||
_keepRunning = false;
|
||||
returnError = true;
|
||||
} else if (packet_length < 0) {
|
||||
// Error condition
|
||||
if (errorMonitor && last_packet_length > 0) { // Error packet wwould have already been printed.
|
||||
char buff[900];
|
||||
beautifyPacket(buff, last_packet_buffer, last_packet_length, true);
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "Previous packet (before error)\n");
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "%s------------------------------\n",buff);
|
||||
//LOG(RSSD_LOG, LOG_NOTICE, "\n");
|
||||
char buff[1024];
|
||||
beautifyPacket(buff, 1024, last_packet_buffer, last_packet_length, true);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Previous packet (before error)\n");
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "%s------------------------------\n",buff);
|
||||
//LOG(SLOG_LOG, LOG_NOTICE, "\n");
|
||||
}
|
||||
} else if (packet_length == 0) {
|
||||
// Nothing read
|
||||
if (++blankReads > (rsSerialSpeedTest?100000000:1000) ) {
|
||||
LOG(RSSD_LOG, LOG_ERR, "ERROR, too many blank reads! Please check %s\n",port_name);
|
||||
LOG(SLOG_LOG, LOG_ERR, "ERROR, too many blank reads! Please check %s\n",port_name);
|
||||
_keepRunning = false;
|
||||
returnError = true;
|
||||
}
|
||||
|
@ -603,10 +718,14 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
delay(1);
|
||||
} else if (packet_length > 0) {
|
||||
blankReads = 0;
|
||||
//LOG(RSSD_LOG, LOG_DEBUG_SERIAL, "Received Packet for ID 0x%02hhx of type %s\n", packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length));
|
||||
//LOG(SLOG_LOG, LOG_DEBUG_SERIAL, "Received Packet for ID 0x%02hhx of type %s\n", packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length));
|
||||
#ifdef SERIAL_LOGGER
|
||||
if (logLevel > LOG_NOTICE)
|
||||
printPacket(lastID, packet_buffer, packet_length, timePackets?extra_message:NULL);
|
||||
#else
|
||||
if (logLevel >= LOG_DEBUG || filterMatch(lastID, packet_buffer, true)) {
|
||||
debuglogPacket(SLOG_LOG, packet_buffer, packet_length, true, true);
|
||||
}
|
||||
#endif
|
||||
if (getProtocolType(packet_buffer) == PENTAIR) {
|
||||
found = false;
|
||||
|
@ -639,7 +758,7 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
}
|
||||
|
||||
if (packet_buffer[PKT_DEST] == DEV_MASTER /*&& packet_buffer[PKT_CMD] == CMD_ACK*/) {
|
||||
//LOG(RSSD_LOG, LOG_NOTICE, "ID is in use 0x%02hhx %x\n", lastID, lastID);
|
||||
//LOG(SLOG_LOG, LOG_NOTICE, "ID is in use 0x%02hhx %x\n", lastID, lastID);
|
||||
for (i = 0; i <= sindex; i++) {
|
||||
if (slog[i].ID == lastID) {
|
||||
slog[i].inuse = true;
|
||||
|
@ -662,7 +781,7 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
|
||||
if (packet_length > 0 && packet_buffer[PKT_DEST] != 0x00) {
|
||||
// Only test for packets from panel, when you test to panel you are timing reply.
|
||||
LOG(RSSD_LOG, LOG_ERR, "SERIOUS RS485 ERROR, Slow serial port read detected, (check RS485 adapteer / os performance / USB serial speed\n");
|
||||
LOG(SLOG_LOG, LOG_ERR, "SERIOUS RS485 ERROR, Slow serial port read detected, (check RS485 adapteer / os performance / USB serial speed\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -670,7 +789,7 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
|
||||
#ifndef SERIAL_LOGGER
|
||||
if(received_packets%100==0) {
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "Read %d of %d packets\n", received_packets, logPackets);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Read %d of %d packets\n", received_packets, logPackets);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -704,42 +823,62 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
|
||||
sl_timespec_subtract(&elapsed, &end_time, &start_time);
|
||||
|
||||
LOG(RSSD_LOG, LOG_DEBUG, "\n\n");
|
||||
LOG(SLOG_LOG, LOG_DEBUG, "\n\n");
|
||||
if (logLevel < LOG_DEBUG)
|
||||
printf("\n\n");
|
||||
|
||||
if (sindex >= SLOG_MAX)
|
||||
LOG(RSSD_LOG, LOG_ERR, "Ran out of storage, some ID's were not captured, please increase SLOG_MAX and recompile\n");
|
||||
LOG(SLOG_LOG, LOG_ERR, "Ran out of storage, some ID's were not captured, please increase SLOG_MAX and recompile\n");
|
||||
|
||||
if (elapsed.tv_sec > 0) {
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "RS485 interface received %d packets in %d seconds (~%.2f Msg/Sec)\n", received_packets, elapsed.tv_sec, (received_packets / (float)elapsed.tv_sec) );
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "RS485 interface received %d packets in %d seconds (~%.2f Msg/Sec)\n", received_packets, elapsed.tv_sec, (received_packets / (float)elapsed.tv_sec) );
|
||||
}
|
||||
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "Jandy Control Panel Model : %s\n", _panelType);
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "Jandy Control Panel Version : %s\n", _panelRev);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Jandy Control Panel Model : %s\n", _panelType);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Jandy Control Panel Version : %s\n", _panelRev);
|
||||
|
||||
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "Jandy ID's found\n");
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Jandy ID's found\n");
|
||||
for (i = 0; i < sindex; i++) {
|
||||
//LOG(RSSD_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", slog[i].ID, (slog[i].inuse == true) ? "in use" : "not used",
|
||||
//LOG(SLOG_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", slog[i].ID, (slog[i].inuse == true) ? "in use" : "not used",
|
||||
// (slog[i].inuse == false && canUse(slog[i].ID) == true)? " <-- can use for Aqualinkd" : "");
|
||||
//if (logLevel >= LOG_DEBUG || slog[i].inuse == true || canUse(slog[i].ID) == true) {
|
||||
if (logLevel >= LOG_DEBUG || slog[i].inuse == true || canUse(slog[i].ID) == true || printAllIDs == true) {
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", slog[i].ID, (slog[i].inuse == true) ? "in use " : "not used",
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", slog[i].ID, (slog[i].inuse == true) ? "in use " : "not used",
|
||||
(slog[i].inuse == false)?canUseExtended(slog[i].ID):getDevice(slog[i].ID));
|
||||
}
|
||||
|
||||
if (slog[i].inuse == true) {
|
||||
if (slog[i].ID >= JANDY_DEC_SWG_MIN && slog[i].ID <= JANDY_DEC_SWG_MAX) {
|
||||
found_swg =true;
|
||||
} else if (slog[i].ID >= JANDY_DEC_PUMP_MIN && slog[i].ID <= JANDY_DEC_PUMP_MAX) {
|
||||
found_vsp =true;
|
||||
} else if (slog[i].ID >= JANDY_DEC_JXI_MIN && slog[i].ID <= JANDY_DEC_JXI_MAX) {
|
||||
found_jxi =true;
|
||||
} else if (slog[i].ID >= JANDY_DEC_LX_MIN && slog[i].ID <= JANDY_DEC_LX_MAX) {
|
||||
found_lx =true;
|
||||
} else if (slog[i].ID >= JANDY_DEC_CHEM_MIN && slog[i].ID <= JANDY_DEC_CHEM_MAX) {
|
||||
found_chem =true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pent_sindex > 0) {
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "\n\n");
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "Pentair ID's found\n");
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "\n\n");
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Pentair ID's found\n");
|
||||
}
|
||||
for (i=0; i < pent_sindex; i++) {
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", pent_slog[i].ID, (pent_slog[i].inuse == true) ? "in use " : "not used",
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", pent_slog[i].ID, (pent_slog[i].inuse == true) ? "in use " : "not used",
|
||||
(pent_slog[i].inuse == false)?canUseExtended(pent_slog[i].ID):getPentairDevice(pent_slog[i].ID));
|
||||
|
||||
if (pent_slog[i].inuse == true) {
|
||||
if (pent_slog[i].ID >= PENTAIR_DEC_PUMP_MIN && pent_slog[i].ID <= PENTAIR_DEC_PUMP_MAX) {
|
||||
found_pent_vsp=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "\n\n");
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "\n\n");
|
||||
|
||||
|
||||
char mainID = 0x00;
|
||||
|
@ -759,37 +898,57 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
rssaID = slog[i].ID;
|
||||
else if (canUseONET(slog[i].ID) && extID == 0x00)
|
||||
extID = slog[i].ID;
|
||||
else if (canUseIQAT(slog[i].ID) && (extID == 0x00 || canUseONET(extID)))
|
||||
extID = slog[i].ID;
|
||||
else if (canUseIQAT(slog[i].ID) && (extID == 0x00 || canUseONET(extID)))
|
||||
{
|
||||
// Check panel rev is higher than REV Q (if it's been found). Panel rev I pings on IAQtouch id but it's not supported.
|
||||
if ( _panelRevInt == 0 || _panelRevInt >= 81 )
|
||||
extID = slog[i].ID;
|
||||
}
|
||||
} else {
|
||||
if (canUsePDA(slog[i].ID) && mainID == 0x00)
|
||||
mainID = slog[i].ID;
|
||||
}
|
||||
|
||||
}
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "Suggested aqualinkd.conf values\n");
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "-------------------------\n");
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Suggested aqualinkd.conf values\n");
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "-------------------------\n");
|
||||
if (strlen (_panelType) > 0)
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "panel_type = %s\n",_panelType);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "panel_type = %s\n",_panelType);
|
||||
|
||||
if (mainID != 0x00)
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "device_id = 0x%02hhx\n",mainID);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "device_id = 0x%02hhx\n",mainID);
|
||||
|
||||
if (rssaID != 0x00)
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "rssa_device_id = 0x%02hhx\n",rssaID);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "rssa_device_id = 0x%02hhx\n",rssaID);
|
||||
|
||||
if (extID != 0x00)
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "extended_device_id = 0x%02hhx\n",extID);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "extended_device_id = 0x%02hhx\n",extID);
|
||||
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "-------------------------\n");
|
||||
if (found_pent_vsp)
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "read_RS485_vsfPump = yes\n");
|
||||
if (found_vsp)
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "read_RS485_ePump = yes\n");
|
||||
if (found_swg)
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "read_RS485_swg = yes\n");
|
||||
if (found_jxi)
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "read_RS485_JXi = yes\n");
|
||||
if (found_lx)
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "read_RS485_LX = yes\n");
|
||||
if (found_chem)
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "read_RS485_Chem = yes\n");
|
||||
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "-------------------------\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "timespec_subtract.h"
|
||||
|
||||
|
||||
|
||||
|
||||
int sl_timespec_subtract (struct timespec *result, const struct timespec *x, const struct timespec *y)
|
||||
{
|
||||
return timespec_subtract(result,x,y);
|
||||
}
|
||||
/*
|
||||
int sl_timespec_subtract (struct timespec *result, const struct timespec *x, const struct timespec *y)
|
||||
{
|
||||
struct timespec tmp;
|
||||
|
@ -816,7 +975,7 @@ int sl_timespec_subtract (struct timespec *result, const struct timespec *x, con
|
|||
|
||||
return x->tv_sec < tmp.tv_sec;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ int logPackets = PACKET_MAX;
|
|||
//int serial_logger(int rs_fd, char *port_name);
|
||||
//int serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, bool panleProbe, bool rsSerialSpeedTest, bool errorMonitor);
|
||||
|
||||
int serial_logger (int rs_fd, char *port_name, int logLevel);
|
||||
//int serial_logger (int rs_fd, char *port_name, int logLevel);
|
||||
int serial_logger (int rs_fd, char *port_name, int logLevel, int slogger_packets, char *slogger_ids);
|
||||
void getPanelInfo(int rs_fd, unsigned char *packet_buffer, int packet_length);
|
||||
|
||||
#endif // SERIAL_LOGGER_H_
|
|
@ -8,6 +8,8 @@
|
|||
#include "aqualink.h"
|
||||
#include "serialadapter.h"
|
||||
#include "packetLogger.h"
|
||||
#include "color_lights.h"
|
||||
#include "allbutton.h"
|
||||
|
||||
#define RSSA_QLEN 20
|
||||
|
||||
|
@ -32,6 +34,14 @@ unsigned char getAux14[] = {0x00,0x01,0x00,RS_SA_AUX14};
|
|||
unsigned char getAux15[] = {0x00,0x01,0x00,RS_SA_AUX15};
|
||||
#endif
|
||||
|
||||
// processLEDstate exists in allbutton.c
|
||||
//void processLEDstate(struct aqualinkdata *aq_data, unsigned char *packet, logmask_t from);
|
||||
void processRSSALEDstate(struct aqualinkdata *aq_data, unsigned char *packet)
|
||||
{
|
||||
processLEDstate(aq_data, packet, RSSA_LOG);
|
||||
}
|
||||
|
||||
|
||||
bool push_rssa_cmd(unsigned char *cmd) {
|
||||
|
||||
if (_rssa_q_length >= RSSA_QLEN ) {
|
||||
|
@ -91,7 +101,8 @@ void queue_aqualink_rssadapter_setpoint(unsigned char typeID, int val) {
|
|||
push_rssa_cmd(setSP);
|
||||
}
|
||||
|
||||
unsigned char devID(int bIndex) {
|
||||
/* NSF Need to delete this and use aqbuttonp[].rssd_code */
|
||||
unsigned char RSSAdevID(int bIndex) {
|
||||
// pool = 0; spa = 1; aux1 = 2 etc
|
||||
// rssa pool / spa are different. aux1 = 21 (0x15) then goes up from their in order.
|
||||
|
||||
|
@ -111,7 +122,8 @@ unsigned char devID(int bIndex) {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
void rssadapter_device_state(unsigned char devID, unsigned char state) {
|
||||
|
||||
void rssadapter_device_state(const unsigned char devID, const unsigned char state) {
|
||||
unsigned char setDev[] = {0x00,0x01,state,devID};
|
||||
push_rssa_cmd(setDev);
|
||||
}
|
||||
|
@ -121,13 +133,34 @@ void rssadapter_device_off(unsigned char devID) {
|
|||
push_rssa_cmd(setDev);
|
||||
}
|
||||
*/
|
||||
|
||||
void set_aqualink_rssadapter_aux_extended_state(const aqkey *button, const unsigned char state) {
|
||||
|
||||
LOG(RSSA_LOG,LOG_DEBUG, "Sending 0x%02hhx to %s\n",state, button->label);
|
||||
|
||||
rssadapter_device_state(button->rssd_code, state); // Set state
|
||||
rssadapter_device_state(button->rssd_code, 0x00); // 0x00 meand Get curent state (for color lights the return state is 0)
|
||||
}
|
||||
|
||||
void set_aqualink_rssadapter_aux_state(const aqkey *button, bool turnOn)
|
||||
{
|
||||
LOG(RSSA_LOG,LOG_DEBUG, "Turning button %s %s\n",button->label,(turnOn?"On":"Off"));
|
||||
|
||||
rssadapter_device_state( button->rssd_code, (turnOn?RS_SA_ON:RS_SA_OFF) );
|
||||
|
||||
// NOTE. If we turn off AUX1 and get this return HEX: 0x10|0x02|0x48|0x13|0x02|0x00|0x0e|0x15|0x92|0x10|0x03|
|
||||
// The 0x0e means some from of oiption is set (ie cleaner). Maybe try to turn cleaner off instead 0x15 is aux1 1x10 is cleaner.
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void set_aqualink_rssadapter_aux_state(int buttonIndex, bool turnOn)
|
||||
{
|
||||
LOG(RSSA_LOG,LOG_DEBUG, "Turning button %d %s\n",buttonIndex,(turnOn?"On":"Off"));
|
||||
|
||||
rssadapter_device_state( devID(buttonIndex), (turnOn?0x81:0x80) );
|
||||
rssadapter_device_state( RSSAdevID(buttonIndex), (turnOn?RS_SA_ON:RS_SA_OFF) );
|
||||
}
|
||||
|
||||
*/
|
||||
void increase_aqualink_rssadapter_pool_setpoint(char *args, struct aqualinkdata *aqdata) {
|
||||
int val = atoi(args);
|
||||
val = setpoint_check(POOL_HTR_SETOINT, aqdata->pool_htr_set_point + val, aqdata);
|
||||
|
@ -185,6 +218,20 @@ void set_aqualink_rssadapter_spa_setpoint(char *args, struct aqualinkdata *aqdat
|
|||
*/
|
||||
}
|
||||
|
||||
|
||||
#ifdef CLIGHT_PANEL_FIX
|
||||
/* This is to overcome Jandy bug where panel doesn;t show the state of color light */
|
||||
void get_aqualink_rssadapter_colorlight_statuses(struct aqualinkdata *aq_data)
|
||||
{
|
||||
for (int i=0; i < aq_data->num_lights; i++) {
|
||||
if (aq_data->lights[i].lightType != LC_PROGRAMABLE ) {
|
||||
// LC_PROGRAMABLE is aqualinkd to set, so works as normal button
|
||||
rssadapter_device_state(aq_data->lights[i].button->rssd_code, 0x00); // 0x00 meand Get curent state
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void get_aqualink_rssadapter_setpoints() {
|
||||
//push_rssa_cmd(getModel);
|
||||
push_rssa_cmd(getUnits);
|
||||
|
@ -225,9 +272,14 @@ bool process_rssadapter_packet(unsigned char *packet, int length, struct aqualin
|
|||
|
||||
//LOG(RSSA_LOG,LOG_DEBUG, " Received message\n");
|
||||
//debuglogPacket(RSSA_LOG, packet, length, true);
|
||||
|
||||
if (cnt == 0 || cnt >= 250) {
|
||||
#ifdef CLIGHT_PANEL_FIX
|
||||
if ( (cnt % 10 == 0) || cnt == 0 ) { // NSF Change to 20 and 1
|
||||
get_aqualink_rssadapter_colorlight_statuses(aq_data);
|
||||
}
|
||||
#endif
|
||||
if (cnt == 0 || cnt >= 100) {
|
||||
LOG(RSSA_LOG,LOG_INFO, "Queue device update requests\n");
|
||||
|
||||
if (cnt == 0) {
|
||||
// The below inturn calls get_aqualink_rssadapter_setpoints()
|
||||
// But do it here as it's the first init, cnt=0 will only happen once
|
||||
|
@ -255,8 +307,13 @@ bool process_rssadapter_packet(unsigned char *packet, int length, struct aqualin
|
|||
LOG(RSSA_LOG,LOG_DEBUG, "Probe received, will queue device update shortly\n");
|
||||
//queueGetProgramData(RSSADAPTER, aq_data);
|
||||
cnt=-5; // Connection reset, so queue the status update
|
||||
}
|
||||
if (packet[PKT_CMD] == 0x13) {
|
||||
|
||||
} else if (packet[PKT_CMD] == CMD_STATUS) {
|
||||
// This is identical to allbutton status packet.
|
||||
//LOG(RSSA_LOG,LOG_DEBUG, "RS Received STATUS length %d.\n", length);
|
||||
//debuglogPacket(RSSA_LOG, packet, length, true, true);
|
||||
processRSSALEDstate(aq_data, packet);
|
||||
} else if (packet[PKT_CMD] == 0x13) {
|
||||
//beautifyPacket(buff, packet, length);
|
||||
//LOG(RSSA_LOG,LOG_DEBUG, "%s", buff);
|
||||
//LOG(RSSA_LOG,LOG_DEBUG," Command 0x%02hhx = |0x%02hhx|0x%02hhx|0x%02hhx %d|%d|%d\n", packet[4], packet[5], packet[6], packet[7], packet[5], packet[6], packet[7]);
|
||||
|
@ -293,8 +350,60 @@ bool process_rssadapter_packet(unsigned char *packet, int length, struct aqualin
|
|||
LOG(RSSA_LOG,LOG_INFO,"Pool SP2 is %d\n", packet[6]);
|
||||
aq_data->spa_htr_set_point = (int) packet[6];
|
||||
rtn = true;
|
||||
} else if (packet[4] == 0x03) {
|
||||
// These are device status messages
|
||||
} else if (packet[4] == 0x03 || packet[4] == 0x02) { // 03 reply from query state, 02 reply from set state
|
||||
// These are device status messages
|
||||
|
||||
for (int i=0; i < aq_data->num_lights; i++) {
|
||||
if (aq_data->lights[i].lightType != LC_PROGRAMABLE &&
|
||||
aq_data->lights[i].button->rssd_code == packet[7] ) {
|
||||
|
||||
// CHANGE TO DEBUG BEFORE RELEASE
|
||||
if (aq_data->lights[i].lightType == LC_DIMMER || aq_data->lights[i].lightType == LC_DIMMER2) {
|
||||
LOG(RSSA_LOG,LOG_DEBUG,"DimmerLight '%s' is %s 0x%02hhx value '%d'%%\n",
|
||||
aq_data->lights[i].button->label,
|
||||
packet[6]==0x00?"OFF":"ON",
|
||||
packet[6],
|
||||
packet[6]==0x00?0:(packet[6] - RSSD_DIMMER_LIGHT_OFFSET));
|
||||
}else{
|
||||
LOG(RSSA_LOG,LOG_DEBUG,"ColorLight '%s' is %s 0x%02hhx value name '%s'\n",
|
||||
aq_data->lights[i].button->label,
|
||||
packet[6]==0x00?"OFF":"ON",
|
||||
packet[6],
|
||||
packet[6]==0x00?"--":light_mode_name( aq_data->lights[i].lightType,(packet[6] - RSSD_COLOR_LIGHT_OFFSET), RSSADAPTER) );
|
||||
}
|
||||
|
||||
aq_data->lights[i].RSSDstate = (packet[6]==0x00?OFF:ON);
|
||||
#ifdef CLIGHT_PANEL_FIX
|
||||
// Set LED to the correct state, but only print warning if light is on and panel states off.
|
||||
if (aq_data->lights[i].RSSDstate == ON && aq_data->lights[i].button->led->state == OFF) {
|
||||
// 0x00 is off, 0x01 is usually on, but get 0x44 for color light 0x4e=gemstone, 0x41=vodo
|
||||
LOG(RSSA_LOG,LOG_DEBUG,"ColorLight '%s' is out of sync with panel, light is '%s', panel states '%s', Fixed Jany bug!\n",
|
||||
aq_data->lights[i].button->label,
|
||||
packet[6]==0x00?"OFF":"ON",
|
||||
aq_data->lights[i].button->led->state==OFF?"OFF":"ON");
|
||||
}
|
||||
aq_data->lights[i].button->led->state = aq_data->lights[i].RSSDstate;
|
||||
#endif
|
||||
switch(aq_data->lights[i].lightType) {
|
||||
case LC_DIMMER:
|
||||
set_currentlight_value(&aq_data->lights[i], (packet[6] - RSSD_DIMMER_LIGHT_OFFSET) / 25);
|
||||
break;
|
||||
case LC_DIMMER2:
|
||||
set_currentlight_value(&aq_data->lights[i], (packet[6] - RSSD_DIMMER_LIGHT_OFFSET));
|
||||
break;
|
||||
default:
|
||||
set_currentlight_value(&aq_data->lights[i], (packet[6] - RSSD_COLOR_LIGHT_OFFSET));
|
||||
break;
|
||||
}
|
||||
/*
|
||||
if (aq_data->lights[i].lightType != LC_DIMMER ) {
|
||||
set_currentlight_value(&aq_data->lights[i], (packet[6] - RSSD_COLOR_LIGHT_OFFSET));
|
||||
} else if (aq_data->lights[i].lightType == LC_DIMMER) {
|
||||
set_currentlight_value(&aq_data->lights[i], (packet[6] - RSSD_DIMMER_LIGHT_OFFSET) / 25);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AQ_RS16
|
||||
if (packet[7] == RS_SA_AUX12) {
|
||||
LOG(RSSA_LOG,LOG_INFO,"AUX12 %d\n", packet[6]);
|
||||
|
@ -311,6 +420,7 @@ bool process_rssadapter_packet(unsigned char *packet, int length, struct aqualin
|
|||
rtn = setLEDstate(aq_data->aqbuttons[16].led, packet[6], aq_data);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,7 +530,7 @@ In return
|
|||
0x10|0x02|0x48|0x13 |0x02 |0x00 |0x0d|0x10|0x8c|0x10|0x03|
|
||||
0x10|0x02|0x48|MsgType|Status1|Status2|0x0e|DeviceID|0xXX|0x10|0x03|
|
||||
MsgType - Byte 3 = 0x13 (some state message)??
|
||||
StatType - Byte 4 = 0x02 or 0x03 (not sure meaning) Status Type ????
|
||||
StatType - Byte 4 = 0x02 reply from setstate / 0x03 reply from getstatus (I THINK)
|
||||
Status1 - Byte 5 = 0x00 0x01 (???) if Byte4 is 0x02 then this is state 0x00=off 0x01=on /
|
||||
Status2 - Byte 6 = 0x00 0x01 0x0e(option switch set can't change???) if byte4 is 0x03, this this looks to be state
|
||||
DeviceID - Byte 7 = Should match request.
|
||||
|
@ -1300,4 +1410,4 @@ Debug: RS Serial: To 0x48 of type RSSA DevStatus | HEX: 0x10|0x02|0x48|0x13|
|
|||
|
||||
*/
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -10,14 +10,21 @@ bool process_rssadapter_packet(unsigned char *packet, int length, struct aqualin
|
|||
//void rssadapter_device_on(unsigned char devID);
|
||||
//void rssadapter_device_off(unsigned char devID);
|
||||
|
||||
void set_aqualink_rssadapter_aux_state(int buttonIndex, bool turnOn);
|
||||
|
||||
//void set_aqualink_rssadapter_aux_state(int buttonIndex, bool turnOn);
|
||||
void set_aqualink_rssadapter_aux_state(const aqkey *button, bool turnOn);
|
||||
//void set_aqualink_rssadapter_aux_extended_state(int buttonIndex, const unsigned char state);
|
||||
void set_aqualink_rssadapter_aux_extended_state(const aqkey *button, const unsigned char state);
|
||||
void get_aqualink_rssadapter_setpoints();
|
||||
void set_aqualink_rssadapter_pool_setpoint(char *args, struct aqualinkdata *aqdata);
|
||||
void set_aqualink_rssadapter_spa_setpoint(char *args, struct aqualinkdata *aqdata);
|
||||
|
||||
void increase_aqualink_rssadapter_pool_setpoint(char *args, struct aqualinkdata *aqdata);
|
||||
void increase_aqualink_rssadapter_spa_setpoint(char *args, struct aqualinkdata *aqdata);
|
||||
|
||||
#ifdef CLIGHT_PANEL_FIX
|
||||
void get_aqualink_rssadapter_colorlight_statuses(struct aqualinkdata *aqdata);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
CAN ONLY REPLY WITH BELOW TO STATUS MESSAGE, UNLESS FOLLOWON 0x07
|
||||
|
@ -43,6 +50,9 @@ Same as previous reply.
|
|||
|
||||
*/
|
||||
|
||||
#define RS_SA_ON 0x81
|
||||
#define RS_SA_OFF 0x80
|
||||
|
||||
#define RS_SA_DEVSTATUS 0x13
|
||||
|
||||
// Setpoints changes are in this group./
|
||||
|
|
|
@ -59,9 +59,9 @@ bool processSimulatorPacket(unsigned char *packet, int packet_length, struct aqu
|
|||
aqdata->simulator_packet_length = packet_length;
|
||||
|
||||
if ( getLogLevel(SIM_LOG) >= LOG_DEBUG ) {
|
||||
char buff[1000];
|
||||
char buff[1024];
|
||||
//sprintf("Sending control command:")
|
||||
beautifyPacket(buff, packet, packet_length, false);
|
||||
beautifyPacket(buff, 1024, packet, packet_length, false);
|
||||
LOG(SIM_LOG,LOG_DEBUG, "Received message : %s", buff);
|
||||
}
|
||||
|
||||
|
|
110
source/utils.c
110
source/utils.c
|
@ -43,6 +43,8 @@
|
|||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
#include "rs_msg_utils.h"
|
||||
#include "aq_serial.h"
|
||||
|
||||
#define DEFAULT_LOG_FILE "/tmp/aqualinkd-inline.log"
|
||||
//#define MAXCFGLINE 265
|
||||
|
@ -63,7 +65,7 @@ static int _cfg_log_level;
|
|||
static int _log_level = LOG_WARNING;
|
||||
|
||||
static char *_loq_display_message = NULL;
|
||||
int16_t _logforcemask = 0;
|
||||
logmask_t _logforcemask = 0;
|
||||
|
||||
//static char _log_filename[256];
|
||||
|
||||
|
@ -104,13 +106,14 @@ int getSystemLogLevel()
|
|||
{
|
||||
return _log_level;
|
||||
}
|
||||
int getLogLevel(int16_t from)
|
||||
int getLogLevel(logmask_t from)
|
||||
{
|
||||
|
||||
// RSSD_LOG should default to INFO unless the mask is explicitly set.
|
||||
// IE Even if DEBUG is set, (Note ignored for the moment)
|
||||
|
||||
if ( from == RSSD_LOG && ((_logforcemask & from) == from ) && _log_level < LOG_DEBUG_SERIAL)
|
||||
//if ( from == RSSD_LOG && ((_logforcemask & from) == from ) && _log_level < LOG_DEBUG_SERIAL)
|
||||
if ( (from == RSSD_LOG || from == SLOG_LOG) && ((_logforcemask & from) == from ) && _log_level < LOG_DEBUG_SERIAL)
|
||||
return LOG_DEBUG_SERIAL;
|
||||
else if ( ((_logforcemask & from) == from ) && _log_level < LOG_DEBUG_SERIAL)
|
||||
return LOG_DEBUG;
|
||||
|
@ -186,7 +189,7 @@ bool islogFileReady()
|
|||
/*
|
||||
* This function reports the last error
|
||||
*/
|
||||
void LOGSystemError (int errnum, int16_t from, const char *on_what)
|
||||
void LOGSystemError (int errnum, logmask_t from, const char *on_what)
|
||||
{
|
||||
fputs (strerror (errno), stderr);
|
||||
fputs (": ", stderr);
|
||||
|
@ -196,7 +199,7 @@ void LOGSystemError (int errnum, int16_t from, const char *on_what)
|
|||
if (_daemonise == TRUE)
|
||||
{
|
||||
//logMessage (LOG_ERR, "%d : %s", errno, on_what);
|
||||
LOG(AQUA_LOG, LOG_ERR, "%s (%d) : %s\n", strerror (errno), errno, on_what);
|
||||
LOG(from, LOG_ERR, "%s (%d) : %s\n", strerror (errno), errno, on_what);
|
||||
closelog ();
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +286,7 @@ const char* loglevel2name(int level)
|
|||
return elevel2text(level);
|
||||
}
|
||||
|
||||
const char* logmask2name(int16_t from)
|
||||
const char* logmask2name(logmask_t from)
|
||||
{
|
||||
switch (from) {
|
||||
case NET_LOG:
|
||||
|
@ -328,6 +331,12 @@ const char* logmask2name(int16_t from)
|
|||
case SIM_LOG:
|
||||
return "Simulator: ";
|
||||
break;
|
||||
case SLOG_LOG:
|
||||
return "Serial Log:";
|
||||
break;
|
||||
case IAQL_LOG:
|
||||
return "iAqualink2: ";
|
||||
break;
|
||||
case AQUA_LOG:
|
||||
default:
|
||||
return "AqualinkD: ";
|
||||
|
@ -478,14 +487,20 @@ void test(int msg_level, char *msg)
|
|||
}
|
||||
*/
|
||||
|
||||
void addDebugLogMask(int16_t flag)
|
||||
void addDebugLogMask(logmask_t flag)
|
||||
{
|
||||
_logforcemask |= flag;
|
||||
|
||||
if (flag == IAQT_LOG) // If AQTouch add iAqualink
|
||||
_logforcemask |= IAQL_LOG;
|
||||
}
|
||||
|
||||
void removeDebugLogMask(int16_t flag)
|
||||
void removeDebugLogMask(logmask_t flag)
|
||||
{
|
||||
_logforcemask &= ~flag;
|
||||
|
||||
if (flag == IAQT_LOG) // If AQTouch remove iAqualink
|
||||
_logforcemask &= ~IAQL_LOG;
|
||||
}
|
||||
|
||||
void clearDebugLogMask()
|
||||
|
@ -493,12 +508,12 @@ void clearDebugLogMask()
|
|||
_logforcemask = 0;
|
||||
}
|
||||
|
||||
bool isDebugLogMaskSet(int16_t flag)
|
||||
bool isDebugLogMaskSet(logmask_t flag)
|
||||
{
|
||||
return _logforcemask & flag;
|
||||
}
|
||||
|
||||
void _LOG(int16_t from, int msg_level, char * message);
|
||||
void _LOG(logmask_t from, int msg_level, char * message, int message_buffer_size);
|
||||
|
||||
/*
|
||||
void logMessage(int msg_level, const char *format, ...)
|
||||
|
@ -518,7 +533,33 @@ void logMessage(int msg_level, const char *format, ...)
|
|||
}
|
||||
*/
|
||||
|
||||
void LOG(int16_t from, int msg_level, const char * format, ...)
|
||||
#define LOG_OFFSET 20 // Number of chars for logging the type example "Info: iAQ Touch: "
|
||||
|
||||
void LOG_LARGEMSG(const logmask_t from, const int msg_level, const char *message, const int message_length)
|
||||
{
|
||||
// message_length is not used at present. But maybe in th future we can add a bufer using malloc and realloc that's
|
||||
// reused between calls and simply use realloc if it's not large enough.
|
||||
// Need to be careful, as it would also need to be thread safe.
|
||||
|
||||
if ( msg_level > getLogLevel(from))
|
||||
return;
|
||||
|
||||
char buffer[LARGELOGBUFFER + LOG_OFFSET + 1];
|
||||
|
||||
memset(buffer, ' ', LOG_OFFSET * sizeof(char));
|
||||
|
||||
strncpy(&buffer[LOG_OFFSET], message, LARGELOGBUFFER);
|
||||
|
||||
int len = rsm_strncpy(&buffer[LOG_OFFSET], (unsigned char*)message, LARGELOGBUFFER, message_length);
|
||||
|
||||
if (len >= LARGELOGBUFFER) {
|
||||
sprintf(&buffer[LARGELOGBUFFER + LOG_OFFSET - 4], "...\n");
|
||||
}
|
||||
|
||||
_LOG(from, msg_level, buffer, LARGELOGBUFFER + LOG_OFFSET);
|
||||
}
|
||||
|
||||
void LOG(const logmask_t from, const int msg_level, const char * format, ...)
|
||||
{
|
||||
//printf("msg_level=%d _log_level=%d mask=%d\n",msg_level,_log_level,(_logforcemask & from));
|
||||
/*
|
||||
|
@ -532,32 +573,49 @@ void LOG(int16_t from, int msg_level, const char * format, ...)
|
|||
char buffer[LOGBUFFER];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
strncpy(buffer, " ", 20);
|
||||
//strncpy(buffer, " ", 20);
|
||||
memset(buffer, ' ', LOG_OFFSET * sizeof(char));
|
||||
|
||||
//vsprintf (&buffer[20], format, args);
|
||||
int size = vsnprintf (&buffer[20], LOGBUFFER-30, format, args);
|
||||
int size = vsnprintf (&buffer[LOG_OFFSET], LOGBUFFER-LOG_OFFSET-4, format, args);
|
||||
va_end(args);
|
||||
if (size >= LOGBUFFER-30 ) {
|
||||
sprintf(&buffer[LOGBUFFER-11], ".........\n");
|
||||
if (size >= LOGBUFFER-LOG_OFFSET-4 ) {
|
||||
sprintf(&buffer[LOGBUFFER-5], "...\n");
|
||||
}
|
||||
|
||||
_LOG(from, msg_level, buffer);
|
||||
_LOG(from, msg_level, buffer, LOGBUFFER);
|
||||
}
|
||||
|
||||
|
||||
void _LOG(int16_t from, int msg_level, char *message)
|
||||
void _LOG(logmask_t from, int msg_level, char *message, int message_buffer_size)
|
||||
{
|
||||
/*
|
||||
message should have the first LOG_OFFSET (20) characters as spaces, this allows us to add Type & From to message.
|
||||
example " The Message ..... "
|
||||
we add "Warning: NetService:The Message ..... "
|
||||
Type is characters 0 to 8
|
||||
From is characters 9 to 20
|
||||
|
||||
*/
|
||||
|
||||
int i;
|
||||
|
||||
// Make all printable chars
|
||||
for(i = 8; i+8 < strlen(&message[8]) && i < LOGBUFFER; i++) {
|
||||
if ( (message[i] < 32 || message[i] > 125) && message[i] != 10 ) {
|
||||
int msglen = strlen(&message[LOG_OFFSET]);
|
||||
|
||||
// Fill first 20 chars and any non printable chars with a space.
|
||||
for(i = 0; i < message_buffer_size && i < (msglen+LOG_OFFSET+1) ; i++) {
|
||||
if (i > LOG_OFFSET && message[i] == '\0')
|
||||
break;
|
||||
|
||||
if ( message[i] != 10 && message[i] != 13 && ( i < LOG_OFFSET || message[i] < 32 || message[i] > 125) ) {
|
||||
//printf ("Change %c to %c in %s\n",message[i], ' ', message);
|
||||
message[i] = ' ';
|
||||
}
|
||||
}
|
||||
// Add return to end of string if not already their.
|
||||
// NSF need to come back to this, doesn;t always work
|
||||
if (message[i] != '\n') {
|
||||
|
||||
// Add line feed to end of string if not already there.
|
||||
// i-1 == 10 and i == 0
|
||||
if (message[i] != '\0' || message[i-1] != '\n') {
|
||||
message[i] = '\n';
|
||||
message[i+1] = '\0';
|
||||
}
|
||||
|
@ -612,7 +670,11 @@ void _LOG(int16_t from, int msg_level, char *message)
|
|||
|
||||
// Sent the log to the UI if configured.
|
||||
if (msg_level <= LOG_ERR && _loq_display_message != NULL) {
|
||||
snprintf(_loq_display_message, 127, "%s\n",message);
|
||||
//printf ("*** Showing error in web **** \n");
|
||||
//snprintf(_loq_display_message, AQ_MSGLONGLEN-2, "%s\n",message);
|
||||
int len = rsm_strncpy(_loq_display_message, (unsigned char*)message, AQ_MSGLONGLEN-1, message_buffer_size);
|
||||
_loq_display_message[len] = '\0';
|
||||
printf ("*** Adding ERROR to buffer '%s' **** \n",_loq_display_message);
|
||||
}
|
||||
|
||||
#ifndef AQ_MANAGER
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#endif
|
||||
|
||||
#define LOGBUFFER 256
|
||||
#define LARGELOGBUFFER 1400 // / Must be at least AQ_MAXPKTLEN * 5 + 100
|
||||
|
||||
//#define MAXLEN 256
|
||||
|
||||
|
@ -27,7 +28,9 @@
|
|||
#define roundf(a) (float) ((a*100)/100) // 2 decimal places
|
||||
#define roundf3(a) (float) ((a*1000)/1000) // 3 decimal places
|
||||
|
||||
// Defined as int16_t so 16 bits to mask
|
||||
|
||||
typedef int32_t logmask_t;
|
||||
// Defined as int32_t so 32 bits to mask
|
||||
#define AQUA_LOG (1 << 0) // Aqualink Generic / catchall
|
||||
#define NET_LOG (1 << 1) // Network
|
||||
// Control protocols
|
||||
|
@ -40,14 +43,17 @@
|
|||
#define DJAN_LOG (1 << 7) // Jange Device
|
||||
#define DPEN_LOG (1 << 8) // Pentair Device
|
||||
// misc
|
||||
#define RSSD_LOG (1 << 9) // RS485 Connection /dev/ttyUSB?
|
||||
#define RSSD_LOG (1 << 9) // RS485 Connection /dev/ttyUSB DO NOT CHANGE THIS, UI HARDCODED to 512.
|
||||
#define PROG_LOG (1 << 10) // Programmer
|
||||
#define SCHD_LOG (1 << 11) // Scheduler Timer
|
||||
#define RSTM_LOG (1 << 12) // RS packet Time
|
||||
#define SIM_LOG (1 << 13) // Simulator
|
||||
#define SIM_LOG (1 << 13) // Simulator
|
||||
|
||||
#define DBGT_LOG (1 << 14) // Debug Timer
|
||||
|
||||
#define SLOG_LOG (1 << 15) // Serial_Logger
|
||||
#define IAQL_LOG (1 << 16) // iAqualink
|
||||
|
||||
#define TIMR_LOG SCHD_LOG
|
||||
#define PANL_LOG PROG_LOG
|
||||
|
||||
|
@ -72,7 +78,7 @@ void setLoggingPrms(int level , bool deamonized, char *error_messages);
|
|||
#else
|
||||
void setLoggingPrms(int level , bool deamonized, char* log_file, char *error_messages);
|
||||
#endif
|
||||
int getLogLevel(int16_t from);
|
||||
int getLogLevel(logmask_t from);
|
||||
int getSystemLogLevel();
|
||||
void setSystemLogLevel( int level);
|
||||
void daemonise ( char *pidFile, void (*main_function)(void) );
|
||||
|
@ -80,11 +86,11 @@ void daemonise ( char *pidFile, void (*main_function)(void) );
|
|||
|
||||
|
||||
|
||||
void addDebugLogMask(int16_t flag);
|
||||
void removeDebugLogMask(int16_t flag);
|
||||
void addDebugLogMask(logmask_t flag);
|
||||
void removeDebugLogMask(logmask_t flag);
|
||||
void clearDebugLogMask();
|
||||
bool isDebugLogMaskSet(int16_t flag);
|
||||
const char* logmask2name(int16_t mask);
|
||||
bool isDebugLogMaskSet(logmask_t flag);
|
||||
const char* logmask2name(logmask_t mask);
|
||||
const char* loglevel2name(int level);
|
||||
//#define logMessage(msg_level, format, ...) LOG (1, msg_level, format, ##__VA_ARGS__)
|
||||
|
||||
|
@ -93,8 +99,10 @@ const char* loglevel2name(int level);
|
|||
|
||||
|
||||
//void LOG(int from, int level, char *format, ...);
|
||||
void LOG(int16_t from, int msg_level, const char *format, ...);
|
||||
void LOGSystemError (int errnum, int16_t from, const char *on_what);
|
||||
void LOG(const logmask_t from, const int msg_level, const char *format, ...);
|
||||
void LOG_LARGEMSG(const logmask_t from, const int msg_level, const char * buffer, const int buffer_length);
|
||||
|
||||
void LOGSystemError (int errnum, logmask_t from, const char *on_what);
|
||||
void displayLastSystemError (const char *on_what);
|
||||
|
||||
int count_characters(const char *str, char character);
|
||||
|
@ -134,9 +142,6 @@ char *getInlineLogFName();
|
|||
bool islogFileReady();
|
||||
#endif
|
||||
|
||||
|
||||
//const char *logmask2name(int16_t from);
|
||||
|
||||
//#ifndef _UTILS_C_
|
||||
extern bool _daemon_;
|
||||
extern bool _debuglog_;
|
||||
|
|
|
@ -2,4 +2,6 @@
|
|||
|
||||
#define AQUALINKD_NAME "Aqualink Daemon"
|
||||
#define AQUALINKD_SHORT_NAME "AqualinkD"
|
||||
#define AQUALINKD_VERSION "2.3.8 (dev)"
|
||||
|
||||
// Use Magor . Minor . Patch
|
||||
#define AQUALINKD_VERSION "2.5.0 (Dev 0.1)"
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
justify-content: center;
|
||||
/*border: 1px solid red;*/
|
||||
row-gap: 20px;
|
||||
|
||||
/*overflow-y: scroll; this only works if we know the height, we can caculate but not important at moment */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -246,6 +246,8 @@
|
|||
var _panel_size = 6;
|
||||
var _panel_set = 0;
|
||||
var _latestVersionAvailable = 0;
|
||||
var _rssd_logmask = 0;
|
||||
const RSSD_MASK_ID = 512; // Must match RSSD_LOG in utils.c
|
||||
|
||||
function init_collapsible() {
|
||||
var coll = document.getElementsByClassName("collapsible");
|
||||
|
@ -355,7 +357,7 @@
|
|||
send_command(msg);
|
||||
}
|
||||
function setlogmask(caller) {
|
||||
console.log(caller.id);
|
||||
//console.log(caller.id);
|
||||
var id = parseInt(caller.id.split('_')[1]);
|
||||
var addremove = "";
|
||||
if (caller.checked) {
|
||||
|
@ -368,6 +370,16 @@
|
|||
uri: addremove,
|
||||
value: id
|
||||
};
|
||||
|
||||
// If it's RSSD logmask, and we have filter, append that to the uri.
|
||||
if (caller.id == _rssd_logmask ) {
|
||||
var filter = document.getElementById("rssd_filter").value;
|
||||
if (filter) {
|
||||
if (addremove == "addlogmask") {
|
||||
msg.uri = msg.uri + "/" + filter;
|
||||
}
|
||||
}
|
||||
}
|
||||
send_command(msg);
|
||||
}
|
||||
function setlogfile(caller) {
|
||||
|
@ -436,6 +448,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
function checkboxClick(caller) {
|
||||
try {
|
||||
if (caller.id == "slog_debug") {
|
||||
if (caller.checked) {
|
||||
document.getElementById("slog_ids").disabled = true;
|
||||
} else {
|
||||
document.getElementById("slog_ids").disabled = false;
|
||||
}
|
||||
}
|
||||
} catch (Error) { }
|
||||
}
|
||||
|
||||
|
||||
|
||||
function update_status(data) {
|
||||
|
@ -540,9 +564,33 @@
|
|||
'<div class="toggle-switch"></div>' +
|
||||
'<span class="toggle-label">' + data['debugmasks'][obj].name + '</span>';
|
||||
eCommands.appendChild(element);
|
||||
|
||||
//if ( data['debugmasks'][obj].name.substr(0,9) == "RS Serial" ) {
|
||||
// _rssd_logmask = element_id;
|
||||
if ( data['debugmasks'][obj].id == RSSD_MASK_ID) {
|
||||
_rssd_logmask = element_id;
|
||||
element = document.createElement('div');
|
||||
element.style.marginTop = '1px';
|
||||
element.style.marginBottom = '2px'; // = 'style="margin-left: 5px';
|
||||
element.innerHTML = '<input id="rssd_filter" type="text" value="" size="10" maxlength="19"> RS Serial Filter <font size="-2">(Eg 0x10 0x0a)</font></input>';
|
||||
eCommands.appendChild(element);
|
||||
var filterentry = document.getElementById("rssd_filter");
|
||||
filterentry.value = "";
|
||||
for (var id in data['debugmasks'][obj].filters) {
|
||||
console.log("Filter "+data['debugmasks'][obj].filters[id]);
|
||||
if (data['debugmasks'][obj].filters[id] != "0x00") {
|
||||
if (filterentry.value.length == 0) {
|
||||
filterentry.value = data['debugmasks'][obj].filters[id];
|
||||
} else {
|
||||
filterentry.value = filterentry.value+" "+data['debugmasks'][obj].filters[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
settoggle(element_id, data['debugmasks'][obj].set);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function get_appropriate_ws_url() {
|
||||
|
@ -698,6 +746,20 @@
|
|||
case "seriallog":
|
||||
cmd.uri = "seriallogger"
|
||||
break;
|
||||
case "seriallogWoptions":
|
||||
var ids = document.getElementById("slog_ids").value;
|
||||
if ( ids.length == 0 )
|
||||
ids='--';
|
||||
|
||||
cmd.uri = "seriallogger/"+ids+"/"+document.getElementById("slog_debug").checked;
|
||||
cmd.value = document.getElementById("slog_packets").value
|
||||
//console.log("Command = "+cmd);
|
||||
//console.log("Packets=" + document.getElementById("slog_packets").value );
|
||||
//console.log("IDs=" + document.getElementById("slog_ids").value );
|
||||
//console.log("ListQueriedID=" + document.getElementById("slog_ids_queried").checked );
|
||||
//console.log("debug=" + document.getElementById("slog_debug").checked );
|
||||
//return; // REMOVE
|
||||
break;
|
||||
default:
|
||||
alert("Unknown button");
|
||||
return;
|
||||
|
@ -737,6 +799,10 @@
|
|||
<tr>
|
||||
<td colspan="2" align="center"><label id="statusmsg" class="statusmsg">status</label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" align="center"><input id="restart" type="button" onclick="send(this);" value="Restart AqualinkD"></td>
|
||||
</tr>
|
||||
<!--
|
||||
<tr>
|
||||
<td align="center">
|
||||
<input id="restart" type="button" onclick="send(this);" value="Restart AqualinkD">
|
||||
|
@ -745,6 +811,7 @@
|
|||
<input id="seriallog" type="button" onclick="send(this);" value="Run Serial Logger">
|
||||
</td>
|
||||
</tr>
|
||||
-->
|
||||
</table>
|
||||
<button class="collapsible" id="systembutton">System Information</button>
|
||||
<div class="content" id="system">
|
||||
|
@ -773,7 +840,7 @@
|
|||
<!-- Will be populated on load -->
|
||||
</div>
|
||||
<button class="collapsible">Log File</button>
|
||||
<div class="content" id="loglevels">
|
||||
<div class="content" id="logfile">
|
||||
<!--
|
||||
<label class="toggle logtoggle"><input class="toggle-checkbox" type="checkbox" id="logfile"
|
||||
onclick="setlogfile(this);">
|
||||
|
@ -797,6 +864,29 @@
|
|||
<div class="debugmasks content" id="debugmasks">
|
||||
<!-- Will be populated on load -->
|
||||
</div>
|
||||
<button class="collapsible">Serial Logger</button>
|
||||
<div class="content" id="seriallogger">
|
||||
<table border='0'>
|
||||
<tr>
|
||||
<td colspan="2" align="center"><input id="seriallogWoptions" type="button" onclick="send(this);" value="Run Serial Logger"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>#Packets</td>
|
||||
<td><input id="slog_packets" type="text" value="800" size="5"></input></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ID's <font size="-2">(Eg 0x08 0x10)</font></td>
|
||||
<td><input id="slog_ids" type="text" value="" size="15"></input></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Debug</td>
|
||||
<td><input id="slog_debug" type="checkbox" onclick="checkboxClick(this)"></input></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" align="center">AqualinkD will be disabled while running</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<button class="collapsible">Config</button>
|
||||
<div class="content" id="config">
|
||||
<!-- Will be populated on load -->
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
// If the device isn't listed below is will NOT be shown.
|
||||
// For a complete list returned from your particular aqualinkd instance
|
||||
// use the below URL and look at the ID value for each device.
|
||||
// http://aqualink.ip.address/?command=devices
|
||||
// http://aqualink.ip.address/api/devices
|
||||
var devices = [
|
||||
"Filter_Pump",
|
||||
"Spa_Mode",
|
||||
"Spa",
|
||||
"Aux_1",
|
||||
"Aux_2",
|
||||
"Aux_3",
|
||||
|
@ -37,6 +37,22 @@
|
|||
"CHEM/pH",
|
||||
"CHEM/ORP",
|
||||
"Solar_Heater",
|
||||
"Extra_Aux",
|
||||
"Aux_V1",
|
||||
"Aux_V2",
|
||||
"Aux_V3",
|
||||
"Aux_V4",
|
||||
"Aux_V5",
|
||||
"Aux_V6",
|
||||
"Aux_V7",
|
||||
"Aux_V8",
|
||||
"Aux_V9",
|
||||
"Aux_V10",
|
||||
"Aux_V11",
|
||||
"Aux_V12",
|
||||
"Aux_V13",
|
||||
"Aux_V14",
|
||||
"Aux_V15",
|
||||
];
|
||||
|
||||
// This get's picked up by dynamic_config.js and used as mode 0
|
||||
|
@ -89,6 +105,7 @@
|
|||
// Reload background image every X seconds.(useful if camera snapshot)
|
||||
// 0 means only load once when page loads.
|
||||
//var background_reload = 10;
|
||||
//var background_reload = 0;
|
||||
|
||||
// By default all Variable Speed Pumps will show RPM.
|
||||
// this will show GPM on VSP's that you can only set GPM (ie Jandy VF pumps)
|
||||
|
@ -138,4 +155,6 @@
|
|||
// var head_background = "#000D53";
|
||||
|
||||
// REMOVE THIS.
|
||||
//document.writeln("<script type='text/javascript' src='extra/extra.js'></script>");
|
||||
//document.writeln("<script type='text/javascript' src='extra/extra.js'></script>");
|
||||
|
||||
|
||||
|
|
|
@ -640,6 +640,7 @@
|
|||
document.getElementById('vspswitch_options').classList.remove("hide");
|
||||
document.getElementById('timer_options').classList.remove("hide");
|
||||
document.getElementById('scheduler_options').classList.remove("hide");
|
||||
document.getElementById('dimmerlight_options').classList.remove("hide");
|
||||
//document.getElementById('simulator_iframe').classList.remove("hide");
|
||||
setColors();
|
||||
load_background();
|
||||
|
@ -683,7 +684,7 @@
|
|||
var row;
|
||||
row = tbody.deleteRow(2);
|
||||
row = tbody.insertRow(2);
|
||||
if (type == 6) {
|
||||
if (type == 10) {
|
||||
row.innerHTML = "<td align='center'>Dimmer</td><td align='center'></td>";
|
||||
} else {
|
||||
row.innerHTML = "<td align='center'>Solid Color</td><td align='center'>Light Show</td>";
|
||||
|
@ -915,7 +916,8 @@
|
|||
subdiv.setAttribute('id', id + '_status');
|
||||
subdiv.textContent = formatSatus(status);
|
||||
div.appendChild(subdiv);
|
||||
if (type == "switch" && (subtype != "switch_program" && subtype != "switch_vsp" && subtype != "switch_timer") ) {
|
||||
if (type == "switch" && (subtype != "switch_program" && subtype != "switch_vsp" &&
|
||||
subtype != "switch_timer" && subtype != "light_dimmer") ) {
|
||||
//if (type == "switch" && subtype != "switch_program" ) {
|
||||
div.setAttribute('onclick', "switchTileState('" + id + "')");
|
||||
//console.log("add onclick switchtilestate to "+id);
|
||||
|
@ -957,6 +959,7 @@
|
|||
send_setpoint(id);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
function setTileValue(id, value) {
|
||||
var ext = '';
|
||||
|
@ -1018,7 +1021,7 @@
|
|||
}
|
||||
} catch (e) {
|
||||
// NSF Do we need to create the device?
|
||||
console.log('ERROR id=' + id + ' Line 837 | element = '+document.getElementById(id));
|
||||
console.log('ERROR id=' + id + ' Line '+new Error().lineNumber+' | element = '+document.getElementById(id));
|
||||
}
|
||||
//document.getElementById(id + '_tile_icon_value').textContent = value;
|
||||
var tile;
|
||||
|
@ -1028,7 +1031,8 @@
|
|||
|
||||
function setTileOnText(id, text) {
|
||||
try {
|
||||
if (document.getElementById(id).getAttribute('status') == 'on') {
|
||||
var tile = document.getElementById(id);
|
||||
if (tile.getAttribute('status') == 'on' || tile.getAttribute('status') == 'enabled') {
|
||||
document.getElementById(id + '_status').innerHTML = text;
|
||||
} else {
|
||||
//console.log("Tile "+id+" status is '"+document.getElementById(id).getAttribute('status')+"' not setting text to '"+text+"'");
|
||||
|
@ -1227,7 +1231,7 @@
|
|||
|
||||
add_tile(object.id, object.name, object.state, 'switch', ext_type, 'hk/' + img + '-off.png', 'hk/' + img + '-on.png');
|
||||
setTileOn(object.id, object.status, null);
|
||||
if (typeof object.type_ext !== 'undefined' && object.type_ext == 'switch_program') {
|
||||
if (typeof object.type_ext !== 'undefined' && (object.type_ext == 'switch_program' || object.type_ext == 'light_dimmer')) {
|
||||
if (typeof object.Light_Type !== 'undefined') {
|
||||
document.getElementById(object.id).setAttribute('lighttype', object.Light_Type);
|
||||
}
|
||||
|
@ -1276,6 +1280,7 @@
|
|||
document.getElementById('vspswitch_options').style.display = 'none';
|
||||
document.getElementById('timer_options').style.display = 'none';
|
||||
document.getElementById('scheduler_options').style.display = 'none';
|
||||
document.getElementById('dimmerlight_options').style.display = 'none';
|
||||
//document.getElementById('simulator_iframe').style.display = 'none';
|
||||
} else if (id != null && document.getElementById(id).getAttribute('type') == 'switch_program') {
|
||||
active_option = document.getElementById('pswitch_options');
|
||||
|
@ -1284,6 +1289,16 @@
|
|||
document.getElementById('vspswitch_options').style.display = 'none';
|
||||
document.getElementById('timer_options').style.display = 'none';
|
||||
document.getElementById('scheduler_options').style.display = 'none';
|
||||
document.getElementById('dimmerlight_options').style.display = 'none';
|
||||
//document.getElementById('simulator_iframe').style.display = 'none';
|
||||
} else if (id != null && document.getElementById(id).getAttribute('type') == 'light_dimmer') {
|
||||
active_option = document.getElementById('dimmerlight_options');
|
||||
document.getElementById('thermostat_options').style.display = 'none';
|
||||
document.getElementById('swg_options').style.display = 'none';
|
||||
document.getElementById('vspswitch_options').style.display = 'none';
|
||||
document.getElementById('timer_options').style.display = 'none';
|
||||
document.getElementById('scheduler_options').style.display = 'none';
|
||||
document.getElementById('dimmerlight_options').style.display = 'none';
|
||||
//document.getElementById('simulator_iframe').style.display = 'none';
|
||||
} else if (id != null && document.getElementById(id).getAttribute('type') == 'setpoint_swg') {
|
||||
active_option = document.getElementById('swg_options');
|
||||
|
@ -1292,6 +1307,7 @@
|
|||
document.getElementById('vspswitch_options').style.display = 'none';
|
||||
document.getElementById('timer_options').style.display = 'none';
|
||||
document.getElementById('scheduler_options').style.display = 'none';
|
||||
document.getElementById('dimmerlight_options').style.display = 'none';
|
||||
//document.getElementById('simulator_iframe').style.display = 'none';
|
||||
} else if (id != null && document.getElementById(id).getAttribute('type') == 'setpoint_freeze') {
|
||||
active_option = document.getElementById('swg_options');
|
||||
|
@ -1300,6 +1316,7 @@
|
|||
document.getElementById('vspswitch_options').style.display = 'none';
|
||||
document.getElementById('timer_options').style.display = 'none';
|
||||
document.getElementById('scheduler_options').style.display = 'none';
|
||||
document.getElementById('dimmerlight_options').style.display = 'none';
|
||||
//document.getElementById('simulator_iframe').style.display = 'none';
|
||||
} else if (id != null && document.getElementById(id).getAttribute('type') == 'switch_vsp') {
|
||||
active_option = document.getElementById('vspswitch_options');
|
||||
|
@ -1308,6 +1325,7 @@
|
|||
document.getElementById('swg_options').style.display = 'none';
|
||||
document.getElementById('timer_options').style.display = 'none';
|
||||
document.getElementById('scheduler_options').style.display = 'none';
|
||||
document.getElementById('dimmerlight_options').style.display = 'none';
|
||||
//document.getElementById('simulator_iframe').style.display = 'none';
|
||||
} else if (id != null && document.getElementById(id).getAttribute('type') == 'switch_timer') {
|
||||
active_option = document.getElementById('timer_options');
|
||||
|
@ -1316,6 +1334,7 @@
|
|||
document.getElementById('swg_options').style.display = 'none';
|
||||
document.getElementById('vspswitch_options').style.display = 'none';
|
||||
document.getElementById('scheduler_options').style.display = 'none';
|
||||
document.getElementById('dimmerlight_options').style.display = 'none';
|
||||
//document.getElementById('simulator_iframe').style.display = 'none';
|
||||
} else if (id != null && document.getElementById(id).getAttribute('type') == 'scheduler') {
|
||||
active_option = document.getElementById('scheduler_options');
|
||||
|
@ -1324,6 +1343,7 @@
|
|||
document.getElementById('swg_options').style.display = 'none';
|
||||
document.getElementById('vspswitch_options').style.display = 'none';
|
||||
document.getElementById('timer_options').style.display = 'none';
|
||||
document.getElementById('dimmerlight_options').style.display = 'none';
|
||||
//document.getElementById('simulator_iframe').style.display = 'none';
|
||||
} /*else if (id != null && document.getElementById(id).getAttribute('type') == 'simulator') {
|
||||
active_option = document.getElementById('simulator_iframe');
|
||||
|
@ -1361,6 +1381,8 @@
|
|||
document.getElementById("timer_options").click();
|
||||
else if (document.getElementById('scheduler_options').style.display == 'flex')
|
||||
document.getElementById("scheduler_options").click();
|
||||
else if (document.getElementById('dimmerlight_options').style.display == 'flex')
|
||||
document.getElementById("dimmerlight_options").click();
|
||||
}
|
||||
document.getElementById('thermostat_options').style.display = 'none';
|
||||
document.getElementById('swg_options').style.display = 'none';
|
||||
|
@ -1368,6 +1390,7 @@
|
|||
document.getElementById('vspswitch_options').style.display = 'none';
|
||||
document.getElementById('timer_options').style.display = 'none';
|
||||
document.getElementById('scheduler_options').style.display = 'none';
|
||||
document.getElementById('dimmerlight_options').style.display = 'none';
|
||||
//document.getElementById('simulator_iframe').style.display = 'none';
|
||||
document.getElementById('wrapper').classList.remove("opaque");
|
||||
return;
|
||||
|
@ -1388,6 +1411,7 @@
|
|||
var tm_ext;
|
||||
var oswitch;
|
||||
var vsp_slider_changed = false;
|
||||
var dimmer_slider_changed = false;
|
||||
if (type == 'setpoint_swg') {
|
||||
slider = document.getElementById("swg_option_slider_range");
|
||||
slider_output = document.getElementById("swg_option_slider_text_value");
|
||||
|
@ -1424,6 +1448,14 @@
|
|||
close_button = document.getElementById("scheduler_options_close");
|
||||
//} else if (type == 'simulator') {
|
||||
// close_button = document.getElementById("simulator_iframe_close");
|
||||
} else if (type == 'light_dimmer') {
|
||||
slider = document.getElementById("dimmeroption_slider_range");
|
||||
slider_output = document.getElementById("dimmeroption_slider_text_value");
|
||||
tm_slider = document.getElementById("dimmer_timer_slider_range");
|
||||
tm_slider_output = document.getElementById("dimmer_timer_slider_text_value");
|
||||
title = document.getElementById("dimmerswitch_option_title");
|
||||
close_button = document.getElementById("dimmerswitch_option_close");
|
||||
ext = "%";
|
||||
} else {
|
||||
slider = document.getElementById("option_slider_range");
|
||||
slider_output = document.getElementById("option_slider_text_value");
|
||||
|
@ -1472,6 +1504,11 @@
|
|||
slider.step = 5;
|
||||
ext = ' RPM';
|
||||
}
|
||||
} else if (type == 'light_dimmer') {
|
||||
slider.min = 0;
|
||||
slider.max = 100;
|
||||
slider.step = 1;
|
||||
ext = ' %';
|
||||
}
|
||||
|
||||
if (type == 'scheduler') {
|
||||
|
@ -1479,6 +1516,7 @@
|
|||
} else if (type == 'simulator') {
|
||||
// title.innerHTML = "Simulator";
|
||||
} else {
|
||||
//console.log("Set "+id+" to "+document.getElementById(id + '_name').innerHTML);
|
||||
title.innerHTML = document.getElementById(id + '_name').innerHTML;
|
||||
}
|
||||
|
||||
|
@ -1532,6 +1570,24 @@
|
|||
oswitch.onclick = function() {
|
||||
oswitch_output.innerHTML = ((oswitch.checked) ? "On" : "Off");
|
||||
}
|
||||
} else if (type == 'light_dimmer') {
|
||||
slider.value = sp_value;
|
||||
oswitch = document.getElementById("dimmeroption_switch");
|
||||
oswitch.checked = tile_state;
|
||||
var oswitch_output = document.getElementById("dimmeroption_switch_text_value");
|
||||
slider_output.innerHTML = slider.value + ext;
|
||||
oswitch_output.innerHTML = ((oswitch.checked) ? "On" : "Off");
|
||||
slider.oninput = function() {
|
||||
dimmer_slider_changed = true;
|
||||
slider_output.innerHTML = this.value + ext;
|
||||
if (this.value <= 0 && oswitch.checked == true) {
|
||||
oswitch.checked = false;
|
||||
oswitch_output.innerHTML = ((oswitch.checked) ? "On" : "Off");
|
||||
} else if (oswitch.checked != true) {
|
||||
oswitch.checked = true;
|
||||
oswitch_output.innerHTML = ((oswitch.checked) ? "On" : "Off");
|
||||
}
|
||||
}
|
||||
} else if (type == 'switch_timer') {
|
||||
oswitch = document.getElementById("timer_switch");
|
||||
oswitch.checked = tile_state;
|
||||
|
@ -1630,6 +1686,12 @@
|
|||
// if (state == (tile.getAttribute('status') == 'off')) // Only bother with this if we didn;t set the light mode.
|
||||
setTileState(id, state);
|
||||
}
|
||||
} else if (type == 'light_dimmer') {
|
||||
var value = slider.value;
|
||||
if (state == (tile.getAttribute('status') == 'off'))
|
||||
setTileState(id, state);
|
||||
if (sp_value != slider.value && dimmer_slider_changed == true)
|
||||
setThermostatSetpoint(id, slider.value)
|
||||
} else if (type == 'setpoint_swg') {
|
||||
//console.log ("Boost attribute = "+tile.getAttribute('boost'));
|
||||
//console.log ("state = "+state);
|
||||
|
@ -2162,9 +2224,33 @@
|
|||
}
|
||||
for (var obj in data.timers) {
|
||||
setTileOnText(obj.toString(),"On (timer)");
|
||||
//console.log("TIMER "+obj.toString());
|
||||
}
|
||||
for (var obj in data.timer_durations) {
|
||||
setTileOnText(obj.toString(),"Timer "+toHoursAndMinutes(data.timer_durations[obj]));
|
||||
//console.log("TIMER "+obj.toString()+" duration "+data.timer_durations[obj]);
|
||||
}
|
||||
|
||||
for (var obj in data.light_program) {
|
||||
if (data.light_program[obj] != "") {
|
||||
var light_mode = data.light_program[obj];
|
||||
// If aqualinkd programmed light, need to convert int to text index, if not value is text
|
||||
try {
|
||||
var light_type = document.getElementById(obj.toString()).getAttribute('lighttype');
|
||||
if (light_type == 0) {
|
||||
var light_mode = _light_program[light_type][parseInt(data.light_program[obj])-1];
|
||||
if (light_mode.endsWith(" - Show"))
|
||||
light_mode = light_mode.slice(0, -7);
|
||||
//console.log("light program -- "+light_mode);
|
||||
} else if (light_type == 10 || light_type == 11) {
|
||||
// Fo Dimmer Lights.
|
||||
document.getElementById(obj.toString()).setAttribute('setpoint', parseInt(light_mode));
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
setTileOnText(obj.toString(),light_mode);
|
||||
// Below is only needed for full dimmer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -2193,7 +2279,8 @@
|
|||
// If we have 2 lines, then BOTTOM (line #1) is ERROR (not priming) or what the pump needs to control (RPM for all except VF which is GPM)
|
||||
// TOP (line #2) is (priming/RPM/GPM).
|
||||
|
||||
// 1,0,-1 are all good states, anything else error
|
||||
// 1,0,-1 are all good states, anything else error
|
||||
try {
|
||||
if (status >= 1 || status <= -3) {
|
||||
if (status == -3) {
|
||||
setTileOnText(tileid, 'Pump Offline');
|
||||
|
@ -2233,6 +2320,10 @@
|
|||
|
||||
setTileOnText(tileid, bLine);
|
||||
setTileOnTextLine2(tileid, tLine);
|
||||
} catch (e) {
|
||||
// NSF Do we need to create the device?
|
||||
console.log('ERROR id=' + tileid + ' Line '+new Error().lineNumber+' | element = '+document.getElementById(tileid));
|
||||
}
|
||||
}
|
||||
|
||||
function deviceSort(a, b) {
|
||||
|
@ -2407,6 +2498,8 @@
|
|||
message.uri = id+"/percent/set";
|
||||
else if (type == "switch_vsp")
|
||||
message.uri = id+"/RPM/set";
|
||||
else if (type == "light_dimmer")
|
||||
message.uri = id+"/brightness/set";
|
||||
else
|
||||
message.uri = id+"/setpoint/set";
|
||||
//console.log("Send value back "+temperature.parameter+" "+temperature.value);
|
||||
|
@ -2520,6 +2613,7 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='thermostat_options' class='options hide'>
|
||||
<div id='thermostat_options_pane' class='options_pane' onclick='event.stopPropagation();'>
|
||||
<table border='0' cellpadding='10px'>
|
||||
|
@ -2569,6 +2663,7 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='swg_options' class='options hide'>
|
||||
<div id='swg_options_pane' class='options_pane' onclick='event.stopPropagation();'>
|
||||
<table border='0' cellpadding='10px'>
|
||||
|
@ -2605,6 +2700,7 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='pswitch_options' class='options hide'>
|
||||
<div id='pswitch_options_pane' class='options_pane' onclick='event.stopPropagation();'>
|
||||
<table id='pswitch_table' border='0' cellpadding='10px' width="100%">
|
||||
|
@ -2651,6 +2747,7 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='vspswitch_options' class='options hide'>
|
||||
<div id='vspswitch_options_pane' class='options_pane' onclick='event.stopPropagation();'>
|
||||
<table border='0' cellpadding='10px'>
|
||||
|
@ -2700,6 +2797,55 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='dimmerlight_options' class='options hide'>
|
||||
<div id='dimmerlight_options_pane' class='options_pane' onclick='event.stopPropagation();'>
|
||||
<table border='0' cellpadding='10px'>
|
||||
<tr class='options_title'>
|
||||
<th colspan='2'><span id="dimmerswitch_option_title"></span>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align='right' width='50%'><span class="option_text" id='dimmeroption_switch_text_value'></span>
|
||||
</td>
|
||||
<td align='left' width='50%'>
|
||||
<label class="option_switch">
|
||||
<input type="checkbox" id='dimmeroption_switch'>
|
||||
<span class="option_switch_slide"></span>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' align='center'><span class="option_text" id="dimmeroption_slider_text_value"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2'>
|
||||
<div class="slidecontainer">
|
||||
<input type="range" class="option_slider" id='dimmeroption_slider_range'>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' align='center'><span class="option_text" id="dimmer_timer_slider_text_value"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2'>
|
||||
<div class="slidecontainer">
|
||||
<input type="range" class="option_slider" id='dimmer_timer_slider_range'>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' align='center'>
|
||||
<input type="button" value="close" id='dimmerswitch_option_close' class='options_button'>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='timer_options' class='options hide'>
|
||||
<div id='timer_options_pane' class='options_pane' onclick='event.stopPropagation();'>
|
||||
<table border='0' cellpadding='10px'>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
|
@ -0,0 +1 @@
|
|||
./switch-off.png
|
|
@ -0,0 +1 @@
|
|||
./switch-on.png
|
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
Loading…
Reference in New Issue