mirror of https://github.com/sfeakes/AqualinkD.git
Compare commits
17 Commits
Author | SHA1 | Date |
---|---|---|
|
be9a518ffa | |
|
71bc573f61 | |
|
f95310d170 | |
|
0518337472 | |
|
de5697bb25 | |
|
9d5d90937b | |
|
e513f14dd6 | |
|
62943ab133 | |
|
c4cc4504d9 | |
|
9a357841aa | |
|
5b704cf3fb | |
|
f7846a8f91 | |
|
d7e45594b3 | |
|
94fc20191b | |
|
c06a0037b6 | |
|
dd7161ef08 | |
|
d182784ae2 |
|
@ -1,293 +0,0 @@
|
|||
|
||||
#####################################
|
||||
#
|
||||
# Build container to compile AqualnkD Release binaries (armhf and arm64)
|
||||
#
|
||||
# armhf is 32 bit armv6l (armhf) stretch and newer - work on all Pi's running 32bit (Pi1 to Pi4)
|
||||
# arm64 is 64 bit aarch64 buster and newer - work on Pi3/Pi4/2w running 64bit os
|
||||
#
|
||||
# docker build -f Dockerfile.releaseBinaries2 -t aqualinkd-releasebin2 .
|
||||
# For better debug logs use --progress=plain
|
||||
# docker build --progress=plain -f Dockerfile.releaseBinaries2 -t aqualinkd-releasebin2 .
|
||||
#
|
||||
# docker run -it --mount type=bind,source=./build,target=/build aqualinkd-releasebin2 bash
|
||||
#
|
||||
# clean method
|
||||
# docker system prune
|
||||
# docker buildx prune <- just build env
|
||||
#
|
||||
# armhf =
|
||||
# COLLECT_GCC=arm-linux-gnueabihf-gcc
|
||||
# COLLECT_LTO_WRAPPER=/opt/cross-pi-gcc/libexec/gcc/arm-linux-gnueabihf/6.3.0/lto-wrapper
|
||||
# Target: arm-linux-gnueabihf
|
||||
# Configured with: ../gcc-6.3.0/configure --prefix=/opt/cross-pi-gcc --target=arm-linux-gnueabihf --enable-languages=c,c++,fortran --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-multilib --enable-linker-build-id
|
||||
# Thread model: posix
|
||||
# gcc version 6.3.0 (GCC)
|
||||
# GLIBC version 2.24
|
||||
#
|
||||
# arm64 =
|
||||
# COLLECT_GCC=aarch64-linux-gnu-gcc
|
||||
# COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/aarch64-linux-gnu/8/lto-wrapper
|
||||
# Target: aarch64-linux-gnu
|
||||
# Configured with: ../src/configure -v --with-pkgversion='Debian 8.3.0-2' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --disable-libphobos --enable-multiarch --enable-fix-cortex-a53-843419 --disable-werror --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=aarch64-linux-gnu --program-prefix=aarch64-linux-gnu- --includedir=/usr/aarch64-linux-gnu/include
|
||||
# Thread model: posix
|
||||
# gcc version 8.3.0 (Debian 8.3.0-2)
|
||||
# GLIBC 2.28-10+deb10u3
|
||||
#####################################
|
||||
|
||||
FROM debian:buster
|
||||
|
||||
# ############
|
||||
# Get arm64 build environment.
|
||||
#
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
build-essential \
|
||||
libsystemd-dev \
|
||||
gcc-aarch64-linux-gnu \
|
||||
binutils-arm-linux-gnueabi \
|
||||
file
|
||||
|
||||
RUN dpkg --add-architecture arm64
|
||||
RUN apt-get update && \
|
||||
apt-get install -y libsystemd-dev:arm64
|
||||
|
||||
# ############
|
||||
# Get armhf build environment
|
||||
# prebuilt armhf doesn't support hard float, (or something that causes it to fail on armhf machines)
|
||||
#RUN apt-get install -y \
|
||||
# gcc-arm-linux-gnueabihf \
|
||||
# binutils-arm-linux-gnueabihf
|
||||
|
||||
#RUN dpkg --add-architecture armhf
|
||||
#RUN apt-get update && \
|
||||
# apt-get install -y libsystemd-dev:armhf
|
||||
|
||||
# So we need to build arnhf our selves. Since we are doing that, using debian/rasbian stretch versions of
|
||||
# everthing for best compatibality
|
||||
|
||||
ENV GCC_VERSION gcc-6.3.0
|
||||
ENV GLIBC_VERSION glibc-2.24
|
||||
ENV BINUTILS_VERSION binutils-2.28
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install some tools and compilers + clean up
|
||||
RUN apt-get update && \
|
||||
#apt-get install -y rsync git wget gcc-6 g++-6 cmake gdb gdbserver bzip2 && \
|
||||
apt-get install -y rsync git wget cmake gdb gdbserver bzip2 && \
|
||||
apt-get clean autoclean && \
|
||||
apt-get autoremove -y && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
# Use GCC 6 as the default
|
||||
#RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-6 999 \
|
||||
# && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-6 999 \
|
||||
# && update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-6 999 \
|
||||
# && update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-6 999
|
||||
|
||||
# Add a user called `develop`
|
||||
RUN useradd -ms /bin/bash develop
|
||||
RUN echo "develop ALL=(ALL:ALL) ALL" >> /etc/sudoers
|
||||
|
||||
WORKDIR /home/develop
|
||||
|
||||
# Download and extract GCC
|
||||
RUN wget https://ftp.gnu.org/gnu/gcc/${GCC_VERSION}/${GCC_VERSION}.tar.gz && \
|
||||
tar xf ${GCC_VERSION}.tar.gz && \
|
||||
rm ${GCC_VERSION}.tar.gz
|
||||
# Download and extract LibC
|
||||
RUN wget https://ftp.gnu.org/gnu/libc/${GLIBC_VERSION}.tar.bz2 && \
|
||||
tar xjf ${GLIBC_VERSION}.tar.bz2 && \
|
||||
rm ${GLIBC_VERSION}.tar.bz2
|
||||
# Download and extract BinUtils
|
||||
RUN wget https://ftp.gnu.org/gnu/binutils/${BINUTILS_VERSION}.tar.bz2 && \
|
||||
tar xjf ${BINUTILS_VERSION}.tar.bz2 && \
|
||||
rm ${BINUTILS_VERSION}.tar.bz2
|
||||
# Download the GCC prerequisites
|
||||
RUN cd ${GCC_VERSION} && contrib/download_prerequisites && rm *.tar.*
|
||||
#RUN cd gcc-9.2.0 && contrib/download_prerequisites && rm *.tar.*
|
||||
|
||||
# Build BinUtils
|
||||
RUN mkdir -p /opt/cross-pi-gcc
|
||||
WORKDIR /home/develop/build-binutils
|
||||
RUN ../${BINUTILS_VERSION}/configure \
|
||||
--prefix=/opt/cross-pi-gcc --target=arm-linux-gnueabihf \
|
||||
--with-arch=armv6 --with-fpu=vfp --with-float=hard \
|
||||
--disable-multilib
|
||||
RUN make -j$(nproc)
|
||||
RUN make install
|
||||
|
||||
|
||||
# Apply batch to GCC
|
||||
# https://github.com/qca/open-ath9k-htc-firmware/issues/135
|
||||
WORKDIR /home/develop
|
||||
RUN sed -i '1474s/file ==/file[0] ==/' gcc-6.3.0/gcc/ubsan.c
|
||||
|
||||
# Build the first part of GCC
|
||||
WORKDIR /home/develop/build-gcc
|
||||
RUN ../${GCC_VERSION}/configure \
|
||||
--prefix=/opt/cross-pi-gcc \
|
||||
--target=arm-linux-gnueabihf \
|
||||
--enable-languages=c,c++,fortran \
|
||||
--with-arch=armv6 --with-fpu=vfp --with-float=hard \
|
||||
--disable-multilib \
|
||||
--enable-linker-build-id
|
||||
RUN make -j$(nproc) 'LIMITS_H_TEST=true' all-gcc
|
||||
RUN make install-gcc
|
||||
ENV PATH=/opt/cross-pi-gcc/bin:${PATH}
|
||||
|
||||
# Install dependencies
|
||||
RUN apt-get update && \
|
||||
apt-get install -y gawk bison python3 && \
|
||||
apt-get clean autoclean && \
|
||||
apt-get autoremove -y && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Download and install the Linux headers
|
||||
WORKDIR /home/develop
|
||||
# Should probably use below and change branch. Known to build with rpi-6.1.y or rpi-6.9.y rpi-6.12.y
|
||||
#RUN git clone -b <branch> --depth=1 https://github.com/raspberrypi/linux
|
||||
RUN git clone --depth=1 https://github.com/raspberrypi/linux
|
||||
WORKDIR /home/develop/linux
|
||||
ENV KERNEL=kernel7
|
||||
RUN make ARCH=arm INSTALL_HDR_PATH=/opt/cross-pi-gcc/arm-linux-gnueabihf headers_install
|
||||
|
||||
# Build GLIBC
|
||||
WORKDIR /home/develop/build-glibc
|
||||
RUN ../${GLIBC_VERSION}/configure \
|
||||
--prefix=/opt/cross-pi-gcc/arm-linux-gnueabihf \
|
||||
--build=$MACHTYPE --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf \
|
||||
--with-arch=armv6 --with-fpu=vfp --with-float=hard \
|
||||
--with-headers=/opt/cross-pi-gcc/arm-linux-gnueabihf/include \
|
||||
--disable-multilib libc_cv_forced_unwind=yes
|
||||
RUN make install-bootstrap-headers=yes install-headers
|
||||
RUN make -j8 csu/subdir_lib
|
||||
RUN install csu/crt1.o csu/crti.o csu/crtn.o /opt/cross-pi-gcc/arm-linux-gnueabihf/lib
|
||||
RUN arm-linux-gnueabihf-gcc -nostdlib -nostartfiles -shared -x c /dev/null \
|
||||
-o /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/libc.so
|
||||
RUN touch /opt/cross-pi-gcc/arm-linux-gnueabihf/include/gnu/stubs.h
|
||||
|
||||
# Continue building GCC
|
||||
WORKDIR /home/develop/build-gcc
|
||||
RUN make -j$(nproc) all-target-libgcc
|
||||
RUN make install-target-libgcc
|
||||
|
||||
# Finish building GLIBC
|
||||
WORKDIR /home/develop/build-glibc
|
||||
RUN make -j$(nproc)
|
||||
RUN make install
|
||||
|
||||
# Finish building GCC
|
||||
WORKDIR /home/develop/build-gcc
|
||||
RUN make -j$(nproc)
|
||||
RUN make install
|
||||
|
||||
|
||||
# Download systemd and it's dependancys.
|
||||
RUN mkdir -p /home/develop/packages
|
||||
WORKDIR /home/develop/packages
|
||||
|
||||
|
||||
####################
|
||||
# Manually libsystemd-dev and all it's depandancys
|
||||
# Commented out ones are what I really want, but couldn;t find.
|
||||
#####RUN wget https://archive.debian.org/debian/pool/main/s/systemd/libsystemd-dev_232-25+deb9u14_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/s/systemd/libsystemd-dev_232-25+deb9u12_armhf.deb
|
||||
#####RUN wget https://archive.debian.org/debian/pool/main/s/systemd/libsystemd0_232-25+deb9u14_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/s/systemd/libsystemd0_232-25+deb9u12_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/g/glibc/libc6_2.24-11+deb9u4_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/libg/libgpg-error/libgpg-error0_1.26-2_armhf.deb
|
||||
#####RUN wget https://archive.debian.org/debian/pool/main/x/xz-utils/liblzma5_5.2.2-1.2+deb9u1_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/x/xz-utils/liblzma5_5.2.2-1.2+b1_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/libs/libselinux/libselinux1_2.6-3+b3_armhf.deb
|
||||
#####RUN wget https://archive.debian.org/debian/pool/main/libg/libgcrypt20//libgcrypt20_1.7.6-2+deb9u4_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/libg/libgcrypt20//libgcrypt20_1.7.6-2+deb9u3_armhf.deb
|
||||
#####RUN wget https://archive.debian.org/debian/pool/main/l/lz4/liblz4-1_0.0~r131-2+deb9u1_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/l/lz4/liblz4-1_0.0~r131-2+b1_armhf.deb
|
||||
#####RUN wget https://archive.debian.org/debian/pool/main/p/pcre3/libpcre3_2%3a8.39-3_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/p/pcre3/libpcre3_8.39-3_armhf.deb
|
||||
#
|
||||
# Now we have all packaged, let's unpack them.
|
||||
#
|
||||
# Install all packages into /opt/cross-pi-gcc/arm-linux-gnueabihf
|
||||
#RUN for file in *; do dpkg-deb -x $file /opt/cross-pi-gcc/arm-linux-gnueabihf; done
|
||||
#
|
||||
|
||||
####################
|
||||
# Rather than manually, Let's do some modifications to apt and get that working (kinda)
|
||||
|
||||
# Get just enough for apt-get and dpk to run. apt-get doesn't actually work, just enough to download
|
||||
ENV APT_ROOT=/opt/cross-pi-gcc/apt-armhf
|
||||
RUN mkdir -p $APT_ROOT
|
||||
#RUN APT_ROOT=/opt/cross-pi-gcc/apt-armhf; export APT_ROOT
|
||||
|
||||
RUN mkdir -p $APT_ROOT/etc/apt/sources.list.d/
|
||||
RUN mkdir -p $APT_ROOT/var/lib/dpkg/updates/
|
||||
RUN mkdir -p $APT_ROOT/var/lib/dpkg/info
|
||||
RUN mkdir -p $APT_ROOT/var/cache/apt/archives/partial
|
||||
RUN mkdir -p $APT_ROOT/var/log/apt/
|
||||
#mkdir -p $APT_ROOT/usr/share/
|
||||
|
||||
RUN echo "deb http://archive.debian.org/debian/ stretch main contrib non-free" > $APT_ROOT/etc/apt/sources.list
|
||||
RUN echo "deb http://archive.debian.org/debian/ stretch-proposed-updates main contrib non-free" >> $APT_ROOT/etc/apt/sources.list
|
||||
RUN echo "deb http://archive.debian.org/debian-security stretch/updates main contrib non-free" >> $APT_ROOT/etc/apt/sources.list
|
||||
|
||||
RUN touch $APT_ROOT/var/lib/dpkg/status
|
||||
|
||||
RUN ln -s /etc/apt/trusted.gpg.d $APT_ROOT/etc/apt/
|
||||
RUN ln -s /etc/apt/preferences.d $APT_ROOT/etc/apt/
|
||||
RUN ln -s /etc/apt/auth.conf.d $APT_ROOT/etc/apt/
|
||||
|
||||
# needed for download
|
||||
RUN dpkg --add-architecture armhf
|
||||
# needed for install
|
||||
RUN dpkg --root=$APT_ROOT --add-architecture armhf
|
||||
|
||||
RUN apt -o Dir=$APT_ROOT update
|
||||
|
||||
RUN apt -o Dir=$APT_ROOT download libsystemd-dev:armhf \
|
||||
libsystemd0:armhf \
|
||||
libc6:armhf \
|
||||
libgcrypt20:armhf \
|
||||
liblz4-1:armhf \
|
||||
liblzma5:armhf \
|
||||
libselinux1:armhf \
|
||||
libpcre3:armhf \
|
||||
libgpg-error0:armhf
|
||||
|
||||
############
|
||||
# Now we have all packaged, let's unpack them.
|
||||
|
||||
# Install all packages into /opt/cross-pi-gcc/arm-linux-gnueabihf
|
||||
# Could use `dpkg --root=$APT_ROOT --force-all -i` in below, but extract works without any warnings.
|
||||
RUN for file in *; do dpkg -x $file /opt/cross-pi-gcc/arm-linux-gnueabihf; done
|
||||
|
||||
# the above will ge installed in /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/arm-linux-gnueabihf,
|
||||
# and we need them in /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/, so make come links.
|
||||
WORKDIR /opt/cross-pi-gcc/arm-linux-gnueabihf/lib
|
||||
RUN for file in ./arm-linux-gnueabihf/*; do ln -s $file ./`basename $file` 2> /dev/null; done; exit 0
|
||||
|
||||
# liblz4.so.1 is installed in a different directory, so link that as well.
|
||||
RUN ln -s /opt/cross-pi-gcc/arm-linux-gnueabihf/usr/lib/arm-linux-gnueabihf/liblz4.so.1 /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/liblz4.so.1
|
||||
|
||||
|
||||
ENV C_INCLUDE_PATH=/opt/cross-pi-gcc/arm-linux-gnueabihf/usr/include
|
||||
|
||||
ENV PATH=$PATH:/opt/cross-pi-gcc/bin:/opt/cross-pi-gcc/libexec/gcc/arm-linux-gnueabihf/6.3.0/
|
||||
|
||||
RUN mkdir /build
|
||||
WORKDIR /build
|
||||
|
||||
# Add a user called `build` uid 1001 & gid 10000
|
||||
# You chould change RB_UID & RB_GID to what works on your build setup
|
||||
ENV RB_USER=build
|
||||
ENV RB_UID=1001
|
||||
ENV RB_GID=1000
|
||||
RUN groupadd -g $RB_GID $RB_USER 2> /dev/null; exit 0
|
||||
RUN useradd $RB_USER -u $RB_UID -g $RB_GID -m -s /bin/bash
|
||||
RUN echo "$RB_USER ALL=(ALL:ALL) ALL" >> /etc/sudoers
|
||||
|
||||
USER $RB_USER
|
||||
|
22
Makefile
22
Makefile
|
@ -141,6 +141,7 @@ DBG_SRC = $(SRCS) debug_timer.c
|
|||
SL_SRC = serial_logger.c aq_serial.c utils.c packetLogger.c rs_msg_utils.c timespec_subtract.c
|
||||
|
||||
DD_SRC = dummy_device.c aq_serial.c utils.c packetLogger.c rs_msg_utils.c timespec_subtract.c
|
||||
DR_SRC = dummy_reader.c aq_serial.c utils.c packetLogger.c rs_msg_utils.c timespec_subtract.c
|
||||
|
||||
# Build durectories
|
||||
SRC_DIR := ./source
|
||||
|
@ -148,6 +149,7 @@ OBJ_DIR := ./build
|
|||
DBG_OBJ_DIR := $(OBJ_DIR)/debug
|
||||
SL_OBJ_DIR := $(OBJ_DIR)/slog
|
||||
DD_OBJ_DIR := $(OBJ_DIR)/dummydevice
|
||||
DR_OBJ_DIR := $(OBJ_DIR)/dummyreader
|
||||
|
||||
INCLUDES := -I$(SRC_DIR)
|
||||
|
||||
|
@ -164,12 +166,14 @@ SRCS := $(patsubst %.c,$(SRC_DIR)/%.c,$(SRCS))
|
|||
DBG_SRC := $(patsubst %.c,$(SRC_DIR)/%.c,$(DBG_SRC))
|
||||
SL_SRC := $(patsubst %.c,$(SRC_DIR)/%.c,$(SL_SRC))
|
||||
DD_SRC := $(patsubst %.c,$(SRC_DIR)/%.c,$(DD_SRC))
|
||||
DR_SRC := $(patsubst %.c,$(SRC_DIR)/%.c,$(DR_SRC))
|
||||
|
||||
# append path to obj files per architecture
|
||||
OBJ_FILES := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRCS))
|
||||
DBG_OBJ_FILES := $(patsubst $(SRC_DIR)/%.c,$(DBG_OBJ_DIR)/%.o,$(DBG_SRC))
|
||||
SL_OBJ_FILES := $(patsubst $(SRC_DIR)/%.c,$(SL_OBJ_DIR)/%.o,$(SL_SRC))
|
||||
DD_OBJ_FILES := $(patsubst $(SRC_DIR)/%.c,$(DD_OBJ_DIR)/%.o,$(DD_SRC))
|
||||
DR_OBJ_FILES := $(patsubst $(SRC_DIR)/%.c,$(DR_OBJ_DIR)/%.o,$(DR_SRC))
|
||||
|
||||
OBJ_FILES_ARMHF := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR_ARMHF)/%.o,$(SRCS))
|
||||
OBJ_FILES_ARM64 := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR_ARM64)/%.o,$(SRCS))
|
||||
|
@ -199,6 +203,7 @@ MAIN = ./release/aqualinkd
|
|||
SLOG = ./release/serial_logger
|
||||
DEBG = ./release/aqualinkd-debug
|
||||
DDEVICE = ./release/dummydevice
|
||||
DREADER = ./release/dummyreader
|
||||
|
||||
MAIN_ARM64 = ./release/aqualinkd-arm64
|
||||
MAIN_ARMHF = ./release/aqualinkd-armhf
|
||||
|
@ -273,6 +278,9 @@ aqdebug: $(DEBG)
|
|||
dummydevice: $(DDEVICE)
|
||||
$(info $(DDEVICE) has been compiled)
|
||||
|
||||
dummyreader: $(DREADER)
|
||||
$(info $(DREADER) has been compiled)
|
||||
|
||||
# Container, add container flag and compile
|
||||
container: CFLAGS := $(CFLAGS) -D AQ_CONTAINER
|
||||
container: $(MAIN) $(SLOG)
|
||||
|
@ -327,6 +335,9 @@ $(SL_OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(SL_OBJ_DIR)
|
|||
$(DD_OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(DD_OBJ_DIR)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
$(DR_OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(DR_OBJ_DIR)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
$(OBJ_DIR_ARMHF)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR_ARMHF)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
|
@ -381,6 +392,10 @@ $(DDEVICE): CFLAGS := $(CFLAGS) -D SERIAL_LOGGER -D DUMMY_DEVICE
|
|||
$(DDEVICE): $(DD_OBJ_FILES)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LIBS)
|
||||
|
||||
$(DREADER): CFLAGS := $(CFLAGS) -D SERIAL_LOGGER -D DUMMY_DEVICE -D DUMMY_READER
|
||||
$(DREADER): $(DR_OBJ_FILES)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LIBS)
|
||||
|
||||
# Rules to make object directories.
|
||||
$(OBJ_DIR):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
@ -391,6 +406,9 @@ $(SL_OBJ_DIR):
|
|||
$(DD_OBJ_DIR):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(DR_OBJ_DIR):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(DBG_OBJ_DIR):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
|
@ -415,10 +433,10 @@ $(SL_OBJ_DIR_AMD64):
|
|||
# Clean rules
|
||||
|
||||
clean: clean-buildfiles
|
||||
$(RM) *.o *~ $(MAIN) $(MAIN_U) $(PLAY) $(PL_EXOBJ) $(DEBG) $(DDEVICE)
|
||||
$(RM) *.o *~ $(MAIN) $(MAIN_U) $(PLAY) $(PL_EXOBJ) $(DEBG) $(DDEVICE) $(DREADER)
|
||||
$(RM) $(wildcard *.o) $(wildcard *~) $(MAIN) $(MAIN_ARM64) $(MAIN_ARMHF) $(MAIN_AMD64) $(SLOG) $(DDEVICE) $(SLOG_ARM64) $(SLOG_ARMHF) $(SLOG_AMD64) $(MAIN_U) $(PLAY) $(PL_EXOBJ) $(LOGR) $(PLAY) $(DEBG)
|
||||
|
||||
clean-buildfiles:
|
||||
$(RM) $(wildcard *.o) $(wildcard *~) $(OBJ_FILES) $(DBG_OBJ_FILES) $(SL_OBJ_FILES) $(DD_OBJ_FILES) $(OBJ_FILES_ARMHF) $(OBJ_FILES_ARM64) $(OBJ_FILES_AMD64) $(SL_OBJ_FILES_ARMHF) $(SL_OBJ_FILES_ARM64) $(SL_OBJ_FILES_AMD64)
|
||||
$(RM) $(wildcard *.o) $(wildcard *~) $(OBJ_FILES) $(DBG_OBJ_FILES) $(SL_OBJ_FILES) $(DD_OBJ_FILES) $(DR_OBJ_FILES) $(OBJ_FILES_ARMHF) $(OBJ_FILES_ARM64) $(OBJ_FILES_AMD64) $(SL_OBJ_FILES_ARMHF) $(SL_OBJ_FILES_ARM64) $(SL_OBJ_FILES_AMD64)
|
||||
|
||||
|
||||
|
|
68
README.md
68
README.md
|
@ -91,6 +91,7 @@ Designed to mimic AqualinkRS devices, used to fully configure the master control
|
|||
# ToDo (future release)
|
||||
* Create iAqualink Touch Simulator
|
||||
* AqualinkD to self configure. (Done for ID's, need to do for Panel type/size)
|
||||
* Support for (non Jandy) external ORP and Ph sensors
|
||||
|
||||
|
||||
<!--
|
||||
|
@ -125,17 +126,52 @@ NEED TO FIX FOR THIS RELEASE.
|
|||
|
||||
* Try an auto-update
|
||||
* Update Mongoose
|
||||
|
||||
* PDA Crap.
|
||||
* pda_aq_programmer line 702/703 color light.
|
||||
* pda_aq_programmer line 782 back menu testing in pda_init
|
||||
|
||||
* FIX Panel name in config to accept output from panel actual name
|
||||
|
||||
|
||||
-->
|
||||
# Updates in 2.6.5
|
||||
|
||||
# Updates in 2.6.9 (July 26 2025)
|
||||
* Config fixes for 0x33 ID / PDA
|
||||
* Changes to virtual buttons and light modes
|
||||
* Updates to aqmanager & config editor
|
||||
* Updates to jandy device logging & heatpump performance.
|
||||
* Increased performance of external sensors
|
||||
* Added unit of measure for External sensors
|
||||
* External sensors now have rexexp support (good for onewire devices)
|
||||
|
||||
# Updates in 2.6.8 (June 29 2025)
|
||||
* Fixed some UI bugs, added download config option
|
||||
* Changes to config options & config editor
|
||||
* Heatpump / chiller updates
|
||||
* PDA updates (detect temperature units, other small changes)
|
||||
|
||||
# Updates in 2.6.7 (May 23 2025)
|
||||
* Fixed bug with iaqualink protocol when no virtual buttons configured.
|
||||
* Updated RS timing debug messages.
|
||||
|
||||
# Updates in 2.6.6 (May 23 2025)
|
||||
* Fixed some HTTP response codes.
|
||||
* Added checks for protocols vs panel revision.
|
||||
* Fixed auto_configure for panel REV I & K.
|
||||
* Updates to install scripts.
|
||||
* Update to WebUI dimmers.
|
||||
|
||||
# Updates in 2.6.5 (May 5 2025)
|
||||
* Changes to virtual buttons.
|
||||
|
||||
# Updates in 2.6.4
|
||||
# Updates in 2.6.4 (Apr 28 2025)
|
||||
* Fix docker crash where journal not configured correctly.
|
||||
* Updates to config editor.
|
||||
* Increased number of virtual buttons. (previous limitation only effected RS 16 panels).
|
||||
* Changed to dimmable lights.
|
||||
|
||||
# Updates in 2.6.3
|
||||
# Updates in 2.6.3 (April 13 2025)
|
||||
* AqualinkD can how self-update directly from github. use `Upgrade AqualinkD` button in Aqmanager
|
||||
* New install and remote_install scripts.
|
||||
* Changed MQTT posting frequency when Timers are enabled for better
|
||||
|
@ -145,13 +181,13 @@ NEED TO FIX FOR THIS RELEASE.
|
|||
* -or-
|
||||
* `curl -fsSL https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/release/remote_install.sh | sudo bash -s -- latest`
|
||||
|
||||
# Updates in 2.6.1
|
||||
# Updates in 2.6.1 (Mar 26 2025)
|
||||
* Added External Sensors to Web UI & HomeKit.
|
||||
* Added Heat Pump / Chiller Thermostat to Web UI & HomeKit.
|
||||
* Fixed some bugs in Configuration Editor.
|
||||
* Link device/virtual/onetouch button with SWG BOOST. (Allows you to set VSP RPM when in Boost mode)
|
||||
|
||||
# Updates in 2.6.0
|
||||
# Updates in 2.6.0 (Mar 22 2025)
|
||||
* Added configuration editor in aqmanager. [Wiki - AQManager](https://github.com/aqualinkd/AqualinkD/wiki#AQManager)
|
||||
* Can now self-configure on startup. set `device_id=0xFF`
|
||||
* Added scheduling of pump after events (Power On, Freeze Protect, Boost)
|
||||
|
@ -162,8 +198,10 @@ NEED TO FIX FOR THIS RELEASE.
|
|||
* Reworked PDA sleep mode.
|
||||
* Added support for Heat Pump / Chiller support.
|
||||
|
||||
# Updates in 2.5.1 (Dec 7 2024)
|
||||
* Patch
|
||||
|
||||
# Updates in 2.5.0
|
||||
# Updates in 2.5.0 (Nov 16 2024)
|
||||
* 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.
|
||||
|
@ -183,7 +221,7 @@ NEED TO FIX FOR THIS RELEASE.
|
|||
* Faster OneTouch device support.
|
||||
|
||||
|
||||
# Updates in Release 2.4.0
|
||||
# Updates in Release 2.4.0 (Sept 7 2024)
|
||||
* <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
|
||||
|
@ -200,10 +238,10 @@ NEED TO FIX FOR THIS RELEASE.
|
|||
* 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
|
||||
# Updates in Release 2.3.8 (Sept 3 2024)
|
||||
* Release removed. Bug with light program 0.
|
||||
|
||||
# Updates in Release 2.3.7
|
||||
# Updates in Release 2.3.7 (Jun 11 2024)
|
||||
* Fix for Pentair VSP losing connection & bouncing SWG to 0 and back.
|
||||
* Added more VSP data (Mode, Status, Pressure Curve, both RPM & GPM) for all Pentair Pumps (VS/VF/VSF).
|
||||
* Few updates to HomeAssistant integration.
|
||||
|
@ -215,14 +253,14 @@ NEED TO FIX FOR THIS RELEASE.
|
|||
* Fix freeze protect button in UI not showing enabled.
|
||||
* Few updates to AQmanager UI.
|
||||
|
||||
# Update in Release 2.3.6
|
||||
# Update in Release 2.3.6 (May 31 2024)
|
||||
* No functionality changes
|
||||
* Build & Docker changes
|
||||
* Going forward AqualinkD will release binaries for both armhf & arm64
|
||||
* armhf = any Pi (or equiv board) running 32 bit Debain based OS, stretch or newer
|
||||
* arm64 = Pi3/4/2w running 64 bit Debain based OS, buster or newer
|
||||
|
||||
# Update in Release 2.3.5
|
||||
# Update in Release 2.3.5 (May 23 2024)
|
||||
* Added Home Assistant integration through MQTT discover
|
||||
* Please read the Home Assistant section of the [Wiki - HASSIO](https://github.com/aqualinkd/AqualinkD/wiki#HASSIO)
|
||||
* There are still some enhacments to come on this.
|
||||
|
@ -232,7 +270,7 @@ NEED TO FIX FOR THIS RELEASE.
|
|||
* Added Color Light to iAqualinkTouch protocol.
|
||||
* Fixed issue mqtt_timed_update (1~2 min rather than between 2 & 20 min)
|
||||
|
||||
# Update in Release 2.3.4
|
||||
# Update in Release 2.3.4 (May 13 2024)
|
||||
* Changes for Docker
|
||||
* Updated simulator code base and added new simulators for AllButton, OneTouch & PDA.
|
||||
* <aqualinkd.ip>/allbutton_sim.html
|
||||
|
@ -241,7 +279,7 @@ NEED TO FIX FOR THIS RELEASE.
|
|||
* On PDA only panel AqualinkD has to share the same ID with the PDA simulator. Therefore for AqualinkD will not respond to commands while simulator is active.
|
||||
* Now you can completely program the control panel with the simulators removing the need to have Jandy device.
|
||||
|
||||
# Update in Release 2.3.3
|
||||
# Update in Release 2.3.3 (May 30 2024)
|
||||
* Introduced Aqualink Manager UI http://aqualink.ip/aqmanager.html
|
||||
* [AqualinkD Manager](https://github.com/aqualinkd/AqualinkD/wiki#AQManager)
|
||||
* Moved logging into systemd/journal (journalctl) from syslog
|
||||
|
@ -254,12 +292,12 @@ NEED TO FIX FOR THIS RELEASE.
|
|||
* Add ```rs485_frame_delay = 4``` to /etc/aqualinkd.conf, 4 is number of milliseconds between frames, 0 will turn off ie no pause.
|
||||
* PDA Changes to support SWG and Boot.
|
||||
|
||||
# Update in Release 2.3.2
|
||||
# Update in Release 2.3.2 (Jul 8 2023)
|
||||
* Added support for VSP on panel versions REV 0.1 & 0.2
|
||||
* Can change heater sliver min/max values in web UI. `./web/config.js`
|
||||
* Added reading ePump RPM/Watts directly from RS485 bus.
|
||||
|
||||
# Update in Release 2.3.1
|
||||
# Update in Release 2.3.1 (Jun 23 2023)
|
||||
* Changed a lot of logic around different protocols.
|
||||
* Added low latency support for FTDI usb driver.
|
||||
* AqualinkD will find out the fastest way to change something depending on the protocols available.
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,32 +0,0 @@
|
|||
# aqualinkd - aqualinkd job file
|
||||
#
|
||||
# check with `initctl check-config aqualinkd`
|
||||
#
|
||||
description "aqualink RS daemon service"
|
||||
author "Me <myself@i.com>"
|
||||
|
||||
# Stanzas
|
||||
#
|
||||
# Stanzas control when and how a process is started and stopped
|
||||
# See a list of stanzas here: http://upstart.ubuntu.com/wiki/Stanzas#respawn
|
||||
|
||||
# When to start the service
|
||||
start on runlevel [2345]
|
||||
|
||||
# When to stop the service
|
||||
stop on runlevel [016]
|
||||
|
||||
# Automatically restart process if crashed
|
||||
respawn
|
||||
|
||||
# Essentially lets upstart know the process will detach itself to the background
|
||||
expect fork
|
||||
|
||||
# Run before process
|
||||
#pre-start script
|
||||
# [ -d /var/run/myservice ] || mkdir -p /var/run/myservice
|
||||
# echo "Put bash code here"
|
||||
#end script
|
||||
|
||||
# Start the process
|
||||
exec /usr/local/bin/aqualinkd -c /etc/aqualinkd/aqualinkd.conf
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
|
||||
BUILD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
PARENT_COMMAND=$(ps -o comm= $PPID)
|
||||
PARENT_COMMAND=$(ps -o comm= $PPID 2>/dev/null)
|
||||
|
||||
SERVICE="aqualinkd"
|
||||
|
||||
|
@ -30,9 +30,10 @@ REMOUNT_RO=1
|
|||
TRUE=0
|
||||
FALSE=1
|
||||
|
||||
_logfile="";
|
||||
_frommake=$FALSE;
|
||||
_ignorearch=$FALSE;
|
||||
_logfile=""
|
||||
_frommake=$FALSE
|
||||
_ignorearch=$FALSE
|
||||
_nosystemd=$FALSE
|
||||
|
||||
log()
|
||||
{
|
||||
|
@ -59,7 +60,7 @@ printHelp()
|
|||
}
|
||||
|
||||
|
||||
log "Called $0 with $*"
|
||||
#log "Called $0 with $*"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
|
@ -83,6 +84,9 @@ while [[ $# -gt 0 ]]; do
|
|||
ignorearch)
|
||||
_ignorearch=$TRUE
|
||||
;;
|
||||
nosystemd)
|
||||
_nosystemd=$TRUE
|
||||
;;
|
||||
help | -help | --help | -h)
|
||||
printHelp
|
||||
exit $TRUE;
|
||||
|
@ -106,15 +110,17 @@ if [[ $EUID -ne 0 ]]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $(mount | grep " / " | grep "(ro,") ]]; then
|
||||
if mount / -o remount,rw &>/dev/null; then
|
||||
if [ "$_nosystemd" -eq $FALSE ]; then
|
||||
if [[ $(mount | grep " / " | grep "(ro,") ]]; then
|
||||
if mount / -o remount,rw &>/dev/null; then
|
||||
# can mount RW.
|
||||
#mount / -o remount,rw &>/dev/null
|
||||
log "Root filesystem is readonly, remounted RW"
|
||||
REMOUNT_RO=0;
|
||||
else
|
||||
log "Root filesystem is readonly, can't install"
|
||||
exit 1
|
||||
log "Root filesystem is readonly, remounted RW"
|
||||
REMOUNT_RO=0;
|
||||
else
|
||||
log "Root filesystem is readonly, can't install"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@ -170,9 +176,11 @@ fi
|
|||
# Exit if we can't find systemctl
|
||||
command -v systemctl >/dev/null 2>&1 || { log "This script needs systemd's systemctl manager, Please check path or install manually" >&2; exit 1; }
|
||||
|
||||
# stop service, hide any error, as the service may not be installed yet
|
||||
systemctl stop $SERVICE > /dev/null 2>&1
|
||||
SERVICE_EXISTS=$(echo $?)
|
||||
if [ "$_nosystemd" -eq $FALSE ]; then
|
||||
# stop service, hide any error, as the service may not be installed yet
|
||||
systemctl stop $SERVICE > /dev/null 2>&1
|
||||
SERVICE_EXISTS=$(echo $?)
|
||||
fi
|
||||
|
||||
# Clean everything if requested.
|
||||
if [ "$1" == "clean" ]; then
|
||||
|
@ -202,19 +210,12 @@ fi
|
|||
|
||||
|
||||
# Check cron.d options
|
||||
if [ ! -d "/etc/cron.d" ]; then
|
||||
log "The version of Cron may not support chron.d, if so AqualinkD Scheduler will not work"
|
||||
log "Please check before starting"
|
||||
else
|
||||
if [ -f "/etc/default/cron" ]; then
|
||||
CD=$(cat /etc/default/cron | grep -v ^# | grep "\-l")
|
||||
if [ -z "$CD" ]; then
|
||||
log "Please enabled cron.d support, if not AqualinkD Scheduler will not work"
|
||||
log "Edit /etc/default/cron and look for the -l option, usually in EXTRA_OPTS"
|
||||
fi
|
||||
else
|
||||
log "Please make sure the version if Cron supports chron.d, if not the AqualinkD Scheduler will not work"
|
||||
if systemctl is-active --quiet cron.service; then
|
||||
if [ ! -d "/etc/cron.d" ]; then
|
||||
log "The version of cron installed may not support chron.d, if so AqualinkD Scheduler will not work"
|
||||
fi
|
||||
else
|
||||
log "Please install cron, if not the AqualinkD Scheduler will not work"
|
||||
fi
|
||||
|
||||
# V2.3.9 & V2.6.0 has kind-a breaking change for config.js, so check existing and rename if needed
|
||||
|
@ -224,7 +225,8 @@ if [ -f "$WEBLocation/config.js" ]; then
|
|||
# Version 2.6.0 added Chiller as well
|
||||
if ! grep -q '"Aux_V1"' "$WEBLocation/config.js" ||
|
||||
! grep -q '"Spa"' "$WEBLocation/config.js" ||
|
||||
! grep -q '"Chiller"' "$WEBLocation/config.js"; then
|
||||
! grep -q '"Chiller"' "$WEBLocation/config.js" ||
|
||||
! grep -q '"Aux_S1"' "$WEBLocation/config.js"; then
|
||||
dateext=`date +%Y%m%d_%H_%M_%S`
|
||||
log "AqualinkD web config is old, making copy to $WEBLocation/config.js.$dateext"
|
||||
log "Please make changes to new version $WEBLocation/config.js"
|
||||
|
@ -287,6 +289,11 @@ fi
|
|||
# remount root ro
|
||||
if [[ $REMOUNT_RO -eq 0 ]]; then
|
||||
mount / -o remount,ro &>/dev/null
|
||||
log "Root filesystem remounted RO"
|
||||
fi
|
||||
|
||||
if [ "$_nosystemd" -eq $TRUE ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
systemctl enable $SERVICE
|
||||
|
|
|
@ -45,6 +45,7 @@ log()
|
|||
echo "$*"
|
||||
|
||||
if [ "$SYSTEMD_LOG" -eq $TRUE ]; then
|
||||
# For some unknown reason, only way below works from aqualinkd process is adding "&>> "$OUTPUT""
|
||||
echo "Upgrade: $*" | systemd-cat -t aqualinkd -p info &>> "$OUTPUT"
|
||||
else
|
||||
logger -p local0.notice -t aqualinkd "Upgrade: $*"
|
||||
|
@ -258,7 +259,7 @@ function cleanup {
|
|||
#
|
||||
|
||||
|
||||
# See if we are called from curl ot local dir.
|
||||
# See if we are called from curl or local dir.
|
||||
# with curl no tty input and script name wil be blank.
|
||||
if ! tty > /dev/null 2>&1; then
|
||||
script=$(basename "$0")
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -612,10 +612,12 @@ void *set_allbutton_light_programmode( void *ptr )
|
|||
} else {
|
||||
for (i = 1; i < val; i++) {
|
||||
const int dt = 0.5; // Time to wait after receiving conformation of light on/off
|
||||
waitfor_queue2empty();
|
||||
LOG(ALLB_LOG, LOG_INFO, "Light Programming button press number %d - %s of %d\n", i, "ON", val);
|
||||
send_cmd(code);
|
||||
waitForButtonState(aq_data, button, ON, 2);
|
||||
delay(dt * seconds);
|
||||
waitfor_queue2empty();
|
||||
LOG(ALLB_LOG, LOG_INFO, "Light Programming button press number %d - %s of %d\n", i, "OFF", val);
|
||||
send_cmd(code);
|
||||
waitForButtonState(aq_data, button, OFF, 2);
|
||||
|
@ -623,7 +625,8 @@ void *set_allbutton_light_programmode( void *ptr )
|
|||
}
|
||||
LOG(ALLB_LOG, LOG_INFO, "Finished - Light Programming button press number %d - %s of %d\n", i, "ON", val);
|
||||
send_cmd(code);
|
||||
waitfor_queue2empty();
|
||||
//waitfor_queue2empty();
|
||||
longwaitfor_queue2empty();
|
||||
}
|
||||
//waitForButtonState(aq_data, &aq_data->aqbuttons[btn], ON, 2);
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button);
|
|||
void printPanelSupport(struct aqualinkdata *aqdata);
|
||||
uint16_t setPanelSupport(struct aqualinkdata *aqdata);
|
||||
|
||||
|
||||
void removePanelRSserialAdapterInterface();
|
||||
void removePanelOneTouchInterface();
|
||||
void removePanelIAQTouchInterface();
|
||||
|
||||
char *name2label(char *str)
|
||||
{
|
||||
int len = strlen(str);
|
||||
|
@ -117,6 +122,40 @@ const char* find_rev_chars(const char *str, int length, int *out_len) {
|
|||
return NULL; // Pattern not found
|
||||
}
|
||||
|
||||
void checkPanelConfig(struct aqualinkdata *aqdata) {
|
||||
|
||||
// Check panel rev for common errors.
|
||||
|
||||
// Aqualink Touch.
|
||||
if ( _aqconfig_.extended_device_id >= 0x30 && _aqconfig_.extended_device_id <= 0x33) {
|
||||
if ( !isMASKSET(aqdata->panel_support_options, RSP_SUP_AQLT)) {
|
||||
LOG(PANL_LOG, LOG_ERR, "Panel REV %s does not support AqualinkTouch protocol, please change configuration option '%s'\n",aqdata->panel_rev, CFG_N_extended_device_id);
|
||||
LOG(PANL_LOG, LOG_WARNING, "Removing option '%s', please correct configuration\n",CFG_N_extended_device_id);
|
||||
_aqconfig_.extended_device_id = 0x00;
|
||||
removePanelIAQTouchInterface();
|
||||
}
|
||||
}
|
||||
|
||||
// One Touch
|
||||
if ( _aqconfig_.extended_device_id >= 0x40 && _aqconfig_.extended_device_id <= 0x43) {
|
||||
if ( !isMASKSET(aqdata->panel_support_options, RSP_SUP_ONET)) {
|
||||
LOG(PANL_LOG, LOG_ERR, "Panel REV %s does not support OneTouch protocol, please change configuration option '%s'\n",aqdata->panel_rev, CFG_N_extended_device_id);
|
||||
LOG(PANL_LOG, LOG_WARNING, "Removing option '%s', please correct configuration\n",CFG_N_extended_device_id);
|
||||
_aqconfig_.extended_device_id = 0x00;
|
||||
removePanelOneTouchInterface();
|
||||
}
|
||||
}
|
||||
|
||||
// Serial Adapter
|
||||
if ( _aqconfig_.rssa_device_id >= 0x48 && _aqconfig_.rssa_device_id <= 0x49) {
|
||||
if ( !isMASKSET(aqdata->panel_support_options, RSP_SUP_RSSA)) {
|
||||
LOG(PANL_LOG, LOG_ERR, "Panel REV %s does not support RS SerialAdapter protocol, please change configuration option '%s'\n",aqdata->panel_rev, CFG_N_rssa_device_id);
|
||||
LOG(PANL_LOG, LOG_WARNING, "Removing option '%s', please correct configuration\n",CFG_N_rssa_device_id);
|
||||
_aqconfig_.rssa_device_id = 0x00;
|
||||
removePanelRSserialAdapterInterface();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pull board CPU, revision & panel string from strings like
|
||||
|
@ -146,7 +185,7 @@ pull board CPU, revision & panel string from strings like
|
|||
uint8_t setPanelInformationFromPanelMsg(struct aqualinkdata *aqdata, const char *input, uint8_t type, emulation_type source) {
|
||||
const char *rev_pos = NULL;
|
||||
uint8_t rtn = 0;
|
||||
|
||||
printf("Calculate panel from %s\n",input);
|
||||
//const char *rev_pos = strstr(input, "REV"); // Find the position of "REV"
|
||||
const char *sp;
|
||||
int length = 0;
|
||||
|
@ -164,6 +203,12 @@ uint8_t setPanelInformationFromPanelMsg(struct aqualinkdata *aqdata, const char
|
|||
LOG(PANL_LOG, LOG_NOTICE, "Panel REV %s from %s\n",aqdata->panel_rev,getJandyDeviceName(source));
|
||||
setPanelSupport(aqdata);
|
||||
//printPanelSupport(aqdata);
|
||||
if (source == SIM_NONE) {
|
||||
// We pass SIM_NONE when we are in auto_config mode, so reset the panel name so we get it again when we fully start
|
||||
aqdata->panel_rev[0] = '\0';
|
||||
} else {
|
||||
checkPanelConfig(aqdata);
|
||||
}
|
||||
} else {
|
||||
//printf("Failed to find REV, length\n");
|
||||
}
|
||||
|
@ -397,6 +442,16 @@ void addPanelIAQTouchInterface() {
|
|||
_aqconfig_.paneltype_mask &= ~RSP_ONET;
|
||||
}
|
||||
|
||||
void removePanelRSserialAdapterInterface() {
|
||||
_aqconfig_.paneltype_mask &= ~RSP_RSSA;
|
||||
}
|
||||
void removePanelOneTouchInterface() {
|
||||
_aqconfig_.paneltype_mask &= ~RSP_ONET;
|
||||
}
|
||||
void removePanelIAQTouchInterface() {
|
||||
_aqconfig_.paneltype_mask &= ~RSP_IAQT;
|
||||
}
|
||||
|
||||
int PANEL_SIZE() {
|
||||
if ((_aqconfig_.paneltype_mask & RSP_4) == RSP_4)
|
||||
return 4;
|
||||
|
@ -570,6 +625,8 @@ void setPanelByName(struct aqualinkdata *aqdata, const char *str)
|
|||
rs = false;
|
||||
if (str[2] == '-' || str[2] == ' ') // Account for PD-8
|
||||
size = atoi(&str[3]);
|
||||
if (str[3] == '-' && str[4] == 'P') // PDA-PS6 Combo
|
||||
size = atoi(&str[6]);
|
||||
else // Account for PDA-8
|
||||
size = atoi(&str[4]);
|
||||
} else {
|
||||
|
@ -1308,12 +1365,15 @@ void programDeviceLightBrightness(struct aqualinkdata *aqdata, int value, int de
|
|||
//void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button)
|
||||
void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int deviceIndex)
|
||||
{
|
||||
|
||||
#ifdef AQ_PDA
|
||||
if (isPDA_PANEL && !isPDA_IAQT) {
|
||||
LOG(PANL_LOG,LOG_ERR, "Light mode control not supported in PDA mode\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
int i;
|
||||
clight_detail *light = NULL;
|
||||
|
@ -1345,7 +1405,12 @@ void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int deviceIn
|
|||
} else if (isRSSA_ENABLED) {
|
||||
// If we are using rs-serial then turn light on first.
|
||||
if (light->button->led->state != ON) {
|
||||
set_aqualink_rssadapter_aux_extended_state(light->button, RS_SA_ON);
|
||||
set_aqualink_rssadapter_aux_state(light->button, TRUE);
|
||||
//set_aqualink_rssadapter_aux_extended_state(light->button, RS_SA_ON);
|
||||
//set_aqualink_rssadapter_aux_extended_state(light->button, 100);
|
||||
// Add a few delays to slow it down. 0 is get status
|
||||
//set_aqualink_rssadapter_aux_extended_state(light->button, 0);
|
||||
//set_aqualink_rssadapter_aux_extended_state(light->button, 0);
|
||||
}
|
||||
if (light->lightType == LC_DIMMER) {
|
||||
// Value 1 = 25, 2 = 50, 3 = 75, 4 = 100 (need to convert value into binary)
|
||||
|
@ -1490,8 +1555,13 @@ void updateButtonLightProgram(struct aqualinkdata *aqdata, int value, int button
|
|||
}
|
||||
|
||||
light->currentValue = value;
|
||||
if (value > 0)
|
||||
if (value > 0 && light->lastValue != value) {
|
||||
light->lastValue = value;
|
||||
if (_aqconfig_.save_light_programming_value && light->lightType == LC_PROGRAMABLE ) {
|
||||
LOG(PANL_LOG,LOG_NOTICE, "Writing light programming value to config\n",button);
|
||||
writeCfg(aqdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clight_detail *getProgramableLight(struct aqualinkdata *aqdata, int button)
|
||||
|
|
|
@ -107,6 +107,7 @@ const func_ptr _prog_functions[AQP_RSSADAPTER_MAX] = {
|
|||
[AQ_PDA_SET_SPA_HEATER_TEMPS] = set_aqualink_PDA_spa_heater_temps,
|
||||
[AQ_PDA_SET_FREEZE_PROTECT_TEMP] = set_aqualink_PDA_freeze_protectsetpoint,
|
||||
[AQ_PDA_SET_TIME] = set_PDA_aqualink_time,
|
||||
[AQ_PDA_SET_LIGHT_MODE] = set_aqualink_PDA_light_mode,
|
||||
//[AQ_PDA_GET_POOL_SPA_HEATER_TEMPS]= get_aqualink_PDA_pool_spa_heater_temps,
|
||||
[AQ_PDA_GET_FREEZE_PROTECT_TEMP] = get_PDA_aqualink_pool_spa_heater_temps
|
||||
/*
|
||||
|
@ -599,6 +600,9 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat
|
|||
case AQ_SET_TIME:
|
||||
type = AQ_PDA_SET_TIME;
|
||||
break;
|
||||
case AQ_SET_LIGHTCOLOR_MODE:
|
||||
type = AQ_PDA_SET_LIGHT_MODE;
|
||||
break;
|
||||
#ifdef BETA_PDA_AUTOLABEL
|
||||
case AQ_GET_AUX_LABELS:
|
||||
type = AQ_PDA_AUX_LABELS:
|
||||
|
@ -963,6 +967,9 @@ const char *ptypeName(program_type type)
|
|||
case AQ_PDA_GET_FREEZE_PROTECT_TEMP:
|
||||
return "Get PDA freeze protect";
|
||||
break;
|
||||
case AQ_PDA_SET_LIGHT_MODE:
|
||||
return "Set PDA light mode";
|
||||
break;
|
||||
#endif
|
||||
case AQP_NULL:
|
||||
default:
|
||||
|
@ -1059,6 +1066,9 @@ const char *programtypeDisplayName(program_type type)
|
|||
case AQ_PDA_WAKE_INIT:
|
||||
return "Programming: PDA wakeup";
|
||||
break;
|
||||
case AQ_PDA_SET_LIGHT_MODE:
|
||||
return "Programming: setting light color";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return "Programming: please wait!";
|
||||
|
|
|
@ -78,6 +78,7 @@ typedef enum {
|
|||
AQ_PDA_SET_TIME,
|
||||
AQ_PDA_GET_POOL_SPA_HEATER_TEMPS,
|
||||
AQ_PDA_GET_FREEZE_PROTECT_TEMP,
|
||||
AQ_PDA_SET_LIGHT_MODE,
|
||||
// ******** OneTouch Delimiter make sure to change MAX/MIN below
|
||||
AQ_SET_ONETOUCH_PUMP_RPM,
|
||||
AQ_SET_ONETOUCH_MACRO,
|
||||
|
|
|
@ -121,13 +121,16 @@ const char *getJandyDeviceName(emulation_type etype) {
|
|||
case AQUAPDA:
|
||||
return "PDA";
|
||||
break;
|
||||
case SIM_NONE:
|
||||
return "AutoConfig";
|
||||
break;
|
||||
default:
|
||||
return "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char* get_pentair_packet_type(unsigned char* packet , int length)
|
||||
const char* get_pentair_packet_type(const unsigned char* packet , int length)
|
||||
{
|
||||
static char buf[15];
|
||||
|
||||
|
@ -165,7 +168,7 @@ const char* get_pentair_packet_type(unsigned char* packet , int length)
|
|||
break;
|
||||
}
|
||||
}
|
||||
const char* get_jandy_packet_type(unsigned char* packet , int length)
|
||||
const char* get_jandy_packet_type(const unsigned char* packet , int length)
|
||||
{
|
||||
static char buf[15];
|
||||
|
||||
|
@ -319,7 +322,7 @@ const char* get_jandy_packet_type(unsigned char* packet , int length)
|
|||
}
|
||||
}
|
||||
|
||||
const char* get_packet_type(unsigned char* packet , int length)
|
||||
const char* get_packet_type(const unsigned char* packet , int length)
|
||||
{
|
||||
if (getProtocolType(packet)==PENTAIR) {
|
||||
return get_pentair_packet_type(packet, length);
|
||||
|
@ -409,7 +412,7 @@ void generate_pentair_checksum(unsigned char* packet, int length)
|
|||
|
||||
}
|
||||
|
||||
protocolType getProtocolType(unsigned char* packet) {
|
||||
protocolType getProtocolType(const unsigned char* packet) {
|
||||
if (packet[0] == DLE)
|
||||
return JANDY;
|
||||
else if (packet[0] == PP1)
|
||||
|
@ -1030,6 +1033,114 @@ int get_packet_lograw(int fd, unsigned char* packet)
|
|||
int _get_packet(int fd, unsigned char* packet, bool rawlog)
|
||||
*/
|
||||
|
||||
#ifdef DUMMY_READER
|
||||
|
||||
int fix_packet(unsigned char *packet_buffer, int packet_length, bool getCached) {
|
||||
|
||||
static unsigned char saved_buffer[AQ_MAXPKTLEN+1];
|
||||
static int saved_buffer_length = 0;
|
||||
|
||||
if (getCached) {
|
||||
if (saved_buffer_length > 0) {
|
||||
memcpy(packet_buffer, saved_buffer, saved_buffer_length);
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "2nd part of fixed frame\n");
|
||||
logPacket(RSSD_LOG, LOG_DEBUG, packet_buffer, saved_buffer_length, true);
|
||||
debuglogPacket(RSSD_LOG, packet_buffer, saved_buffer_length, true, true);
|
||||
} else {
|
||||
printf("NO 2nd PACKET %d\n",saved_buffer_length );
|
||||
}
|
||||
return saved_buffer_length;
|
||||
}
|
||||
|
||||
char pbuf[256];
|
||||
int rtn = 0;
|
||||
|
||||
memset(saved_buffer, 0, sizeof(saved_buffer));
|
||||
saved_buffer_length = 0;
|
||||
|
||||
//LOG(RSSD_LOG,LOG_DEBUG, "Trying to fix bad packet\n");
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad Jandy checksum, Trying to fix bad packet\n");
|
||||
// Check end is valid
|
||||
|
||||
if ( packet_buffer[packet_length-2] == DLE && packet_buffer[packet_length-1] == ETX ) {
|
||||
//LOG(RSSD_LOG,LOG_DEBUG, "Packet Fix: good end\n");
|
||||
} else {
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Packet Fix: bad end\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Specific fix for 2 frames where the first didn't end (but still holds the checksum)
|
||||
// HEX: 0x10|0x02|0x00|0x0d|0x40|0x00|0x00|0x5f|0x10|0x02|0x84|0x00|0x96|0x10|0x03| <- no end 0x10|0x03, start 0x10|0x02 in middle
|
||||
// HEX: 0x10|0x02|0x00|0x0d|0x40|0x00|0x00|0x5f|0x10|0x10|0x02|0x33|0x30|0x75|0x10|0x03| <- no 0x03 for end, start 0x10|0x02 in middle
|
||||
|
||||
// Run over the packet, see if their is a start in the middle.
|
||||
// Ignore the first two bytes, assuming they are 0x10, 0x02
|
||||
|
||||
|
||||
for (int i=2; i <= packet_length; i++ ) {
|
||||
if (packet_buffer[i] == DLE && packet_buffer[i+1] == STX) {
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Packet Fix: found start in middle of frame\n");
|
||||
int p1_length = i;
|
||||
int p2_length = packet_length-i;
|
||||
unsigned char *p2_start = &packet_buffer[i];
|
||||
bool validstart=FALSE;
|
||||
bool validend=FALSE;
|
||||
// Something we catch the end DLE as well as start DLE
|
||||
while (packet_buffer[p1_length] == DLE) {
|
||||
p1_length--;
|
||||
}
|
||||
|
||||
beautifyPacket(pbuf, 256, packet_buffer, packet_length, TRUE);
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Packet Fix: SPLITTING start to: %s\n",pbuf);
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Packet Fix: Check 0x%02hhx (%d)\n",packet_buffer[p1_length], p1_length);
|
||||
|
||||
// see if we have a valid end
|
||||
if (check_jandy_checksum(p2_start, p2_length) == true){
|
||||
//LOG(RSSD_LOG,LOG_DEBUG, "Valid packet found at end\n");
|
||||
beautifyPacket(pbuf, 256, p2_start, p2_length, TRUE);
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Packet Fix: FIXED end to: %s\n",pbuf);
|
||||
validend=TRUE;
|
||||
}
|
||||
|
||||
if (check_jandy_checksum(packet_buffer, p1_length+3) == true){
|
||||
//LOG(RSSD_LOG,LOG_DEBUG, "Valid packet found at start\n");
|
||||
beautifyPacket(pbuf, 256, packet_buffer, p1_length, TRUE);
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Packet Fix: FIXED start to: %s\n",pbuf);
|
||||
validstart=TRUE;
|
||||
}
|
||||
|
||||
if (validstart && validend) {
|
||||
// Save the 2nd frame
|
||||
memcpy(saved_buffer, p2_start, p2_length);
|
||||
saved_buffer_length = p2_length;
|
||||
// correct the 1st frame
|
||||
packet_buffer[p1_length+1] = DLE;
|
||||
packet_buffer[p1_length+2] = ETX;
|
||||
rtn = p1_length+3;
|
||||
} else if (validend) {
|
||||
// Return the valid part of the packet.
|
||||
memcpy(packet_buffer, p2_start, p2_length);
|
||||
rtn = p2_length;
|
||||
} else if (validstart) {
|
||||
// correct the 1st frame
|
||||
packet_buffer[p1_length+1] = DLE;
|
||||
packet_buffer[p1_length+2] = ETX;
|
||||
rtn = p1_length+3;
|
||||
}
|
||||
// Try the start.
|
||||
//memcpy(new_buffer, packet_buffer, i);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
beautifyPacket(pbuf, 256, packet_buffer, rtn, TRUE);
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Packet Fix: RETURNING: %s\n",pbuf);
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int get_packet(int fd, unsigned char* packet)
|
||||
{
|
||||
|
@ -1050,6 +1161,17 @@ int get_packet(int fd, unsigned char* packet)
|
|||
|
||||
memset(packet, 0, AQ_MAXPKTLEN);
|
||||
|
||||
#ifdef DUMMY_READER
|
||||
static bool haveFixedPacket = false;
|
||||
if (haveFixedPacket) {
|
||||
haveFixedPacket = false;
|
||||
int rtn = fix_packet(packet, AQ_MAXPKTLEN, true);
|
||||
if (rtn > 0) {
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "RETURNING PART 2 OF FIXED PACKET:\n");
|
||||
return rtn;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Read packet in byte order below
|
||||
// DLE STX ........ ETX DLE
|
||||
// sometimes we get ETX DLE and no start, so for now just ignoring that. Seem to be more applicable when busy RS485 traffic
|
||||
|
@ -1198,11 +1320,19 @@ int get_packet(int fd, unsigned char* packet)
|
|||
|
||||
//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) {
|
||||
if (check_jandy_checksum(packet, index) != true){
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
|
||||
logPacketError(packet, index);
|
||||
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
return AQSERR_CHKSUM;
|
||||
if (check_jandy_checksum(packet, index) != true) {
|
||||
#ifdef DUMMY_READER
|
||||
int size = fix_packet(packet, index, false);
|
||||
if (size > 0) {
|
||||
haveFixedPacket = true;
|
||||
index = size;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
|
||||
logPacketError(packet, index);
|
||||
return AQSERR_CHKSUM;
|
||||
}
|
||||
}
|
||||
} else if (pentairPacketStarted) {
|
||||
if (check_pentair_checksum(packet, index) != true){
|
||||
|
|
|
@ -48,7 +48,7 @@ const char *getJandyDeviceName(emulation_type etype);
|
|||
#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_PUMP2_MAX 228 // 0xe3 // (should be 0xEF?????) Their are probably more, but this is a guess
|
||||
|
||||
#define JANDY_DEC_JXI_MIN 104 // 0x68
|
||||
#define JANDY_DEC_JXI_MAX 107 // 0x6B
|
||||
|
@ -65,6 +65,9 @@ const char *getJandyDeviceName(emulation_type etype);
|
|||
|
||||
#define JANDY_DEV_HPUMP_MIN 0x70
|
||||
#define JANDY_DEV_HPUMP_MAX 0x73
|
||||
|
||||
#define JANDY_DEV_JLIGHT_MIN 0xF0
|
||||
#define JANDY_DEV_JLIGHT_MAX 0xF4 // 0xF4 is total guess.
|
||||
/*
|
||||
//===== Device ID's =====//
|
||||
//=========================================================================//
|
||||
|
@ -524,7 +527,8 @@ typedef enum {
|
|||
DRS_JXI,
|
||||
DRS_LX,
|
||||
DRS_CHEM,
|
||||
DRS_HEATPUMP
|
||||
DRS_HEATPUMP,
|
||||
DRS_JLIGHT
|
||||
} rsDeviceType;
|
||||
|
||||
typedef enum {
|
||||
|
@ -567,7 +571,7 @@ bool serial_blockingmode();
|
|||
//bool pda_mode();
|
||||
//#endif
|
||||
int generate_checksum(unsigned char* packet, int length);
|
||||
protocolType getProtocolType(unsigned char* packet);
|
||||
protocolType getProtocolType(const unsigned char* packet);
|
||||
bool check_jandy_checksum(unsigned char* packet, int length);
|
||||
bool check_pentair_checksum(unsigned char* packet, int length);
|
||||
void send_ack(int file_descriptor, unsigned char command);
|
||||
|
@ -582,7 +586,7 @@ int is_valid_port(int fd);
|
|||
//void close_serial_port(int file_descriptor, struct termios* oldtio);
|
||||
//void process_status(void const * const ptr);
|
||||
void process_status(unsigned char* ptr);
|
||||
const char* get_packet_type(unsigned char* packet , int length);
|
||||
const char* get_packet_type(const unsigned char* packet , int length);
|
||||
/*
|
||||
void set_onetouch_enabled(bool mode);
|
||||
bool onetouch_enabled();
|
||||
|
|
|
@ -83,12 +83,13 @@ bool isVirtualButtonEnabled();
|
|||
#define PUMP_GPM_MAX 130
|
||||
#define PUMP_GPM_MIN 15
|
||||
|
||||
|
||||
enum {
|
||||
/*
|
||||
typedef enum temperatureUOM {
|
||||
FAHRENHEIT,
|
||||
CELSIUS,
|
||||
UNKNOWN
|
||||
};
|
||||
} temperatureUOM;
|
||||
*/
|
||||
|
||||
typedef struct aqualinkkey
|
||||
{
|
||||
|
@ -258,7 +259,7 @@ typedef enum clight_type {
|
|||
LC_CLOGIG,
|
||||
LC_INTELLIB,
|
||||
LC_HAYWCL,
|
||||
LC_SPARE_1,
|
||||
LC_JANDYINFINATE, // was SPARE_1 (Infinate watercolors LED)
|
||||
LC_SPARE_2,
|
||||
LC_SPARE_3,
|
||||
LC_DIMMER, // use 0, 25, 50, 100
|
||||
|
@ -295,6 +296,7 @@ typedef struct clightd
|
|||
{
|
||||
clight_type lightType;
|
||||
aqkey *button;
|
||||
unsigned char lightID; // RS485 ID (only Jandy infinate watercolor)
|
||||
int currentValue;
|
||||
int lastValue; // Used for AqualinkD self programming
|
||||
aqledstate RSSDstate; // state from rs serial adapter
|
||||
|
|
|
@ -740,7 +740,7 @@ void caculate_ack_packet(int rs_fd, unsigned char *packet_buffer, emulation_type
|
|||
|
||||
#define MAX_AUTO_PACKETS 1200
|
||||
|
||||
bool auto_configure(unsigned char* packet) {
|
||||
bool auto_configure(unsigned char* packet, int rs_fd) {
|
||||
// Loop over PROBE packets and store any we can use,
|
||||
// once we see the 2nd probe of any ID we fave stored, then the loop is complete,
|
||||
// set ID's and exit true, exit falce to get called again.
|
||||
|
@ -755,9 +755,16 @@ bool auto_configure(unsigned char* packet) {
|
|||
static unsigned char firstprobe = 0x00;
|
||||
static unsigned char lastID = 0x00;
|
||||
static bool seen_iAqualink2 = false;
|
||||
static bool ignore_AqualinkTouch = false;
|
||||
static int foundIDs = 0;
|
||||
static int packetsReceived=0;
|
||||
|
||||
static bool gotRev = false;
|
||||
static unsigned char gettingRevID = 0xFF;
|
||||
|
||||
static int loopsCompleted=0;
|
||||
//static char message[AQ_MSGLONGLEN + 1];
|
||||
|
||||
if (++packetsReceived >= MAX_AUTO_PACKETS ) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Received %d packets, and didn't get a full probe cycle, stoping Auto Configure!\n",packetsReceived);
|
||||
return true;
|
||||
|
@ -766,6 +773,35 @@ bool auto_configure(unsigned char* packet) {
|
|||
if ( packet[PKT_CMD] == CMD_PROBE ) {
|
||||
LOG(AQUA_LOG,LOG_INFO, "Got Probe on ID 0x%02hhx\n",packet[PKT_DEST]);
|
||||
//printf(" *** Got Probe on ID 0x%02hhx\n",packet[PKT_DEST]);
|
||||
if ( packet[PKT_DEST] >= 0x08 && packet[PKT_DEST] <= 0x0B && gotRev == false && gettingRevID == 0xFF) {
|
||||
// Try replying to get panel rev
|
||||
gettingRevID = packet[PKT_DEST];
|
||||
caculate_ack_packet(rs_fd, packet, ALLBUTTON);
|
||||
return false; // We don't want to store this ID since we use it for getting REV and is won't go back to probe when AqualinkD starts
|
||||
}
|
||||
} else if (packet[PKT_DEST] == gettingRevID) {
|
||||
if ( packet[PKT_CMD] == CMD_MSG ) {
|
||||
if ( rsm_strnstr((char *)&packet[5], " REV", AQ_MSGLEN) != NULL ) {
|
||||
// We need to get the rev to cater for panel rev I & k (maybe others) that send AqualinkTouch probe messages
|
||||
// then they don't support that protocol.
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Got %15s from ID 0x%02hhx\n",(char *)&packet[5],packet[PKT_DEST]);
|
||||
gotRev = true;
|
||||
gettingRevID = 0xFF;
|
||||
setPanelInformationFromPanelMsg(&_aqualink_data, (char *)&packet[5], PANEL_CPU | PANEL_REV, SIM_NONE);
|
||||
if ( !isMASKSET(_aqualink_data.panel_support_options, RSP_SUP_AQLT)) {
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Ignoring AqualinkTouch probes due to panel rev\n");
|
||||
ignore_AqualinkTouch = true;
|
||||
if ( _aqconfig_.extended_device_id >= 0x30 && _aqconfig_.extended_device_id <= 0x33 ) {
|
||||
_aqconfig_.extended_device_id = 0x00;
|
||||
_aqconfig_.enable_iaqualink = false;
|
||||
_aqconfig_.read_RS485_devmask &= ~ READ_RS485_IAQUALNK;
|
||||
//firstprobe = 0x00;
|
||||
foundIDs--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
caculate_ack_packet(rs_fd, packet, ALLBUTTON);
|
||||
}
|
||||
|
||||
if (lastID != 0x00 && packet[PKT_DEST] == DEV_MASTER ) { // Can't use got a reply to the late probe.
|
||||
|
@ -803,7 +839,7 @@ bool auto_configure(unsigned char* packet) {
|
|||
_aqconfig_.extended_device_id_programming = true;
|
||||
// Don't increase foundIDs as we prefer not to use this one.
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Found valid unused extended ID 0x%02hhx\n",lastID);
|
||||
} else if ( (lastID >= 0x30 && lastID <= 0x33) &&
|
||||
} else if ( (lastID >= 0x30 && lastID <= 0x33) && ignore_AqualinkTouch == false &&
|
||||
(_aqconfig_.extended_device_id < 0x30 || _aqconfig_.extended_device_id > 0x33)) { //Overide is it's been set to Touch or not set.
|
||||
_aqconfig_.extended_device_id = lastID;
|
||||
_aqconfig_.extended_device_id_programming = true;
|
||||
|
@ -816,9 +852,17 @@ bool auto_configure(unsigned char* packet) {
|
|||
}
|
||||
// Now reset ID
|
||||
lastID = 0x00;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( foundIDs >= 3 || (packet[PKT_DEST] == firstprobe && packet[PKT_CMD] == CMD_PROBE) ) {
|
||||
if (packet[PKT_DEST] == firstprobe && packet[PKT_CMD] == CMD_PROBE) {
|
||||
loopsCompleted++;
|
||||
//LOG(AQUA_LOG,LOG_DEBUG, "***** Loop %d *****\n",loopsCompleted);
|
||||
}
|
||||
|
||||
//if ( foundIDs >= 3 || (packet[PKT_DEST] == firstprobe && packet[PKT_CMD] == CMD_PROBE) ) {
|
||||
if ( (foundIDs >= 3 && gotRev) || loopsCompleted == 2 ) {
|
||||
// We should have seen one complete probe cycle my now.
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Finished Autoconfigure using device_id=0x%02hhx rssa_device_id=0x%02hhx extended_device_id=0x%02hhx (%s iAqualink2/3)\n",
|
||||
_aqconfig_.device_id,_aqconfig_.rssa_device_id,_aqconfig_.extended_device_id, _aqconfig_.enable_iaqualink?"Enable":"Disable");
|
||||
|
@ -1003,7 +1047,7 @@ void main_loop()
|
|||
}
|
||||
*/
|
||||
if (is_valid_port(rs_fd)) {
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Listening to Aqualink RS8 on serial port: %s\n", _aqconfig_.serial_port);
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Listening to Aqualink %s on serial port: %s\n", getPanelString(), _aqconfig_.serial_port);
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Error Aqualink bad serial port: %s\n", _aqconfig_.serial_port);
|
||||
AddAQDstatusMask(ERROR_SERIAL);
|
||||
|
@ -1072,6 +1116,7 @@ void main_loop()
|
|||
stopPacketLogger();
|
||||
close_serial_port(rs_fd);
|
||||
stop_net_services();
|
||||
stop_sensors_thread();
|
||||
return;
|
||||
}
|
||||
/*
|
||||
|
@ -1084,7 +1129,7 @@ void main_loop()
|
|||
|
||||
if (packet_length > 0 && auto_config_complete == false) {
|
||||
blank_read = 0;
|
||||
auto_config_complete = auto_configure(packet_buffer);
|
||||
auto_config_complete = auto_configure(packet_buffer, rs_fd);
|
||||
AddAQDstatusMask(AUTOCONFIGURE_ID);
|
||||
_aqualink_data.updated = true;
|
||||
if (auto_config_complete) {
|
||||
|
@ -1171,6 +1216,7 @@ void main_loop()
|
|||
stopPacketLogger();
|
||||
close_serial_port(rs_fd);
|
||||
stop_net_services();
|
||||
stop_sensors_thread();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1216,6 +1262,12 @@ void main_loop()
|
|||
_aqconfig_.extended_device_id_programming = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( _aqualink_data.num_sensors > 0){
|
||||
start_sensors_thread(&_aqualink_data);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* This is the main loop
|
||||
|
@ -1232,7 +1284,7 @@ void main_loop()
|
|||
blank_read_reconnect = blank_read_reconnect * 50;
|
||||
#endif
|
||||
|
||||
int loopnum=0;
|
||||
//int loopnum=0;
|
||||
blank_read = 0;
|
||||
// OK, Now go into infinate loop
|
||||
while (_keepRunning == true)
|
||||
|
@ -1441,6 +1493,7 @@ void main_loop()
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if ( _aqualink_data.num_sensors > 0 && ++loopnum >= 200 ) {
|
||||
loopnum=0;
|
||||
for (int i=0; i < _aqualink_data.num_sensors; i++) {
|
||||
|
@ -1448,7 +1501,8 @@ void main_loop()
|
|||
_aqualink_data.updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//tcdrain(rs_fd); // Make sure buffer has been sent.
|
||||
//delay(10);
|
||||
|
@ -1459,6 +1513,7 @@ void main_loop()
|
|||
|
||||
if (! _restart) { // Stop network if we are not restarting
|
||||
stop_net_services();
|
||||
stop_sensors_thread();
|
||||
}
|
||||
|
||||
// Reset and close the port.
|
||||
|
|
|
@ -52,7 +52,7 @@ char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] =
|
|||
"Violet",
|
||||
"Slow Splash",
|
||||
"Fast Splash",
|
||||
"USA",
|
||||
"USA", // America the Beautiful <- Think this is Infinite Water Colors. Need to check what version that changed.
|
||||
"Fat Tuesday",
|
||||
"Disco Tech"
|
||||
},
|
||||
|
@ -116,7 +116,24 @@ char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] =
|
|||
"Mardi Gras", // 0x50 (home panel) // 0x4b (simulator)
|
||||
"Cool Cabaret" // 0x51 (home panel) // 0x4c
|
||||
},
|
||||
{/*Spare 1*/},
|
||||
{// Jandy Infinate Water Colors (RS485)
|
||||
"Off",
|
||||
"Alpine White",
|
||||
"Sky Blue",
|
||||
"Cobalt Blue",
|
||||
"Caribbean Blue",
|
||||
"Spring Green",
|
||||
"Emerald Green",
|
||||
"Emerald Rose",
|
||||
"Ruby Red", // Added over Jandy LED
|
||||
"Magenta",
|
||||
"Violet",
|
||||
"Slow Splash",
|
||||
"Fast Splash",
|
||||
"America The Beautiful", // America the Beautiful <- Think this is Infinite Water Colors. Need to check what version that changed.
|
||||
"Fat Tuesday",
|
||||
"Disco Tech"
|
||||
},
|
||||
{/*Spare 2*/},
|
||||
{/*Spare 3*/},
|
||||
{ // Dimmer // From manual this is 0 for off, 128+<value%> so 153 = 25% = 0x99
|
||||
|
@ -309,7 +326,7 @@ int build_color_lights_js(struct aqualinkdata *aqdata, char* buffer, int size)
|
|||
length += sprintf(buffer+length, "var _light_program = [];\n");
|
||||
|
||||
if ( _color_light_options[0][1] == NULL || strcmp(_color_light_options[0][1], "1") == 0) {
|
||||
length += sprintf(buffer+length, "_light_program[0] = light_program;\n");
|
||||
length += sprintf(buffer+length, "_light_program[0] = [];\n");
|
||||
i=1;
|
||||
} else {
|
||||
i=0;
|
||||
|
|
281
source/config.c
281
source/config.c
|
@ -23,6 +23,8 @@
|
|||
|
||||
#include <libgen.h>
|
||||
|
||||
//#include <locale.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
//#include <sys/socket.h>
|
||||
//#include <sys/time.h>
|
||||
|
@ -34,6 +36,8 @@
|
|||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
#include <regex.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
#define CONFIG_C
|
||||
#include "config.h"
|
||||
|
@ -55,7 +59,9 @@
|
|||
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);
|
||||
bool populateLightData(struct aqualinkdata *aqdata, char *lightcfg ,aqkey *button, char *value);
|
||||
pump_detail *getPumpFromButtonID(struct aqualinkdata *aqdata, aqkey *button);
|
||||
clight_detail *getLightFromButtonID(struct aqualinkdata *aqdata, aqkey *button);
|
||||
aqkey *getVirtualButton(struct aqualinkdata *aqdata, int num);
|
||||
struct aqualinkdata *_aqdata = NULL;
|
||||
|
||||
|
@ -162,6 +168,7 @@ const int _dcfg_light_programming_mode = 0;
|
|||
const int _dcfg_light_programming_initial_on = 15;
|
||||
const int _dcfg_light_programming_initial_off = 12;
|
||||
|
||||
const int _dcfg_sensor_poll_time = 300;
|
||||
|
||||
void init_parameters (struct aqconfig * parms)
|
||||
{
|
||||
|
@ -203,6 +210,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_READONLY;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
|
||||
_cfgParams[_numCfgParams].default_value = NULL;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -210,6 +218,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].value_type = CFG_SPECIAL;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_panel_type;
|
||||
_cfgParams[_numCfgParams].default_value = NULL;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.device_id;
|
||||
|
@ -217,6 +226,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_device_id;
|
||||
_cfgParams[_numCfgParams].valid_values = CFG_V_device_id;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_findIDHex;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.rssa_device_id;
|
||||
|
@ -262,12 +272,15 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].value_type = CFG_STRING;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_mqtt_server;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)_dcfg_null;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_user;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_STRING;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_mqtt_user;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)NULL;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_passwd;
|
||||
|
@ -275,18 +288,21 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_mqtt_passwd;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_PASSWD_MASK;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)NULL;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_aq_topic;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_STRING;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_mqtt_aq_topic;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)_dcfg_mqtt_aq_tp;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_hass_discover_topic;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_STRING;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_mqtt_hass_discover_topic;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)_dcfg_mqtt_ha_discover;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -313,6 +329,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_mqtt_dz_sub_topic;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
_cfgParams[_numCfgParams].default_value = NULL;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -321,6 +338,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_mqtt_dz_pub_topic;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
_cfgParams[_numCfgParams].default_value = NULL;
|
||||
/*
|
||||
_numCfgParams++;
|
||||
|
@ -336,6 +354,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_dzidx_air_temp;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&unknownInt;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -344,6 +363,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_dzidx_pool_water_temp;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&unknownInt;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -352,6 +372,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_dzidx_spa_water_temp;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&unknownInt;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -360,6 +381,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_dzidx_swg_percent;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&unknownInt;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -368,6 +390,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_dzidx_swg_ppm;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&unknownInt;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -376,6 +399,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_dzidx_swg_status;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&unknownInt;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -384,6 +408,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_convert_dz_temp;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&unknownInt;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -513,6 +538,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_event_check_usecron;
|
||||
_cfgParams[_numCfgParams].mask = AQS_USE_CRON_PUMP_TIME;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_false;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.schedule_event_mask;
|
||||
|
@ -520,6 +546,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_event_check_poweron;
|
||||
_cfgParams[_numCfgParams].mask = AQS_POWER_ON;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_false;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.schedule_event_mask;
|
||||
|
@ -527,6 +554,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_event_check_freezeprotectoff;
|
||||
_cfgParams[_numCfgParams].mask = AQS_FRZ_PROTECT_OFF;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_false;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.schedule_event_mask;
|
||||
|
@ -534,24 +562,28 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_event_check_boostoff;
|
||||
_cfgParams[_numCfgParams].mask = AQS_BOOST_OFF;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_false;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.sched_chk_pumpon_hour;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_INT;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_event_check_pumpon_hour;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_zero;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.sched_chk_pumpoff_hour;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_INT;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_event_check_pumpoff_hour;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_zero;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.sched_chk_booston_device;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_STRING;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_event_check_booston_device;
|
||||
_cfgParams[_numCfgParams].default_value = NULL;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.ftdi_low_latency;
|
||||
|
@ -610,6 +642,30 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_true;
|
||||
#endif
|
||||
|
||||
// Sensor poll time
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.sensor_poll_time;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_INT;
|
||||
_cfgParams[_numCfgParams].name = "sensor_poll_time";
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_sensor_poll_time;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
|
||||
|
||||
// Optional values to store in config
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.save_debug_log_masks;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_BOOL;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_save_debug_log_masks;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_READONLY;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_false;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.save_light_programming_value;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_BOOL;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_save_light_programming_value;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_READONLY;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_false;
|
||||
|
||||
//#endif
|
||||
|
||||
// Default to daemonize
|
||||
|
@ -947,7 +1003,7 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
|
|||
}
|
||||
|
||||
if (strlen(cleanwhitespace(value)) <= 0) {
|
||||
LOG(AQUA_LOG,LOG_NOTICE,"Set configuration option `%s` to default since value is blank\n",_cfgParams[i].name );
|
||||
LOG(AQUA_LOG,LOG_INFO,"Set configuration option `%s` to default since value is blank\n",_cfgParams[i].name );
|
||||
set_cfg_parm_to_default(&_cfgParams[i]);
|
||||
return true;
|
||||
}
|
||||
|
@ -1125,9 +1181,8 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
char *name = cleanalloc(value);
|
||||
int len = strlen(name);
|
||||
if (len > 0) {
|
||||
if ( strncmp(name+len-7, " - Show", 7) == 0 ) {
|
||||
if ( strncasecmp(name+len-7, " - show", 7) == 0 ) {
|
||||
name[len-7] = '\0';
|
||||
//printf("Value '%s' index %d is show\n",name,num);
|
||||
set_aqualinkd_light_mode_name(name,num,true);
|
||||
} else {
|
||||
set_aqualinkd_light_mode_name(name,num,false);
|
||||
|
@ -1159,6 +1214,20 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
aqdata->aqbuttons[num].label = cleanalloc(value);
|
||||
rtn=true;
|
||||
#endif
|
||||
/*
|
||||
} else if (strncasecmp(param + 9, "_lightModeCacheValue", 20) == 0) {
|
||||
if (isPLIGHT(aqdata->aqbuttons[num].special_mask)) {
|
||||
if ( ((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lightType == LC_PROGRAMABLE ) {
|
||||
int val = strtoul(value, NULL, 10);
|
||||
((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lastValue = val;
|
||||
printf("**** Set lastValue=%d for %s\n",val,aqdata->aqbuttons[num].label);
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, '%s' is invalied for light type '%s'\n",value,((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lightType);
|
||||
}
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, Couldn't find light for '%s'\n",value);
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 9, "_lightMode", 10) == 0) {
|
||||
int type = strtoul(value, NULL, 10);
|
||||
|
||||
|
@ -1186,6 +1255,28 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
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, "_light", 6) == 0) {
|
||||
|
||||
if ( ! populateLightData(aqdata, param + 10, &aqdata->aqbuttons[num], value) )
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, %s=%s Ignored!",param,value);
|
||||
}
|
||||
|
||||
rtn=true;
|
||||
|
||||
/*
|
||||
} else if (strncasecmp(param + 9, "_lightModeCacheValue", 20) == 0) {
|
||||
int val = strtoul(value, NULL, 20);
|
||||
if (isPLIGHT(aqdata->aqbuttons[num].special_mask)) {
|
||||
if ( ((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lightType == LC_PROGRAMABLE ) {
|
||||
((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lastValue = val;
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, '%s' is invalied for light type '%s'\n",value,((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lightType);
|
||||
}
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, Couldn't find light for '%s'\n",value);
|
||||
}*/
|
||||
} else if (strncasecmp(param + 9, "_pump", 5) == 0) {
|
||||
|
||||
if ( ! populatePumpData(aqdata, param + 10, &aqdata->aqbuttons[num], value) )
|
||||
|
@ -1197,7 +1288,7 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
}
|
||||
//#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.
|
||||
|
@ -1212,6 +1303,7 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
} else {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Error with '%s', total buttons=%d, config has %d already, ignoring!\n",param, TOTAL_BUTTONS, aqdata->total_buttons);
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 17, "_altLabel", 9) == 0) {
|
||||
char *label = cleanalloc(value);
|
||||
aqkey *button = getVirtualButton(aqdata, num);
|
||||
|
@ -1220,6 +1312,7 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
} else {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Error with '%s', total buttons=%d, config has %d already, ignoring!\n",param, TOTAL_BUTTONS, aqdata->total_buttons);
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 17, "_pump", 5) == 0) {
|
||||
aqkey *vbutton = getVirtualButton(aqdata, num);
|
||||
if (vbutton != NULL) {
|
||||
|
@ -1231,6 +1324,18 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, could not find vitrual button for `%s`",param);
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 17, "_light", 6) == 0) {
|
||||
aqkey *vbutton = getVirtualButton(aqdata, num);
|
||||
if (vbutton != NULL) {
|
||||
if ( ! populateLightData(aqdata, param + 18, vbutton, value) )
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, %s=%s Ignored!",param,value);
|
||||
}
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, could not find vitrual button for `%s`",param);
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 17, "_onetouchID", 11) == 0) {
|
||||
aqkey *vbutton = getVirtualButton(aqdata, num);
|
||||
if (vbutton != NULL) {
|
||||
|
@ -1268,6 +1373,7 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, could not find vitrual button for `%s`",param);
|
||||
}
|
||||
rtn=true;
|
||||
}
|
||||
} else if (strncasecmp(param, "sensor_", 7) == 0) {
|
||||
int num = strtoul(param + 7, NULL, 10) - 1;
|
||||
|
@ -1277,6 +1383,7 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
if ( num + 1 > aqdata->num_sensors ) {
|
||||
aqdata->num_sensors = num + 1;
|
||||
}
|
||||
sprintf(aqdata->sensors[num].ID, "Aux_S%d", num+1);
|
||||
if (strncasecmp(param + 9, "_label", 6) == 0) {
|
||||
aqdata->sensors[num].label = ncleanalloc(value, AQ_MSGLEN);
|
||||
rtn=true;
|
||||
|
@ -1290,8 +1397,14 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
LOG(AQUA_LOG,LOG_ERR, "Config error, couldn't understand `%s` from `%s`, using `1.0`!",value,param);
|
||||
aqdata->sensors[num].factor = 1;
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 9, "_regex", 5) == 0) {
|
||||
aqdata->sensors[num].regex = cleanalloc(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 9, "_uom", 3) == 0) {
|
||||
aqdata->sensors[num].uom = cleanalloc(value);
|
||||
rtn=true;
|
||||
}
|
||||
rtn=true;
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, blank value for `%s`\n",param);
|
||||
rtn = false;
|
||||
|
@ -1367,11 +1480,46 @@ bool populatePumpData(struct aqualinkdata *aqdata, char *pumpcfg ,aqkey *button,
|
|||
pump->maxSpeed = strtoul(value, NULL, 10);
|
||||
} else if (strncasecmp(pumpcfg, "pumpMinSpeed", 12) == 0) {
|
||||
pump->minSpeed = strtoul(value, NULL, 10);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// lightcfg is pointer to lightMode, lightID, lightModeCacheValue (ie pull off button_??_ or vurtual_button_??_)
|
||||
bool populateLightData(struct aqualinkdata *aqdata, char *lightcfg ,aqkey *button, char *value)
|
||||
{
|
||||
|
||||
clight_detail *light = getLightFromButtonID(aqdata, button);
|
||||
if (light == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strncasecmp(lightcfg, "lightModeCacheValue", 19) == 0) {
|
||||
light->lastValue = strtoul(value, NULL, 10);
|
||||
return true;
|
||||
} else if (strncasecmp(lightcfg, "lightMode", 9) == 0) {
|
||||
light->lightType = strtoul(value, NULL, 10);
|
||||
if (light->lightType < LC_PROGRAMABLE || light->lightType >= NUMBER_LIGHT_COLOR_TYPES) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, unknown light mode '%d'\n",light->lightType);
|
||||
}
|
||||
if ( light->lightType == LC_DIMMER2 && _aqconfig_.rssa_device_id != 0x48 ) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, button '%s' has light mode '%d' set. This only supported when 'rssa_device_id' is enabled, changing to light mode '%d'\n",
|
||||
button->label, LC_DIMMER2,LC_DIMMER);
|
||||
light->lightType = LC_DIMMER;
|
||||
}
|
||||
return true;
|
||||
} else if (strncasecmp(lightcfg, "lightID", 7) == 0) {
|
||||
light->lightID = strtoul(cleanwhitespace(value), NULL, 16);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
pump_detail *getPumpFromButtonID(struct aqualinkdata *aqdata, aqkey *button)
|
||||
{
|
||||
int pi;
|
||||
|
@ -1406,6 +1554,29 @@ pump_detail *getPumpFromButtonID(struct aqualinkdata *aqdata, aqkey *button)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
clight_detail *getLightFromButtonID(struct aqualinkdata *aqdata, aqkey *button)
|
||||
{
|
||||
int li;
|
||||
|
||||
// Does it exist
|
||||
for (li=0; li < aqdata->num_lights; li++) {
|
||||
if (aqdata->lights[li].button == button) {
|
||||
return &aqdata->lights[li];
|
||||
}
|
||||
}
|
||||
|
||||
// Create new entry
|
||||
if (aqdata->num_lights < MAX_LIGHTS) {
|
||||
button->special_mask |= PROGRAM_LIGHT;
|
||||
button->special_mask_ptr = (void*)&aqdata->lights[aqdata->num_lights];
|
||||
aqdata->lights[aqdata->num_lights].button = button;
|
||||
aqdata->num_lights++;
|
||||
return &aqdata->lights[aqdata->num_lights-1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
pump_detail *getpump(struct aqualinkdata *aqdata, int button)
|
||||
{
|
||||
|
@ -1447,6 +1618,8 @@ void init_config()
|
|||
init_parameters(&_aqconfig_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//void readCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqdata, char *cfgFile)
|
||||
void read_config (struct aqualinkdata *aqdata, char *cfgFile)
|
||||
{
|
||||
|
@ -1459,6 +1632,9 @@ void read_config (struct aqualinkdata *aqdata, char *cfgFile)
|
|||
//int tokenindex = 0;
|
||||
char *b_ptr;
|
||||
|
||||
|
||||
//setlocale(LC_ALL, "en_US.UTF-8");
|
||||
|
||||
_aqconfig_.config_file = cleanalloc(cfgFile);
|
||||
|
||||
if( (fp = fopen(cfgFile, "r")) != NULL){
|
||||
|
@ -1539,7 +1715,7 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
|
||||
|
||||
// Sanity checks
|
||||
|
||||
|
||||
// If no panel has been set, use default one
|
||||
if (_aqconfig_.paneltype_mask == 0) {
|
||||
//printf("Set temp panel info Size=%d, RS=%d, combo=%d, dual=%d\n",_defaultPanel.size,_defaultPanel.rs,_defaultPanel.combo, _defaultPanel.dual);
|
||||
|
@ -1549,6 +1725,9 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
|
||||
// Make sure all sensors are fully populated
|
||||
for (i=0; i < aqdata->num_sensors; i++ ) {
|
||||
//if (aqdata->sensors[i].uom == NULL) {
|
||||
// aqdata->sensors[i].uom = cleanalloc("°C");
|
||||
//}
|
||||
if ( aqdata->sensors[i].label == NULL || aqdata->sensors[i].path == NULL ) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Invalid sensor %d, removing!\n",i+1);
|
||||
if (i == (aqdata->num_sensors-1) ) { // last sensor
|
||||
|
@ -1558,6 +1737,8 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
aqdata->sensors[j].label = aqdata->sensors[j+1].label;
|
||||
aqdata->sensors[j].path = aqdata->sensors[j+1].path;
|
||||
aqdata->sensors[j].factor = aqdata->sensors[j+1].factor;
|
||||
aqdata->sensors[j].regex = aqdata->sensors[j+1].regex;
|
||||
aqdata->sensors[j].uom = aqdata->sensors[j+1].uom;
|
||||
}
|
||||
}
|
||||
aqdata->num_sensors --;
|
||||
|
@ -1655,6 +1836,26 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
PDA Mode
|
||||
|
||||
No light mode 11
|
||||
(chiller????? )
|
||||
<probably ton of other stuff>
|
||||
*/
|
||||
|
||||
if (_aqconfig_.device_id == 0x60) {
|
||||
// Check lights.
|
||||
for (i = 0; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
if (isPLIGHT(aqdata->aqbuttons[i].special_mask)) {
|
||||
if ( ((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType == LC_DIMMER2 ) {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, PDA does not support lightmode %d setting to %d\n",LC_DIMMER2,LC_DIMMER);
|
||||
((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType = LC_DIMMER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
PDA sleep and PDA ID.
|
||||
*/
|
||||
|
@ -1680,6 +1881,28 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
|
||||
|
||||
for ( i=0; i <= _numCfgParams; i++) {
|
||||
|
||||
// Reconfigure some CFG values depending on PDA
|
||||
if ( strcmp(_cfgParams[i].name, CFG_N_device_id) == 0 ) {
|
||||
if (isPDA_PANEL) {
|
||||
_cfgParams[i].valid_values = CFG_V_device_id_PDA;
|
||||
} else {
|
||||
_cfgParams[i].valid_values = CFG_V_device_id_RS;
|
||||
}
|
||||
}
|
||||
if ( strcmp(_cfgParams[i].name, CFG_N_rssa_device_id) == 0 && isPDA_PANEL) {
|
||||
_cfgParams[i].config_mask |= CFG_GREYED_OUT;
|
||||
}
|
||||
if ( strcmp(_cfgParams[i].name, CFG_N_extended_device_id) == 0 && isPDA_PANEL) {
|
||||
_cfgParams[i].config_mask |= CFG_GREYED_OUT;
|
||||
}
|
||||
|
||||
// Don't show PDA stuff on RS panel
|
||||
if ( strcmp(_cfgParams[i].name, CFG_N_pda_sleep_mode) == 0 && !isPDA_PANEL) {
|
||||
_cfgParams[i].config_mask |= CFG_GREYED_OUT;
|
||||
_cfgParams[i].config_mask |= CFG_READONLY;
|
||||
}
|
||||
|
||||
rsm_nchar_replace(name, MAX_PRINTLEN, _cfgParams[i].name, "_", " ");
|
||||
switch (_cfgParams[i].value_type) {
|
||||
case CFG_STRING:
|
||||
|
@ -1775,14 +1998,21 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
if ( ((aqdata->aqbuttons[i].special_mask & VIRTUAL_BUTTON) == VIRTUAL_BUTTON) &&
|
||||
((aqdata->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'",aqdata->aqbuttons[i].label);
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, extended_device_id must be one of the folowing (0x30,0x31,0x32,0x33) to use virtual button : '%s'",aqdata->aqbuttons[i].label);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < aqdata->num_sensors; i++)
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config Sensor %02d = label %-15s | %s\n", i+1, aqdata->sensors[i].label,aqdata->sensors[i].path);
|
||||
//LOG(AQUA_LOG,LOG_NOTICE, "Sensor %-13s = label %-15s | %s\n", aqdata->sensors[i].ID, aqdata->sensors[i].label,aqdata->sensors[i].path);
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Sensor %-13s = label %-15s | %s | %s%s %s\n",
|
||||
aqdata->sensors[i].ID,
|
||||
aqdata->sensors[i].label,
|
||||
aqdata->sensors[i].path,
|
||||
(aqdata->sensors[i].uom==NULL?"":aqdata->sensors[i].uom),
|
||||
(aqdata->sensors[i].uom==NULL?"":" |"),
|
||||
(aqdata->sensors[i].regex==NULL?"":aqdata->sensors[i].regex));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1842,7 +2072,7 @@ int save_config_js(const char* inBuf, int inSize, char* outBuf, int outSize, str
|
|||
regmatch_t groupArray[maxGroups];
|
||||
regex_t regexCompiled;
|
||||
int rc;
|
||||
char * cursor = (char *)inBuf;;
|
||||
char * cursor = (char *)inBuf;
|
||||
unsigned int m;
|
||||
char key[64];
|
||||
char value[64];
|
||||
|
@ -1878,6 +2108,11 @@ int save_config_js(const char* inBuf, int inSize, char* outBuf, int outSize, str
|
|||
free(aqdata->sensors[i].path);
|
||||
aqdata->sensors[i].label = NULL;
|
||||
aqdata->sensors[i].path = NULL;
|
||||
// NSF When fixed the JSON & config editor, put these lines back.
|
||||
//free(aqdata->sensors[i].regex);
|
||||
//aqdata->sensors[i].regex = NULL;
|
||||
free(aqdata->sensors[i].uom);
|
||||
aqdata->sensors[i].uom = NULL;
|
||||
}
|
||||
aqdata->num_sensors=0;
|
||||
|
||||
|
@ -1918,6 +2153,8 @@ int save_config_js(const char* inBuf, int inSize, char* outBuf, int outSize, str
|
|||
snprintf(value, 64, "%.*s", (groupArray[2].rm_eo - groupArray[2].rm_so), (cursor + groupArray[2].rm_so));
|
||||
//printf("**** Pair = %s : %s \n",key,value);
|
||||
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Read json cfg Pair = %s : %s \n",key,value);
|
||||
|
||||
// If panel size changed, see if we should ignore the label
|
||||
if (strncasecmp(key, "button_", 7 ) == 0) {
|
||||
if ( strtoul(key + 7, NULL, 10) >= ignodeBtnLabelsGrater) {
|
||||
|
@ -2015,6 +2252,18 @@ bool writeCfg (struct aqualinkdata *aqdata)
|
|||
|
||||
//char fp[100];
|
||||
|
||||
// Testing shit
|
||||
if (_aqconfig_.save_debug_log_masks) {
|
||||
for (int i = 0; i < (sizeof(logmask_t) * CHAR_BIT); i++) {
|
||||
if(isDebugLogMaskSet((1 << i))) {
|
||||
fprintf(fp, "debug_log_mask=%d\n", (1 << i));
|
||||
}
|
||||
}
|
||||
fprintf(fp,"\n");
|
||||
}
|
||||
|
||||
// Loop over config parameters.
|
||||
|
||||
for ( i=0; i <= _numCfgParams; i++) {
|
||||
if (isMASK_SET(_cfgParams[i].config_mask, CFG_HIDE) ) {
|
||||
continue;
|
||||
|
@ -2075,6 +2324,17 @@ bool writeCfg (struct aqualinkdata *aqdata)
|
|||
fprintf(fp,"\nsensor_%.2d_path=%s\n",i,aqdata->sensors[i-1].path);
|
||||
fprintf(fp,"sensor_%.2d_label=%s\n",i,aqdata->sensors[i-1].label);
|
||||
fprintf(fp,"sensor_%.2d_factor=%f\n",i,aqdata->sensors[i-1].factor);
|
||||
if (aqdata->sensors[i-1].regex != NULL) {
|
||||
fprintf(fp,"sensor_%.2d_regex=%s\n",i,aqdata->sensors[i-1].regex);
|
||||
}
|
||||
if (aqdata->sensors[i-1].uom != NULL) {
|
||||
fprintf(fp,"sensor_%.2d_uom=%s\n",i,aqdata->sensors[i-1].uom);
|
||||
}
|
||||
/*
|
||||
if (aqdata->sensors[i-1].regex != NULL) {
|
||||
fprintf(fp,"sensor_%.2d_regex=%f\n",i,aqdata->sensors[i-1].regex);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
fprintf(fp,"\n");
|
||||
|
@ -2137,6 +2397,9 @@ bool writeCfg (struct aqualinkdata *aqdata)
|
|||
} else if (isPLIGHT(aqdata->aqbuttons[i].special_mask)) {
|
||||
//if (((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType > 0) {
|
||||
fprintf(fp,"%s_lightMode=%d\n", prefix, ((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType);
|
||||
if (_aqconfig_.save_light_programming_value && ((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType == LC_PROGRAMABLE ) {
|
||||
fprintf(fp,"%s_lightModeCacheValue=%d\n", prefix, ((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lastValue);
|
||||
}
|
||||
//}
|
||||
} else if ( (isVBUTTON(aqdata->aqbuttons[i].special_mask) && aqdata->aqbuttons[i].rssd_code >= IAQ_ONETOUCH_1 && aqdata->aqbuttons[i].rssd_code <= IAQ_ONETOUCH_6 ) ) {
|
||||
fprintf(fp,"%s_onetouchID=%d\n", prefix, (aqdata->aqbuttons[i].rssd_code - 15));
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#define READ_RS485_JAN_CHEM (1 << 5) // Jandy Chemical Feeder
|
||||
#define READ_RS485_IAQUALNK (1 << 6) // Read iAqualink messages
|
||||
#define READ_RS485_HEATPUMP (1 << 7) // Read HeatPump messages
|
||||
#define READ_RS485_JLIGHT (1 << 8) // Read Jandy infinite watercolor light
|
||||
|
||||
#define MAX_RSSD_LOG_FILTERS 4
|
||||
|
||||
|
@ -107,6 +108,9 @@ struct aqconfig
|
|||
bool ftdi_low_latency;
|
||||
int frame_delay;
|
||||
bool device_pre_state;
|
||||
bool save_debug_log_masks;
|
||||
bool save_light_programming_value;
|
||||
int sensor_poll_time;
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
int rs_poll_speed; // Need to remove
|
||||
bool thread_netservices; // Need to remove
|
||||
|
@ -128,6 +132,7 @@ struct aqconfig _aqconfig_;
|
|||
#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 READ_RSDEV_HPUMP ((_aqconfig_.read_RS485_devmask & READ_RS485_HEATPUMP) == READ_RS485_HEATPUMP)
|
||||
#define READ_RSDEV_JLIGHT ((_aqconfig_.read_RS485_devmask & READ_RS485_JLIGHT) == READ_RS485_JLIGHT)
|
||||
|
||||
#define isPDA_IAQT (_aqconfig_.device_id == 0x33)
|
||||
//#define isPDA ((_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA)
|
||||
|
@ -192,6 +197,8 @@ typedef enum cfg_value_type{
|
|||
//#define CFG_READONLY (1 << 4) // Don't show in UI, but do write to CFG file.
|
||||
#define CFG_PASSWD_MASK (1 << 4) // Mask password with *****
|
||||
#define CFG_FORCE_RESTART (1 << 5) // Force aqualinkd to restart
|
||||
#define CFG_ALLOW_BLANK (1 << 6) // Allow blank entry
|
||||
#define CFG_GREYED_OUT (1 << 7) // Greyout in UI, show but not editable
|
||||
//#define CFG_ (1 << 3)
|
||||
|
||||
// Text to show when CFG_PASSWD_MASK is set
|
||||
|
@ -222,152 +229,98 @@ int _numCfgParams;
|
|||
// Below are missed
|
||||
//RSSD_LOG_filter
|
||||
//debug_log_mask
|
||||
|
||||
#define CFG_V_BOOL "[\"Yes\", \"No\"]"
|
||||
|
||||
#define CFG_N_serial_port "serial_port"
|
||||
#define CFG_C_serial_port 11
|
||||
#define CFG_N_log_level "log_level"
|
||||
#define CFG_V_log_level "[\"DEBUG\", \"INFO\", \"NOTICE\", \"WARNING\", \"ERROR\"]"
|
||||
#define CFG_C_log_level 9
|
||||
#define CFG_N_socket_port "socket_port" // Change to Web_socket
|
||||
#define CFG_C_socket_port 11
|
||||
#define CFG_V_log_level "[\"DEBUG_SERIAL\", \"DEBUG\", \"INFO\", \"NOTICE\", \"WARNING\", \"ERROR\"]"
|
||||
#define CFG_N_socket_port "socket_port"
|
||||
#define CFG_N_web_directory "web_directory"
|
||||
#define CFG_C_web_directory 13
|
||||
#define CFG_N_device_id "device_id"
|
||||
#define CFG_V_device_id "[\"0x0a\", \"0x0b\", \"0x09\", \"0x08\", \"0x60\", \"0xFF\"]"
|
||||
#define CFG_C_device_id 9
|
||||
|
||||
#define CFG_V_device_id "[\"0x0a\", \"0x0b\", \"0x09\", \"0x08\", \"0x60\", \"0x33\", \"0xFF\"]"
|
||||
#define CFG_V_device_id_RS "[\"0x0a\", \"0x0b\", \"0x09\", \"0x08\", \"0xFF\"]"
|
||||
#define CFG_V_device_id_PDA "[\"0x60\", \"0x33\", \"0xFF\"]"
|
||||
|
||||
#define CFG_N_rssa_device_id "rssa_device_id"
|
||||
#define CFG_V_rssa_device_id "[\"0x00\", \"0x48\"]"
|
||||
#define CFG_C_rssa_device_id 14
|
||||
|
||||
#define CFG_N_RSSD_LOG_filter "RSSD_LOG_filter"
|
||||
#define CFG_C_RSSD_LOG_filter 15
|
||||
|
||||
#define CFG_N_panel_type "panel_type"
|
||||
#define CFG_C_panel_type 10
|
||||
#define CFG_N_extended_device_id "extended_device_id"
|
||||
#define CFG_V_extended_device_id "[\"0x00\", \"0x30\", \"0x31\", \"0x32\", \"0x33\", \"0x40\", \"0x41\", \"0x42\", \"0x43\"]"
|
||||
#define CFG_C_extended_device_id 18
|
||||
|
||||
#define CFG_N_sync_panel_time "sync_panel_time"
|
||||
#define CFG_C_sync_panel_time 15
|
||||
|
||||
//#define CFG_N_extended_device_id2 "extended_device_id2"
|
||||
//#define CFG_C_extended_device_id2 20
|
||||
#define CFG_N_extended_device_id_programming "extended_device_id_programming"
|
||||
#define CFG_C_extended_device_id_programming 30
|
||||
#define CFG_N_enable_iaqualink "enable_iaqualink"
|
||||
#define CFG_C_enable_iaqualink 16
|
||||
#define CFG_N_log_file "log_file"
|
||||
#define CFG_C_log_file 8
|
||||
#define CFG_N_mqtt_aq_topic "mqtt_aq_topic"
|
||||
#define CFG_C_mqtt_aq_topic 13
|
||||
#define CFG_N_mqtt_server "mqtt_address"
|
||||
#define CFG_C_mqtt_server 12
|
||||
#define CFG_N_mqtt_user "mqtt_user"
|
||||
#define CFG_C_mqtt_user 9
|
||||
#define CFG_N_mqtt_passwd "mqtt_passwd"
|
||||
#define CFG_C_mqtt_passwd 11
|
||||
#define CFG_N_mqtt_hass_discover_topic "mqtt_ha_discover_topic"
|
||||
#define CFG_C_mqtt_hass_discover_topic 24
|
||||
#define CFG_N_mqtt_hass_discover_use_mac "mqtt_ha_discover_use_mac"
|
||||
#define CFG_C_mqtt_hass_discover_use_mac 27
|
||||
#define CFG_N_mqtt_timed_update "mqtt_timed_update"
|
||||
#define CFG_C_mqtt_timed_update 17
|
||||
//#define CFG_N_mqtt_ID "mqtt_ID"
|
||||
//#define CFG_C_mqtt_ID 7
|
||||
#define CFG_N_mqtt_dz_sub_topic "mqtt_dz_sub_topic"
|
||||
#define CFG_C_mqtt_dz_sub_topic 17
|
||||
#define CFG_N_mqtt_dz_pub_topic "mqtt_dz_pub_topic"
|
||||
#define CFG_C_mqtt_dz_pub_topic 17
|
||||
#define CFG_N_dzidx_air_temp "dzidx_air_temp"
|
||||
#define CFG_C_dzidx_air_temp 14
|
||||
#define CFG_N_dzidx_pool_water_temp "dzidx_pool_water_temp"
|
||||
#define CFG_C_dzidx_pool_water_temp 21
|
||||
#define CFG_N_dzidx_spa_water_temp "dzidx_spa_water_temp"
|
||||
#define CFG_C_dzidx_spa_water_temp 20
|
||||
#define CFG_N_dzidx_swg_percent "dzidx_SWG_percent"
|
||||
#define CFG_C_dzidx_swg_percent 17
|
||||
#define CFG_N_dzidx_swg_ppm "dzidx_SWG_PPM"
|
||||
#define CFG_C_dzidx_swg_ppm 13
|
||||
#define CFG_N_dzidx_swg_status "dzidx_SWG_Status"
|
||||
#define CFG_C_dzidx_swg_status 16
|
||||
#define CFG_N_light_programming_mode "light_programming_mode"
|
||||
#define CFG_C_light_programming_mode 22
|
||||
#define CFG_N_light_programming_initial_on "light_programming_initial_on"
|
||||
#define CFG_C_light_programming_initial_on 28
|
||||
#define CFG_N_light_programming_initial_off "light_programming_initial_off"
|
||||
#define CFG_C_light_programming_initial_off 29
|
||||
#define CFG_N_override_freeze_protect "override_freeze_protect"
|
||||
#define CFG_C_override_freeze_protect 23
|
||||
#define CFG_N_pda_sleep_mode "pda_sleep_mode"
|
||||
#define CFG_C_pda_sleep_mode 14
|
||||
#define CFG_N_convert_mqtt_temp "mqtt_convert_temp_to_c"
|
||||
#define CFG_C_convert_mqtt_temp 22
|
||||
#define CFG_N_convert_dz_temp "dz_convert_temp_to_c"
|
||||
#define CFG_C_convert_dz_temp 20
|
||||
#define CFG_N_report_zero_spa_temp "report_zero_spa_temp"
|
||||
#define CFG_C_report_zero_spa_temp 20
|
||||
#define CFG_N_report_zero_pool_temp "report_zero_pool_temp"
|
||||
#define CFG_C_report_zero_pool_temp 21
|
||||
#define CFG_N_read_RS485_devmask "read_RS485_devmask"
|
||||
#define CFG_C_read_RS485_devmask 18
|
||||
#define CFG_N_use_panel_aux_labels "use_panel_aux_labels"
|
||||
#define CFG_C_use_panel_aux_labels 20
|
||||
#define CFG_N_force_swg "force_swg"
|
||||
#define CFG_C_force_swg 9
|
||||
#define CFG_N_force_ps_setpoints "force_ps_setpoints"
|
||||
#define CFG_C_force_ps_setpoints 18
|
||||
#define CFG_N_force_frzprotect_setpoints "force_frzprotect_setpoints"
|
||||
#define CFG_C_force_frzprotect_setpoints 26
|
||||
#define CFG_N_force_chem_feeder "force_chem_feeder"
|
||||
#define CFG_C_force_chem_feeder 17
|
||||
#define CFG_N_force_chiller "force_chiller"
|
||||
#define CFG_N_display_warnings_web "display_warnings_web"
|
||||
#define CFG_C_display_warnings_web 20
|
||||
#define CFG_N_log_protocol_packets "log_protocol_packets"
|
||||
#define CFG_C_log_protocol_packets 20
|
||||
#define CFG_N_device_pre_state "device_pre_state"
|
||||
#define CFG_C_device_pre_state 16
|
||||
|
||||
#define CFG_N_read_RS485_swg "read_RS485_swg"
|
||||
#define CFG_C_read_RS485_swg 14
|
||||
#define CFG_N_read_RS485_ePump "read_RS485_ePump"
|
||||
#define CFG_C_read_RS485_ePump 16
|
||||
#define CFG_N_read_RS485_vsfPump "read_RS485_vsfPump"
|
||||
#define CFG_C_read_RS485_vsfPump 18
|
||||
#define CFG_N_read_RS485_JXi "read_RS485_JXi"
|
||||
#define CFG_C_read_RS485_JXi 14
|
||||
#define CFG_N_read_RS485_LX "read_RS485_LX"
|
||||
#define CFG_C_read_RS485_LX 13
|
||||
#define CFG_N_read_RS485_Chem "read_RS485_Chem"
|
||||
#define CFG_C_read_RS485_Chem 15
|
||||
#define CFG_N_read_RS485_iAqualink "read_RS485_iAqualink"
|
||||
#define CFG_C_read_RS485_iAqualink 20
|
||||
#define CFG_N_read_RS485_HeatPump "read_RS485_HeatPump"
|
||||
|
||||
|
||||
#define CFG_N_enable_scheduler "enable_scheduler"
|
||||
#define CFG_C_enable_scheduler 16
|
||||
|
||||
#define CFG_N_event_check_poweron "event_poweron_check_pump"
|
||||
#define CFG_C_event_check_poweron 24
|
||||
#define CFG_N_event_check_freezeprotectoff "event_freezeprotectoff_check_pump"
|
||||
#define CFG_C_event_check_freezeprotectoff 33
|
||||
#define CFG_N_event_check_boostoff "event_boostoff_check_pump"
|
||||
#define CFG_C_event_check_boostoff 25
|
||||
#define CFG_N_event_check_pumpon_hour "event_check_pumpon_hour"
|
||||
#define CFG_C_event_check_pumpon_hour 23
|
||||
#define CFG_N_event_check_pumpoff_hour "event_check_pumpoff_hour"
|
||||
#define CFG_C_event_check_pumpoff_hour 24
|
||||
#define CFG_N_event_check_usecron "event_check_use_scheduler_times"
|
||||
#define CFG_C_event_check_usecron 32
|
||||
|
||||
#define CFG_N_event_check_booston_device "event_booston_check_device"
|
||||
|
||||
#define CFG_N_ftdi_low_latency "ftdi_low_latency"
|
||||
#define CFG_C_ftdi_low_latency 16
|
||||
#define CFG_N_rs485_frame_delay "rs485_frame_delay"
|
||||
#define CFG_C_rs485_frame_delay 17
|
||||
|
||||
#endif
|
||||
#define CFG_N_save_debug_log_masks "save_debug_log_masks"
|
||||
#define CFG_N_save_light_programming_value "save_light_programming_value"
|
||||
|
||||
|
||||
//#define CFG_V_UOM "[\"°C\", \"°F\", \"K\", \"Hz\", \"GHz\", \"Pa\", \"0x41\", \"hPa\", \"bar\", \"mbar\", \"inHg\", \"psi\", \"L\", \"mL\", \"m³\", \"ft³\", \"fl. oz.\", \"m³/h\", \"ft³/m\"]"
|
||||
|
||||
#endif
|
|
@ -42,7 +42,31 @@ typedef enum heatpumpstate{
|
|||
HP_UNKNOWN
|
||||
} heatpumpstate;
|
||||
|
||||
void updateHeatPumpLed(heatpumpstate state, aqledstate ledstate, struct aqualinkdata *aqdata, bool fromMessage);
|
||||
typedef enum heatpumpmsgfrom{
|
||||
HP_TO_PANEL,
|
||||
HP_FROM_PANEL,
|
||||
HP_DISPLAY
|
||||
} heatpumpmsgfrom;
|
||||
|
||||
void updateHeatPumpLed(heatpumpstate state, aqledstate ledstate, struct aqualinkdata *aqdata, heatpumpmsgfrom from);
|
||||
|
||||
|
||||
void printJandyDebugPacket (const char *msg, const unsigned char *packet, int packet_length)
|
||||
{
|
||||
// Only log if we are jandy debug mode and not serial debug (otherwise it'll print twice)
|
||||
if (getLogLevel(DJAN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
|
||||
char frame[1024];
|
||||
//beautifyPacket(frame, 1024, packet, packet_length, true);
|
||||
|
||||
sprintFrame(frame, 1024, packet, packet_length);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "%-4s %-6s: 0x%02hhx of type %16.16s | HEX: %s",
|
||||
(packet[PKT_DEST]==0x00?"From":"To"),
|
||||
msg,
|
||||
packet[PKT_DEST],
|
||||
get_packet_type(packet, packet_length),
|
||||
frame);
|
||||
}
|
||||
}
|
||||
|
||||
bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
|
@ -55,28 +79,39 @@ bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct
|
|||
{
|
||||
if (interestedInNextAck == DRS_SWG)
|
||||
{
|
||||
printJandyDebugPacket("SWG", packet_buffer, packet_length);
|
||||
rtn = processPacketFromSWG(packet_buffer, packet_length, aqdata, previous_packet_to);
|
||||
}
|
||||
else if (interestedInNextAck == DRS_EPUMP)
|
||||
{
|
||||
printJandyDebugPacket("EPump", packet_buffer, packet_length);
|
||||
rtn = processPacketFromJandyPump(packet_buffer, packet_length, aqdata, previous_packet_to);
|
||||
}
|
||||
else if (interestedInNextAck == DRS_JXI)
|
||||
{
|
||||
printJandyDebugPacket("JXi", packet_buffer, packet_length);
|
||||
rtn = processPacketFromJandyJXiHeater(packet_buffer, packet_length, aqdata, previous_packet_to);
|
||||
}
|
||||
else if (interestedInNextAck == DRS_LX)
|
||||
{
|
||||
printJandyDebugPacket("LX", packet_buffer, packet_length);
|
||||
rtn = processPacketFromJandyLXHeater(packet_buffer, packet_length, aqdata, previous_packet_to);
|
||||
}
|
||||
else if (interestedInNextAck == DRS_CHEM)
|
||||
{
|
||||
printJandyDebugPacket("CHEM", packet_buffer, packet_length);
|
||||
rtn = processPacketFromJandyChemFeeder(packet_buffer, packet_length, aqdata, previous_packet_to);
|
||||
}
|
||||
else if (interestedInNextAck == DRS_HEATPUMP)
|
||||
{
|
||||
printJandyDebugPacket("HPump", packet_buffer, packet_length);
|
||||
rtn = processPacketFromHeatPump(packet_buffer, packet_length, aqdata, previous_packet_to);
|
||||
}
|
||||
else if (interestedInNextAck == DRS_JLIGHT)
|
||||
{
|
||||
printJandyDebugPacket("JLight", packet_buffer, packet_length);
|
||||
rtn = processPacketFromJandyLight(packet_buffer, packet_length, aqdata, previous_packet_to);
|
||||
}
|
||||
interestedInNextAck = DRS_NONE;
|
||||
previous_packet_to = NUL;
|
||||
}
|
||||
|
@ -97,6 +132,7 @@ 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;
|
||||
printJandyDebugPacket("SWG", packet_buffer, packet_length);
|
||||
rtn = processPacketToSWG(packet_buffer, packet_length, aqdata/*, _aqconfig_.swg_zero_ignore*/);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
|
@ -104,24 +140,28 @@ bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct
|
|||
|| (packet_buffer[PKT_DEST] >= JANDY_DEC_PUMP2_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_PUMP2_MAX) ) )
|
||||
{
|
||||
interestedInNextAck = DRS_EPUMP;
|
||||
printJandyDebugPacket("EPump", packet_buffer, packet_length);
|
||||
rtn = processPacketToJandyPump(packet_buffer, packet_length, aqdata);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
else if (READ_RSDEV_JXI && packet_buffer[PKT_DEST] >= JANDY_DEC_JXI_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_JXI_MAX)
|
||||
{
|
||||
interestedInNextAck = DRS_JXI;
|
||||
printJandyDebugPacket("JXi", packet_buffer, packet_length);
|
||||
rtn = processPacketToJandyJXiHeater(packet_buffer, packet_length, aqdata);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
else if (READ_RSDEV_LX && packet_buffer[PKT_DEST] >= JANDY_DEC_LX_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_LX_MAX)
|
||||
{
|
||||
interestedInNextAck = DRS_LX;
|
||||
printJandyDebugPacket("LX", packet_buffer, packet_length);
|
||||
rtn = processPacketToJandyLXHeater(packet_buffer, packet_length, aqdata);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
else if (READ_RSDEV_CHEM && packet_buffer[PKT_DEST] >= JANDY_DEC_CHEM_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_CHEM_MAX)
|
||||
{
|
||||
interestedInNextAck = DRS_CHEM;
|
||||
printJandyDebugPacket("CHEM", packet_buffer, packet_length);
|
||||
rtn = processPacketToJandyChemFeeder(packet_buffer, packet_length, aqdata);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
|
@ -133,9 +173,17 @@ bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct
|
|||
else if (READ_RSDEV_HPUMP && packet_buffer[PKT_DEST] >= JANDY_DEV_HPUMP_MIN && packet_buffer[PKT_DEST] <= JANDY_DEV_HPUMP_MAX)
|
||||
{
|
||||
interestedInNextAck = DRS_HEATPUMP;
|
||||
printJandyDebugPacket("HPump", packet_buffer, packet_length);
|
||||
rtn = processPacketToHeatPump(packet_buffer, packet_length, aqdata);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
else if (READ_RSDEV_JLIGHT && packet_buffer[PKT_DEST] >= JANDY_DEV_JLIGHT_MIN && packet_buffer[PKT_DEST] <= JANDY_DEV_JLIGHT_MAX)
|
||||
{
|
||||
interestedInNextAck = DRS_JLIGHT;
|
||||
printJandyDebugPacket("JLight", packet_buffer, packet_length);
|
||||
rtn = processPacketToJandyLight(packet_buffer, packet_length, aqdata);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
else
|
||||
{
|
||||
interestedInNextAck = DRS_NONE;
|
||||
|
@ -151,16 +199,16 @@ 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 changedAnything = false;
|
||||
|
||||
// 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, 1024, packet, packet_length, true);
|
||||
LOG(DJAN_LOG,LOG_DEBUG, "To SWG: %s", buff);
|
||||
}
|
||||
|
||||
// Only read message from controller to SWG to set SWG Percent if we are not programming, as we might be changing this
|
||||
if (packet[3] == CMD_PERCENT && aqdata->active_thread.thread_id == 0 && packet[4] != 0xFF) {
|
||||
|
@ -219,13 +267,6 @@ bool processPacketFromSWG(unsigned char *packet, int packet_length, struct aqual
|
|||
return changedAnything;
|
||||
}
|
||||
|
||||
// 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, 1024, packet, packet_length, true);
|
||||
LOG(DJAN_LOG,LOG_DEBUG, "From SWG: %s", buff);
|
||||
}
|
||||
|
||||
if (packet[PKT_CMD] == CMD_PPM) {
|
||||
//aqdata->ar_swg_device_status = packet[5];
|
||||
setSWGdeviceStatus(aqdata, JANDY_DEVICE, packet[5]);
|
||||
|
@ -588,12 +629,6 @@ bool processPacketToJandyPump(unsigned char *packet_buffer, int packet_length, s
|
|||
|
||||
Type 0x1F and cmd 0x45 is RPM = 39 * (256) + 96 / 4 = 2520 or Byte 8 * 265 + Byte 7 / 4
|
||||
*/
|
||||
// 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[1024];
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "To ePump: %s", msg);
|
||||
}
|
||||
|
||||
// If type 0x45 and 0x44 set to interested in next command.
|
||||
if (packet_buffer[3] == CMD_EPUMP_RPM) {
|
||||
|
@ -620,14 +655,6 @@ bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length,
|
|||
{
|
||||
bool found=false;
|
||||
|
||||
// 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[1024];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "From ePump: %s", msg);
|
||||
}
|
||||
|
||||
if (packet_buffer[3] == CMD_EPUMP_STATUS && packet_buffer[4] == CMD_EPUMP_RPM) {
|
||||
for (int i = 0; i < MAX_PUMPS; i++) {
|
||||
if ( aqdata->pumps[i].prclType == JANDY && aqdata->pumps[i].pumpID == previous_packet_to ) {
|
||||
|
@ -686,13 +713,6 @@ int getPumpStatus(int pumpIndex, struct aqualinkdata *aqdata)
|
|||
bool processPacketToJandyJXiHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
|
||||
if (getLogLevel(DJAN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
|
||||
char msg[1024];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "To JXi: %s", msg);
|
||||
}
|
||||
|
||||
if (packet_buffer[3] != CMD_JXI_PING) {
|
||||
// Not sure what this message is, so ignore
|
||||
// Maybe print a messsage.
|
||||
|
@ -819,12 +839,6 @@ 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[1024];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "From JXi: %s", msg);
|
||||
}
|
||||
|
||||
if (packet_buffer[3] != CMD_JXI_STATUS) {
|
||||
// Not sure what this message is, so ignore
|
||||
|
@ -879,9 +893,6 @@ bool processPacketToJandyLXHeater(unsigned char *packet_buffer, int packet_lengt
|
|||
char msg[1024];
|
||||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "To LX: %s", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
||||
for (int i=0; i < aqdata->total_buttons; i++)
|
||||
|
@ -908,9 +919,6 @@ bool processPacketFromJandyLXHeater(unsigned char *packet_buffer, int packet_len
|
|||
char msg[1024];
|
||||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "From LX: %s", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
||||
for (int i=0; i < aqdata->total_buttons; i++)
|
||||
|
@ -937,9 +945,6 @@ bool processPacketToJandyChemFeeder(unsigned char *packet_buffer, int packet_len
|
|||
char msg[1024];
|
||||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "To Chem: %s", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
||||
length += sprintf(msg+length, ", pH=%f, ORP=%d",aqdata->ph, aqdata->orp);
|
||||
|
@ -953,9 +958,6 @@ bool processPacketFromJandyChemFeeder(unsigned char *packet_buffer, int packet_l
|
|||
char msg[1024];
|
||||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "From Chem: %s", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
||||
length += sprintf(msg+length, ", pH=%f, ORP=%d",aqdata->ph, aqdata->orp);
|
||||
|
@ -974,10 +976,6 @@ bool processPacketFromJandyChemFeeder(unsigned char *packet_buffer, int packet_l
|
|||
|
||||
bool processPacketToHeatPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
char msg[1024];
|
||||
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "To HPump: %s", msg);
|
||||
/* Byted 3 and 4
|
||||
0x0c|0x01 = Heat Pump Enabled
|
||||
0x0c|0x29 = Chiller on
|
||||
|
@ -989,25 +987,39 @@ bool processPacketToHeatPump(unsigned char *packet_buffer, int packet_length, st
|
|||
0x0c|0x00 = Request off
|
||||
0x0c|0x09 = Request Heat
|
||||
0x0c|0x29 = Request Cool
|
||||
*/
|
||||
/*
|
||||
0x0c|0x00|0x00|0x00|0x00| CMD HP Disabled
|
||||
0x0c|0x0a|0x00|0x00|0x00| CMD HP Heat SPA
|
||||
0x0c|0x01|0x00|0x00|0x00| CMD HP Enabled Pool
|
||||
0x0c|0x02|0x00|0x00|0x00| CMD HP Enabled SPA
|
||||
0x0c|0x09|0x00|0x00|0x00| CMD HP Heat Pool
|
||||
*/
|
||||
if (packet_buffer[3] == 0x0c ) {
|
||||
if (packet_buffer[4] == 0x00) {
|
||||
// Heat Pump is off
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx request to Off - status 0x%02hhx\n",packet_buffer[PKT_DEST],packet_buffer[4] );
|
||||
updateHeatPumpLed(false, OFF, aqdata, false);
|
||||
} else if (packet_buffer[4] == 0x09) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx request to Heat - status 0x%02hhx\n",packet_buffer[PKT_DEST],packet_buffer[4] );
|
||||
// Heat
|
||||
updateHeatPumpLed(false, ENABLE, aqdata, false);
|
||||
} else if (packet_buffer[4] == 0x29) {
|
||||
// Cool
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx request to Cool - status 0x%02hhx\n",packet_buffer[PKT_DEST],packet_buffer[4] );
|
||||
updateHeatPumpLed(true, ENABLE, aqdata, false);
|
||||
} else {
|
||||
// Heat Pump is on or enabled (not sure what state), but set to something other than off
|
||||
LOG(DJAN_LOG, LOG_INFO, "Heat Pump 0x%02hhx request to (unknown status) 0x%02hhx\n",packet_buffer[PKT_DEST], packet_buffer[4]);
|
||||
if (aqdata->chiller_button != NULL && aqdata->chiller_button->led->state == OFF)
|
||||
updateHeatPumpLed(false, ENABLE, aqdata, false); // Guess at enabled. ()
|
||||
switch(packet_buffer[4]) {
|
||||
case 0x00: // Heat Pump is off
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx request to Off - status 0x%02hhx\n",packet_buffer[PKT_DEST],packet_buffer[4] );
|
||||
updateHeatPumpLed(HP_UNKNOWN, OFF, aqdata, HP_FROM_PANEL);
|
||||
break;
|
||||
case 0x09: // Heat Pool
|
||||
case 0x0a: // Heat Spa
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx request to Heat - status 0x%02hhx\n",packet_buffer[PKT_DEST],packet_buffer[4] );
|
||||
updateHeatPumpLed(HP_HEAT, ON, aqdata, HP_FROM_PANEL);
|
||||
break;
|
||||
case 0x01: // Enabled Pool
|
||||
case 0x02: // Enabled SPA
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx Enabled - status 0x%02hhx\n",packet_buffer[PKT_DEST],packet_buffer[4] );
|
||||
updateHeatPumpLed(HP_UNKNOWN, ENABLE, aqdata, HP_FROM_PANEL);
|
||||
break;
|
||||
case 0x29: // Cool
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx request to Cool - status 0x%02hhx\n",packet_buffer[PKT_DEST],packet_buffer[4] );
|
||||
updateHeatPumpLed(HP_COOL, ENABLE, aqdata, HP_FROM_PANEL);
|
||||
break;
|
||||
default:
|
||||
LOG(DJAN_LOG, LOG_INFO, "Heat Pump 0x%02hhx request to (unknown status) 0x%02hhx\n",packet_buffer[PKT_DEST], packet_buffer[4]);
|
||||
//if (aqdata->chiller_button != NULL && aqdata->chiller_button->led->state == OFF)
|
||||
// updateHeatPumpLed(HP_UNKNOWN, ENABLE, aqdata, HP_FROM_PANEL); // Guess at enabled. ()
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LOG(DJAN_LOG, LOG_INFO, "Heat Pump 0x%02hhx request unknown 0x%02hhx 0x%02hhx\n",packet_buffer[PKT_DEST], packet_buffer[3] , packet_buffer[4]);
|
||||
|
@ -1018,7 +1030,6 @@ bool processPacketToHeatPump(unsigned char *packet_buffer, int packet_length, st
|
|||
}
|
||||
bool processPacketFromHeatPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to)
|
||||
{
|
||||
char msg[1024];
|
||||
/*
|
||||
HEX: 0x10|0x02|0x00|0x0d|0x40|0x00|0x00|0x5f|0x10|0x03|
|
||||
HEX: 0x10|0x02|0x00|0x0d|0x48|0x00|0x00|0x67|0x10|0x03|
|
||||
|
@ -1032,11 +1043,12 @@ bool processPacketFromHeatPump(unsigned char *packet_buffer, int packet_length,
|
|||
|
||||
if (packet_buffer[3] == 0x0d ) {
|
||||
if (packet_buffer[4] == 0x40) {
|
||||
updateHeatPumpLed(HP_HEAT, OFF, aqdata, false);
|
||||
//updateHeatPumpLed(HP_HEAT, OFF, aqdata, HP_TO_PANEL);
|
||||
updateHeatPumpLed(HP_HEAT, ENABLE, aqdata, HP_TO_PANEL);
|
||||
} else if (packet_buffer[4] == 0x48) {
|
||||
updateHeatPumpLed(HP_HEAT, ON, aqdata, false);
|
||||
updateHeatPumpLed(HP_HEAT, ON, aqdata, HP_TO_PANEL);
|
||||
} else if (packet_buffer[4] == 0x68) {
|
||||
updateHeatPumpLed(HP_COOL, ON, aqdata, false);
|
||||
updateHeatPumpLed(HP_COOL, ON, aqdata, HP_TO_PANEL);
|
||||
} else {
|
||||
//LOG(DJAN_LOG, LOG_INFO, "Heat Pump 0x%02hhx ");
|
||||
LOG(DJAN_LOG, LOG_INFO, "Heat Pump 0x%02hhx returned unknown state 0x%02hhx\n",packet_buffer[PKT_DEST], packet_buffer[4]);
|
||||
|
@ -1045,9 +1057,6 @@ bool processPacketFromHeatPump(unsigned char *packet_buffer, int packet_length,
|
|||
LOG(DJAN_LOG, LOG_INFO, "Heat Pump 0x%02hhx returned unknown information 0x%02hhx 0x%02hhx\n",packet_buffer[PKT_DEST], packet_buffer[3], packet_buffer[4]);
|
||||
}
|
||||
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "From HPump: %s", msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1067,11 +1076,11 @@ void processHeatPumpDisplayMessage(char *msg, struct aqualinkdata *aqdata) {
|
|||
hpstate = HP_COOL;
|
||||
}
|
||||
if (stristr(msg," ENA") != NULL) {
|
||||
updateHeatPumpLed(hpstate, ENABLE, aqdata, true);
|
||||
updateHeatPumpLed(hpstate, ENABLE, aqdata, HP_DISPLAY);
|
||||
} else if (stristr(msg," OFF") != NULL) {
|
||||
updateHeatPumpLed(hpstate, OFF, aqdata, true);
|
||||
updateHeatPumpLed(hpstate, OFF, aqdata, HP_DISPLAY);
|
||||
} else if (stristr(msg," ON") != NULL) {
|
||||
updateHeatPumpLed(hpstate, ON, aqdata, true);
|
||||
updateHeatPumpLed(hpstate, ON, aqdata, HP_DISPLAY);
|
||||
}
|
||||
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Set %s to %s from message '%s'",
|
||||
|
@ -1080,11 +1089,28 @@ void processHeatPumpDisplayMessage(char *msg, struct aqualinkdata *aqdata) {
|
|||
}
|
||||
|
||||
//void updateHeatPumpLed(bool chiller, aqledstate state, struct aqualinkdata *aqdata) {
|
||||
void updateHeatPumpLed(heatpumpstate state, aqledstate ledstate, struct aqualinkdata *aqdata, bool fromMessage)
|
||||
void updateHeatPumpLed(heatpumpstate state, aqledstate ledstate, struct aqualinkdata *aqdata, heatpumpmsgfrom from)
|
||||
{
|
||||
if (aqdata->chiller_button == NULL)
|
||||
return;
|
||||
|
||||
// ledstate Enabled is valied from Display and FromPanel HP_FROM_PANEL, HP_DISPLAY (NOT valid from HP ie HP_TO_PANEL)
|
||||
// ledstate on off is only valid from HP or DISPLAY HP_TO_PANEL or HP_TO_PANEL (NOT FROM HP_FROM_PANEL)
|
||||
|
||||
if ( (ledstate == ENABLE && (from == HP_DISPLAY || from == HP_FROM_PANEL)) ||
|
||||
( (ledstate == ON || ledstate == OFF) && (from == HP_DISPLAY || from == HP_TO_PANEL) )) {
|
||||
if ( ledstate != aqdata->chiller_button->led->state) {
|
||||
aqdata->chiller_button->led->state = ledstate;
|
||||
aqdata->updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == HP_COOL) {
|
||||
((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode = true;
|
||||
} else if (state == HP_HEAT) {
|
||||
((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode = false;
|
||||
}
|
||||
/*
|
||||
// If LED state is enable (that's a reqest), so only change if off.
|
||||
// if froma displayed message, that's from ON to ENA, so set that one.
|
||||
if ( !fromMessage && ledstate == ENABLE && aqdata->chiller_button->led->state == ON) {
|
||||
|
@ -1104,7 +1130,36 @@ void updateHeatPumpLed(heatpumpstate state, aqledstate ledstate, struct aqualink
|
|||
} else {
|
||||
//printf("**** Heat Pump %s, already %s, ignore!\n",LED2text(ledstate),LED2text(aqdata->chiller_button->led->state));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
bool processPacketToJandyLight(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
if (packet_buffer[3] == 0x4b) {
|
||||
LOG(DJAN_LOG, LOG_INFO, "Request to set Jandy Light brightness to %d\n", packet_buffer[6]);
|
||||
} else if (packet_buffer[3] == 0x3a) {
|
||||
LOG(DJAN_LOG, LOG_INFO, "Request to set Jandy Light RGB to %d:%d:%d\n", packet_buffer[6],packet_buffer[7],packet_buffer[8]);
|
||||
}
|
||||
|
||||
logPacket(DJAN_LOG, LOG_INFO, packet_buffer, packet_length, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool processPacketFromJandyLight(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to)
|
||||
{
|
||||
if (packet_buffer[3] == 0x31 ) {
|
||||
// This has most of the info.
|
||||
LOG(DJAN_LOG, LOG_INFO, "Light brightness=%d\n", packet_buffer[38]);
|
||||
}
|
||||
|
||||
logPacket(DJAN_LOG, LOG_INFO, packet_buffer, packet_length, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
// JXi Heater
|
||||
|
@ -1173,6 +1228,9 @@ LXi status | HEX: 0x10|0x02|0x00|0x0d|0x40|0x00|0x00|0x5f|0x10|0x03|
|
|||
LXi heater ping | HEX: 0x10|0x02|0x70|0x0c|0x29|0x00|0x00|0x00|0xb7|0x10|0x03|. byte 4 0x29 This is some on / enable
|
||||
LXi status | HEX: 0x10|0x02|0x00|0x0d|0x68|0x00|0x00|0x87|0x10|0x03| 0x68 probably is chiller ON
|
||||
|
||||
Below is when heatpump chiller is enabled but NOT on (heat or cool)
|
||||
JandyDvce: To HPump: Read Jandy packet To 0x70 of type LXi heater ping | HEX: 0x10|0x02|0x70|0x0c|0x01|0x00|0x00|0x00|0x8f|0x10|0x03|
|
||||
JandyDvce: From HPump: Read Jandy packet To 0x00 of type LXi status | HEX: 0x10|0x02|0x00|0x0d|0x40|0x00|0x00|0x5f|0x10|0x03|
|
||||
|
||||
0x0c|0x01 = Enabled
|
||||
0x0c|0x29 = Chiller on
|
||||
|
@ -1195,4 +1253,98 @@ Heat Pump Off
|
|||
JandyDvce: To HPump: Read Jandy packet To 0x70 of type LXi heater ping | HEX: 0x10|0x02|0x70|0x0c|0x00|0x00|0x00|0x00|0x8e|0x10|0x03|
|
||||
JandyDvce: From HPump: Read Jandy packet To 0x00 of type LXi status | HEX: 0x10|0x02|0x00|0x0d|0x40|0x00|0x00|0x5f|0x10|0x03|
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
RS485 Color Lights.
|
||||
|
||||
Turned lights on (was already set to "America the Beautiful") <- USA?? index 12
|
||||
Switch color to "Alpine White". <- index 1
|
||||
Turned brightness down to 50%
|
||||
Turned brightness down to 25%
|
||||
Turned off
|
||||
|
||||
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x00|0x72|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x10|0x82|0x10|0x03|
|
||||
--
|
||||
******. Below reply byte 11 = 0x23 (color mode)????
|
||||
packet To 0xf0 of type iAq Poll | HEX: 0x10|0x02|0xf0|0x30|0x00|0x32|0x10|0x03|
|
||||
packet To 0x00 of type iAq receive read | HEX: 0x10|0x02|0x00|0x31|0x2d|0x06|0x02|0x22|0x02|0x21|0x01|0x23|0x02|0x21|0x01|0x23|0x01|0x24|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0x64|0x64|0x64|0x64|0x00|0x00|0x00|0x81|0x0c|0x0f|0x03|0x72|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x00|0x72|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x10|0x82|0x10|0x03|
|
||||
--
|
||||
***** Below reply packed 38 is 0x64 (brightness 100%)
|
||||
***** Below reply packet 11 = 0x24 (color mode)?????
|
||||
packet To 0xf0 of type iAq Poll | HEX: 0x10|0x02|0xf0|0x30|0x00|0x32|0x10|0x03|
|
||||
packet To 0x00 of type iAq receive read | HEX: 0x10|0x02|0x00|0x31|0x2d|0x06|0x02|0x22|0x02|0x21|0x01|0x24|0x02|0x21|0x01|0x24|0x01|0x24|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0x64|0x64|0x64|0x64|0x00|0x00|0x00|0x81|0x0c|0x0f|0x03|0x74|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x00|0x72|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x00|0x72|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x00|0x72|0x10|0x03|
|
||||
--
|
||||
********** Below Change to 50% ***********
|
||||
packet To 0xf0 of type Unknown '0x4b' | HEX: 0x10|0x02|0xf0|0x4b|0x00|0x01|0x32|0x00|0x00|0x00|0x00|0x80|0x10|0x03|
|
||||
packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x4b|0x00|0x5e|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x50|0xc2|0x10|0x03|
|
||||
--
|
||||
***** Below reply packed 38 is 0x32 (brightness 50%)
|
||||
packet To 0xf0 of type iAq Poll | HEX: 0x10|0x02|0xf0|0x30|0x00|0x32|0x10|0x03|
|
||||
packet To 0x00 of type iAq receive read | HEX: 0x10|0x02|0x00|0x31|0x2d|0x06|0x02|0x22|0x02|0x21|0x01|0x23|0x02|0x21|0x01|0x23|0x01|0x24|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0x32|0x64|0x64|0x64|0x00|0x00|0x00|0x81|0x0c|0x0f|0x03|0x40|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x02|0x74|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x00|0x72|0x10|0x03|
|
||||
--
|
||||
***** Below reply packed 38 is 0x19 (brightness 25%)
|
||||
*********** Below Change to 25% ************
|
||||
packet To 0xf0 of type Unknown '0x4b' | HEX: 0x10|0x02|0xf0|0x4b|0x00|0x01|0x19|0x00|0x00|0x00|0x00|0x67|0x10|0x03|
|
||||
packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x4b|0x00|0x5e|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x50|0xc2|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type iAq Poll | HEX: 0x10|0x02|0xf0|0x30|0x00|0x32|0x10|0x03|
|
||||
packet To 0x00 of type iAq receive read | HEX: 0x10|0x02|0x00|0x31|0x2d|0x06|0x02|0x22|0x02|0x21|0x01|0x23|0x02|0x21|0x01|0x23|0x01|0x23|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0x19|0x64|0x64|0x64|0x00|0x00|0x00|0x81|0x0c|0x0f|0x03|0x26|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x00|0x72|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x00|0x72|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x40|0xb2|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type iAq Poll | HEX: 0x10|0x02|0xf0|0x30|0x00|0x32|0x10|0x03|
|
||||
packet To 0x00 of type iAq receive read | HEX: 0x10|0x02|0x00|0x31|0x2d|0x06|0x02|0x22|0x02|0x21|0x01|0x23|0x02|0x21|0x01|0x23|0x01|0x23|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0x19|0x64|0x64|0x64|0x00|0x00|0x00|0x01|0x0c|0x0f|0x03|0xa6|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type Unknown '0x32' | HEX: 0x10|0x02|0xf0|0x32|0x00|0x34|0x10|0x03|
|
||||
packet To 0x00 of type Unknown '0x33' | HEX: 0x10|0x02|0x00|0x33|0x2d|0x10|0x82|0x10|0x03|
|
||||
--
|
||||
packet To 0xf0 of type iAq Poll | HEX: 0x10|0x02|0xf0|0x30|0x00|0x32|0x10|0x03|
|
||||
packet To 0x00 of type iAq receive read | HEX: 0x10|0x02|0x00|0x31|0x2d|0x06|0x02|0x22|0x02|0x21|0x01|0x22|0x02|0x21|0x01|0x23|0x01|0x23|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0xff|0x00|0x19|0x64|0x64|0x64|0x00|0x00|0x00|0x01|0x0c|0x0f|0x03|0xa5|0x10|0x03|
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
|
@ -25,6 +25,9 @@ bool processPacketToJandyChemFeeder(unsigned char *packet_buffer, int packet_len
|
|||
bool processPacketToHeatPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
bool processPacketFromHeatPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to);
|
||||
|
||||
bool processPacketToJandyLight(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
bool processPacketFromJandyLight(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to);
|
||||
|
||||
void get_swg_status_mqtt(struct aqualinkdata *aqdata, char *message, int *status, int *dzalert);
|
||||
aqledstate get_swg_led_state(struct aqualinkdata *aqdata);
|
||||
|
||||
|
|
|
@ -28,7 +28,14 @@
|
|||
#include "config.h"
|
||||
|
||||
|
||||
#define SWG
|
||||
//#define HEATPUMP
|
||||
|
||||
#ifdef SWG
|
||||
unsigned char DEVICE_ID = 0x50;
|
||||
#else
|
||||
unsigned char DEVICE_ID = 0x70;
|
||||
#endif
|
||||
|
||||
bool _keepRunning = true;
|
||||
int _rs_fd;
|
||||
|
@ -43,6 +50,7 @@ bool isAqualinkDStopping() {
|
|||
return !_keepRunning;
|
||||
}
|
||||
|
||||
void process_swg_packet(unsigned char *packet_buffer, const int packet_length);
|
||||
void process_heatpump_packet(unsigned char *packet_buffer, const int packet_length);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -143,7 +151,11 @@ int main(int argc, char *argv[])
|
|||
|
||||
if (packet_buffer[PKT_DEST] == DEVICE_ID)
|
||||
{
|
||||
#ifdef SWG
|
||||
process_swg_packet(packet_buffer, packet_length);
|
||||
#else
|
||||
process_heatpump_packet(packet_buffer, packet_length);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -206,3 +218,36 @@ void process_heatpump_packet(unsigned char *packet_buffer, const int packet_leng
|
|||
}
|
||||
|
||||
|
||||
void process_swg_packet(unsigned char *packet_buffer, const int packet_length)
|
||||
{
|
||||
//(packet[3] = 0x16
|
||||
//(packet[4] * 100) = PPM
|
||||
static unsigned char swg_ack[] = {0x00,0x01,0x00,0x00};
|
||||
static unsigned char swg_ppm[] = {0x00, 0x16, 0x1f, 0x00, 0x00, 0x00};
|
||||
//static unsigned char swg_id[] = {0x00,0x03,0x00,0x49,0x6e,0x74,0x65,0x6c,0x6c,0x69,0x63,0x68,0x6c,0x6f,0x72,0x2d,0x2d,0x34,0x30};
|
||||
//static unsigned char swg_id[] = {0x00,0x03,0x00,0x41,0x71,0x75,0x61,0x50,0x75,0x72,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
static unsigned char swg_id[] = {0x00,0x03,0x01,0x41,0x71,0x75,0x61,0x50,0x75,0x72,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
// 0x11 set SWG %
|
||||
if (packet_buffer[PKT_CMD] == CMD_PROBE)
|
||||
{
|
||||
//send_ack(_rs_fd, 0x00);
|
||||
send_jandy_command(_rs_fd, swg_ack, 4);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Replied to Probe packet to 0x%02hhx with ACK\n",packet_buffer[PKT_DEST]);
|
||||
}
|
||||
else if (packet_buffer[3] == 0x11)
|
||||
{
|
||||
//int percent = (int)packet_buffer[4];
|
||||
send_jandy_command(_rs_fd, swg_ppm, 6);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Received %%=%d, Replied PPM=%d\n",(int)packet_buffer[4],swg_ppm[2] * 100);
|
||||
}
|
||||
else if (packet_buffer[3] == 0x14)
|
||||
{
|
||||
send_jandy_command(_rs_fd, swg_id, 19);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Receive ID request, replied\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(SLOG_LOG, LOG_ERR, "************* Unknown Request 0x%02hhx *************",packet_buffer[3]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
|
||||
// #include "serial_logger.h"
|
||||
#include "aq_serial.h"
|
||||
#include "utils.h"
|
||||
#include "packetLogger.h"
|
||||
#include "rs_msg_utils.h"
|
||||
|
||||
#define CONFIG_C // Make us look like config.c when we load config.h so we get globals.
|
||||
#include "config.h"
|
||||
|
||||
bool _keepRunning = true;
|
||||
int _rs_fd;
|
||||
|
||||
void intHandler(int dummy)
|
||||
{
|
||||
_keepRunning = false;
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Stopping!\n");
|
||||
}
|
||||
|
||||
bool isAqualinkDStopping() {
|
||||
return !_keepRunning;
|
||||
}
|
||||
|
||||
int get_bytes(FILE *fd, unsigned char* buffer)
|
||||
{
|
||||
int packet_length = 0;
|
||||
char line[4000];
|
||||
char hex[6];
|
||||
int i;
|
||||
bool foundHex=false;
|
||||
/*
|
||||
const char *hex_string = "0xFF";
|
||||
unsigned char value;
|
||||
|
||||
// Use strtoul to convert the hex string to an unsigned long
|
||||
// The third argument, 16, specifies the base (hexadecimal)
|
||||
unsigned long temp_value = strtoul(hex_string, NULL, 16);
|
||||
|
||||
// Cast the unsigned long to unsigned char
|
||||
value = (unsigned char)temp_value;
|
||||
*/
|
||||
|
||||
if ( fgets ( line, sizeof line, fd ) != NULL ) /* read a line */
|
||||
{
|
||||
packet_length=0;
|
||||
for (i=0; i < strlen(line); i++)
|
||||
{
|
||||
if (line[i] == 'H' && line[i+1] == 'E' && line[i+2] == 'X' && line[i+3] == ':') {
|
||||
foundHex=true;
|
||||
i=i+4;
|
||||
}
|
||||
if (line[i] == '0' && line[i+1] == 'x' && foundHex) {
|
||||
break;
|
||||
}
|
||||
if (i<=1 && line[i] == '0' && line[i+1] == 'x') {
|
||||
//printf(stdout,"Line starting with hex\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == strlen(line)) {
|
||||
//printf( "PLAYBACK No binary\n");
|
||||
return 0;
|
||||
} else {
|
||||
//printf(" Transposed from index %d=",i);
|
||||
//printf( "%s",line);
|
||||
LOG(SLOG_LOG, LOG_DEBUG, "Read bytes %s", line);
|
||||
}
|
||||
|
||||
for (i=i; i < strlen(line); i=i+5)
|
||||
{
|
||||
strncpy(hex, &line[i], 4);
|
||||
hex[5] = '\0';
|
||||
buffer[packet_length] = (int)strtol(hex, NULL, 16);
|
||||
packet_length++;
|
||||
}
|
||||
packet_length--;
|
||||
|
||||
//printf("End Char = 0x%02hhx\n",buffer[packet_length-1]);
|
||||
buffer[packet_length] = '\0';
|
||||
|
||||
return packet_length;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool createBinaryFile(char *dest, char *source) {
|
||||
int size = 0;
|
||||
unsigned char buffer[4000];
|
||||
|
||||
FILE *sfp = fopen ( source, "r" );
|
||||
if ( sfp == NULL )
|
||||
{
|
||||
perror ( source ); /* why didn't the file open? */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FILE *dfp = fopen ( dest, "wb" );
|
||||
if ( dfp == NULL )
|
||||
{
|
||||
perror ( dest ); /* why didn't the file open? */
|
||||
fclose(sfp);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (size != -1) {
|
||||
size = get_bytes(sfp, buffer);
|
||||
|
||||
if (size > 0) {
|
||||
//printf("GOT %d bytes\n",size);
|
||||
//fputs(buffer, dfp);
|
||||
fwrite(&buffer, sizeof(unsigned char), size, dfp);
|
||||
|
||||
//char pbuf[256];
|
||||
//beautifyPacket(pbuf, 256, buffer, size, TRUE);
|
||||
//printf("%s\n",pbuf);
|
||||
}
|
||||
//printf("-----------------\n");
|
||||
//if (buffer[3] == 0x72) {
|
||||
// print72pck(buffer, size);
|
||||
//process_iAqualinkStatusPacket(buffer, size);
|
||||
//}
|
||||
}
|
||||
|
||||
fclose(sfp);
|
||||
fclose(dfp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int logLevel = LOG_DEBUG;
|
||||
int fp;
|
||||
int packet_length;
|
||||
unsigned char packet_buffer[AQ_MAXPKTLEN+1];
|
||||
|
||||
if (argc < 2 || access(argv[1], F_OK) == -1)
|
||||
{
|
||||
fprintf(stderr, "ERROR, first param must be valid filename\n");
|
||||
return 1;
|
||||
}
|
||||
setLoggingPrms(logLevel, false, NULL);
|
||||
|
||||
LOG(SLOG_LOG, LOG_INFO, "Start reading %s\n", basename(argv[1]));
|
||||
|
||||
createBinaryFile("/tmp/tmp.tmp", argv[1]);
|
||||
|
||||
|
||||
if ((fp = open("/tmp/tmp.tmp", O_RDONLY)) == -1)
|
||||
{
|
||||
fprintf(stderr, "Cannot open %s\n",argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//packet_length = get_packet(fp, packet_buffer);
|
||||
|
||||
while ((packet_length = get_packet(fp, packet_buffer)) != 0) {
|
||||
LOG(SLOG_LOG, LOG_INFO, "Read %d bytes\n", packet_length);
|
||||
}
|
||||
/*
|
||||
if (packet_length == 0)
|
||||
{
|
||||
LOG(SLOG_LOG, LOG_ERR, "Error Read, %d\n", packet_length);
|
||||
close(fp);
|
||||
return 1;
|
||||
} else {
|
||||
LOG(SLOG_LOG, LOG_INFO, "Read %d bytes\n", packet_length);
|
||||
}
|
||||
*/
|
||||
|
||||
LOG(SLOG_LOG, LOG_INFO, "Stopping!\n");
|
||||
close(fp);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -725,14 +725,29 @@ void publish_mqtt_hassio_discover(struct aqualinkdata *aqdata, struct mg_connect
|
|||
|
||||
for (i=0; i < aqdata->num_sensors; i++) {
|
||||
//sprintf(idbuf, "%s_%s","sensor",aqdata->sensors[i].label);
|
||||
sprintf(topic, "%s/%s",SENSOR_TOPIC,aqdata->sensors[i].label);
|
||||
//sprintf(topic, "%s/%s",SENSOR_TOPIC,aqdata->sensors[i].label);
|
||||
sprintf(topic, "%s/%s",SENSOR_TOPIC,aqdata->sensors[i].ID);
|
||||
rsm_char_replace(idbuf, topic, "/", "_");
|
||||
//sprintf(msg, HASSIO_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,idbuf,aqdata->sensors[i].label,_aqconfig_.mqtt_aq_topic,topic, "°C", "mdi:thermometer");
|
||||
// Use HASSIO_TEMP_SENSOR_DISCOVER over HASSIO_SENSOR_DISCOVER since it has device class temperature and HA will convert automatically.
|
||||
//sprintf(msg, HASSIO_TEMP_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,idbuf,aqdata->sensors[i].label,_aqconfig_.mqtt_aq_topic,topic, "°C", "mdi:thermometer");
|
||||
|
||||
sprintf(msg, HASSIO_TEMP_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,idbuf,aqdata->sensors[i].label,_aqconfig_.mqtt_aq_topic,topic, "°C", "mdi:thermometer");
|
||||
|
||||
if (aqdata->sensors[i].uom != NULL) {
|
||||
if (isUomTemperature(aqdata->sensors[i].uom) ) {
|
||||
sprintf(msg, HASSIO_TEMP_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,idbuf,aqdata->sensors[i].label,_aqconfig_.mqtt_aq_topic,topic, aqdata->sensors[i].uom, "mdi:thermometer");
|
||||
} else {
|
||||
sprintf(msg, HASSIO_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,idbuf,aqdata->sensors[i].label,_aqconfig_.mqtt_aq_topic,topic, aqdata->sensors[i].uom, "mdi:thermometer-water");
|
||||
}
|
||||
} else {
|
||||
sprintf(msg, HASSIO_TEMP_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,idbuf,aqdata->sensors[i].label,_aqconfig_.mqtt_aq_topic,topic, "°C", "mdi:thermometer");
|
||||
}
|
||||
|
||||
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, idbuf);
|
||||
send_mqtt(nc, topic, msg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -489,7 +489,11 @@ bool process_iAqualinkStatusPacket(unsigned char *packet, int length, struct aqu
|
|||
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.
|
||||
|
||||
// NSF This needs to check strlingth, ie "Spa Mode" vs "Spa"
|
||||
if ( aq_data->virtual_button_start > 0 ) {
|
||||
for (int bi=aq_data->virtual_button_start ; bi < aq_data->total_buttons ; bi++) {
|
||||
//LOG(IAQL_LOG, LOG_INFO, "Check %s against %s\n",(char *)&packet[start + 2], aq_data->aqbuttons[bi].label);
|
||||
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
|
||||
|
@ -501,6 +505,7 @@ bool process_iAqualinkStatusPacket(unsigned char *packet, int length, struct aqu
|
|||
}
|
||||
}
|
||||
start = start + packet[start + 1] + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (packet[PKT_CMD] == CMD_IAQ_AUX_STATUS)
|
||||
|
|
|
@ -545,12 +545,36 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
{
|
||||
if (aqdata->sensors[i].value != TEMP_UNKNOWN) {
|
||||
//length += sprintf(buffer+length, "\"%s\": \"%.2f\",", aqdata->sensors[i].label, aqdata->sensors[i].value );
|
||||
/*
|
||||
length += sprintf(buffer+length, "{\"type\": \"temperature\", \"id\": \"%s/%s\", \"name\": \"%s\", \"state\": \"%s\", \"value\": \"%.*f\" },",
|
||||
SENSOR_TOPIC,aqdata->sensors[i].label,
|
||||
aqdata->sensors[i].label,
|
||||
"on",
|
||||
((homekit)?2:0),
|
||||
((homekit_f)?aqdata->sensors[i].value:aqdata->sensors[i].value));*/
|
||||
|
||||
temperatureUOM uom = getTemperatureUOM(aqdata->sensors[i].uom);
|
||||
|
||||
if (uom == UNKNOWN) {
|
||||
length += sprintf(buffer+length, "{\"type\": \"value\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"on\", \"value\": \"%.*f\" },",
|
||||
aqdata->sensors[i].ID,
|
||||
aqdata->sensors[i].label,
|
||||
2,
|
||||
aqdata->sensors[i].value);
|
||||
} else if ( !homekit && (aqdata->temp_units == FAHRENHEIT && uom == CELSIUS) ) {
|
||||
length += sprintf(buffer+length, "{\"type\": \"temperature\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"on\", \"value\": \"%.*f\" },",
|
||||
aqdata->sensors[i].ID,
|
||||
aqdata->sensors[i].label,
|
||||
2,
|
||||
degCtoF(aqdata->sensors[i].value));
|
||||
} else {
|
||||
length += sprintf(buffer+length, "{\"type\": \"temperature\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"value\": \"%.*f\" },",
|
||||
aqdata->sensors[i].ID,
|
||||
aqdata->sensors[i].label,
|
||||
"on",
|
||||
((homekit)?2:0),
|
||||
((homekit_f)?aqdata->sensors[i].value:aqdata->sensors[i].value));
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
@ -567,6 +591,8 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
|
||||
buffer[length] = '\0';
|
||||
|
||||
//printf("%s\n",buffer);
|
||||
|
||||
return strlen(buffer);
|
||||
|
||||
//return length;
|
||||
|
@ -829,14 +855,16 @@ printf("Pump Type %d\n",aqdata->pumps[i].pumpType);
|
|||
|
||||
|
||||
length += sprintf(buffer+length, ",\"alternate_modes\":{" );
|
||||
for (i=aqdata->virtual_button_start; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
if (isVBUTTON_ALTLABEL(aqdata->aqbuttons[i].special_mask)) {
|
||||
length += sprintf(buffer+length, "\"%s\": \"%s\",",aqdata->aqbuttons[i].name, ((vbutton_detail *)aqdata->aqbuttons[i].special_mask_ptr)->in_alt_mode?JSON_ON:JSON_OFF );
|
||||
if (aqdata->virtual_button_start > 0) {
|
||||
for (i=aqdata->virtual_button_start; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
if (isVBUTTON_ALTLABEL(aqdata->aqbuttons[i].special_mask)) {
|
||||
length += sprintf(buffer+length, "\"%s\": \"%s\",",aqdata->aqbuttons[i].name, ((vbutton_detail *)aqdata->aqbuttons[i].special_mask_ptr)->in_alt_mode?JSON_ON:JSON_OFF );
|
||||
}
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
length += sprintf(buffer+length, "}");
|
||||
|
||||
|
||||
|
@ -844,8 +872,14 @@ printf("Pump Type %d\n",aqdata->pumps[i].pumpType);
|
|||
for (i=0; i < aqdata->num_sensors; i++)
|
||||
{
|
||||
//printf("Sensor value %f %.2f\n",aqdata->sensors[i].value,aqdata->sensors[i].value);
|
||||
|
||||
if (aqdata->sensors[i].value != TEMP_UNKNOWN) {
|
||||
length += sprintf(buffer+length, "\"%s\": \"%.2f\",", aqdata->sensors[i].label, aqdata->sensors[i].value );
|
||||
//length += sprintf(buffer+length, "\"%s\": \"%.2f\",", aqdata->sensors[i].label, aqdata->sensors[i].value );
|
||||
if ( aqdata->temp_units == FAHRENHEIT && getTemperatureUOM(aqdata->sensors[i].uom) == CELSIUS ) {
|
||||
length += sprintf(buffer+length, "\"%s\": \"%.1f\",", aqdata->sensors[i].ID, degCtoF(aqdata->sensors[i].value) );
|
||||
} else {
|
||||
length += sprintf(buffer+length, "\"%s\": \"%.1f\",", aqdata->sensors[i].ID, aqdata->sensors[i].value );
|
||||
}
|
||||
}
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
|
@ -1183,7 +1217,7 @@ int json_cfg_element(char* buffer, int size, const char *name, const void *value
|
|||
int result = 0;
|
||||
|
||||
char valid_values[256];
|
||||
char adv[128];
|
||||
char adv[256];
|
||||
int adv_size=0;
|
||||
|
||||
// We shouldn't get CFG_HIDE here. Since we can't exit with 0, simply add a space
|
||||
|
@ -1200,8 +1234,19 @@ int json_cfg_element(char* buffer, int size, const char *name, const void *value
|
|||
if (isMASKSET(config_mask, CFG_READONLY))
|
||||
adv_size += sprintf(adv+adv_size,",\"readonly\": \"yes\"");
|
||||
|
||||
if (isMASKSET(config_mask, CFG_FORCE_RESTART))
|
||||
if (isMASKSET(config_mask, CFG_FORCE_RESTART)) {
|
||||
adv_size += sprintf(adv+adv_size,",\"force_restart\": \"yes\"");
|
||||
if ( strcmp(name, CFG_N_panel_type) == 0 ) {
|
||||
adv_size += sprintf(adv+adv_size,",\"force_restart_msg\": \"If you panel_type, you must save and reload config for correct config options to show, and must also restart AqualinkD once finished!\"");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isMASKSET(config_mask, CFG_ALLOW_BLANK))
|
||||
adv_size += sprintf(adv+adv_size,",\"allow_blank\": \"yes\"");
|
||||
|
||||
if (isMASKSET(config_mask, CFG_GREYED_OUT))
|
||||
adv_size += sprintf(adv+adv_size,",\"greyed_out\": \"yes\"");
|
||||
|
||||
|
||||
switch(type){
|
||||
|
@ -1316,18 +1361,11 @@ int build_aqualink_config_JSON(char* buffer, int size, struct aqualinkdata *aq_d
|
|||
|
||||
//#ifdef CONFIG_DEV_TEST
|
||||
for (int i=0; i <= _numCfgParams; i++) {
|
||||
|
||||
if (isMASK_SET(_cfgParams[i].config_mask, CFG_HIDE) ) {
|
||||
continue;
|
||||
}
|
||||
// We can't change web_directory or port while running, so don;t even chow those options.
|
||||
// mongoose holds a pointer to the string web_directoy, so can;t change that easily while running
|
||||
// web port = well derr we are using that currently
|
||||
/*
|
||||
if ( strncasecmp(_cfgParams[i].name, CFG_N_socket_port, strlen(CFG_N_socket_port)) == 0 ||
|
||||
strncasecmp(_cfgParams[i].name, CFG_N_web_directory, strlen(CFG_N_web_directory)) == 0 ) {
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
|
||||
if (isMASK_SET(_cfgParams[i].config_mask, CFG_READONLY) ) {
|
||||
// NSF in the future we should allow these to pass, but set the UI as readonly.
|
||||
continue;
|
||||
|
@ -1368,6 +1406,25 @@ int build_aqualink_config_JSON(char* buffer, int size, struct aqualinkdata *aq_d
|
|||
else
|
||||
length += result;
|
||||
|
||||
sprintf(buf,"sensor_%.2d_uom", i);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &aq_data->sensors[i-1].uom, CFG_STRING, 0, NULL, CFG_GRP_ADVANCED)) <= 0)
|
||||
return length;
|
||||
else
|
||||
length += result;
|
||||
//(&aq_data->sensors[i-1].uom==NULL ? "" : &aq_data->sensors[i-1].uom)
|
||||
|
||||
/*
|
||||
// Need to escape / with /// for this to work, and fix the disply that will show // for ////
|
||||
// Don;t forget config.c, Line 2096, search comment // NSF When fixed the JSON & config editor, put these lines back.
|
||||
if (&aq_data->sensors[i-1].regex != NULL) {
|
||||
sprintf(buf,"sensor_%.2d_regex", i);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &aq_data->sensors[i-1].regex, CFG_STRING, 0, NULL, CFG_GRP_ADVANCED)) <= 0)
|
||||
return length;
|
||||
else
|
||||
length += result;
|
||||
}
|
||||
*/
|
||||
|
||||
length += sprintf(buffer+length, "}" );
|
||||
if (delectCharAt != 0) {
|
||||
buffer[delectCharAt] = ' ';
|
||||
|
@ -1485,7 +1542,7 @@ int build_aqualink_config_JSON(char* buffer, int size, struct aqualinkdata *aq_d
|
|||
|
||||
|
||||
} else if (isPLIGHT(aq_data->aqbuttons[i].special_mask)) {
|
||||
if (((clight_detail *)aq_data->aqbuttons[i].special_mask_ptr)->lightType > 0) {
|
||||
if (((clight_detail *)aq_data->aqbuttons[i].special_mask_ptr)->lightType >= 0) {
|
||||
sprintf(buf,"%s_lightMode", prefix);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &((clight_detail *)aq_data->aqbuttons[i].special_mask_ptr)->lightType, CFG_INT, 0, NULL, 0)) <= 0) {
|
||||
LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length);
|
||||
|
|
|
@ -221,14 +221,20 @@ sd_journal *open_journal() {
|
|||
return journal;
|
||||
}
|
||||
|
||||
void find_aqualinkd_startupmsg(sd_journal *journal)
|
||||
void find_aqualinkd_startupmsg(sd_journal *journal, int fallbacklines)
|
||||
{
|
||||
static bool once=false;
|
||||
const void *log;
|
||||
size_t len;
|
||||
|
||||
if (fallbacklines == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only going to do this one time, incase re reset while reading.
|
||||
if (once) {
|
||||
// Simply go back number of lines since we have already gone back to startup message
|
||||
sd_journal_previous_skip(journal, fallbacklines);
|
||||
return;
|
||||
}
|
||||
once=true;
|
||||
|
@ -276,8 +282,8 @@ bool _broadcast_systemd_logmessages(bool aqMgrActive, bool reOpenStaleConnection
|
|||
} else {
|
||||
sd_journal_close(journal);
|
||||
active = false;
|
||||
return true;
|
||||
cursor = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// aqManager is active
|
||||
|
@ -299,8 +305,9 @@ bool _broadcast_systemd_logmessages(bool aqMgrActive, bool reOpenStaleConnection
|
|||
if (cursor != NULL) {
|
||||
sd_journal_seek_cursor(journal, cursor);
|
||||
sd_journal_next(journal);
|
||||
} else
|
||||
find_aqualinkd_startupmsg(journal);
|
||||
} else {
|
||||
find_aqualinkd_startupmsg(journal, (reOpenStaleConnection?0:10) );
|
||||
}
|
||||
|
||||
active = true;
|
||||
}
|
||||
|
@ -1020,7 +1027,7 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
|
|||
for (i=0; i < _aqualink_data->num_sensors; i++) {
|
||||
if ( _aqualink_data->sensors[i].value != TEMP_UNKNOWN && _last_mqtt_aqualinkdata.sensors[i].value != _aqualink_data->sensors[i].value) {
|
||||
char topic[50];
|
||||
sprintf(topic, "%s/%s", SENSOR_TOPIC, _aqualink_data->sensors[i].label);
|
||||
sprintf(topic, "%s/%s", SENSOR_TOPIC, _aqualink_data->sensors[i].ID);
|
||||
send_mqtt_float_msg(nc, topic, _aqualink_data->sensors[i].value);
|
||||
_last_mqtt_aqualinkdata.sensors[i].value = _aqualink_data->sensors[i].value;
|
||||
}
|
||||
|
@ -1028,7 +1035,7 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
|
|||
}
|
||||
|
||||
|
||||
typedef enum {uActioned, uBad, uDevices, uStatus, uHomebridge, uDynamicconf, uDebugStatus, uDebugDownload, uSimulator, uSchedules, uSetSchedules, uAQmanager, uLogDownload, uNotAvailable, uConfig, uSaveConfig} uriAtype;
|
||||
typedef enum {uActioned, uBad, uDevices, uStatus, uHomebridge, uDynamicconf, uDebugStatus, uDebugDownload, uSimulator, uSchedules, uSetSchedules, uAQmanager, uLogDownload, uNotAvailable, uConfig, uSaveConfig, uConfigDownload} uriAtype;
|
||||
//typedef enum {NET_MQTT=0, NET_API, NET_WS, DZ_MQTT} netRequest;
|
||||
const char actionName[][5] = {"MQTT", "API", "WS", "DZ"};
|
||||
|
||||
|
@ -1117,6 +1124,8 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
return uSetSchedules;
|
||||
} else if (strncmp(ri1, "schedules", 9) == 0) {
|
||||
return uSchedules;
|
||||
} else if (strncmp(ri1, "config/download", 10) == 0) {
|
||||
return uConfigDownload;
|
||||
} else if (strncmp(ri1, "config/set", 10) == 0) {
|
||||
return uSaveConfig;
|
||||
} else if (strncmp(ri1, "config", 6) == 0) {
|
||||
|
@ -1173,14 +1182,8 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
}
|
||||
return uAQmanager; // Want to resent updated status
|
||||
} else if (strncmp(ri1, "logfile", 7) == 0) {
|
||||
/*
|
||||
if (ri2 != NULL && strncmp(ri2, "start", 5) == 0) {
|
||||
startInlineLog2File();
|
||||
} else if (ri2 != NULL && strncmp(ri2, "stop", 4) == 0) {
|
||||
stopInlineLog2File();
|
||||
} else if (ri2 != NULL && strncmp(ri2, "clean", 5) == 0) {
|
||||
cleanInlineLog2File();
|
||||
} else*/ if (ri2 != NULL && strncmp(ri2, "download", 8) == 0) {
|
||||
if (ri2 != NULL && strncmp(ri2, "download", 8) == 0) {
|
||||
LOG(NET_LOG,LOG_INFO, "Received download log request!\n");
|
||||
return uLogDownload;
|
||||
}
|
||||
return uAQmanager; // Want to resent updated status
|
||||
|
@ -1344,6 +1347,8 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
*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;
|
||||
} else {
|
||||
rtn = uActioned;
|
||||
}
|
||||
} else if ((ri3 != NULL && (strncasecmp(ri2, "brightness", 10) == 0) && (strncasecmp(ri3, "set", 3) == 0))) {
|
||||
found = false;
|
||||
|
@ -1360,6 +1365,8 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
*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;
|
||||
} else {
|
||||
rtn = uActioned;
|
||||
}
|
||||
// Action a pump RPM/GPM message
|
||||
} 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))) {
|
||||
|
@ -1787,6 +1794,11 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
|
|||
remove("/dev/shm/aqualinkd.log");
|
||||
}
|
||||
break;
|
||||
|
||||
case uConfigDownload:
|
||||
LOG(NET_LOG, LOG_DEBUG, "Downloading config\n");
|
||||
mg_http_serve_file(nc, http_msg, _aqconfig_.config_file, mg_mk_str("text/plain"), mg_mk_str("Content-Disposition: attachment; filename=\"aqualinkd.conf\""));
|
||||
break;
|
||||
#endif
|
||||
case uBad:
|
||||
default:
|
||||
|
|
|
@ -300,13 +300,13 @@ bool log_panelversion(struct aqualinkdata *aq_data)
|
|||
if (strlen(aq_data->version) > 0) {
|
||||
// If another protocol set the version, we need to check the rev.
|
||||
if (!revTest){
|
||||
LOG(ONET_LOG,LOG_NOTICE, "Control Panel revision %s\n", aq_data->revision);
|
||||
//LOG(ONET_LOG,LOG_NOTICE, "Control Panel revision %s\n", aq_data->revision);
|
||||
if ( strcmp(aq_data->revision, "O.1") == 0 || strcmp(aq_data->revision, "O.2") == 0 ) {
|
||||
LOG(ONET_LOG,LOG_NOTICE, "Setting early version for OneTouch\n");
|
||||
_panel_version_P2 = true;
|
||||
revTest = true;
|
||||
}
|
||||
LOG(ONET_LOG,LOG_NOTICE, "Control Panel revision %s\n", aq_data->revision);
|
||||
//LOG(ONET_LOG,LOG_NOTICE, "Control Panel revision %s\n", aq_data->revision);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ static bool _logfile_packets = false;
|
|||
//static bool _includePentair = false;
|
||||
//static unsigned char _lastReadFrom = NUL;
|
||||
|
||||
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 _logPacket(logmask_t from, const unsigned char *packet_buffer, int packet_length, bool error, bool force, bool is_read);
|
||||
int _beautifyPacket(char *buff, int buff_size, const unsigned char *packet_buffer, int packet_length, bool error, bool is_read);
|
||||
|
||||
//void startPacketLogger(bool debug_RSProtocol_packets) {
|
||||
void startPacketLogger() {
|
||||
|
@ -56,7 +56,7 @@ void writePacketLog(char *buffer) {
|
|||
}
|
||||
|
||||
// Log Raw Bytes
|
||||
void logPacketByte(unsigned char *byte)
|
||||
void logPacketByte(const unsigned char *byte)
|
||||
{
|
||||
if (!_logfile_raw)
|
||||
return;
|
||||
|
@ -77,24 +77,24 @@ void logPacket(unsigned char *packet_buffer, int packet_length) {
|
|||
_logPacket(RSSD_LOG, packet_buffer, packet_length, false, false);
|
||||
}
|
||||
*/
|
||||
void logPacketRead(unsigned char *packet_buffer, int packet_length) {
|
||||
void logPacketRead(const unsigned char *packet_buffer, int packet_length) {
|
||||
_logPacket(RSSD_LOG, packet_buffer, packet_length, false, false, true);
|
||||
}
|
||||
void logPacketWrite(unsigned char *packet_buffer, int packet_length) {
|
||||
void logPacketWrite(const unsigned char *packet_buffer, int packet_length) {
|
||||
_logPacket(RSSD_LOG, packet_buffer, packet_length, false, false, false);
|
||||
}
|
||||
|
||||
void logPacketError(unsigned char *packet_buffer, int packet_length) {
|
||||
void logPacketError(const unsigned char *packet_buffer, int packet_length) {
|
||||
_logPacket(RSSD_LOG, packet_buffer, packet_length, true, false, true);
|
||||
}
|
||||
|
||||
/* This should never be used in production */
|
||||
void debuglogPacket(logmask_t from, unsigned char *packet_buffer, int packet_length, bool is_read, bool forcelog) {
|
||||
void debuglogPacket(logmask_t from, const 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(logmask_t from, int level, unsigned char *packet_buffer, int packet_length, bool is_read) {
|
||||
void logPacket(logmask_t from, int level, const unsigned char *packet_buffer, int packet_length, bool is_read) {
|
||||
if ( getLogLevel(from) >= level )
|
||||
_logPacket(from, packet_buffer, packet_length, false, false, is_read);
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ bool RSSD_LOG_filter_match(unsigned char ID) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void _logPacket(logmask_t from, unsigned char *packet_buffer, int packet_length, bool error, bool force, bool is_read)
|
||||
void _logPacket(logmask_t from, const unsigned char *packet_buffer, int packet_length, bool error, bool force, bool is_read)
|
||||
{
|
||||
static unsigned char lastPacketTo = NUL;
|
||||
|
||||
|
@ -164,13 +164,13 @@ void _logPacket(logmask_t from, unsigned char *packet_buffer, int packet_length,
|
|||
}
|
||||
}
|
||||
|
||||
int beautifyPacket(char *buff, int buff_size, unsigned char *packet_buffer, int packet_length, bool is_read)
|
||||
int beautifyPacket(char *buff, int buff_size, const unsigned char *packet_buffer, int packet_length, bool is_read)
|
||||
{
|
||||
return _beautifyPacket(buff, buff_size, packet_buffer, packet_length, false, is_read);
|
||||
}
|
||||
int _beautifyPacket(char *buff, int buff_size, unsigned char *packet_buffer, int packet_length, bool error, bool is_read)
|
||||
int _beautifyPacket(char *buff, int buff_size, const unsigned char *packet_buffer, int packet_length, bool error, bool is_read)
|
||||
{
|
||||
int i = 0;
|
||||
//int i = 0;
|
||||
int cnt = 0;
|
||||
protocolType ptype = getProtocolType(packet_buffer);
|
||||
|
||||
|
@ -188,6 +188,27 @@ int _beautifyPacket(char *buff, int buff_size, unsigned char *packet_buffer, int
|
|||
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));
|
||||
}
|
||||
*/
|
||||
return cnt + ( sprintFrame( (buff + cnt), (buff_size - cnt), packet_buffer, packet_length));
|
||||
|
||||
/*
|
||||
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");
|
||||
|
||||
return cnt;*/
|
||||
}
|
||||
|
||||
int sprintFrame(char *buff, int buff_size, const unsigned char *packet_buffer, int packet_length)
|
||||
{
|
||||
int i = 0;
|
||||
int cnt = 0;
|
||||
|
||||
for (i = 0; i < packet_length; i++) {
|
||||
// Check we have enough space for next set of chars
|
||||
if ( (cnt + 6) > buff_size)
|
||||
|
|
|
@ -16,15 +16,17 @@ void startPacketLogging(bool debug_protocol_packets, bool debug_raw_bytes); // S
|
|||
void stopPacketLogger();
|
||||
//void logPacket(unsigned char *packet_buffer, int packet_length, bool checksumerror);
|
||||
//void logPacket(unsigned char *packet_buffer, int packet_length);
|
||||
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);
|
||||
void logPacketRead(const unsigned char *packet_buffer, int packet_length);
|
||||
void logPacketWrite(const unsigned char *packet_buffer, int packet_length);
|
||||
void logPacketError(const unsigned char *packet_buffer, int packet_length);
|
||||
void logPacketByte(const unsigned char *byte);
|
||||
void logPacket(logmask_t from, int level, const unsigned char *packet_buffer, int packet_length, bool is_read) ;
|
||||
int beautifyPacket(char *buff, int buff_size, const unsigned char *packet_buffer, int packet_length, bool is_read);
|
||||
|
||||
int sprintFrame(char *buff, int buff_size, const unsigned char *packet_buffer, int packet_length);
|
||||
|
||||
// Only use for manual debugging
|
||||
void debuglogPacket(logmask_t from, unsigned char *packet_buffer, int packet_length, bool is_read, bool forcelog);
|
||||
void debuglogPacket(logmask_t from, const unsigned char *packet_buffer, int packet_length, bool is_read, bool forcelog);
|
||||
|
||||
|
||||
#endif //PACKETLOGGER_H_
|
43
source/pda.c
43
source/pda.c
|
@ -43,6 +43,7 @@ static struct aqualinkdata *_aqualink_data;
|
|||
static unsigned char _last_packet_type;
|
||||
static unsigned long _pda_loop_cnt = -0;
|
||||
static bool _initWithRS = false;
|
||||
static bool _first_status_after_clear = false;
|
||||
|
||||
// Each RS message is around 0.25 seconds apart
|
||||
//#define PDA_SLEEP_FOR 120 //
|
||||
|
@ -169,6 +170,10 @@ void set_pda_led(struct aqualinkled *led, char state)
|
|||
{
|
||||
led->state = FLASH;
|
||||
}
|
||||
else if (state == '%')
|
||||
{
|
||||
led->state = ON;
|
||||
}
|
||||
else
|
||||
{
|
||||
led->state = OFF;
|
||||
|
@ -252,7 +257,10 @@ void process_pda_packet_msg_long_temp(const char *msg)
|
|||
// 'AIR '
|
||||
// ' 86` '
|
||||
// 'AIR WATER' // In case of single device.
|
||||
_aqualink_data->temp_units = FAHRENHEIT; // Force FAHRENHEIT
|
||||
if (_aqualink_data->temp_units == UNKNOWN && !in_programming_mode(_aqualink_data)) {
|
||||
LOG(PDA_LOG,LOG_NOTICE, "Forcing temperature units to FAHRENHEIT\n");
|
||||
_aqualink_data->temp_units = FAHRENHEIT; // Force FAHRENHEIT
|
||||
}
|
||||
if (stristr(pda_m_line(1), "AIR") != NULL)
|
||||
_aqualink_data->air_temp = atoi(msg);
|
||||
|
||||
|
@ -407,6 +415,27 @@ void process_pda_packet_msg_long_set_time(const char *msg)
|
|||
*/
|
||||
}
|
||||
|
||||
//
|
||||
//PDA Line 2 = POOL HEAT 70`F
|
||||
//PDA Line 3 = SPA HEAT 98`F
|
||||
// temp units are last char as above.
|
||||
void get_pda_temp_units(const char *msg)
|
||||
{
|
||||
if (_aqualink_data->temp_units != UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg[15] == 'F') {
|
||||
_aqualink_data->temp_units = FAHRENHEIT;
|
||||
LOG(PDA_LOG,LOG_DEBUG, "Set temperature units to FAHRENHEIT\n");
|
||||
} else if (msg[15] == 'C') {
|
||||
_aqualink_data->temp_units = CELSIUS;
|
||||
LOG(PDA_LOG,LOG_DEBUG, "Set temperature units to CELSIUS\n");
|
||||
} else {
|
||||
LOG(PDA_LOG,LOG_DEBUG, "Unknown temperature units '%c'\n",msg[15]);
|
||||
}
|
||||
}
|
||||
|
||||
void process_pda_packet_msg_long_set_temp(const char *msg)
|
||||
{
|
||||
LOG(PDA_LOG,LOG_DEBUG, "process_pda_packet_msg_long_set_temp\n");
|
||||
|
@ -415,23 +444,27 @@ void process_pda_packet_msg_long_set_temp(const char *msg)
|
|||
{
|
||||
_aqualink_data->pool_htr_set_point = atoi(msg + 10);
|
||||
LOG(PDA_LOG,LOG_DEBUG, "pool_htr_set_point = %d\n", _aqualink_data->pool_htr_set_point);
|
||||
get_pda_temp_units(msg);
|
||||
}
|
||||
else if (stristr(msg, "SPA HEAT") != NULL)
|
||||
{
|
||||
_aqualink_data->spa_htr_set_point = atoi(msg + 10);
|
||||
LOG(PDA_LOG,LOG_DEBUG, "spa_htr_set_point = %d\n", _aqualink_data->spa_htr_set_point);
|
||||
get_pda_temp_units(msg);
|
||||
}
|
||||
else if (stristr(msg, "TEMP1") != NULL)
|
||||
{
|
||||
setSingleDeviceMode();
|
||||
_aqualink_data->pool_htr_set_point = atoi(msg + 10);
|
||||
LOG(PDA_LOG,LOG_DEBUG, "pool_htr_set_point = %d\n", _aqualink_data->pool_htr_set_point);
|
||||
get_pda_temp_units(msg);
|
||||
}
|
||||
else if (stristr(msg, "TEMP2") != NULL)
|
||||
{
|
||||
setSingleDeviceMode();
|
||||
_aqualink_data->spa_htr_set_point = atoi(msg + 10);
|
||||
LOG(PDA_LOG,LOG_DEBUG, "spa_htr_set_point = %d\n", _aqualink_data->spa_htr_set_point);
|
||||
get_pda_temp_units(msg);
|
||||
}
|
||||
|
||||
|
||||
|
@ -518,7 +551,7 @@ void process_pda_packet_msg_long_unknown(const char *msg)
|
|||
// Lets make a guess here and just see if there is an ON/OFF/ENA/*** at the end of the line
|
||||
// When you turn on/off a piece of equiptment, a clear screen followed by single message is sent.
|
||||
// So we are not in any PDA menu, try to catch that message here so we catch new device state ASAP.
|
||||
if (msg[AQ_MSGLEN - 1] == 'N' || msg[AQ_MSGLEN - 1] == 'F' || msg[AQ_MSGLEN - 1] == 'A' || msg[AQ_MSGLEN - 1] == '*')
|
||||
if (msg[AQ_MSGLEN - 1] == 'N' || msg[AQ_MSGLEN - 1] == 'F' || msg[AQ_MSGLEN - 1] == 'A' || msg[AQ_MSGLEN - 1] == '*' || msg[AQ_MSGLEN - 1] == '%')
|
||||
{
|
||||
for (i = 0; i < _aqualink_data->total_buttons; i++)
|
||||
{
|
||||
|
@ -875,6 +908,7 @@ bool process_pda_packet(unsigned char *packet, int length)
|
|||
|
||||
case CMD_PDA_CLEAR:
|
||||
read_equiptment_menu = false; // Reset the have read menu flag, since this is new menu.
|
||||
_first_status_after_clear = true;
|
||||
break;
|
||||
|
||||
case CMD_STATUS:
|
||||
|
@ -911,6 +945,11 @@ bool process_pda_packet(unsigned char *packet, int length)
|
|||
//printf("**** PDA INIT PUT BACK IN ****\n");
|
||||
queueGetProgramData(AQUAPDA, _aqualink_data);
|
||||
}
|
||||
else if (_first_status_after_clear && (pda_m_type() == PM_FREEZE_PROTECT_DEVICES))
|
||||
{
|
||||
process_pda_freeze_protect_devices();
|
||||
}
|
||||
_first_status_after_clear = false;
|
||||
break;
|
||||
|
||||
case CMD_MSG_LONG:
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
* https://github.com/sfeakes/aqualinkd
|
||||
*/
|
||||
|
||||
|
||||
#define _GNU_SOURCE 1 // for strcasestr & strptime
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -34,7 +35,7 @@
|
|||
#include "config.h"
|
||||
#include "aq_panel.h"
|
||||
#include "rs_msg_utils.h"
|
||||
|
||||
#include "color_lights.h"
|
||||
|
||||
#ifdef AQ_DEBUG
|
||||
#include "timespec_subtract.h"
|
||||
|
@ -347,7 +348,8 @@ bool find_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, int charli
|
|||
// Line 9 = BOOST
|
||||
|
||||
// "SET AquaPure" and "BOOST" are only present when filter pump is running
|
||||
if (strncasecmp(pda_m_line(9)," BOOST ", 16) == 0) {
|
||||
if ((strncasecmp(pda_m_line(9)," BOOST ", 16) == 0) ||
|
||||
(strncasecmp(pda_m_line(9)," BOOST POOL ", 16) == 0)) {
|
||||
min_index = 1;
|
||||
max_index = 8; // to account for 8 missing
|
||||
if (index == 9) { // looking for boost
|
||||
|
@ -657,26 +659,37 @@ void *set_aqualink_PDA_device_on_off( void *ptr )
|
|||
// NSF Added this since DEBUG hitting wrong command
|
||||
//waitfor_pda_queue2empty();
|
||||
|
||||
if ( find_pda_menu_item(aq_data, device_name, 13) ) {
|
||||
if ( find_pda_menu_item(aq_data, device_name, 12) ) { // Remove 1 char to account for '100%' (4 chars not the usual 3)
|
||||
if (aq_data->aqbuttons[device].led->state != state) {
|
||||
//printf("*** Select State ***\n");
|
||||
LOG(PDA_LOG,LOG_INFO, "PDA Device On/Off, found device '%s', changing state\n",aq_data->aqbuttons[device].label,state);
|
||||
LOG(PDA_LOG,LOG_INFO, "PDA Device On/Off, found device '%s', changing state\n",aq_data->aqbuttons[device].label);
|
||||
force_queue_delete(); // NSF This is a bad thing to do. Need to fix this
|
||||
send_pda_cmd(KEY_PDA_SELECT);
|
||||
while (get_pda_queue_length() > 0) { delay(500); }
|
||||
// If you are turning on a heater there will be a sub menu to set temp
|
||||
if ((state == ON) && ((device == aq_data->pool_heater_index) || (device == aq_data->spa_heater_index))) {
|
||||
if (! waitForPDAnextMenu(aq_data)) {
|
||||
LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: %s on - waitForPDAnextMenu\n",
|
||||
aq_data->aqbuttons[device].label);
|
||||
} else {
|
||||
send_pda_cmd(KEY_PDA_SELECT);
|
||||
while (get_pda_queue_length() > 0) { delay(500); }
|
||||
if (!waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHT,20)) {
|
||||
LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: %s on - wait for CMD_PDA_HIGHLIGHT\n",
|
||||
aq_data->aqbuttons[device].label);
|
||||
}
|
||||
if (! waitForPDAnextMenu(aq_data)) {
|
||||
LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: %s on - waitForPDAnextMenu\n", aq_data->aqbuttons[device].label);
|
||||
} else {
|
||||
send_pda_cmd(KEY_PDA_SELECT);
|
||||
while (get_pda_queue_length() > 0) { delay(500); }
|
||||
if (!waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHT,20)) {
|
||||
LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: %s on - wait for CMD_PDA_HIGHLIGHT\n",aq_data->aqbuttons[device].label);
|
||||
}
|
||||
}
|
||||
} else if ( isPLIGHT(aq_data->aqbuttons[device].special_mask) ) {
|
||||
// THIS EXTRA ENTER IS ONLY FOR ON, NOT OFF
|
||||
// PDA Menu Line 0 = Set Color // for color light
|
||||
// PDA Menu Line 0 = Set // for dimmer light
|
||||
if ( state == ON ) {
|
||||
waitForPDAMessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,5);
|
||||
if (strncasecmp(pda_m_line(0),"Set", 3) == 0) {
|
||||
LOG(PDA_LOG,LOG_DEBUG, "PDA Device On/Off, '%s' is programmable light, but no mode using default\n",aq_data->aqbuttons[device].label);
|
||||
send_pda_cmd(KEY_PDA_SELECT);
|
||||
} else {
|
||||
LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: expected Set menu for programmable light '%s', not found\n",aq_data->aqbuttons[device].label);
|
||||
}
|
||||
}
|
||||
} else { // not turning on heater wait for line update
|
||||
// worst case spa when pool is running
|
||||
if (!waitForPDAMessageType(aq_data,CMD_MSG_LONG,2)) {
|
||||
|
@ -700,6 +713,100 @@ void *set_aqualink_PDA_device_on_off( void *ptr )
|
|||
}
|
||||
|
||||
|
||||
void *set_aqualink_PDA_light_mode( void *ptr )
|
||||
{
|
||||
struct programmingThreadCtrl *threadCtrl;
|
||||
threadCtrl = (struct programmingThreadCtrl *) ptr;
|
||||
struct aqualinkdata *aq_data = threadCtrl->aq_data;
|
||||
//int i=0;
|
||||
//int found;
|
||||
//char device_name[15];
|
||||
|
||||
waitForSingleThreadOrTerminate(threadCtrl, AQ_PDA_SET_LIGHT_MODE);
|
||||
|
||||
char *buf = (char*)threadCtrl->thread_args;
|
||||
const char *mode_name = NULL;
|
||||
int val = atoi(&buf[0]);
|
||||
int btn = atoi(&buf[5]);
|
||||
int typ = atoi(&buf[10]);
|
||||
bool use_current_mode = false;
|
||||
|
||||
if (btn < 0 || btn >= aq_data->total_buttons ) {
|
||||
LOG(PDA_LOG, LOG_ERR, "Can't program light mode on button %d\n", btn);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
aqkey *button = &aq_data->aqbuttons[btn];
|
||||
|
||||
|
||||
if ( ! isPLIGHT(button->special_mask) ) {
|
||||
LOG(PDA_LOG, LOG_ERR, "Can't program light mode on button %d, it's not a programmable light\n", btn);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
clight_type lighttype = ((clight_detail *)button->special_mask_ptr)->lightType;
|
||||
|
||||
|
||||
if (val <= 0) {
|
||||
use_current_mode = true;
|
||||
LOG(PDA_LOG, LOG_INFO, "PDA Light Programming #: %d, on button: %s, color light type: %d, using current mode\n", val, button->label, typ);
|
||||
} else {
|
||||
if (lighttype == LC_DIMMER2 || LC_DIMMER2 == LC_DIMMER) {
|
||||
mode_name = light_mode_name(typ, val-1, AQUAPDA);
|
||||
} else {
|
||||
mode_name = light_mode_name(typ, val, AQUAPDA);
|
||||
}
|
||||
use_current_mode = false;
|
||||
if (mode_name == NULL) {
|
||||
LOG(PDA_LOG, LOG_ERR, "PDA Light Programming #: %d, on button: %s, color light type: %d, couldn't find mode name '%s'\n", val, button->label, typ, mode_name);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
return ptr;
|
||||
} else {
|
||||
LOG(PDA_LOG, LOG_INFO, "PDA Light Programming #: %d, on button: %s, color light type: %d, name '%s'\n", val, button->label, typ, mode_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (! goto_pda_menu(aq_data, PM_EQUIPTMENT_CONTROL)) {
|
||||
LOG(PDA_LOG,LOG_ERR, "PDA light Programming :- can't find EQUIPTMENT CONTROL menu\n");
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
if ( find_pda_menu_item(aq_data, button->label, 0) ) { // Remove 1 char to account for '100%' (4 chars not the usual 3)
|
||||
LOG(PDA_LOG,LOG_INFO, "PDA Light Programming, found device '%s', changing to '%s'\n",button->label,mode_name);
|
||||
force_queue_delete(); // NSF This is a bad thing to do. Need to fix this
|
||||
send_pda_cmd(KEY_PDA_SELECT);
|
||||
waitForPDAMessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,15);
|
||||
// if we get `PDA Menu Line 3 = Light will turn ` light is on and we need to press enter again.
|
||||
// if we get `PDA Menu Line 2 = Dimmer Power ` we need to cycle over 25%/50%/75%/100%
|
||||
// if we get `Menu Line 0 = Set Color` we can set color.
|
||||
if (lighttype == LC_DIMMER2 || LC_DIMMER2 == LC_DIMMER) {
|
||||
|
||||
} else {
|
||||
if (strncasecmp(pda_m_line(3),"Light will turn", 15) == 0) {
|
||||
send_pda_cmd(KEY_PDA_SELECT);
|
||||
waitForPDAMessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,5);
|
||||
}
|
||||
if (use_current_mode && mode_name != NULL) {
|
||||
if (find_pda_menu_item(aq_data,(char *)mode_name,strlen(mode_name))) {
|
||||
send_pda_cmd(KEY_PDA_SELECT);
|
||||
} else {
|
||||
LOG(PDA_LOG,LOG_ERR, "PDA Light Programming, could find mode '%s' for device '%s'\n",mode_name,button->label);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG(PDA_LOG,LOG_ERR, "PDA Light Programming, device '%s' not found\n",button->label);
|
||||
}
|
||||
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
||||
// just stop compiler error, ptr is not valid as it's just been freed
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void *get_aqualink_PDA_device_status( void *ptr )
|
||||
{
|
||||
|
@ -753,8 +860,11 @@ void *set_aqualink_PDA_init( void *ptr )
|
|||
|
||||
//printf("****** Version '%s' ********\n",aq_data->version);
|
||||
LOG(PDA_LOG,LOG_DEBUG, "PDA type=%d, version=%s\n", _PDA_Type, aq_data->version);
|
||||
|
||||
// don't wait for version menu to time out press back to get to home menu faster
|
||||
//send_pda_cmd(KEY_PDA_BACK);
|
||||
send_pda_cmd(KEY_PDA_BACK);
|
||||
|
||||
|
||||
//if (! waitForPDAnextMenu(aq_data)) { // waitForPDAnextMenu waits for highlight chars, which we don't get on normal menu
|
||||
|
||||
if (! waitForPDAMessageType(aq_data,CMD_PDA_CLEAR,10)) {
|
||||
|
|
|
@ -43,6 +43,8 @@ void *set_PDA_aqualink_boost(void *ptr);
|
|||
//bool set_PDA_aqualink_time(struct aqualinkdata *aq_data);
|
||||
void *set_PDA_aqualink_time( void *ptr );
|
||||
|
||||
void *set_aqualink_PDA_light_mode( void *ptr );
|
||||
|
||||
/*
|
||||
// These are from aq_programmer.c , exposed here for PDA AQ PROGRAMMER
|
||||
void send_cmd(unsigned char cmd);
|
||||
|
|
206
source/sensors.c
206
source/sensors.c
|
@ -2,9 +2,31 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
//#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <regex.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sensors.h"
|
||||
#include "aqualink.h"
|
||||
//#include "utils.h"
|
||||
#include "sensors.h"
|
||||
|
||||
|
||||
/*
|
||||
----------
|
||||
GPIO and thermal sensors are simply read value in file
|
||||
----------
|
||||
1Wire is similar to
|
||||
/sys/bus/w1/devices/28-011564e2feff/w1_slave
|
||||
90 01 4b 46 7f ff 0c 10 33 : crc=33 YES
|
||||
90 01 4b 46 7f ff 0c 10 33 t=25000
|
||||
read the t= value.
|
||||
|
||||
regex would be something like .*t=([0-9|\.]*)
|
||||
-----------
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
@ -13,7 +35,152 @@
|
|||
return true if current reading is different to last value stored
|
||||
*/
|
||||
|
||||
struct sensorthread {
|
||||
pthread_t thread_id;
|
||||
pthread_mutex_t thread_mutex;
|
||||
pthread_cond_t thread_cond;
|
||||
struct aqualinkdata *aq_data;
|
||||
struct timespec timeout;
|
||||
};
|
||||
|
||||
struct sensorthread *_sthread = NULL;
|
||||
|
||||
void *sensors_worker( void *ptr );
|
||||
|
||||
void stop_sensors_thread() {
|
||||
LOG(AQUA_LOG, LOG_INFO, "Stopping sensor thread\n");
|
||||
|
||||
pthread_cond_broadcast(&_sthread->thread_cond);
|
||||
}
|
||||
|
||||
void start_sensors_thread(struct aqualinkdata *aq_data) {
|
||||
|
||||
_sthread = calloc(1, sizeof(struct sensorthread));
|
||||
|
||||
_sthread->aq_data = aq_data;
|
||||
_sthread->thread_id = 0;
|
||||
|
||||
if( pthread_create( &_sthread->thread_id , NULL , sensors_worker, (void*)_sthread) < 0) {
|
||||
LOG(AQUA_LOG, LOG_ERR, "could not create sensors thread\n");
|
||||
free(_sthread);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( _sthread->thread_id != 0 ) {
|
||||
pthread_detach(_sthread->thread_id);
|
||||
}
|
||||
}
|
||||
|
||||
void *sensors_worker( void *ptr )
|
||||
{
|
||||
struct sensorthread *sthread;
|
||||
sthread = (struct sensorthread *) ptr;
|
||||
int retval = 0;
|
||||
|
||||
LOG(AQUA_LOG, LOG_NOTICE, "Started sensor thread\n");
|
||||
|
||||
pthread_mutex_lock(&sthread->thread_mutex);
|
||||
|
||||
do {
|
||||
if (retval != 0 && retval != ETIMEDOUT) {
|
||||
LOG(AQUA_LOG, LOG_ERR, "Sensor thread pthread_cond_timedwait failed for error %d %s\n",retval,strerror(retval));
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i=0; i < sthread->aq_data->num_sensors; i++) {
|
||||
//LOG(AQUA_LOG, LOG_DEBUG, "Sensor thread reading %s\n",sthread->aq_data->sensors[i].label);
|
||||
if (read_sensor(&sthread->aq_data->sensors[i]) ) {
|
||||
sthread->aq_data->updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &sthread->timeout);
|
||||
sthread->timeout.tv_sec += _aqconfig_.sensor_poll_time;
|
||||
//sthread->started_at = time(0);
|
||||
//LOG(AQUA_LOG, LOG_DEBUG, "Sensor thread will sleep for %d seconds\n",_aqconfig_.sensor_poll_time);
|
||||
} while ((retval = pthread_cond_timedwait(&sthread->thread_cond, &sthread->thread_mutex, &sthread->timeout)) == ETIMEDOUT);
|
||||
|
||||
pthread_mutex_unlock(&sthread->thread_mutex);
|
||||
|
||||
LOG(AQUA_LOG, LOG_DEBUG, "End sensor thread\n");
|
||||
|
||||
free(sthread);
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
#define READ_BUFFER_SIZE 256
|
||||
|
||||
bool read_sensor(external_sensor *sensor) {
|
||||
int fp;
|
||||
float value = 0.0;
|
||||
char buffer[READ_BUFFER_SIZE];
|
||||
char *startptr = &buffer[0];
|
||||
char *endptr;
|
||||
|
||||
fp = open(sensor->path, O_RDONLY, 0);
|
||||
if (fp < 0) {
|
||||
LOGSystemError(errno, AQUA_LOG, sensor->path);
|
||||
LOG(AQUA_LOG,LOG_ERR, "Reading sensor %s %s\n",sensor->label, sensor->path);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Read the sensor
|
||||
if ( read(fp, buffer, READ_BUFFER_SIZE) <= 0 ) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Reading value from sensor %s %s\n",sensor->label, sensor->path);
|
||||
close(fp);
|
||||
return FALSE;
|
||||
}
|
||||
close(fp);
|
||||
|
||||
// If regex pass that
|
||||
if (sensor->regex != NULL) {
|
||||
regex_t preg;
|
||||
regmatch_t pmatch[2];
|
||||
//const char *pattern = ".*t=([0-9|\\.]*)";
|
||||
//const char *pattern = ".*([0-9]+).*";
|
||||
int status;
|
||||
// Compile the regular expression
|
||||
status = regcomp(&preg, sensor->regex, REG_EXTENDED);
|
||||
if (status != 0) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Compiling sensor regex %s\n",sensor->regex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Run regex
|
||||
if ( (status = regexec(&preg, buffer, 2, pmatch, 0)) == 0) {
|
||||
startptr = buffer + pmatch[1].rm_so;
|
||||
} else if (status == REG_NOMATCH) {
|
||||
//LOG(AQUA_LOG,LOG_DEBUG, "No sensor regex match '%s' on line '%s'\n",sensor->regex,line_buffer);
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "regex match error %d using '%s' on line '%s'\n",status,sensor->regex,buffer);
|
||||
}
|
||||
// Free the compiled regular expression
|
||||
regfree(&preg);
|
||||
}
|
||||
|
||||
// Convert value to float
|
||||
value = strtof(startptr, &endptr);
|
||||
if (endptr == buffer) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Reading sensor value from %s\n", sensor->path);
|
||||
}
|
||||
|
||||
value = value * sensor->factor;
|
||||
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Read sensor %s value=%.2f\n",sensor->label, value);
|
||||
|
||||
if (sensor->value != value) {
|
||||
sensor->value = value;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef DO_NOT_COMPILE
|
||||
/* TRY not to use this unless have too, unbuffered is far quicker for sysfs */
|
||||
bool read_sensor_buffered(external_sensor *sensor) {
|
||||
|
||||
FILE *fp;
|
||||
float value;
|
||||
|
@ -25,12 +192,37 @@ bool read_sensor(external_sensor *sensor) {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
fscanf(fp, "%f", &value);
|
||||
if (sensor->regex != NULL) {
|
||||
char line_buffer[256];
|
||||
regex_t preg;
|
||||
regmatch_t pmatch[2];
|
||||
int status;
|
||||
// Compile the regular expression
|
||||
status = regcomp(&preg, sensor->regex, REG_EXTENDED);
|
||||
if (status != 0) {
|
||||
|
||||
LOG(AQUA_LOG,LOG_ERR, "Compiling sensor regex %s\n",sensor->regex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (fgets(line_buffer, sizeof(line_buffer), fp) != NULL) {
|
||||
if ( (status = regexec(&preg, line_buffer, 2, pmatch, 0)) == 0) {
|
||||
value = atof(line_buffer + pmatch[1].rm_so);
|
||||
break;
|
||||
} else if (status == REG_NOMATCH) {
|
||||
//LOG(AQUA_LOG,LOG_DEBUG, "No sensor regex match '%s' on line '%s'\n",sensor->regex,line_buffer);
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "regex match error %d using '%s' on line '%s'\n",status,sensor->regex,line_buffer);
|
||||
}
|
||||
}
|
||||
// Free the compiled regular expression
|
||||
regfree(&preg);
|
||||
} else {
|
||||
fscanf(fp, "%f", &value);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
// Convert usually from millidegrees Celsius to degrees Celsius
|
||||
//printf("Factor = %f - value %f\n",sensor->factor, value);
|
||||
//printf("Read Sensor value %f %.2f\n",value,value * sensor->factor);
|
||||
value = value * sensor->factor;
|
||||
//printf("Converted value %f\n",value);
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Read sensor %s value=%.2f\n",sensor->label, value);
|
||||
|
@ -41,4 +233,6 @@ bool read_sensor(external_sensor *sensor) {
|
|||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -3,13 +3,20 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "aqualink.h"
|
||||
|
||||
typedef struct external_sensor{
|
||||
char *path;
|
||||
float factor;
|
||||
char *label;
|
||||
float value;
|
||||
char ID[7];
|
||||
char *regex;
|
||||
char *uom;
|
||||
} external_sensor;
|
||||
|
||||
bool read_sensor(external_sensor *sensor);
|
||||
void stop_sensors_thread();
|
||||
void start_sensors_thread(struct aqualinkdata *aq_data);
|
||||
|
||||
#endif
|
|
@ -163,6 +163,8 @@ int serial_logger (int rs_fd, char *port_name, int logLevel, int slogger_packets
|
|||
#define HEAT_PUMP " <-- Heat Pump"
|
||||
#define REM_PWR_CENT " <-- Remote Power Center"
|
||||
|
||||
#define JWC_LIGHTS " <-- Jandy WaterColor Lights"
|
||||
|
||||
#define UNKNOWN " <-- Unknown Device"
|
||||
|
||||
#define P_VSP " <-- Pentair VSP"
|
||||
|
@ -225,9 +227,11 @@ const char *getDevice(unsigned char ID) {
|
|||
if (ID >= 0x28 && ID <= 0x2B)
|
||||
return REM_PWR_CENT;
|
||||
|
||||
if (ID >= 0xE0 && ID <= 0xEF) // this could end at 0xF0
|
||||
if (ID >= 0xE0 && ID <= 0xEF)
|
||||
return EPUMP2;
|
||||
|
||||
if (ID >= 0xF0 && ID <= 0xF4) // 0xF4 is total guess.
|
||||
return JWC_LIGHTS;
|
||||
//if (ID == 0x08)
|
||||
// return KEYPAD;
|
||||
|
||||
|
|
|
@ -363,7 +363,7 @@ bool process_rssadapter_packet(unsigned char *packet, int length, struct aqualin
|
|||
|
||||
// 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",
|
||||
LOG(RSSA_LOG,LOG_DEBUG,"DimmerLight '%s' is %s, rawvalue 0x%02hhx value '%d'%%\n",
|
||||
aq_data->lights[i].button->label,
|
||||
packet[6]==0x00?"OFF":"ON",
|
||||
packet[6],
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "utils.h"
|
||||
#include "rs_msg_utils.h"
|
||||
#include "aq_serial.h"
|
||||
#include "aqualink.h"
|
||||
|
||||
#define DEFAULT_LOG_FILE "/tmp/aqualinkd-inline.log"
|
||||
//#define MAXCFGLINE 265
|
||||
|
@ -109,15 +110,15 @@ int getSystemLogLevel()
|
|||
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 || from == SLOG_LOG) && ((_logforcemask & from) == from ) && _log_level < LOG_DEBUG_SERIAL)
|
||||
if ( (from == RSSD_LOG || from == SLOG_LOG) && isMASK_SET(_logforcemask, from) && _log_level < LOG_DEBUG_SERIAL) {
|
||||
return LOG_DEBUG_SERIAL;
|
||||
else if ( ((_logforcemask & from) == from ) && _log_level < LOG_DEBUG_SERIAL)
|
||||
} else if ( isMASK_SET(_logforcemask, from) && _log_level < LOG_DEBUG_SERIAL) {
|
||||
return LOG_DEBUG;
|
||||
|
||||
} else if (from == RSTM_LOG && _log_level < LOG_DEBUG_SERIAL && !isMASK_SET(_logforcemask, from)) {
|
||||
// RSTM_LOG (RS serial timings) should only print if debug_serial or explicitly set in the forcelogmask.
|
||||
return LOG_NOTICE;
|
||||
}
|
||||
|
||||
return _log_level;
|
||||
}
|
||||
|
||||
|
@ -593,8 +594,9 @@ void LOG(const logmask_t from, const int msg_level, const char * format, ...)
|
|||
return;
|
||||
}
|
||||
*/
|
||||
if ( msg_level > getLogLevel(from))
|
||||
if ( msg_level > getLogLevel(from)) {
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[LOGBUFFER];
|
||||
va_list args;
|
||||
|
@ -963,3 +965,61 @@ char *prittyString(char *str)
|
|||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
temperatureUOM getTemperatureUOM(const char *uom) {
|
||||
|
||||
if (uom == NULL)
|
||||
return UNKNOWN;
|
||||
|
||||
if (uom[0] == 194 && uom[1] == 176) { // Deg symbol is 2 chars '°'
|
||||
switch (uom[2]) {
|
||||
case 'F':
|
||||
case 'f':
|
||||
//printf("UOM %s is FAHRENHEIT\n", uom);
|
||||
return FAHRENHEIT;
|
||||
break;
|
||||
case 'C':
|
||||
case 'c':
|
||||
//printf("UOM %s is CELSIUS\n", uom);
|
||||
return CELSIUS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("UOM %s is UNKNOWN\n", uom);
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
bool isUomTemperature( const char *uom) {
|
||||
|
||||
/*
|
||||
for (int i=0; i<strlen(uom); i++) {
|
||||
printf(" %d |",uom[i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
if (uom == NULL)
|
||||
return false;
|
||||
|
||||
if (uom[0] == 194 && uom[1] == 176) { // Deg symbol is 2 chars '°'
|
||||
//printf("UOM %s is temp\n", uom);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strlen(uom) == 1) {
|
||||
switch (uom[0]) {
|
||||
case 'F':
|
||||
case 'f':
|
||||
case 'C':
|
||||
case 'c':
|
||||
//printf("UOM %s is temp\n", uom);
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("UOM %s is NOT temp %d %c\n", uom, uom[0], uom[0]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
//#include "aqualink.h"
|
||||
|
||||
|
||||
#ifndef UTILS_H_
|
||||
#define UTILS_H_
|
||||
|
||||
|
@ -18,6 +21,12 @@
|
|||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
typedef enum tempUOM {
|
||||
FAHRENHEIT,
|
||||
CELSIUS,
|
||||
UNKNOWN
|
||||
} temperatureUOM;
|
||||
|
||||
#define LOGBUFFER 256
|
||||
#define LARGELOGBUFFER 1400 // / Must be at least AQ_MAXPKTLEN * 5 + 100
|
||||
|
||||
|
@ -129,6 +138,10 @@ char *prittyString(char *str);
|
|||
//void writePacketLog(char *buff);
|
||||
//void closePacketLog();
|
||||
float timespec2float(const struct timespec *elapsed);
|
||||
bool isUomTemperature( const char *uom);
|
||||
|
||||
|
||||
temperatureUOM getTemperatureUOM(const char *uom);
|
||||
|
||||
#ifdef AQ_MANAGER
|
||||
//void startInlineLog2File();
|
||||
|
|
|
@ -4,4 +4,5 @@
|
|||
#define AQUALINKD_SHORT_NAME "AqualinkD"
|
||||
|
||||
// Use Magor . Minor . Patch
|
||||
#define AQUALINKD_VERSION "2.6.5"
|
||||
#define AQUALINKD_VERSION "2.6.9"
|
||||
|
|
@ -18,7 +18,9 @@
|
|||
--aqualinkd-scale: 0.75;
|
||||
--aqualinkd-container: 265px;
|
||||
--aqualinkd-iframe: 350px; /* Seems backwards, but the way the iframe scales the iframe need to be the same amount bigger 350*0.75*/
|
||||
--grid-width: 300px; /* Width of left column */
|
||||
--logcontainer-height: 510px; /* This will get changed on page load */
|
||||
--logcontainer-width: 1040px; /* This will get changed on page load */
|
||||
}
|
||||
html {}
|
||||
|
||||
|
@ -33,8 +35,10 @@
|
|||
|
||||
.wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 300px 1fr;
|
||||
grid-gap: 1rem;
|
||||
/*grid-template-columns: 300px 1fr;*/
|
||||
grid-template-columns: var(--grid-width) 1fr;
|
||||
/*grid-gap: 1rem;*/
|
||||
grid-gap: 0px;
|
||||
}
|
||||
|
||||
.inner {
|
||||
|
@ -44,12 +48,16 @@
|
|||
justify-content: center;
|
||||
/*border: 1px solid red;*/
|
||||
align-items: flex-start;
|
||||
|
||||
margin-top: 10px;
|
||||
margin-left: 5px;
|
||||
margin-right: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.aqualinkd {
|
||||
grid-column: 1 / -1;
|
||||
width: 133%;
|
||||
/*width: 100%;*/
|
||||
height: var(--aqualinkd-container); /* Iframe is set to 350px in the HTML so scale it back here */
|
||||
/*transform: scale(0.75);*/
|
||||
transform: scale(var(--aqualinkd-scale));
|
||||
|
@ -73,7 +81,7 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
/*border: 1px solid red;*/
|
||||
row-gap: 20px;
|
||||
/*row-gap: 10px;*/
|
||||
/*overflow-y: scroll; this only works if we know the height, we can caculate but not important at moment */
|
||||
}
|
||||
|
||||
|
@ -170,15 +178,25 @@
|
|||
/*height: 510px;*//* This was size before scaling aqualinkd iframe*/
|
||||
/*height: 650px;*/
|
||||
height: var(--logcontainer-height);
|
||||
width: 100%;
|
||||
/*width: 100%;*/
|
||||
/*width: 500px;*/
|
||||
width: var(--logcontainer-width);
|
||||
/*width: calc(100% - 300px);*/
|
||||
overflow: auto;
|
||||
overflow-x: auto;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
/*flex-direction: column-reverse;*/
|
||||
flex-direction: column;
|
||||
background-color: #2b2b2b;
|
||||
color: white;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.logline {
|
||||
margin-left: 2px;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
|
@ -351,6 +369,9 @@
|
|||
_addedBlankLightProgram = false;
|
||||
_addedBlankSensor = false;
|
||||
_addedBlankVirtualButton = false;
|
||||
|
||||
//var _cfgRestartAlertShown = false;
|
||||
let _AlertsShown = {};
|
||||
|
||||
var _config = {};
|
||||
|
||||
|
@ -428,36 +449,69 @@
|
|||
return number;
|
||||
}
|
||||
|
||||
var last_message_element = null;
|
||||
var log_element_count = 0;
|
||||
var _last_message_element = null;
|
||||
var _log_element_count = 0;
|
||||
const LOGS2DISPLAY = 500;
|
||||
var _log_div_pressed = -1;
|
||||
|
||||
function update_log_message(message) {
|
||||
if (_log_div_pressed == -1) {
|
||||
document.getElementById("logs").addEventListener("mousedown", function (e) {_log_div_pressed = true;})
|
||||
document.getElementById("logs").addEventListener("mouseup", function (e) {_log_div_pressed = false;})
|
||||
_log_div_pressed = false;
|
||||
}
|
||||
//console.log(message);
|
||||
var element = document.createElement("div");
|
||||
element.classList.add("logline");
|
||||
|
||||
if (message.startsWith("Error:")) {
|
||||
element.classList.add("logmsgerror");
|
||||
}
|
||||
|
||||
var logcontainer = document.getElementById("logs");
|
||||
|
||||
if (log_element_count >= LOGS2DISPLAY) {
|
||||
if (_log_element_count >= LOGS2DISPLAY) {
|
||||
try {
|
||||
//console.log("Removing " + logcontainer.lastElementChild.innerHTML);
|
||||
logcontainer.lastElementChild.remove();
|
||||
logcontainer.firstElementChild.remove();
|
||||
} catch (e) {
|
||||
//console.log("ERROR Removing log '" + logcontainer.lastElementChild.innerHTML + "'");
|
||||
log_element_count++;
|
||||
_log_element_count++;
|
||||
}
|
||||
} else {
|
||||
log_element_count++;
|
||||
_log_element_count++;
|
||||
}
|
||||
|
||||
element.appendChild(document.createTextNode(message));
|
||||
logcontainer.insertBefore(element, last_message_element);
|
||||
last_message_element = element;
|
||||
logcontainer.appendChild(element);
|
||||
_last_message_element = element;
|
||||
|
||||
if (_log_div_pressed == false) {
|
||||
logcontainer.scrollTop = logcontainer.scrollHeight - logcontainer.clientHeight;
|
||||
}
|
||||
}
|
||||
|
||||
/* Below needs flex-direction: column-reverse; set in CSS .logcontainer */
|
||||
/*
|
||||
function OLD_update_log_message_OLD(message) {
|
||||
var element = document.createElement("div");
|
||||
if (message.startsWith("Error:")) {
|
||||
element.classList.add("logmsgerror");
|
||||
}
|
||||
var logcontainer = document.getElementById("logs");
|
||||
if (_log_element_count >= LOGS2DISPLAY) {
|
||||
try {
|
||||
logcontainer.lastElementChild.remove();
|
||||
} catch (e) {
|
||||
_log_element_count++;
|
||||
}
|
||||
} else {
|
||||
_log_element_count++;
|
||||
}
|
||||
element.appendChild(document.createTextNode(message));
|
||||
logcontainer.insertBefore(element, _last_message_element);
|
||||
_last_message_element = element;
|
||||
}
|
||||
*/
|
||||
|
||||
function update_status(data) {
|
||||
}
|
||||
|
||||
|
@ -496,43 +550,28 @@
|
|||
}
|
||||
send_command(msg);
|
||||
}
|
||||
function setlogfile(caller) {
|
||||
function requestFileDownload(caller) {
|
||||
var msg = {};
|
||||
/*
|
||||
if (caller.id == "logfile") {
|
||||
var startstop = "";
|
||||
if (caller.checked) {
|
||||
startstop = "start";
|
||||
} else {
|
||||
startstop = "stop";
|
||||
}
|
||||
msg = {
|
||||
uri: "logfile/" + startstop,
|
||||
value: 0
|
||||
};
|
||||
} else if (caller.id == "cleanlog") {
|
||||
msg = {
|
||||
uri: "logfile/clean",
|
||||
value: 0
|
||||
};
|
||||
} else*/
|
||||
if (caller.id == "downloadlog") {
|
||||
|
||||
if (caller.id == "downloadlog") {
|
||||
//window.location = '/api/debug/download';
|
||||
downloadFile('/api/logfile/download', document.getElementById("logsize").value);
|
||||
return;
|
||||
downloadFile('/api/logfile/download', "aqualinkd.log", document.getElementById("logsize").value);
|
||||
return;
|
||||
} else if ( caller.id == "downloadconfig") {
|
||||
downloadFile('/api/config/download', "aqualinkd.conf");
|
||||
return;
|
||||
}
|
||||
|
||||
send_command(msg);
|
||||
}
|
||||
|
||||
function downloadFile(filePath, lines) {
|
||||
function downloadFile(filePath, fname, lines=0) {
|
||||
//console.log("Lines=" + lines);
|
||||
|
||||
var link = document.createElement('a');
|
||||
link.href = filePath + "/" + lines;
|
||||
//link.download = filePath.substr(filePath.lastIndexOf('/') + 1);
|
||||
link.download = "aqualinkd.log"
|
||||
link.download = fname
|
||||
link.click();
|
||||
// Can't get a form post to cleanly download, and "a download" above can only do get. So add value
|
||||
/*
|
||||
|
@ -587,11 +626,15 @@
|
|||
values: {}
|
||||
};
|
||||
|
||||
for (var obj in _config) {
|
||||
//console.log(_config);
|
||||
|
||||
for (var obj in _config) {
|
||||
if (_config[obj].value !== undefined) {
|
||||
if (_config[obj].value) {
|
||||
json_ordered.values[obj] = _config[obj].value;
|
||||
} else if (_config[obj].allow_blank !== undefined && _config[obj].allow_blank == "yes") {
|
||||
//console.log("----- Add Blank value for "+ obj+"\n");
|
||||
json_ordered.values[obj] = "";
|
||||
}
|
||||
} else if (obj.toString().startsWith("button_") || obj.toString().startsWith("virtual_button_") || obj.toString().startsWith("sensor_") ) {
|
||||
for (var obj1 in _config[obj]) {
|
||||
|
@ -670,11 +713,13 @@
|
|||
if (deletable) {
|
||||
cell3.innerHTML = '<input type="button" class="config_option_deletebutton" id="delete" key="'+obj.toString()+'" value="X" onclick="deleteCfgOption(this);">';
|
||||
}
|
||||
|
||||
|
||||
var input;
|
||||
|
||||
if (data[obj]["valid values"] !== undefined) {
|
||||
//console.log(data[obj]["valid values"]);
|
||||
const input = document.createElement("select");
|
||||
//const
|
||||
input = document.createElement("select");
|
||||
array = data[obj]["valid values"];
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
var option = document.createElement("option");
|
||||
|
@ -688,24 +733,26 @@
|
|||
input.appendChild(option);
|
||||
}
|
||||
input.addEventListener('change', cfgValueChanged);
|
||||
if (data[obj].force_restart == "yes") {
|
||||
input.addEventListener('click', cfgAlertForceRestart);
|
||||
}
|
||||
//if (data[obj].force_restart == "yes") {
|
||||
// input.addEventListener('click', cfgAlertForceRestart);
|
||||
// }
|
||||
cell2.appendChild(input);
|
||||
} else if (data[obj].type == "string") {
|
||||
const input = document.createElement("input");
|
||||
//const
|
||||
input = document.createElement("input");
|
||||
input.type = "text";
|
||||
if (data[obj].value != "(null)") {
|
||||
input.value = data[obj].value;
|
||||
}
|
||||
input.setAttribute('key', obj.toString());
|
||||
input.addEventListener('change', cfgValueChanged);
|
||||
if (data[obj].force_restart == "yes") {
|
||||
input.addEventListener('click', cfgAlertForceRestart);
|
||||
}
|
||||
//if (data[obj].force_restart == "yes") {
|
||||
// input.addEventListener('click', cfgAlertForceRestart);
|
||||
//}
|
||||
cell2.appendChild(input);
|
||||
} else if (data[obj].type == "int") {
|
||||
const input = document.createElement("input");
|
||||
//const
|
||||
input = document.createElement("input");
|
||||
input.type = "number";
|
||||
if (data[obj].value != -999) {
|
||||
input.value = data[obj].value;
|
||||
|
@ -714,36 +761,52 @@
|
|||
input.step = 1;
|
||||
input.setAttribute('key', obj.toString());
|
||||
input.addEventListener('change', cfgValueChanged);
|
||||
if (data[obj].force_restart == "yes") {
|
||||
input.addEventListener('click', cfgAlertForceRestart);
|
||||
}
|
||||
//if (data[obj].force_restart == "yes") {
|
||||
// input.addEventListener('click', cfgAlertForceRestart);
|
||||
//}
|
||||
cell2.appendChild(input);
|
||||
} else if (data[obj].type == "float") {
|
||||
const input = document.createElement("input");
|
||||
//const
|
||||
input = document.createElement("input");
|
||||
input.type = "number";
|
||||
input.value = data[obj].value;
|
||||
input.size = 4;
|
||||
input.step = 0.01;
|
||||
input.setAttribute('key', obj.toString());
|
||||
input.addEventListener('change', cfgValueChanged);
|
||||
if (data[obj].force_restart == "yes") {
|
||||
input.addEventListener('click', cfgAlertForceRestart);
|
||||
}
|
||||
//if (data[obj].force_restart == "yes") {
|
||||
// input.addEventListener('click', cfgAlertForceRestart);
|
||||
//}
|
||||
cell2.appendChild(input);
|
||||
} else if (data[obj].type == "hex") {
|
||||
const input = document.createElement("input");
|
||||
//const
|
||||
input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.value = data[obj].value;
|
||||
input.size = 4;
|
||||
input.setAttribute('key', obj.toString());
|
||||
input.addEventListener('change', cfgValueChanged);
|
||||
if (data[obj].force_restart == "yes") {
|
||||
input.addEventListener('click', cfgAlertForceRestart);
|
||||
}
|
||||
//if (data[obj].force_restart == "yes") {
|
||||
// input.addEventListener('click', cfgAlertForceRestart);
|
||||
//}
|
||||
cell2.appendChild(input);
|
||||
} else {
|
||||
cell2.textContent = data[obj].value;
|
||||
}
|
||||
|
||||
// Set any generic stuff.
|
||||
if (typeof input !== "undefined") {
|
||||
if (data[obj].force_restart == "yes") {
|
||||
input.addEventListener('click', cfgAlertForceRestart);
|
||||
}
|
||||
if (data[obj].greyed_out == "yes") {
|
||||
console.log("GREYED OUT");
|
||||
console.log(newRow);
|
||||
newRow.style.opacity = '0.4'; // Sets 40% opacity
|
||||
input.enabled = false;
|
||||
input.disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -929,19 +992,22 @@
|
|||
console.log(_config);
|
||||
}
|
||||
|
||||
console.log("cfgValueUnhide key="+key+" value="+value);
|
||||
//console.log("cfgValueUnhide key="+key+" value="+value);
|
||||
|
||||
event.target.removeEventListener('change', cfgValueUnhide);
|
||||
event.target.addEventListener('change', cfgValueChanged);
|
||||
|
||||
// Show the next table row.
|
||||
event.target.parentNode.parentNode.nextSibling.style.display = '';
|
||||
|
||||
// If sensor show next 2 rows.
|
||||
if (key.startsWith("sensor_") ) {
|
||||
event.srcElement.parentNode.parentNode.childNodes[0].innerHTML = key;
|
||||
event.target.parentNode.parentNode.nextSibling.nextSibling.style.display = '';
|
||||
event.target.parentNode.parentNode.nextSibling.nextSibling.nextSibling.style.display = '';
|
||||
}
|
||||
|
||||
console.log(event);
|
||||
//console.log(event);
|
||||
}
|
||||
|
||||
function deleteCfgOption(event) {
|
||||
|
@ -958,7 +1024,7 @@
|
|||
//console.log(event.parentNode.parentNode);
|
||||
//console.log("deleteCfgOption - "+key);
|
||||
//console.log(_config[key]);
|
||||
console.log(_config);
|
||||
//console.log(_config);
|
||||
|
||||
if (!rebuild) {
|
||||
const configtable = document.getElementById("config_table");
|
||||
|
@ -1039,7 +1105,7 @@
|
|||
var cell1 = newRow.insertCell();
|
||||
var cell2 = newRow.insertCell();
|
||||
//var cell3 = newRow.insertCell();
|
||||
|
||||
//console.log("num="+num+" String="+String(num+1)+" Key="+key);
|
||||
cell1.style.paddingLeft = "20px";
|
||||
cell1.innerHTML = "<small>Add</small> "+key+"_path";
|
||||
|
||||
|
@ -1090,6 +1156,23 @@
|
|||
input.addEventListener('change', cfgAddSensor);
|
||||
cell2.appendChild(input);
|
||||
|
||||
// Add sensor_xx_uom row
|
||||
if (row != -1){row++};
|
||||
newRow = configtable.insertRow(row);
|
||||
newRow.style.display = 'none';
|
||||
cell1 = newRow.insertCell();
|
||||
cell2 = newRow.insertCell();
|
||||
cell1.style.paddingLeft = "20px";
|
||||
cell1.innerHTML = key+"_uom";
|
||||
|
||||
input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.setAttribute('key', key+"_uom");
|
||||
input.setAttribute('root_key', key);
|
||||
input.id = key+"_uom";
|
||||
input.addEventListener('change', cfgAddSensor);
|
||||
cell2.appendChild(input);
|
||||
|
||||
_addedBlankSensor = true;
|
||||
}
|
||||
|
||||
|
@ -1175,7 +1258,7 @@
|
|||
var value = event.srcElement.value;
|
||||
var key = event.srcElement.getAttribute('key');
|
||||
var root_key = event.srcElement.getAttribute('root_key');
|
||||
console.log(key + " = "+ value);
|
||||
//console.log(key + " = "+ value);
|
||||
|
||||
//event.srcElement.parentNode.parentNode.childNodes[1].childNodes[0].removeEventListener('change', cfgAddLightProgram);
|
||||
//event.srcElement.parentNode.parentNode.childNodes[1].childNodes[0].addEventListener('change', cfgValueChanged);
|
||||
|
@ -1194,28 +1277,34 @@
|
|||
//_config[key] = js;
|
||||
|
||||
if (_config[root_key]) {
|
||||
console.log("Json exists");
|
||||
//console.log("Json exists");
|
||||
_config[root_key][key] = js;
|
||||
} else {
|
||||
console.log("Json not exists");
|
||||
//console.log("Json not exists");
|
||||
jsobj={};
|
||||
jsobj.advanced="yes";
|
||||
jsobj[key] = js;
|
||||
_config[root_key] = jsobj
|
||||
}
|
||||
|
||||
console.log(_config);
|
||||
//console.log(_config);
|
||||
// If all 3 have an entry, add another sensor
|
||||
if ( (document.getElementById(root_key+"_path").value) &&
|
||||
(document.getElementById(root_key+"_label").value) &&
|
||||
(document.getElementById(root_key+"_factor").value)) {
|
||||
(document.getElementById(root_key+"_factor").value) &&
|
||||
(document.getElementById(root_key+"_uom").value)) {
|
||||
|
||||
const configtable = document.getElementById("config_table");
|
||||
//console.log("Searching for key "+key+" | root key "+root_key);
|
||||
var found=false;
|
||||
for (let i = 0; i < configtable.rows.length; i++) {
|
||||
try{
|
||||
console.log(configtable.rows[i].cells[0].innerHTML);
|
||||
if(configtable.rows[i].cells[0].innerHTML == key) {
|
||||
addSensorRow( parseInt(key.match(/[0-9]+/)), i+1 )
|
||||
if ( root_key === configtable.rows[i].cells[0].innerHTML.substring(0, root_key.length ) ) {
|
||||
//console.log("Found "+configtable.rows[i].cells[0].innerHTML);
|
||||
found = true;
|
||||
} else if (found == true) {
|
||||
//console.log("Should Add add element here index="+i+" name="+configtable.rows[i].cells[0].innerHTML);
|
||||
addSensorRow( parseInt(key.match(/[0-9]+/)), i);
|
||||
break;
|
||||
}
|
||||
} catch (e){}
|
||||
|
@ -1224,7 +1313,8 @@
|
|||
|
||||
}
|
||||
|
||||
|
||||
function isNumber(n) { return !isNaN(parseFloat(n)) && !isNaN(n - 0) }
|
||||
|
||||
function populateconfigtable(data=null) {
|
||||
_addedBlankLightProgram = false;
|
||||
_addedBlankSensor = false;
|
||||
|
@ -1286,17 +1376,19 @@
|
|||
if (lastKey.startsWith("light_program_") && ! obj.toString().startsWith("light_program_") ) {
|
||||
addLightProgramRow(parseInt(lastKey.match(/[0-9]+/)));
|
||||
} else if (lastKey.startsWith("sensor_") && ! obj.toString().startsWith("sensor_") ) {
|
||||
addSensorRow(parseInt(lastKey.match(/[0-9]+/)));
|
||||
if (isNumber(lastKey.match(/[0-9]+/))) {
|
||||
addSensorRow(parseInt(lastKey.match(/[0-9]+/)));
|
||||
}
|
||||
} else if (lastKey.startsWith("virtual_button_") && ! obj.toString().startsWith("virtual_button_") ) {
|
||||
addVirtualButtonRow(parseInt(lastKey.match(/[0-9]+/)));
|
||||
}
|
||||
|
||||
if (_config[obj].value !== undefined) {
|
||||
if (obj.toString().startsWith("light_program_") ) {
|
||||
console.log(obj.toString());
|
||||
//console.log(obj.toString());
|
||||
num = parseInt(lastKey.match(/[0-9]+/));
|
||||
num++;
|
||||
console.log("check for light_program_"+String(num+1).padStart(2, '0'));
|
||||
//console.log("check for light_program_"+String(num+1).padStart(2, '0'));
|
||||
//console.log("check for light_program_"+num);
|
||||
if ( !('light_program_'+String(num+1).padStart(2, '0') in _config)) {
|
||||
addConfigRow(hideLineSeperator, _config, obj, -1, true);
|
||||
|
@ -1351,19 +1443,27 @@
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function cfgAlertForceRestart(event) {
|
||||
console.log("Caught event");
|
||||
var key = event.srcElement.getAttribute('key');
|
||||
var value = event.srcElement.value;
|
||||
|
||||
alert("If you change "+key+" You will need to restart AqualinkD after saving config!");
|
||||
//console.log( _AlertsShown[key]);
|
||||
if ( _AlertsShown[key] == undefined || _AlertsShown[key] == false) {
|
||||
_AlertsShown[key] = true;
|
||||
if ("force_restart_msg" in _config[key]) {
|
||||
alert(_config[key].force_restart_msg);
|
||||
} else {
|
||||
alert("If you change "+key+" You will need to restart AqualinkD after saving config!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cfgValueChanged(event) {
|
||||
var key = event.srcElement.getAttribute('key');
|
||||
var value = event.srcElement.value;
|
||||
|
||||
console.log("Config set "+key+" to "+value)
|
||||
//console.log("Config set '"+key+"'' to '"+value+"'");
|
||||
|
||||
try {
|
||||
_config[key].value = value;
|
||||
|
@ -1379,7 +1479,7 @@
|
|||
console.log("Error setting cfg '"+key+"' to '"+value+"'");
|
||||
}
|
||||
}
|
||||
console.log(_config);
|
||||
//console.log(_config);
|
||||
}
|
||||
|
||||
function update_status(data) {
|
||||
|
@ -1438,6 +1538,26 @@
|
|||
} catch (Error) { }
|
||||
}
|
||||
|
||||
function delayedVersionCheck(currentVersion, call=0) {
|
||||
//console.log("DELAY VERSION call="+call+" - "+currentVersion+". latest "+_latestVersionAvailable);
|
||||
if (_latestVersionAvailable == 0) {
|
||||
if (call > 5) {
|
||||
console.log("ERROR getting latest Aqualinkd version information");
|
||||
return;
|
||||
}
|
||||
setTimeout(function() {
|
||||
delayedVersionCheck(currentVersion, ++call);
|
||||
}, 100);
|
||||
} else {
|
||||
//console.log("VERSION call="+call+" - "+currentVersion+". latest "+_latestVersionAvailable);
|
||||
if ( isNewerVersion(_latestVersionAvailable, currentVersion ) || _urlParams.get('upgrade') != null) {
|
||||
enablebutton("upgrade");
|
||||
} else {
|
||||
disablebutton("upgrade");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setAqManagerOptions(data) {
|
||||
/*
|
||||
read deamonized logging2file logfilename debugmasks[] loglevels[]
|
||||
|
@ -1462,10 +1582,11 @@
|
|||
} else {
|
||||
document.getElementById("latesversionavailable").classList.add("newversion");
|
||||
}
|
||||
if ( isNewerVersion(_latestVersionAvailable, data['aqualinkd_version'] ) || _urlParams.get('upgrade') != null) {
|
||||
enablebutton("upgrade");
|
||||
} else {
|
||||
disablebutton("upgrade");
|
||||
|
||||
delayedVersionCheck(data['aqualinkd_version']);
|
||||
|
||||
if (_urlParams.get('upgrade') != null) {
|
||||
enablebutton("upgrade");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1629,7 +1750,7 @@
|
|||
}, 5000);
|
||||
}
|
||||
} catch (exception) {
|
||||
alert('<p>Error' + exception);
|
||||
//alert('<p>Error' + exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1681,8 +1802,34 @@
|
|||
function init() {
|
||||
// Resize log container
|
||||
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
|
||||
//console.log("Height="+h+" Setting to "+(h-290) );
|
||||
document.documentElement.style.setProperty('--logcontainer-height', (h-290)+'px');
|
||||
var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
|
||||
|
||||
if (h > 0) {
|
||||
try {
|
||||
document.documentElement.style.setProperty('--logcontainer-height', (h-290)+'px');
|
||||
} catch (e) {}
|
||||
} else {
|
||||
console.log("ERROR can't get browser width");
|
||||
}
|
||||
|
||||
|
||||
if (w > 0) {
|
||||
try {
|
||||
var computedStyles = getComputedStyle(document.documentElement);
|
||||
var gw = parseInt(computedStyles.getPropertyValue('--grid-width'));
|
||||
document.documentElement.style.setProperty('--logcontainer-width', (w - gw - 20)+'px');
|
||||
} catch (e) {}
|
||||
//console.log("grid width = " + gw );
|
||||
//console.log("Setting logcontainer width to "+(w-gw) );
|
||||
} else {
|
||||
console.log("ERROR can't get browser height");
|
||||
}
|
||||
|
||||
//computedStyles.getPropertyValue
|
||||
//var element = document.documentElement; // For a variable defined on :root
|
||||
//var computedStyles = getComputedStyle(document.documentElement);
|
||||
//console.log("grid width = " + computedStyles.getPropertyValue('--grid-width') );
|
||||
//console.log("grid width complete= " + computedStyles.getPropertyValue('--grid-width-complete') );
|
||||
|
||||
disablebutton("restart");
|
||||
disablebutton("upgrade");
|
||||
|
@ -1852,14 +1999,14 @@
|
|||
<div class="content" id="logfile">
|
||||
<!--
|
||||
<label class="toggle logtoggle"><input class="toggle-checkbox" type="checkbox" id="logfile"
|
||||
onclick="setlogfile(this);">
|
||||
onclick="requestFileDownload(this);">
|
||||
<div class="toggle-switch"></div><span class="toggle-label">Log to file</span>
|
||||
</label>
|
||||
-->
|
||||
<table border='0'>
|
||||
<tr>
|
||||
<td>
|
||||
<input id="downloadlog" type="button" onclick="setlogfile(this);"
|
||||
<input id="downloadlog" type="button" onclick="requestFileDownload(this);"
|
||||
value="Download logfile"></input>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -1904,6 +2051,10 @@
|
|||
<input id="editconfig" type="button" onclick="editconfig(this);"
|
||||
value="edit config"></input>
|
||||
</td>
|
||||
<td align="center">
|
||||
<input id="downloadconfig" type="button" onclick="requestFileDownload(this);""
|
||||
value="download config"></input>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
// 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/api/devices
|
||||
|
||||
|
||||
var devices = [
|
||||
"Filter_Pump",
|
||||
"Spa",
|
||||
|
@ -38,6 +40,7 @@
|
|||
"CHEM/ORP",
|
||||
"Solar_Heater",
|
||||
"Extra_Aux",
|
||||
"Chiller",
|
||||
"Aux_V1",
|
||||
"Aux_V2",
|
||||
"Aux_V3",
|
||||
|
@ -53,32 +56,18 @@
|
|||
"Aux_V13",
|
||||
"Aux_V14",
|
||||
"Aux_V15",
|
||||
"Chiller",
|
||||
"Sensor/CPU",
|
||||
"Aux_S1",
|
||||
"Aux_S2",
|
||||
"Aux_S3",
|
||||
"Aux_S4",
|
||||
"Aux_S5",
|
||||
"Aux_S6",
|
||||
"Aux_S7",
|
||||
"Aux_S8",
|
||||
"Aux_S9",
|
||||
"Aux_S10",
|
||||
];
|
||||
|
||||
// This get's picked up by dynamic_config.js and used as mode 0
|
||||
// As version 2.5.0 Please use aqualinkd.conf for this configuration.
|
||||
var light_program = [
|
||||
"Voodoo Lounge - Show",
|
||||
"Blue Sea",
|
||||
"Royal Blue",
|
||||
"Afternoon Skies",
|
||||
"Aqua Green",
|
||||
"Emerald",
|
||||
"Cloud White",
|
||||
"Warm Red",
|
||||
"Flamingo",
|
||||
"Vivid Violet",
|
||||
"Sangria",
|
||||
"Twilight - Show",
|
||||
"Tranquility - Show",
|
||||
"Gemstone - Show",
|
||||
"USA - Show",
|
||||
"Mardi Gras - Show",
|
||||
"Cool Cabaret - Show"
|
||||
];
|
||||
|
||||
// all SWG return a status number, some have different meanings. Change the text below to suit, NOT THE NUMBER.
|
||||
var swgStatus = {
|
||||
0: "On",
|
||||
|
|
|
@ -5,4 +5,9 @@ _confighelp["mqtt_address"]="MQTT address has to be set to ip:port enable MQTT"
|
|||
_confighelp["read_RS485_swg"]="Read device information directly from RS485 bus"
|
||||
_confighelp["force_swg"]="Force any devices to be active at startup. Must set these for Home Assistant integration"
|
||||
_confighelp["enable_scheduler"]="AqualinkD's internal scheduler"
|
||||
_confighelp["event_check_use_scheduler_times"]="Turn on filter pump from events that can cause it to turn off"
|
||||
_confighelp["event_check_use_scheduler_times"]="Turn on filter pump from events that can cause it to turn off"
|
||||
_confighelp["sync_panel_time"]="Keep panel time synced with computer"
|
||||
_confighelp["ftdi_low_latency"]="Give RS485 adapter higher priority in kernel (FTDI chips only)"
|
||||
_confighelp["rs485_frame_delay"]="Time for AqualinkD to reply to RS485 messages"
|
||||
_confighelp["light_programming_mode"]="Valid only for AqualinkD programming light color (button_??_light_mode = 0)"
|
||||
//_confighelp["light_program_01"]="Light colors for AqualinkD programmed lights ie (button_??_light_mode = 0)"
|
|
@ -961,7 +961,7 @@
|
|||
|
||||
function switchTileState(id, details) {
|
||||
if (details) {
|
||||
console.log("TILE DETAILS WHAY ARE WE HERE??? '" + id + "'");
|
||||
console.log("TILE DETAILS WHY ARE WE HERE??? '" + id + "'");
|
||||
} else {
|
||||
setTileState(id, (document.getElementById(id).getAttribute('status') == 'off'))
|
||||
}
|
||||
|
@ -1050,8 +1050,8 @@
|
|||
setTileOn(id, 'on');
|
||||
}
|
||||
} catch (e) {
|
||||
// NSF Do we need to create the device?
|
||||
console.log('ERROR id=' + id + ' Line '+new Error().lineNumber+' | element = '+document.getElementById(id));
|
||||
// Devices that are hidden are not found
|
||||
//console.log('ERROR id=' + id + ' Line '+new Error().lineNumber+' | element = '+document.getElementById(id));
|
||||
}
|
||||
//document.getElementById(id + '_tile_icon_value').textContent = value;
|
||||
var tile;
|
||||
|
@ -1284,13 +1284,21 @@
|
|||
return num.toString().padStart(2, "0");
|
||||
}
|
||||
|
||||
function caseInsensitiveIndexOf(array, searchString) {
|
||||
const lowerCaseArray = array.map(element => String(element).toLowerCase());
|
||||
return lowerCaseArray.indexOf(searchString.toLowerCase());
|
||||
}
|
||||
|
||||
function createTile(object) {
|
||||
//console.log("Create tile "+object.id);
|
||||
if (object.name == 'NONE') {
|
||||
//console.log("Create tile <exclude name> "+object);
|
||||
return;
|
||||
}
|
||||
if (typeof devices !== 'undefined' && devices.indexOf(object.id) < 0) {
|
||||
//console.log("Create tile <exclude list> "+object.label);
|
||||
//if (typeof devices !== 'undefined' && devices.indexOf(object.id) < 0) {
|
||||
if (typeof devices !== 'undefined' && caseInsensitiveIndexOf(devices, object.id) < 0) {
|
||||
//console.log("Create tile <exclude list> "+object);
|
||||
//console.log(object);
|
||||
return;
|
||||
}
|
||||
//if (object.type == 'switch' || object.type == 'switch_program') {
|
||||
|
@ -1784,12 +1792,26 @@
|
|||
setTileState(id, state);
|
||||
}
|
||||
} else if (type == 'light_dimmer') {
|
||||
//console.log("DIMMER "+state+" - "+tile.getAttribute('status'));
|
||||
var value = slider.value;
|
||||
if (state == (tile.getAttribute('status') == 'off')) {
|
||||
if (state == false) { //Turn off
|
||||
//console.log("State off");
|
||||
setTileState(id, state);
|
||||
} else if (sp_value != slider.value && dimmer_slider_changed == true) {
|
||||
//console.log("SLIDER CHANGED");
|
||||
setThermostatSetpoint(id, slider.value);
|
||||
} else {
|
||||
//console.log("State on/off");
|
||||
setTileState(id, state);
|
||||
}
|
||||
/*
|
||||
if (state == (tile.getAttribute('status') == 'off')) {
|
||||
console.log("ON/OFF "+state+" = "+(tile.getAttribute('status') == 'off'));
|
||||
setTileState(id, state);
|
||||
} else if (sp_value != slider.value && dimmer_slider_changed == true) {
|
||||
console.log("SLIDER CHANGED");
|
||||
setThermostatSetpoint(id, slider.value);
|
||||
}*/
|
||||
} else if (type == 'setpoint_swg') {
|
||||
//console.log ("Boost attribute = "+tile.getAttribute('boost'));
|
||||
//console.log ("state = "+state);
|
||||
|
@ -2350,7 +2372,8 @@
|
|||
|
||||
for (var obj in data.sensors) {
|
||||
//console.log("Set Value `Sensor/"+obj.toString()+"' to "+data.sensors[obj]);
|
||||
setTileValue("Sensor/"+obj.toString(), data.sensors[obj]);
|
||||
//setTileValue("Sensor/"+obj.toString(), data.sensors[obj]);
|
||||
setTileValue(obj.toString(), data.sensors[obj]);
|
||||
}
|
||||
|
||||
for (var obj in data.alternate_modes) {
|
||||
|
@ -2480,8 +2503,10 @@
|
|||
var pa;
|
||||
var pb;
|
||||
try {
|
||||
pa = devices.indexOf(a.id);
|
||||
pb = devices.indexOf(b.id);
|
||||
//pa = devices.indexOf(a.id);
|
||||
//pb = devices.indexOf(b.id);
|
||||
pa = caseInsensitiveIndexOf(devices,a.id);
|
||||
pb = caseInsensitiveIndexOf(devices,b.id);
|
||||
if (pa > pb)
|
||||
return 1;
|
||||
else if (pa < pb)
|
||||
|
|
Loading…
Reference in New Issue