mirror of https://github.com/sfeakes/AqualinkD.git
Compare commits
161 Commits
Author | SHA1 | Date |
---|---|---|
|
6472e3ccd8 | |
|
d789fc2cfb | |
|
76f3adfcb9 | |
|
d23db569d0 | |
|
c04ec5ce01 | |
|
47c56ee5d4 | |
|
5fcbc2a2e9 | |
|
a410d31ad6 | |
|
4faa2e0db0 | |
|
a38a1c6e00 | |
|
1965a7460c | |
|
39a8ca5684 | |
|
411891fd88 | |
|
766ddbc502 | |
|
0b3e98559e | |
|
b0ead8dfe9 | |
|
53c88deda2 | |
|
c3a15de5ab | |
|
d203927d12 | |
|
2e6140aa67 | |
|
25bcdce8ff | |
|
b7a41968d6 | |
|
7973213889 | |
|
65b845743d | |
|
d6e55357d5 | |
|
3b79c83d02 | |
|
32f1aac02e | |
|
fd3c64b9c2 | |
|
6ef38924ed | |
|
765339a51f | |
|
3608f9f4ae | |
|
0b1b7f055f | |
|
465534c9af | |
|
3399664ee5 | |
|
3f2544b1a4 | |
|
0491f2ab01 | |
|
f62f7f786c | |
|
1b785e0cb8 | |
|
eede6d129a | |
|
a972030fd0 | |
|
e52bc7aada | |
|
e81569c3ee | |
|
6bba1462a4 | |
|
c1675b94e3 | |
|
74b149afbc | |
|
e88f21569a | |
|
cbf65679bc | |
|
32f3d8b042 | |
|
d447c13777 | |
|
e0109d738b | |
|
e3dc3dbabb | |
|
2d717fbe74 | |
|
f4e67c8a4f | |
|
e47aaeff78 | |
|
375f66437e | |
|
eee110b043 | |
|
bdbe315c10 | |
|
d945d438d7 | |
|
dba4f553b7 | |
|
d4397f8f27 | |
|
336224a66c | |
|
47820a1ef9 | |
|
cb605b94a6 | |
|
a54f55c60b | |
|
3f9a5d130d | |
|
b684f920a3 | |
|
a3b8546557 | |
|
461b204a22 | |
|
60e6541d09 | |
|
40e2c38ce0 | |
|
748f6f0bfa | |
|
c5c04e30e4 | |
|
3c2b67b37d | |
|
7cd5846864 | |
|
2f7c001059 | |
|
b85f3b5620 | |
|
b09bd63b83 | |
|
2af8f552ef | |
|
0520aee4a0 | |
|
decec48293 | |
|
09029c9202 | |
|
bbb5ff3c86 | |
|
f3943043f5 | |
|
7a27d80b73 | |
|
322924617d | |
|
08f23243d8 | |
|
10bd3a4dcb | |
|
fdd549196e | |
|
c70f4cea21 | |
|
f78c0f43e7 | |
|
8efb82a94f | |
|
d7b1fc8d9b | |
|
dbbd0dda0c | |
|
dd72a3c8da | |
|
b2d0a165b1 | |
|
33aa440eff | |
|
3732ec81c6 | |
|
767745c97d | |
|
675b0f52d1 | |
|
7c37a7cc23 | |
|
868cb8b790 | |
|
d042fd481a | |
|
54c8584c3f | |
|
1365e76628 | |
|
0c156be8a6 | |
|
9697969de0 | |
|
df0c529261 | |
|
a033fc3fbf | |
|
9d580cb3d3 | |
|
6768ca5d90 | |
|
69f9a5c176 | |
|
61a09820b6 | |
|
c3e0e319b4 | |
|
22adf0642f | |
|
4e4afc1071 | |
|
54b44b6c70 | |
|
41c5f69fd6 | |
|
8fbdabeb54 | |
|
6e5d4be956 | |
|
218d427b0e | |
|
921980cac6 | |
|
07cbff0104 | |
|
d4bc8227eb | |
|
aac882dca9 | |
|
a98dcd62d3 | |
|
17b3f853a5 | |
|
25e3e80f5a | |
|
052d44c404 | |
|
f5a530700f | |
|
7cca4215aa | |
|
1f8001e939 | |
|
ad8a07cebd | |
|
28a50be715 | |
|
64bc1c3e5f | |
|
4aedcc722d | |
|
ac48a5e677 | |
|
82367eb42c | |
|
42064d1880 | |
|
6417b59a30 | |
|
a62b7fe03e | |
|
79cf3e8c94 | |
|
636892e494 | |
|
de5c062eb4 | |
|
796bb3e2b0 | |
|
3ad7b71b49 | |
|
a97d058dda | |
|
2d0647ab8d | |
|
94320139f1 | |
|
642bfc3383 | |
|
4a6c948a6a | |
|
1e1e825829 | |
|
487685d24b | |
|
b7ad1eac03 | |
|
07dc69ad60 | |
|
57978e4419 | |
|
000ccca55f | |
|
09e665bebc | |
|
77b24688aa | |
|
d86e25cd35 | |
|
5aab2be415 | |
|
52d336d2a4 |
547
Makefile
547
Makefile
|
@ -1,29 +1,38 @@
|
|||
#
|
||||
# Options
|
||||
#
|
||||
# make // standard everything
|
||||
# make debug // Give standard binary just with debugging
|
||||
# make // standard build aqualinkd and serial_logger
|
||||
# make debug // Compule standard aqualinkd binary just with debugging
|
||||
# make aqdebug // Compile with extra aqualink debug information like timings
|
||||
# make slog // Serial logger
|
||||
# make <other> // not documenting
|
||||
# make <other> // not documenting
|
||||
#
|
||||
|
||||
# Valid flags for AQ_FLAGS
|
||||
AQ_RS16 = true
|
||||
#AQ_RS16 = true
|
||||
AQ_PDA = true
|
||||
AQ_ONETOUCH = true
|
||||
AQ_IAQTOUCH = true
|
||||
#AQ_ONETOUCH = true
|
||||
#AQ_IAQTOUCH = true
|
||||
AQ_MANAGER = true
|
||||
|
||||
#AQ_RS_EXTRA_OPTS = false
|
||||
#AQ_CONTAINER = false // this is for compiling for containers
|
||||
#AQ_MEMCMP = true // Not implimented correctly yet.
|
||||
|
||||
# Turn off threadded net services
|
||||
AQ_NO_THREAD_NETSERVICE = false
|
||||
|
||||
# define the C compiler to use
|
||||
# define the C compiler(s) to use
|
||||
CC = gcc
|
||||
CC_ARM64 = aarch64-linux-gnu-gcc
|
||||
CC_ARMHF = arm-linux-gnueabihf-gcc
|
||||
CC_AMD64 = x86_64-linux-gnu-gcc
|
||||
|
||||
#LIBS := -lpthread -lm
|
||||
LIBS := -l pthread -l m
|
||||
#LIBS := -l pthread -l m
|
||||
#LIBS := -l pthread -l m -static # Take out -static, just for dev
|
||||
# from documentation -lrt would be needed for glibc 2.17 & prior (debug clock realtime messages), but seems to be needed for armhf 2.24
|
||||
LIBS := -lpthread -lm -lrt
|
||||
|
||||
# Standard compile flags
|
||||
GCCFLAGS = -Wall -O3
|
||||
|
@ -43,67 +52,82 @@ DBGFLAGS = -g -O0 -Wall -D AQ_DEBUG -D AQ_TM_DEBUG
|
|||
#MGFLAGS = -D MG_DISABLE_MD5 -D MG_DISABLE_HTTP_DIGEST_AUTH -D MG_DISABLE_MD5 -D MG_DISABLE_JSON_RPC
|
||||
# Mongoose 6.18 flags
|
||||
MGFLAGS = -D MG_ENABLE_HTTP_SSI=0 -D MG_ENABLE_DIRECTORY_LISTING=0 -D MG_ENABLE_HTTP_CGI=0
|
||||
#MGFLAGS =
|
||||
#MGFLAGS =
|
||||
|
||||
# Detect OS and set some specifics
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows Make.
|
||||
RM = del /Q
|
||||
MKDIR = mkdir
|
||||
FixPath = $(subst /,\,$1)
|
||||
else
|
||||
UNAME_S := $(shell uname -s)
|
||||
# Linux
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
RM = rm -f
|
||||
MKDIR = mkdir -p
|
||||
FixPath = $1
|
||||
FixPath = $1
|
||||
# Get some system information
|
||||
PI_OS_VERSION = $(shell cat /etc/os-release | grep VERSION= | cut -d\" -f2)
|
||||
$(info OS: $(PI_OS_VERSION) )
|
||||
GLIBC_VERSION = $(shell ldd --version | grep ldd)
|
||||
$(info GLIBC build with: $(GLIBC_VERSION) )
|
||||
$(info GLIBC Prefered : 2.24-11+deb9u1 2.24 )
|
||||
# PI_OS_VERSION = $(shell cat /etc/os-release | grep VERSION= | cut -d\" -f2)
|
||||
# $(info OS: $(PI_OS_VERSION) )
|
||||
# GLIBC_VERSION = $(shell ldd --version | grep ldd)
|
||||
# $(info GLIBC build with: $(GLIBC_VERSION) )
|
||||
# $(info GLIBC Prefered : 2.24-11+deb9u1 2.24 )
|
||||
endif
|
||||
# OSX
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
MKDIR = mkdir -p
|
||||
FixPath = $1
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# Main source files
|
||||
SRCS = aqualinkd.c utils.c config.c aq_serial.c aq_panel.c aq_programmer.c net_services.c json_messages.c rs_msg_utils.c\
|
||||
SRCS = aqualinkd.c utils.c config.c aq_serial.c aq_panel.c aq_programmer.c allbutton.c allbutton_aq_programmer.c net_services.c json_messages.c rs_msg_utils.c\
|
||||
onetouch.c onetouch_aq_programmer.c iaqtouch.c iaqtouch_aq_programmer.c iaqualink.c\
|
||||
devices_jandy.c packetLogger.c devices_pentair.c color_lights.c serialadapter.c aq_timer.c aq_scheduler.c web_config.c\
|
||||
mongoose.c
|
||||
serial_logger.c mongoose.c hassio.c simulator.c sensors.c aq_systemutils.c timespec_subtract.c
|
||||
|
||||
|
||||
AQ_FLAGS =
|
||||
AQ_FLAGS =
|
||||
# Add source and flags depending on protocols to support.
|
||||
ifeq ($(AQ_PDA), true)
|
||||
SRCS := $(SRCS) pda.c pda_menu.c pda_aq_programmer.c
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_PDA
|
||||
endif
|
||||
|
||||
ifeq ($(AQ_ONETOUCH), true)
|
||||
SRCS := $(SRCS) onetouch.c onetouch_aq_programmer.c
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_ONETOUCH
|
||||
endif
|
||||
#ifeq ($(AQ_ONETOUCH), true)
|
||||
# SRCS := $(SRCS) onetouch.c onetouch_aq_programmer.c
|
||||
# AQ_FLAGS := $(AQ_FLAGS) -D AQ_ONETOUCH
|
||||
#endif
|
||||
|
||||
ifeq ($(AQ_IAQTOUCH), true)
|
||||
SRCS := $(SRCS) iaqtouch.c iaqtouch_aq_programmer.c
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_IAQTOUCH
|
||||
endif
|
||||
#ifeq ($(AQ_IAQTOUCH), true)
|
||||
# SRCS := $(SRCS) iaqtouch.c iaqtouch_aq_programmer.c iaqualink.c
|
||||
# AQ_FLAGS := $(AQ_FLAGS) -D AQ_IAQTOUCH
|
||||
#endif
|
||||
|
||||
ifeq ($(AQ_RS16), true)
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_RS16
|
||||
endif
|
||||
#ifeq ($(AQ_RS16), true)
|
||||
# AQ_FLAGS := $(AQ_FLAGS) -D AQ_RS16
|
||||
#endif
|
||||
|
||||
ifeq ($(AQ_MEMCMP), true)
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_MEMCMP
|
||||
endif
|
||||
|
||||
ifeq ($(AQ_NO_THREAD_NETSERVICE), true)
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_NO_THREAD_NETSERVICE
|
||||
|
||||
ifeq ($(AQ_MANAGER), true)
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_MANAGER
|
||||
LIBS := $(LIBS) -lsystemd
|
||||
# aq_manager requires threads, so make sure that's turned on.
|
||||
ifeq ($(AQ_NO_THREAD_NETSERVICE), true)
|
||||
# Show error
|
||||
$(warning AQ_MANAGER requires threads, ignoring AQ_NO_THREAD_NETSERVICE)
|
||||
endif
|
||||
else
|
||||
# No need for serial_logger without aq_manager
|
||||
SRCS := $(filter-out serial_logger.c, $(SRCS))
|
||||
# no threadded net service only valid without aq manager.
|
||||
ifeq ($(AQ_NO_THREAD_NETSERVICE), true)
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_NO_THREAD_NETSERVICE
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
|
@ -114,27 +138,118 @@ DBG_CFLAGS = $(DBGFLAGS) $(AQ_FLAGS) $(MGFLAGS)
|
|||
|
||||
# Other sources.
|
||||
DBG_SRC = $(SRCS) debug_timer.c
|
||||
SL_SRC = serial_logger.c aq_serial.c utils.c packetLogger.c rs_msg_utils.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
|
||||
|
||||
# Build durectories
|
||||
SRC_DIR := ./source
|
||||
OBJ_DIR := ./build
|
||||
DBG_OBJ_DIR := $(OBJ_DIR)/debug
|
||||
SL_OBJ_DIR := $(OBJ_DIR)/slog
|
||||
DD_OBJ_DIR := $(OBJ_DIR)/dummydevice
|
||||
|
||||
# Object files
|
||||
OBJ_FILES := $(patsubst %.c,$(OBJ_DIR)/%.o,$(SRCS))
|
||||
DBG_OBJ_FILES := $(patsubst %.c,$(DBG_OBJ_DIR)/%.o,$(DBG_SRC))
|
||||
SL_OBJ_FILES := $(patsubst %.c,$(SL_OBJ_DIR)/%.o,$(SL_SRC))
|
||||
INCLUDES := -I$(SRC_DIR)
|
||||
|
||||
# define path for obj files per architecture
|
||||
OBJ_DIR_ARMHF := $(OBJ_DIR)/armhf
|
||||
OBJ_DIR_ARM64 := $(OBJ_DIR)/arm64
|
||||
OBJ_DIR_AMD64 := $(OBJ_DIR)/amd64
|
||||
SL_OBJ_DIR_ARMHF := $(OBJ_DIR_ARMHF)/slog
|
||||
SL_OBJ_DIR_ARM64 := $(OBJ_DIR_ARM64)/slog
|
||||
SL_OBJ_DIR_AMD64 := $(OBJ_DIR_AMD64)/slog
|
||||
|
||||
# append path to source
|
||||
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))
|
||||
|
||||
# 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))
|
||||
|
||||
OBJ_FILES_ARMHF := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR_ARMHF)/%.o,$(SRCS))
|
||||
OBJ_FILES_ARM64 := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR_ARM64)/%.o,$(SRCS))
|
||||
OBJ_FILES_AMD64 := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR_AMD64)/%.o,$(SRCS))
|
||||
|
||||
SL_OBJ_FILES_ARMHF := $(patsubst $(SRC_DIR)/%.c,$(SL_OBJ_DIR_ARMHF)/%.o,$(SL_SRC))
|
||||
SL_OBJ_FILES_ARM64 := $(patsubst $(SRC_DIR)/%.c,$(SL_OBJ_DIR_ARM64)/%.o,$(SL_SRC))
|
||||
SL_OBJ_FILES_AMD64 := $(patsubst $(SRC_DIR)/%.c,$(SL_OBJ_DIR_AMD64)/%.o,$(SL_SRC))
|
||||
|
||||
#OBJ_FILES := $(patsubst %.c,$(OBJ_DIR)/%.o,$(SRCS))
|
||||
#DBG_OBJ_FILES := $(patsubst %.c,$(DBG_OBJ_DIR)/%.o,$(DBG_SRC))
|
||||
#SL_OBJ_FILES := $(patsubst %.c,$(SL_OBJ_DIR)/%.o,$(SL_SRC))
|
||||
|
||||
#OBJ_FILES_ARMHF := $(patsubst %.c,$(OBJ_DIR_ARMHF)/%.o,$(SRCS))
|
||||
#OBJ_FILES_ARM64 := $(patsubst %.c,$(OBJ_DIR_ARM64)/%.o,$(SRCS))
|
||||
#OBJ_FILES_AMD64 := $(patsubst %.c,$(OBJ_DIR_AMD64)/%.o,$(SRCS))
|
||||
|
||||
#SL_OBJ_FILES_ARMHF := $(patsubst %.c,$(SL_OBJ_DIR_ARMHF)/%.o,$(SL_SRC))
|
||||
#SL_OBJ_FILES_ARM64 := $(patsubst %.c,$(SL_OBJ_DIR_ARM64)/%.o,$(SL_SRC))
|
||||
#SL_OBJ_FILES_AMD64 := $(patsubst %.c,$(SL_OBJ_DIR_AMD64)/%.o,$(SL_SRC))
|
||||
|
||||
|
||||
#MG_OBJ_FILES := $(patsubst %.c,$(OBJ_DIR)/%.o,$(MG_SRC))
|
||||
|
||||
# define the executable file
|
||||
MAIN = ./release/aqualinkd
|
||||
SLOG = ./release/serial_logger
|
||||
DEBG = ./release/aqualinkd-debug
|
||||
DDEVICE = ./release/dummydevice
|
||||
|
||||
MAIN_ARM64 = ./release/aqualinkd-arm64
|
||||
MAIN_ARMHF = ./release/aqualinkd-armhf
|
||||
MAIN_AMD64 = ./release/aqualinkd-amd64
|
||||
|
||||
SLOG_ARM64 = ./release/serial_logger-arm64
|
||||
SLOG_ARMHF = ./release/serial_logger-armhf
|
||||
SLOG_AMD64 = ./release/serial_logger-amd64
|
||||
|
||||
#LOGR = ./release/log_reader
|
||||
#PLAY = ./release/aqualinkd-player
|
||||
|
||||
|
||||
# Rules with no targets
|
||||
.PHONY: clean clean-buildfiles buildrelease release install
|
||||
|
||||
# Default target
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
# Before the below works, you need to build the aqualinkd-releasebin docker for compiling.
|
||||
# sudo docker build -f Dockerfile.releaseBinaries -t aqualinkd-releasebin .
|
||||
# Something like below
|
||||
#releasebuilddocker:
|
||||
# sudo docker build -f ./docker/Dockerfile.releaseBinaries -t aqualinkd-releasebin .
|
||||
# $(info Docker for building release binaries has been created)
|
||||
|
||||
release:
|
||||
sudo docker run -it --mount type=bind,source=./,target=/build aqualinkd-releasebin make buildrelease
|
||||
$(info Binaries for release have been built)
|
||||
|
||||
quick:
|
||||
sudo docker run -it --mount type=bind,source=./,target=/build aqualinkd-releasebin make quickbuild
|
||||
$(info Binaries for release have been built)
|
||||
|
||||
debugbinaries:
|
||||
sudo docker run -it --mount type=bind,source=./,target=/build aqualinkd-releasebin make debugbuild
|
||||
$(info Binaries for release have been built)
|
||||
|
||||
# This is run inside container Dockerfile.releaseBinariies (aqualinkd-releasebin)
|
||||
buildrelease: clean armhf arm64
|
||||
$(shell cd release && ln -s ./aqualinkd-armhf ./aqualinkd && ln -s ./serial_logger-armhf ./serial_logger)
|
||||
|
||||
# This is run inside container Dockerfile.releaseBinariies (aqualinkd-releasebin)
|
||||
quickbuild: armhf arm64
|
||||
$(shell cd release && [ ! -f "./aqualinkd-armhf" ] && ln -s ./aqualinkd-armhf ./aqualinkd && ln -s ./serial_logger-armhf ./serial_logger)
|
||||
|
||||
debugbuild: CFLAGS = $(DFLAGS)
|
||||
debugbuild: armhf arm64
|
||||
$(shell cd release && [ ! -f "./aqualinkd-armhf" ] && ln -s ./aqualinkd-armhf ./aqualinkd && ln -s ./serial_logger-armhf ./serial_logger)
|
||||
|
||||
|
||||
# Rules to pass to make.
|
||||
all: $(MAIN) $(SLOG)
|
||||
$(info $(MAIN) has been compiled)
|
||||
|
@ -146,271 +261,155 @@ slog: $(SLOG)
|
|||
aqdebug: $(DEBG)
|
||||
$(info $(DEBG) has been compiled)
|
||||
|
||||
dummydevice: $(DDEVICE)
|
||||
$(info $(DDEVICE) has been compiled)
|
||||
|
||||
# Container, add container flag and compile
|
||||
container: CFLAGS := $(CFLAGS) -D AQ_CONTAINER
|
||||
container: $(MAIN) $(SLOG)
|
||||
$(info $(MAIN) has been compiled (** For Container use **))
|
||||
$(info $(SLOG) has been compiled (** For Container use **))
|
||||
|
||||
container-arm64: CC := $(CC_ARM64)
|
||||
container-arm64: container
|
||||
|
||||
container-amd64: CC := $(CC_AMD64)
|
||||
container-amd64: container
|
||||
|
||||
# armhf
|
||||
armhf: CC := $(CC_ARMHF)
|
||||
armhf: $(MAIN_ARMHF) $(SLOG_ARMHF)
|
||||
$(info $(MAIN_ARMHF) has been compiled)
|
||||
$(info $(SLOG_ARMHF) has been compiled)
|
||||
|
||||
# arm64
|
||||
arm64: CC := $(CC_ARM64)
|
||||
arm64: $(MAIN_ARM64) $(SLOG_ARM64)
|
||||
$(info $(MAIN_ARM64) has been compiled)
|
||||
$(info $(SLOG_ARM64) has been compiled)
|
||||
|
||||
# amd64
|
||||
amd64: CC := $(CC_AMD64)
|
||||
amd64: $(MAIN_AMD64) $(SLOG_AMD64)
|
||||
$(info $(MAIN_AMD64) has been compiled)
|
||||
$(info $(SLOG_AMD64) has been compiled)
|
||||
|
||||
#debug, Just change compile flags and call MAIN
|
||||
debug: CFLAGS = $(DFLAGS)
|
||||
debug: $(MAIN) $(SLOG)
|
||||
$(info $(MAIN) has been compiled (** DEBUG **))
|
||||
$(info $(SLOG) has been compiled (** DEBUG **))
|
||||
|
||||
install: $(MAIN)
|
||||
./release/install.sh
|
||||
#install: $(MAIN)
|
||||
install:
|
||||
./release/install.sh from-make
|
||||
|
||||
|
||||
# Rules to compile
|
||||
$(OBJ_DIR)/%.o: %.c | $(OBJ_DIR)
|
||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
$(DBG_OBJ_DIR)/%.o: %.c | $(DBG_OBJ_DIR)
|
||||
$(DBG_OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(DBG_OBJ_DIR)
|
||||
$(CC) $(DBG_CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
$(SL_OBJ_DIR)/%.o: %.c | $(SL_OBJ_DIR)
|
||||
$(SL_OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(SL_OBJ_DIR)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
$(DD_OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(DD_OBJ_DIR)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
$(OBJ_DIR_ARMHF)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR_ARMHF)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
$(SL_OBJ_DIR_ARMHF)/%.o: $(SRC_DIR)/%.c | $(SL_OBJ_DIR_ARMHF)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
$(OBJ_DIR_ARM64)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR_ARM64)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
$(SL_OBJ_DIR_ARM64)/%.o: $(SRC_DIR)/%.c | $(SL_OBJ_DIR_ARM64)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
$(OBJ_DIR_AMD64)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR_AMD64)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
$(SL_OBJ_DIR_AMD64)/%.o: $(SRC_DIR)/%.c | $(SL_OBJ_DIR_AMD64)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
# Rules to link
|
||||
$(MAIN): $(OBJ_FILES)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) $(LIBS) -o $@ $^
|
||||
$(MAIN): $(OBJ_FILES)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LIBS)
|
||||
|
||||
$(DEBG): $(DBG_OBJ_FILES)
|
||||
$(CC) $(DBG_CFLAGS) $(INCLUDES) $(LIBS) -o $@ $^
|
||||
$(MAIN_ARM64): $(OBJ_FILES_ARM64)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LIBS)
|
||||
|
||||
$(MAIN_ARMHF): $(OBJ_FILES_ARMHF)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LIBS)
|
||||
|
||||
$(MAIN_AMD64): $(OBJ_FILES_AMD64)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LIBS)
|
||||
|
||||
$(DEBG): $(DBG_OBJ_FILES)
|
||||
$(CC) $(DBG_CFLAGS) $(INCLUDES) -o $@ $^ $(LIBS)
|
||||
|
||||
$(SLOG): CFLAGS := $(CFLAGS) -D SERIAL_LOGGER
|
||||
$(SLOG): $(SL_OBJ_FILES)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) $(LIBS) -o $@ $^
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LIBS)
|
||||
|
||||
$(SLOG_ARMHF): CFLAGS := $(CFLAGS) -D SERIAL_LOGGER
|
||||
$(SLOG_ARMHF): $(SL_OBJ_FILES_ARMHF)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LIBS)
|
||||
|
||||
$(SLOG_ARM64): CFLAGS := $(CFLAGS) -D SERIAL_LOGGER
|
||||
$(SLOG_ARM64): $(SL_OBJ_FILES_ARM64)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LIBS)
|
||||
|
||||
$(SLOG_AMD64): CFLAGS := $(CFLAGS) -D SERIAL_LOGGER
|
||||
$(SLOG_AMD64): $(SL_OBJ_FILES_AMD64)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LIBS)
|
||||
|
||||
$(DDEVICE): CFLAGS := $(CFLAGS) -D SERIAL_LOGGER -D DUMMY_DEVICE
|
||||
$(DDEVICE): $(DD_OBJ_FILES)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LIBS)
|
||||
|
||||
# Rules to make object directories.
|
||||
$(OBJ_DIR):
|
||||
$(MKDIR) $@
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(SL_OBJ_DIR):
|
||||
$(MKDIR) $@
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(DD_OBJ_DIR):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(DBG_OBJ_DIR):
|
||||
$(MKDIR) $@
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(OBJ_DIR_ARMHF):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(SL_OBJ_DIR_ARMHF):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(OBJ_DIR_ARM64):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(SL_OBJ_DIR_ARM64):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(OBJ_DIR_AMD64):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(SL_OBJ_DIR_AMD64):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
# Clean rules
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) *.o *~ $(MAIN) $(MAIN_U) $(PLAY) $(PL_EXOBJ) $(DEBG)
|
||||
$(RM) $(wildcard *.o) $(wildcard *~) $(OBJ_FILES) $(DBG_OBJ_FILES) $(SL_OBJ_FILES) $(MAIN) $(MAIN_U) $(PLAY) $(PL_EXOBJ) $(LOGR) $(PLAY) $(DEBG)
|
||||
|
||||
clean: clean-buildfiles
|
||||
$(RM) *.o *~ $(MAIN) $(MAIN_U) $(PLAY) $(PL_EXOBJ) $(DEBG) $(DDEVICE)
|
||||
$(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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
define DO_NOT_USE
|
||||
|
||||
# OLD MAKEFILE, STILL NEED TO MOVE THE BELOW OVER TO NEW Makefile
|
||||
LOGR = ./release/log_reader
|
||||
PLAY = ./release/aqualinkd-player
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Options
|
||||
#
|
||||
# make // standard everything
|
||||
# make debug // Give standard binary just with debugging
|
||||
# make aqdebug // Compile with extra aqualink debug information like timings
|
||||
# make slog // Serial logger
|
||||
# make <other> // not documenting
|
||||
#
|
||||
|
||||
# Valid flags for AQ_FLAGS
|
||||
AQ_RS16 = true
|
||||
AQ_PDA = true
|
||||
AQ_ONETOUCH = true
|
||||
AQ_IAQTOUCH = true
|
||||
#AQ_MEMCMP = true // Not implimented correctly yet.
|
||||
|
||||
# Turn off threadded net services
|
||||
AQ_NO_THREAD_NETSERVICE = false
|
||||
|
||||
# Get some system information
|
||||
PI_OS_VERSION = $(shell cat /etc/os-release | grep VERSION= | cut -d\" -f2)
|
||||
$(info OS: $(PI_OS_VERSION) )
|
||||
GLIBC_VERSION = $(shell ldd --version | grep ldd)
|
||||
$(info GLIBC build with: $(GLIBC_VERSION) )
|
||||
$(info GLIBC Prefered : 2.24-11+deb9u1 2.24 )
|
||||
|
||||
|
||||
# define the C compiler to use
|
||||
CC = gcc
|
||||
|
||||
#LIBS := -lpthread -lm
|
||||
LIBS := -l pthread -l m
|
||||
#LIBS := -l pthread -l m -static # Take out -static, just for dev
|
||||
|
||||
# Standard compile flags
|
||||
GCCFLAGS = -Wall -O3
|
||||
#GCCFLAGS = -O3
|
||||
#GCCFLAGS = -Wall -O3 -Wextra
|
||||
#GCCFLAGS = -Wl,--gc-sections,--print-gc-sections
|
||||
#GCCFLAGS = -Wall -O3 -ffunction-sections -fdata-sections
|
||||
|
||||
# Standard debug flags
|
||||
DGCCFLAGS = -Wall -O0 -g
|
||||
|
||||
# Aqualink Debug flags
|
||||
#DBGFLAGS = -g -O0 -Wall -fsanitize=address -D AQ_DEBUG -D AQ_TM_DEBUG
|
||||
DBGFLAGS = -g -O0 -Wall -D AQ_DEBUG -D AQ_TM_DEBUG
|
||||
|
||||
# Mongoose flags
|
||||
#MGFLAGS = -D MG_DISABLE_MD5 -D MG_DISABLE_HTTP_DIGEST_AUTH -D MG_DISABLE_MD5 -D MG_DISABLE_JSON_RPC
|
||||
# Mongoose 6.18 flags
|
||||
MGFLAGS = -D MG_ENABLE_HTTP_SSI=0 -D MG_ENABLE_DIRECTORY_LISTING=0 -D MG_ENABLE_HTTP_CGI=0
|
||||
#MGFLAGS =
|
||||
|
||||
# define the C source files
|
||||
#SRCS = aqualinkd.c utils.c config.c aq_serial.c init_buttons.c aq_programmer.c net_services.c json_messages.c pda.c pda_menu.c \
|
||||
# pda_aq_programmer.c devices_jandy.c onetouch.c onetouch_aq_programmer.c packetLogger.c devices_pentair.c color_lights.c mongoose.c
|
||||
|
||||
SRCS = aqualinkd.c utils.c config.c aq_serial.c aq_panel.c aq_programmer.c net_services.c json_messages.c rs_msg_utils.c\
|
||||
devices_jandy.c packetLogger.c devices_pentair.c color_lights.c serialadapter.c aq_timer.c aq_scheduler.c web_config.c\
|
||||
mongoose.c
|
||||
|
||||
|
||||
AQ_FLAGS =
|
||||
# Add source and flags depending on protocols to support.
|
||||
ifeq ($(AQ_PDA), true)
|
||||
SRCS := $(SRCS) pda.c pda_menu.c pda_aq_programmer.c
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_PDA
|
||||
endif
|
||||
|
||||
ifeq ($(AQ_ONETOUCH), true)
|
||||
SRCS := $(SRCS) onetouch.c onetouch_aq_programmer.c
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_ONETOUCH
|
||||
endif
|
||||
|
||||
ifeq ($(AQ_IAQTOUCH), true)
|
||||
SRCS := $(SRCS) iaqtouch.c iaqtouch_aq_programmer.c
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_IAQTOUCH
|
||||
endif
|
||||
|
||||
ifeq ($(AQ_RS16), true)
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_RS16
|
||||
endif
|
||||
|
||||
ifeq ($(AQ_MEMCMP), true)
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_MEMCMP
|
||||
endif
|
||||
|
||||
ifeq ($(AQ_NO_THREAD_NETSERVICE), true)
|
||||
AQ_FLAGS := $(AQ_FLAGS) -D AQ_NO_THREAD_NETSERVICE
|
||||
endif
|
||||
|
||||
|
||||
# Put all flags together.
|
||||
CFLAGS = $(GCCFLAGS) $(AQ_FLAGS) $(MGFLAGS)
|
||||
DFLAGS = $(DGCCFLAGS) $(AQ_FLAGS) $(MGFLAGS)
|
||||
DBG_CFLAGS = $(DBGFLAGS) $(AQ_FLAGS) $(MGFLAGS)
|
||||
|
||||
# Other sources.
|
||||
#DBG_SRC = timespec_subtract.c debug_timer.c
|
||||
DBG_SRC = debug_timer.c
|
||||
SL_SRC = serial_logger.c aq_serial.c utils.c packetLogger.c rs_msg_utils.c
|
||||
LR_SRC = log_reader.c aq_serial.c utils.c packetLogger.c
|
||||
PL_EXSRC = aq_serial.c
|
||||
PL_EXOBJ = aq_serial_player.o
|
||||
PL_SRC := $(filter-out aq_serial.c, $(SRCS))
|
||||
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
DBG_OBJS = $(DBG_SRC:.c=.o)
|
||||
|
||||
SL_OBJS = $(SL_SRC:.c=.o)
|
||||
LR_OBJS = $(LR_SRC:.c=.o)
|
||||
PL_OBJS = $(PL_SRC:.c=.o)
|
||||
|
||||
|
||||
# define the executable file
|
||||
MAIN = ./release/aqualinkd
|
||||
SLOG = ./release/serial_logger
|
||||
LOGR = ./release/log_reader
|
||||
PLAY = ./release/aqualinkd-player
|
||||
DEBG = ./release/aqualinkd-debug
|
||||
|
||||
|
||||
all: $(MAIN) $(SLOG)
|
||||
$(info $(MAIN) has been compiled)
|
||||
$(info $(SLOG) has been compiled)
|
||||
|
||||
# debug, Just change compile flags and call MAIN
|
||||
debug: CFLAGS = $(DFLAGS)
|
||||
debug: $(MAIN)
|
||||
$(info $(MAIN) has been compiled)
|
||||
|
||||
$(MAIN): $(OBJS)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LIBS)
|
||||
$(info $(MAIN) has been compiled)
|
||||
|
||||
slog: $(SLOG)
|
||||
$(info $(SLOG) has been compiled)
|
||||
|
||||
$(SLOG): CFLAGS := $(CFLAGS) -D SERIAL_LOGGER
|
||||
$(SLOG): $(SL_OBJS)
|
||||
# $(CC) $(CFLAGS) $(INCLUDES) -o $(SLOG) $(SL_OBJS)
|
||||
$(CC) $(INCLUDES) -o $(SLOG) $(SL_OBJS)
|
||||
|
||||
|
||||
#.PHONY: clean_slog_o
|
||||
#clean_slog_o:
|
||||
# $(RM) $(SL_OBJS)
|
||||
#
|
||||
#.PHONY: test
|
||||
#test: $(SLOG)
|
||||
#test: clean_slog_o
|
||||
#test: $(MAIN)
|
||||
|
||||
# Shouldn't need to use any of these options unless you're developing.
|
||||
|
||||
aqdebug: $(DEBG)
|
||||
$(info $(DEBG) has been compiled)
|
||||
|
||||
$(DEBG): CFLAGS = $(DBG_CFLAGS)
|
||||
$(DEBG): $(OBJS) $(DBG_OBJS)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $(DEBG) $(OBJS) $(DBG_OBJS) $(DBGFLAGS) $(LIBS)
|
||||
|
||||
logr: $(LOGR)
|
||||
$(info $(LOGR) has been compiled)
|
||||
|
||||
$(LOGR): $(LR_OBJS)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $(LOGR) $(LR_OBJS)
|
||||
|
||||
player: $(PLAY)
|
||||
$(info $(PLAY) has been compiled)
|
||||
|
||||
$(PL_EXOBJ): $(PL_EXSRC)
|
||||
$(CC) $(CFLAGS) -D PLAYBACK_MODE $(INCLUDES) -c $(PL_EXSRC) -o $(PL_EXOBJ)
|
||||
|
||||
$(PLAY): $(PL_OBJS) $(PL_EXOBJ)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $(PLAY) $(PL_OBJS) $(PL_EXOBJ)
|
||||
|
||||
# Fof github publishing
|
||||
.PHONY: git
|
||||
git: clean $(MAIN) $(SLOG)
|
||||
./release/git_version.sh
|
||||
|
||||
|
||||
# this is a suffix replacement rule for building .o's from .c's
|
||||
# it uses automatic variables $<: the name of the prerequisite of
|
||||
# the rule(a .c file) and $@: the name of the target of the rule (a .o file)
|
||||
# (see the gnu make manual section about automatic variables)
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) *.o *~ $(MAIN) $(MAIN_U) $(PLAY) $(PL_EXOBJ) $(DEBG)
|
||||
$(RM) $(wildcard *.o) $(wildcard *~) $(MAIN) $(MAIN_U) $(PLAY) $(PL_EXOBJ) $(LOGR) $(PLAY) $(DEBG)
|
||||
|
||||
depend: $(SRCS)
|
||||
makedepend $(INCLUDES) $^
|
||||
|
||||
install: $(MAIN)
|
||||
./release/install.sh
|
||||
|
||||
|
||||
|
||||
endef
|
||||
|
||||
|
|
219
README.md
219
README.md
|
@ -1,7 +1,7 @@
|
|||
# Aqualinkd
|
||||
Linux daemon to control Aqualink RS pool controllers. Provides web UI, MQTT client & HTTP API endpoints. Control your pool equiptment from any phone/tablet or computer. Is also compatible with most Home control systems including Apple HomeKit, Samsung, Alexa, Google, etc.
|
||||
Linux daemon to control Aqualink RS pool controllers. Provides web UI, MQTT client & HTTP API endpoints. Control your pool equipment from any phone/tablet or computer. Is also compatible with most Home control systems including Apple HomeKit, Home Assistant, Samsung, Alexa, Google, etc.
|
||||
<br>
|
||||
Binaries are supplied for Raspberry Pi, Has bean, and can be compiled for many different SBC's.
|
||||
Binaries are supplied for Raspberry Pi both 32 & 64 bit OS, Has been, and can be compiled for many different SBC's, and a Docker is also available.
|
||||
|
||||
### It does not, and will never provide any layer of security. NEVER directly expose the device running this software to the outside world; only indirectly through the use of Home Automation hub's or other security measures. e.g. VPNs.
|
||||
|
||||
|
@ -11,21 +11,29 @@ If you like this project, you can buy me a cup of coffee :)
|
|||
<br>
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SEGN9UNS38TXJ)
|
||||
|
||||
|
||||
## AqualinkD new home
|
||||
AqualinkD has grown over the years and now has multiple repositories for software / hardware. We are brining them all together under one organization. [AqualinkD home page (under construction)](https://www.aqualinkd.com) -or- [AqualinkD organization](https://github.com/aqualinkd).<br>
|
||||
AqualinkD will always be open source and so will every associated repository. Nothing will change from that perspective. You will always be able to run this on cheap off the shelf hardware.
|
||||
|
||||
|
||||
## AqualinkD discussions
|
||||
|
||||
* Please use github Discussions for for questions / issues / problems (Link at top of page).
|
||||
https://github.com/sfeakes/AqualinkD/discussions
|
||||
* Please use github Discussions for questions (Link at top of page).
|
||||
https://github.com/aqualinkd/AqualinkD/discussions
|
||||
* For Bugs, please use issues link on top of page. ( please add AqualinkD version to posts )
|
||||
https://github.com/sfeakes/AqualinkD/issues
|
||||
https://github.com/aqualinkd/AqualinkD/issues
|
||||
|
||||
## Please see Wiki for installation instructions
|
||||
https://github.com/sfeakes/AqualinkD/wiki
|
||||
https://github.com/aqualinkd/AqualinkD/wiki
|
||||
|
||||
<!--
|
||||
For information on Control panel versions and upgrading the chips.<br>
|
||||
https://github.com/sfeakes/AqualinkD/wiki/Upgrading-Jandy-Aqualink-PDA-to-RS-panel
|
||||
https://github.com/aqualinkd/AqualinkD/wiki/Upgrading-Jandy-Aqualink-PDA-to-RS-panel
|
||||
-->
|
||||
<!--
|
||||
Here's where I started to document what I know about the Jandy RS485 protocol.<br>
|
||||
https://github.com/sfeakes/AqualinkD/wiki/Jandy-Aqualink-RS485-protocol
|
||||
https://github.com/aqualinkd/AqualinkD/wiki/Jandy-Aqualink-RS485-protocol
|
||||
-->
|
||||
|
||||
## AqualinkD built in WEB Interface(s).
|
||||
|
@ -56,9 +64,10 @@ https://github.com/sfeakes/AqualinkD/wiki/Jandy-Aqualink-RS485-protocol
|
|||
</td></tr>
|
||||
</table>
|
||||
|
||||
### Simulator
|
||||
Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to fully configure the master control panel<br>
|
||||
<img src="extras/simulator.png?raw=true" width="550">
|
||||
### Simulators
|
||||
Designed to mimic AqualinkRS devices, used to fully configure the master control panel<br>
|
||||
<img src="extras/onetouch_sim.png?raw=true">
|
||||
<img src="extras/allbutton_sim.png?raw=true">
|
||||
|
||||
### In Apple Home app.
|
||||
<img src="extras/HomeKit2.png?raw=true" width="800"></img>
|
||||
|
@ -66,17 +75,180 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
|
|||
* Full support for homekit scenes: ie: Create a "Spa scene" to: "turn spa on, set spa heater to X temperature and turn spa blower on", etc etc).
|
||||
|
||||
### In Home Assistant
|
||||
<img src="extras/HomeAssistant2.png?raw=true" width="800"></img>
|
||||
<img src="extras/HASSIO.png?raw=true" width="800"></img>
|
||||
|
||||
## All Web interfaces.
|
||||
* http://aqualink.ip/ <- (Standard WEB UI
|
||||
* http://aqualink.ip/simple.html <- (Simple opion if you don't like the above)
|
||||
* http://aqualink.ip/simulator.html <- (RS8 All Button Control Panel simulator)
|
||||
* http://aqualink.ip/debug.html <- (Turn on/off debug/serial debug & download logs)
|
||||
* http://aqualink.ip/simulator.html <- (Displays all simulators in one page with tabs)
|
||||
* http://aqualink.ip/aqmanager.html <- (Manage AqualinkD configuration & runtime)
|
||||
* http://aqualink.ip/allbutton_sim.html <- (All Button Simulator)
|
||||
* http://aqualink.ip/onetouch_sim.html <- (One Touch Simulator)
|
||||
* http://aqualink.ip/aquapda_sim.html <- (PDA simulator)
|
||||
#<a name="release"></a>
|
||||
|
||||
|
||||
# ToDo (future release)
|
||||
* Allow selecting of pre-defined VSP programs (Aqualink Touch & OneTouch protocols.)
|
||||
* Add set time to OneTouch protocol.
|
||||
* Create iAqualink Touch Simulator
|
||||
* AqualinkD to self configure. (Done for ID's, need to do for Panel type/size)
|
||||
|
||||
|
||||
<!--
|
||||
* NEED TO FIX for PDA and iAQT protocol.
|
||||
* Not always doing on/off
|
||||
* Heaters are slow to turn on, need to hit extra button
|
||||
* Spa turns on Spa Heat (first button on home page ???)
|
||||
* SWG Stays on
|
||||
* serial_logger
|
||||
* Add wiki documentation
|
||||
* about Heat vs Heater
|
||||
* Panel version
|
||||
* can't use iaquatouch panel / wireless
|
||||
|
||||
-->
|
||||
|
||||
# Call for Help.
|
||||
* The only Jandy devices I have not decoded yet are LX heater & Chemical Feeder. If you have either of these devices and are willing to post some logs, please let me know, or post in the [Discussions area](https://github.com/aqualinkd/AqualinkD/discussions)
|
||||
|
||||
|
||||
<!--
|
||||
NEED TO FIX FOR THIS RELEASE.
|
||||
* check panel version reported against config.
|
||||
* pickup speed faster on iaqualinktouch after change
|
||||
* with iaqualink2 no need to poll iaqtouch devices as frequently
|
||||
* update documentation on how vbutton / vpump / pump_max & min / enable_iauqalink2
|
||||
* check rs serial adapter is active if light color mode 11 is used.
|
||||
|
||||
* Check SWG messages like "#1 TruClear", see log in this post https://github.com/aqualinkd/AqualinkD/discussions/388
|
||||
|
||||
* Heat Pump / Chiller for OneTouch
|
||||
|
||||
* Try an auto-update
|
||||
* Update Mongoose
|
||||
-->
|
||||
# Updates in 2.6.3
|
||||
* AqualinkD can how self-update directly from github. use `Upgrade AqualinkD` button in Aqmanager
|
||||
* New install and remote_install scripts.
|
||||
* Changed MQTT posting frequency when Timers are enabled for better
|
||||
* Updates for new repo location. [AqualinkD organization](https://github.com/aqualinkd/AqualinkD)
|
||||
* Please use the following to upgrade
|
||||
* `curl -fsSL https://install.aqualinkd.com | sudo bash -s -- latest`
|
||||
* -or-
|
||||
* `curl -fsSL https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/release/remote_install.sh | sudo bash -s -- latest`
|
||||
|
||||
# Updates in 2.6.1
|
||||
* Added External Sensors to Web UI & HomeKit.
|
||||
* 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
|
||||
* Added configuration editor in aqmanager. [Wiki - AQManager](https://github.com/aqualinkd/AqualinkD/wiki#AQManager)
|
||||
* Can now self-configure on startup. set `device_id=0xFF`
|
||||
* Added scheduling of pump after events (Power On, Freeze Protect, Boost)
|
||||
* Fixed HA bug for thermostats not converting to °C when HA is set to display °C.
|
||||
* Added support for monitoring SBC system sensors, like CPU / GPU / Board (CPU temp being most useful).
|
||||
* Reduced load on panel over AqualinkTouch protocol.
|
||||
* Fixed higher than normal CPU load when leaving aqmanager open and sending no messages (leaving aqmanager open for over 14days).
|
||||
* Reworked PDA sleep mode.
|
||||
* Added support for Heat Pump / Chiller support.
|
||||
|
||||
|
||||
# Updates in 2.5.0
|
||||
* PDA panel Rev 6.0 or newer that do not have a Jandy iAqualink device attached can use the AqualinkTouch protocol rather than PDA protocol.
|
||||
* This is faster, more reliable and does not intefear with the physical PDA device (like existing implimentation)
|
||||
* Please consider this very much BETA at the moment.
|
||||
* use `device_id=0x33` in aqualinkd.conf.
|
||||
* PDA panel Rev 6.0 of newer WITH a Jandy iAqualink device attached can use `read_RS485_iAqualink = yes` to speed up device state change detection.
|
||||
* Added MQTT vsp_pump/speed/set for setting speed (RPM/GPM) by %, for automation hubs.
|
||||
* Added full dimmer range support for dimmable lights (not limited to 0,25,50,75,100 anymore)
|
||||
* Added vsp and dimmer to Hassio and homebridge-aqualinkd plugin as full range dimmer controls.
|
||||
* Added color lights & dimmer to Hassio as selectors.
|
||||
* Updated UI for support fullrange dimmer.
|
||||
* cleaned up code for spa_mode and spa for newer pannels.
|
||||
* Allow VSP to be asigned to virtual button.
|
||||
* Fixed bug with timer not starting.
|
||||
* Increase Speed of detecting device state changes.
|
||||
* Added iAqualink2 protocol support.
|
||||
* Chaged color light logic.
|
||||
* Faster OneTouch device support.
|
||||
|
||||
|
||||
# Updates in Release 2.4.0
|
||||
* <b>WARNING</b> Breaking change if you use dimmer (please change button_??_lightMode from 6 to 10)
|
||||
* Fixed bugs with particular Jandy panel versions and color lights.
|
||||
* Added support for more color lights, and sped up programming
|
||||
* Code & Repo refactor
|
||||
* Decoded more Pentair VSP pump status.
|
||||
* Changed VSP pump status handling (display more in web UI).
|
||||
* VSP Pump status & other attributes in HASSIO.
|
||||
* Dual temperature sensors supported.
|
||||
* Updates to serial_logger.
|
||||
* Changes to aqmanager for adding more options for decoding protocols.
|
||||
* Support for packets changes from panels REV Yg
|
||||
* Support VSP by label (not pump number), REV Yg
|
||||
* Added support for One Touch Buttons & Virtual Buttons.
|
||||
* look at `virtual_button??_label` in aqualinkd.conf
|
||||
* have to use AqualinkTouch protocol for `extended_device_id` 0x31->0x33 in aqualinkd.conf
|
||||
|
||||
# Updates in Release 2.3.8
|
||||
* Release removed. Bug with light program 0.
|
||||
|
||||
# Updates in Release 2.3.7
|
||||
* Fix for Pentair VSP losing connection & bouncing SWG to 0 and back.
|
||||
* Added more VSP data (Mode, Status, Pressure Curve, both RPM & GPM) for all Pentair Pumps (VS/VF/VSF).
|
||||
* Few updates to HomeAssistant integration.
|
||||
* Will now convert from C to F so setting `convert_mqtt_temp_to_c` doesn't effect hassio anymore
|
||||
* Added VSP support to change RPM/GPM (uses fan type since hassio doesn't support RPM, so it's a % setting or the full RPM or GPM range of your pump)
|
||||
* Updates to serial_logger.
|
||||
* Few updates to UI.
|
||||
* Will display both RPM & GPM for VSP (space providing)
|
||||
* Fix freeze protect button in UI not showing enabled.
|
||||
* Few updates to AQmanager UI.
|
||||
|
||||
# Update in Release 2.3.6
|
||||
* 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
|
||||
* 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.
|
||||
* Included Docker into main releases
|
||||
* Please read Docker section of the [Wiki - Docker](https://github.com/aqualinkd/AqualinkD/wiki#Docker)
|
||||
* Added support for reading extended information for Jandy JXi heaters.
|
||||
* Added Color Light to iAqualinkTouch protocol.
|
||||
* Fixed issue mqtt_timed_update (1~2 min rather than between 2 & 20 min)
|
||||
|
||||
# Update in Release 2.3.4
|
||||
* Changes for Docker
|
||||
* Updated simulator code base and added new simulators for AllButton, OneTouch & PDA.
|
||||
* <aqualinkd.ip>/allbutton_sim.html
|
||||
* <aqualinkd.ip>/onetouch_sim.html
|
||||
* <aqualinkd.ip>/aquapda_sim.html
|
||||
* 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
|
||||
* 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
|
||||
* [AqualinkD Log](https://github.com/aqualinkd/AqualinkD/wiki#Log)
|
||||
* Updated to scheduler
|
||||
* [AqualinkD Scheduler](https://github.com/aqualinkd/AqualinkD/wiki#Scheduler)
|
||||
* Introduced RS485 frame delay / timer.
|
||||
* Improve PDA panels reliability (PDA pannels are slower than RS panels)
|
||||
* Potentially fixed Pentair VSP / SWG problems since Pentair VSP use a different protocol, this will allow a timed delay for the VSP to post a status messages. Seems to only effect RS485 bus when both a Pentair VSP and Jandy SWG are present.
|
||||
* 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
|
||||
* 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
|
||||
* Changed a lot of logic around different protocols.
|
||||
|
@ -100,7 +272,7 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
|
|||
|
||||
# Update in Release 2.2.2
|
||||
* Fixed some Web UI bugs
|
||||
* Color lights now quicker when selecting existing comor mode.
|
||||
* Color lights now quicker when selecting existing color mode.
|
||||
|
||||
# Update in Release 2.2.1
|
||||
* Supports serial adapter protocol `rssa_device_id`, (provides instant heater setpoint changes & setpoint increment)
|
||||
|
@ -123,7 +295,7 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
|
|||
* Fixed RS-4 panel bug.
|
||||
* Fixed some AqualinkTouch programming issues.
|
||||
* Increased timeout for startup probe.
|
||||
* This release WILL require you to make aqualinkd.conf changes. <b>Make sure to read wiki section https://github.com/sfeakes/AqualinkD/wiki#Version_2</b>
|
||||
* This release WILL require you to make aqualinkd.conf changes. <b>Make sure to read wiki section https://github.com/aqualinkd/AqualinkD/wiki#Version_2</b>
|
||||
* Extensive work to reduce CPU cycles and unnesessary logic.
|
||||
* iAqualink Touch protocol supported for VSP & extended programming.
|
||||
* This protocol is a lot faster for programming, ID's are between 0x38 & 0x3B `extended_device_id`, use Serial_logger to find valid ID.
|
||||
|
@ -140,7 +312,7 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
|
|||
* AqualinkD startup changed to fix some 'systemctl restart' issues.
|
||||
* More detailed API replys.
|
||||
# Update in Release 2.1.0
|
||||
* Big update, lots of core changes, <b>please read wiki section https://github.com/sfeakes/AqualinkD/wiki#Version_2</b>
|
||||
* Big update, lots of core changes, <b>please read wiki section https://github.com/aqualinkd/AqualinkD/wiki#Version_2</b>
|
||||
* Full Variable Speed Pump support. (Can read,set & change RPM,GPM)
|
||||
* Full support for all Colored Lights (even if Jandy Control Panel doesn't support them)
|
||||
* Chemlink pH & ORP now supported. (along with posting MQTT information)
|
||||
|
@ -286,12 +458,15 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
|
|||
* Freeze protect, heater temperature and SWG set-points have been added to support for standard HTTP requests (MQTT & WS always had support).
|
||||
|
||||
# Please see Wiki for install instructions
|
||||
https://github.com/sfeakes/AqualinkD/wiki
|
||||
https://github.com/aqualinkd/AqualinkD/wiki
|
||||
|
||||
#
|
||||
|
||||
# Aqualink Versions tested
|
||||
This was designed for Jandy Aqualink RS, so should work with AqualinkRS and iAqualink Combo control panels. It will work with Aqualink PDA/AquaPalm and NON Combo iAqualink; but with limitations.
|
||||
This was designed for Jandy Aqualink RS, so does work with AqualinkRS and iAqualink Combo control panels. It will work with Aqualink PDA/AquaPalm; but with limitations.
|
||||
|
||||
AqualinkD is known to work with Panel Versions from Rev H to the Latest Rev Yg
|
||||
<!--
|
||||
Below are verified versions, but should work with any AqualinkRS :-
|
||||
|
||||
|
||||
|
@ -309,7 +484,7 @@ Below are verified versions, but should work with any AqualinkRS :-
|
|||
|
||||
If you have tested a version not listed here, please let me know by opening an issue.
|
||||
#
|
||||
|
||||
-->
|
||||
# License
|
||||
## Non Commercial Project
|
||||
All non commercial projects can be run using our open source code under GPLv2 licensing. As long as your project remains in this category there is no charge.
|
||||
|
|
1235
aq_panel.c
1235
aq_panel.c
File diff suppressed because it is too large
Load Diff
78
aq_panel.h
78
aq_panel.h
|
@ -1,78 +0,0 @@
|
|||
|
||||
#ifndef AQ_PANEL_H_
|
||||
#define AQ_PANEL_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "aqualink.h"
|
||||
|
||||
#define PUMP_INDEX 0
|
||||
#define SPA_INDEX 1
|
||||
/*
|
||||
#define POOL_HEAT_INDEX 9
|
||||
#define SPA_HEAT_INDEX 10
|
||||
*/
|
||||
|
||||
// Defined as int16_t so 16 bits to mask
|
||||
#define RSP_4 (1 << 0) // 1
|
||||
#define RSP_6 (1 << 1) // 16
|
||||
#define RSP_8 (1 << 2) // 4
|
||||
#define RSP_10 (1 << 3) // 2
|
||||
#define RSP_12 (1 << 4) // 32
|
||||
#define RSP_14 (1 << 5) // 8
|
||||
#define RSP_16 (1 << 6) // 64
|
||||
#define RSP_COMBO (1 << 7) // 128
|
||||
#define RSP_SINGLE (1 << 8) // 128
|
||||
#define RSP_DUAL_EQPT (1 << 9) // 128
|
||||
#define RSP_RS (1 << 10) // 128
|
||||
#define RSP_PDA (1 << 11) // 128
|
||||
#define RSP_ONET (1 << 12) // 128
|
||||
#define RSP_IAQT (1 << 13) // 128
|
||||
#define RSP_RSSA (1 << 14) // 128
|
||||
#define RSP_EXT_PROG (1 << 15) // 128
|
||||
|
||||
//void initButtons(struct aqualinkdata *aqdata);
|
||||
void setPanelByName(struct aqualinkdata *aqdata, const char *str);
|
||||
void setPanel(struct aqualinkdata *aqdata, bool rs, int size, bool combo, bool dual);
|
||||
const char* getPanelString();
|
||||
|
||||
bool panel_device_request(struct aqualinkdata *aqdata, action_type type, int deviceIndex, int value, request_source source);
|
||||
|
||||
void changePanelToMode_Only();
|
||||
void addPanelOneTouchInterface();
|
||||
void addPanelIAQTouchInterface();
|
||||
void addPanelRSserialAdapterInterface();
|
||||
void changePanelToExtendedIDProgramming();
|
||||
//void panneltest();
|
||||
|
||||
#define isPDA_PANEL ((_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA)
|
||||
#define isRS_PANEL ((_aqconfig_.paneltype_mask & RSP_RS) == RSP_RS)
|
||||
#define isCOMBO_PANEL ((_aqconfig_.paneltype_mask & RSP_COMBO) == RSP_COMBO)
|
||||
#define isSINGLE_DEV_PANEL ((_aqconfig_.paneltype_mask & RSP_SINGLE) == RSP_SINGLE)
|
||||
#define isDUAL_EQPT_PANEL ((_aqconfig_.paneltype_mask & RSP_DUAL_EQPT) == RSP_DUAL_EQPT)
|
||||
#define isONET_ENABLED ((_aqconfig_.paneltype_mask & RSP_ONET) == RSP_ONET)
|
||||
#define isIAQT_ENABLED ((_aqconfig_.paneltype_mask & RSP_IAQT) == RSP_IAQT)
|
||||
#define isRSSA_ENABLED ((_aqconfig_.paneltype_mask & RSP_RSSA) == RSP_RSSA)
|
||||
#define isEXTP_ENABLED ((_aqconfig_.paneltype_mask & RSP_EXT_PROG) == RSP_EXT_PROG)
|
||||
int PANEL_SIZE();
|
||||
//
|
||||
//#define PANEL_SIZE PANEL_SIZE()
|
||||
/*
|
||||
#define PANEL_SIZE ((_aqconfig_.paneltype_mask & RSP_4) == RSP_4)?4:(\
|
||||
((_aqconfig_.paneltype_mask & RSP_6) == RSP_6)?6:(\
|
||||
((_aqconfig_.paneltype_mask & RSP_8) == RSP_8)?8:(\
|
||||
((_aqconfig_.paneltype_mask & RSP_10) == RSP_10)?10:(\
|
||||
((_aqconfig_.paneltype_mask & RSP_12) == RSP_12)?12:(\
|
||||
((_aqconfig_.paneltype_mask & RSP_14) == RSP_14)?14:(\
|
||||
((_aqconfig_.paneltype_mask & RSP_16) == RSP_16)?16:0))))))
|
||||
*/
|
||||
|
||||
|
||||
#ifndef AQ_RS16
|
||||
#define TOTAL_BUTTONS 12
|
||||
#else
|
||||
#define TOTAL_BUTTONS 20
|
||||
// This needs to be called AFTER and as well as initButtons
|
||||
void initButtons_RS16(struct aqualinkdata *aqdata);
|
||||
#endif
|
||||
|
||||
#endif
|
1187
aq_panel.x.c
1187
aq_panel.x.c
File diff suppressed because it is too large
Load Diff
2727
aq_programmer.c
2727
aq_programmer.c
File diff suppressed because it is too large
Load Diff
285
aq_scheduler.c
285
aq_scheduler.c
|
@ -1,285 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Shaun Feakes - All rights reserved
|
||||
*
|
||||
* You may use redistribute and/or modify this code under the terms of
|
||||
* the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. For the terms of this license,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* https://github.com/sfeakes/aqualinkd
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <regex.h>
|
||||
|
||||
|
||||
#include "mongoose.h"
|
||||
#include "aqualink.h"
|
||||
#include "aq_scheduler.h"
|
||||
#include "config.h"
|
||||
//#include "utils.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Example /etc/cron.d/aqualinkd
|
||||
|
||||
01 10 1 * * curl localhost:80/api/Filter_Pump/set -d value=2 -X PUT
|
||||
*/
|
||||
|
||||
bool remount_root_ro(bool readonly) {
|
||||
// NSF Check if config is RO_ROOT set
|
||||
|
||||
if (readonly) {
|
||||
LOG(SCHD_LOG,LOG_INFO, "reMounting root RO\n");
|
||||
mount (NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
|
||||
return true;
|
||||
} else {
|
||||
struct statvfs fsinfo;
|
||||
statvfs("/", &fsinfo);
|
||||
if ((fsinfo.f_flag & ST_RDONLY) == 0) // We are readwrite, ignore
|
||||
return false;
|
||||
|
||||
LOG(SCHD_LOG,LOG_INFO, "reMounting root RW\n");
|
||||
mount (NULL, "/", NULL, MS_REMOUNT, NULL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool passJson_scObj(char* line, int length, aqs_cron *values)
|
||||
{
|
||||
int keystart=0;
|
||||
//int keyend=0;
|
||||
int valuestart=0;
|
||||
int captured=0;
|
||||
bool readingvalue=false;
|
||||
bool invalue=false;
|
||||
//char value;
|
||||
values->enabled = true;
|
||||
|
||||
//LOG(SCHD_LOG,LOG_DEBUG, "Obj body:'%.*s'\n", length, line);
|
||||
|
||||
for (int i=0; i < length; i++) {
|
||||
if (line[i] == '}') {
|
||||
return (captured >= 7)?true:false;
|
||||
} else if (line[i] == '"' && keystart==0 && invalue==false && readingvalue==false) {
|
||||
keystart=i+1;
|
||||
} else if (line[i] == '"' && keystart > 0 && invalue==false && readingvalue==false) {
|
||||
//keyend=i;
|
||||
} else if (line[i] == ':' && keystart > 0 ) {
|
||||
invalue=true;
|
||||
} else if (line[i] == '"' && invalue == true && readingvalue == false && keystart > 0 ) {
|
||||
readingvalue=true;
|
||||
valuestart=i+1;
|
||||
} else if (line[i] == '"' && readingvalue == true) {
|
||||
// i is end of key
|
||||
if ( strncmp(&line[keystart], "enabled", 7) == 0) {
|
||||
values->enabled = (line[valuestart]=='0'?false:true);
|
||||
captured++;
|
||||
} else if ( strncmp(&line[keystart], "min", 3) == 0) {
|
||||
strncpy(values->minute, &line[valuestart], (i-valuestart) );
|
||||
values->minute[i-valuestart] = '\0';
|
||||
captured++;
|
||||
} else if( strncmp(&line[keystart], "hour", 4) == 0) {
|
||||
strncpy(values->hour, &line[valuestart], (i-valuestart) );
|
||||
values->hour[i-valuestart] = '\0';
|
||||
captured++;
|
||||
} else if( strncmp(&line[keystart], "daym", 4) == 0) {
|
||||
strncpy(values->daym, &line[valuestart], (i-valuestart) );
|
||||
values->daym[i-valuestart] = '\0';
|
||||
captured++;
|
||||
} else if( strncmp(&line[keystart], "month", 5) == 0) {
|
||||
strncpy(values->month, &line[valuestart], (i-valuestart) );
|
||||
values->month[i-valuestart] = '\0';
|
||||
captured++;
|
||||
} else if( strncmp(&line[keystart], "dayw", 4) == 0) {
|
||||
strncpy(values->dayw, &line[valuestart], (i-valuestart) );
|
||||
values->dayw[i-valuestart] = '\0';
|
||||
captured++;
|
||||
} else if( strncmp(&line[keystart], "url", 3) == 0) {
|
||||
strncpy(values->url, &line[valuestart], (i-valuestart) );
|
||||
values->url[i-valuestart] = '\0';
|
||||
captured++;
|
||||
} else if( strncmp(&line[keystart], "value", 5) == 0) {
|
||||
strncpy(values->value, &line[valuestart], (i-valuestart) );
|
||||
values->value[i-valuestart] = '\0';
|
||||
captured++;
|
||||
}
|
||||
keystart=0;
|
||||
//keyend=0;
|
||||
valuestart=0;
|
||||
invalue=false;
|
||||
readingvalue=false;
|
||||
}
|
||||
}
|
||||
|
||||
return (captured >= 7)?true:false;
|
||||
}
|
||||
|
||||
int save_schedules_js(char* inBuf, int inSize, char* outBuf, int outSize)
|
||||
{
|
||||
int length=0;
|
||||
FILE *fp;
|
||||
int i;
|
||||
bool inarray = false;
|
||||
aqs_cron cline;
|
||||
|
||||
if ( !_aqconfig_.enable_scheduler) {
|
||||
LOG(SCHD_LOG,LOG_WARNING, "Schedules are disabled\n");
|
||||
length += sprintf(outBuf, "{\"message\":\"Error Schedules disabled\"}");
|
||||
return length;
|
||||
}
|
||||
|
||||
LOG(SCHD_LOG,LOG_NOTICE, "Saving Schedule:\n");
|
||||
|
||||
bool fs = remount_root_ro(false);
|
||||
fp = fopen(CRON_FILE, "w");
|
||||
if (fp == NULL) {
|
||||
LOG(SCHD_LOG,LOG_ERR, "Open file failed '%s'\n", CRON_FILE);
|
||||
remount_root_ro(true);
|
||||
length += sprintf(outBuf, "{\"message\":\"Error Saving Schedules\"}");
|
||||
return length;
|
||||
}
|
||||
fprintf(fp, "#***** AUTO GENERATED DO NOT EDIT *****\n");
|
||||
fprintf(fp, "PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n");
|
||||
|
||||
LOG(SCHD_LOG,LOG_DEBUG, "Schedules Message body:\n'%.*s'\n", inSize, inBuf);
|
||||
|
||||
length += sprintf(outBuf, "{\"message\":\"Saved Schedules\"}");
|
||||
|
||||
for (i=0; i < inSize; i++) {
|
||||
if ( inBuf[i] == '[' ) {
|
||||
inarray=true;
|
||||
} else if ( inBuf[i] == ']' ) {
|
||||
inarray=false;
|
||||
} else if ( inarray && inBuf[i] == '{') {
|
||||
passJson_scObj( &inBuf[i], (inSize-i), &cline);
|
||||
LOG(SCHD_LOG,LOG_DEBUG, "Write to cron Min:%s Hour:%s DayM:%s Month:%s DayW:%s URL:%s Value:%s\n",cline.minute,cline.hour,cline.daym,cline.month,cline.dayw,cline.url,cline.value);
|
||||
LOG(SCHD_LOG,LOG_INFO, "%s%s %s %s %s %s curl localhost:%s%s -d value=%s -X PUT\n",(cline.enabled?"":"#"),cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, _aqconfig_.socket_port, cline.url, cline.value);
|
||||
fprintf(fp, "%s%s %s %s %s %s root curl localhost:%s%s -d value=%s -X PUT\n",(cline.enabled?"":"#"),cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, _aqconfig_.socket_port, cline.url, cline.value);
|
||||
} else if ( inarray && inBuf[i] == '}') {
|
||||
//inobj=false;
|
||||
//objed=i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fprintf(fp, "#***** AUTO GENERATED DO NOT EDIT *****\n");
|
||||
fclose(fp);
|
||||
|
||||
remount_root_ro(fs);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int build_schedules_js(char* buffer, int size)
|
||||
{
|
||||
memset(&buffer[0], 0, size);
|
||||
FILE *fp;
|
||||
char *line = NULL;
|
||||
int length = 0;
|
||||
int rc;
|
||||
aqs_cron cline;
|
||||
size_t len = 0;
|
||||
ssize_t read_size;
|
||||
regex_t regexCompiled;
|
||||
|
||||
if ( !_aqconfig_.enable_scheduler) {
|
||||
LOG(SCHD_LOG,LOG_WARNING, "Schedules are disabled\n");
|
||||
length += sprintf(buffer, "{\"message\":\"Error Schedules disabled\"}");
|
||||
return length;
|
||||
}
|
||||
|
||||
// Below works for curl but not /usr/bin/curl in command. NSF come back and fix the regexp
|
||||
//char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(/api/.*)\\s-d value=([^\\d]+)\\s(.*)";
|
||||
// \d doesn't seem to be supported, so using [0-9]+ instead
|
||||
//char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(\\/api\\/.*\\/set).* value=([0-9]+).*";
|
||||
|
||||
//char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(\\/api\\/.*\\/set).* value=([0-9]+).*";
|
||||
char *regexString="(#{0,1})([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(\\/api\\/.*\\/set).* value=([0-9]+).*";
|
||||
|
||||
//char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(/api/.*/set).*value=([0-9]+).*";
|
||||
|
||||
|
||||
size_t maxGroups = 15;
|
||||
regmatch_t groupArray[maxGroups];
|
||||
//static char buf[100];
|
||||
|
||||
length += sprintf(buffer+length,"{\"type\": \"schedules\",");
|
||||
|
||||
if (0 != (rc = regcomp(®exCompiled, regexString, REG_EXTENDED))) {
|
||||
LOG(SCHD_LOG,LOG_ERR, "regcomp() failed, returning nonzero (%d)\n", rc);
|
||||
length += sprintf(buffer+length,"\"message\": \"Error reading schedules\"}");
|
||||
return length;
|
||||
}
|
||||
|
||||
fp = fopen(CRON_FILE, "r");
|
||||
if (fp == NULL) {
|
||||
LOG(SCHD_LOG,LOG_ERR, "Open file failed '%s'\n", CRON_FILE);
|
||||
length += sprintf(buffer+length,"\"message\": \"Error reading schedules\"}");
|
||||
return length;
|
||||
}
|
||||
|
||||
length += sprintf(buffer+length,"\"schedules\": [ ");
|
||||
|
||||
while ((read_size = getline(&line, &len, fp)) != -1) {
|
||||
//printf("Read from cron:-\n %s", line);
|
||||
//lc++;
|
||||
//rc = regexec(®exCompiled, line, maxGroups, groupArray, 0);
|
||||
if (0 == (rc = regexec(®exCompiled, line, maxGroups, groupArray, REG_EXTENDED))) {
|
||||
// Group 1 is # (enable or not)
|
||||
// Group 2 is minute
|
||||
// Group 3 is hour
|
||||
// Group 4 is day of month
|
||||
// Group 5 is month
|
||||
// Group 6 is day of week
|
||||
// Group 7 is root
|
||||
// Group 8 is curl
|
||||
// Group 9 is URL
|
||||
// Group 10 is value
|
||||
if (groupArray[8].rm_so == (size_t)-1) {
|
||||
LOG(SCHD_LOG,LOG_ERR, "No matching information from cron file\n");
|
||||
} else {
|
||||
cline.enabled = (line[groupArray[1].rm_so] == '#')?false:true;
|
||||
sprintf(cline.minute, "%.*s", (groupArray[2].rm_eo - groupArray[2].rm_so), (line + groupArray[2].rm_so));
|
||||
sprintf(cline.hour, "%.*s", (groupArray[3].rm_eo - groupArray[3].rm_so), (line + groupArray[3].rm_so));
|
||||
sprintf(cline.daym, "%.*s", (groupArray[4].rm_eo - groupArray[4].rm_so), (line + groupArray[4].rm_so));
|
||||
sprintf(cline.month, "%.*s", (groupArray[5].rm_eo - groupArray[5].rm_so), (line + groupArray[5].rm_so));
|
||||
sprintf(cline.dayw, "%.*s", (groupArray[6].rm_eo - groupArray[6].rm_so), (line + groupArray[6].rm_so));
|
||||
sprintf(cline.url, "%.*s", (groupArray[9].rm_eo - groupArray[9].rm_so), (line + groupArray[9].rm_so));
|
||||
sprintf(cline.value, "%.*s", (groupArray[10].rm_eo - groupArray[10].rm_so), (line + groupArray[10].rm_so));
|
||||
LOG(SCHD_LOG,LOG_INFO, "Read from cron. Enabled:%d Min:%s Hour:%s DayM:%s Month:%s DayW:%s URL:%s Value:%s\n",cline.enabled,cline.minute,cline.hour,cline.daym,cline.month,cline.dayw,cline.url,cline.value);
|
||||
length += sprintf(buffer+length, "{\"enabled\":\"%d\", \"min\":\"%s\",\"hour\":\"%s\",\"daym\":\"%s\",\"month\":\"%s\",\"dayw\":\"%s\",\"url\":\"%s\",\"value\":\"%s\"},",
|
||||
cline.enabled,
|
||||
cline.minute,
|
||||
cline.hour,
|
||||
cline.daym,
|
||||
cline.month,
|
||||
cline.dayw,
|
||||
cline.url,
|
||||
cline.value);
|
||||
//LOG(SCHD_LOG,LOG_DEBUG, "Read from cron Day %d | Time %d:%d | Zone %d | Runtime %d\n",day,hour,minute,zone,runtime);
|
||||
}
|
||||
} else {
|
||||
LOG(SCHD_LOG,LOG_DEBUG, "regexp no match (%d) %s\n", rc, line);
|
||||
}
|
||||
}
|
||||
|
||||
buffer[--length] = '\0';
|
||||
length += sprintf(buffer+length,"]}\n");
|
||||
|
||||
fclose(fp);
|
||||
regfree(®exCompiled);
|
||||
|
||||
return length;
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
|
||||
|
||||
|
||||
|
||||
#ifndef AQ_SCHEDULER_H_
|
||||
#define AQ_SCHEDULER_H_
|
||||
|
||||
|
||||
#define CRON_FILE "/etc/cron.d/aqualinkd"
|
||||
#define CURL "curl"
|
||||
|
||||
#define CV_SIZE 20
|
||||
|
||||
typedef struct aqs_cron
|
||||
{
|
||||
int enabled;
|
||||
char minute[CV_SIZE];
|
||||
char hour[CV_SIZE];
|
||||
char daym[CV_SIZE];
|
||||
char month[CV_SIZE];
|
||||
char dayw[CV_SIZE];
|
||||
char url[CV_SIZE * 2];
|
||||
char value[CV_SIZE];
|
||||
} aqs_cron;
|
||||
|
||||
int build_schedules_js(char* buffer, int size);
|
||||
int save_schedules_js(char* inBuf, int inSize, char* outBuf, int outSize);
|
||||
//void read_schedules();
|
||||
//void write_schedules();
|
||||
|
||||
#endif // AQ_SCHEDULER_H_
|
1934
aqualinkd.c
1934
aqualinkd.c
File diff suppressed because it is too large
Load Diff
145
color_lights.c
145
color_lights.c
|
@ -1,145 +0,0 @@
|
|||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
//#define COLOR_LIGHTS_C_
|
||||
#include "color_lights.h"
|
||||
|
||||
/****** This list MUST be in order of clight_type enum *******/
|
||||
const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] =
|
||||
{
|
||||
// AqualnkD Colors ignored as no names in control panel.
|
||||
{ "bogus" },
|
||||
{ // Jandy Color
|
||||
"Alpine White",
|
||||
"Sky Blue",
|
||||
"Cobalt Blue",
|
||||
"Caribbean Blue",
|
||||
"Spring Green",
|
||||
"Emerald Green",
|
||||
"Emerald Rose",
|
||||
"Magenta",
|
||||
"Violet",
|
||||
"Color Splash"
|
||||
},
|
||||
{ // Jandy LED
|
||||
"Alpine White",
|
||||
"Sky Blue",
|
||||
"Cobalt Blue",
|
||||
"Caribbean Blue",
|
||||
"Spring Green",
|
||||
"Emerald Green",
|
||||
"Emerald Rose",
|
||||
"Magenta",
|
||||
"Violet",
|
||||
"Slow Splash",
|
||||
"Fast Splash",
|
||||
"USA",
|
||||
"Fat Tuesday",
|
||||
"Disco Tech"
|
||||
},
|
||||
{ // SAm/SAL
|
||||
"White",
|
||||
"Light Green",
|
||||
"Green",
|
||||
"Cyan",
|
||||
"Blue",
|
||||
"Lavender",
|
||||
"Magenta"
|
||||
},
|
||||
{ // Color Logic
|
||||
"Voodoo Lounge",
|
||||
"Blue Sea",
|
||||
"Royal Blue",
|
||||
"Afternoon Skies",
|
||||
//"Aqua Green",
|
||||
"Emerald",
|
||||
"Sangria",
|
||||
"Cloud White",
|
||||
//"Warm Red",
|
||||
//"Flamingo",
|
||||
//"Vivid Violet",
|
||||
//"Sangria",
|
||||
"Twilight",
|
||||
"Tranquility",
|
||||
"Gemstone",
|
||||
"USA",
|
||||
"Mardi Gras",
|
||||
"Cool Cabaret"
|
||||
},
|
||||
{ // IntelliBrite
|
||||
"SAm",
|
||||
"Party",
|
||||
"Romance",
|
||||
"Caribbean",
|
||||
"American",
|
||||
"Cal Sunset",
|
||||
"Royal",
|
||||
"Blue",
|
||||
"Green",
|
||||
"Red",
|
||||
"White",
|
||||
"Magenta"
|
||||
},
|
||||
{ // Dimmer
|
||||
"25%",
|
||||
"50%",
|
||||
"75%",
|
||||
"100%"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const char *light_mode_name(clight_type type, int index)
|
||||
{
|
||||
return _color_light_options[type][index];
|
||||
}
|
||||
|
||||
bool isShowMode(const char *mode)
|
||||
{
|
||||
if (strcmp(mode, "Color Splash") == 0 ||
|
||||
strcmp(mode, "Slow Splash") == 0 ||
|
||||
strcmp(mode, "Fast Splash") == 0 ||
|
||||
strcmp(mode, "Fat Tuesday") == 0 ||
|
||||
strcmp(mode, "Disco Tech") == 0 ||
|
||||
strcmp(mode, "Voodoo Lounge") == 0 ||
|
||||
strcmp(mode, "Twilight") == 0 ||
|
||||
strcmp(mode, "Tranquility") == 0 ||
|
||||
strcmp(mode, "Gemstone") == 0 ||
|
||||
strcmp(mode, "USA") == 0 ||
|
||||
strcmp(mode, "Mardi Gras") == 0 ||
|
||||
strcmp(mode, "Cool Cabaret") == 0 ||
|
||||
strcmp(mode, "SAm") == 0 ||
|
||||
strcmp(mode, "Party") == 0 ||
|
||||
strcmp(mode, "Romance") == 0 ||
|
||||
strcmp(mode, "Caribbean") == 0 ||
|
||||
strcmp(mode, "American") == 0 ||
|
||||
strcmp(mode, "Cal Sunset") == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
int build_color_lights_js(struct aqualinkdata *aqdata, char* buffer, int size)
|
||||
{
|
||||
memset(&buffer[0], 0, size);
|
||||
int length = 0;
|
||||
int i, j;
|
||||
|
||||
length += sprintf(buffer+length, "var _light_program = [];\n");
|
||||
length += sprintf(buffer+length, "_light_program[0] = light_program;\n");
|
||||
|
||||
for (i=1; i < NUMBER_LIGHT_COLOR_TYPES; i++) {
|
||||
length += sprintf(buffer+length, "_light_program[%d] = [", i);
|
||||
for (j=0; j < LIGHT_COLOR_OPTIONS; j++) {
|
||||
if (_color_light_options[i][j] != NULL)
|
||||
length += sprintf(buffer+length, "\"%s%s\",", _color_light_options[i][j], (isShowMode(_color_light_options[i][j])?" - Show":"") );
|
||||
}
|
||||
buffer[--length] = '\0';
|
||||
length += sprintf(buffer+length, "];\n");
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
925
config.c
925
config.c
|
@ -1,925 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Shaun Feakes - All rights reserved
|
||||
*
|
||||
* You may use redistribute and/or modify this code under the terms of
|
||||
* the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. For the terms of this license,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* https://github.com/sfeakes/aqualinkd
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <libgen.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
//#include <sys/socket.h>
|
||||
//#include <sys/time.h>
|
||||
//#include <syslog.h>
|
||||
//#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
//#include <linux/if.h>
|
||||
//#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#define CONFIG_C
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
#include "aq_serial.h"
|
||||
#include "aq_panel.h"
|
||||
#include "aqualink.h"
|
||||
|
||||
#define MAXCFGLINE 256
|
||||
|
||||
|
||||
|
||||
char *generate_mqtt_id(char *buf, int len);
|
||||
pump_detail *getpump(struct aqualinkdata *aqdata, int button);
|
||||
|
||||
struct tmpPanelInfo {
|
||||
int size;
|
||||
bool rs;
|
||||
bool combo;
|
||||
bool dual;
|
||||
};
|
||||
|
||||
struct tmpPanelInfo *_tmpPanel;
|
||||
|
||||
/*
|
||||
* initialize data to default values
|
||||
*/
|
||||
void init_parameters (struct aqconfig * parms)
|
||||
{
|
||||
// Set default panel if it get's missed from config
|
||||
_tmpPanel = malloc(sizeof(struct tmpPanelInfo));
|
||||
_tmpPanel->size = 8;
|
||||
_tmpPanel->rs = true;
|
||||
_tmpPanel->combo = true;
|
||||
_tmpPanel->dual = false;
|
||||
|
||||
clearDebugLogMask();
|
||||
|
||||
//int i;
|
||||
//char *p;
|
||||
//parms->rs_panel_size = 8;
|
||||
parms->serial_port = DEFAULT_SERIALPORT;
|
||||
parms->log_level = DEFAULT_LOG_LEVEL;
|
||||
parms->socket_port = DEFAULT_WEBPORT;
|
||||
parms->web_directory = DEFAULT_WEBROOT;
|
||||
//parms->device_id = strtoul(DEFAULT_DEVICE_ID, &p, 16);
|
||||
parms->device_id = strtoul(DEFAULT_DEVICE_ID, NULL, 16);
|
||||
parms->rssa_device_id = NUL;
|
||||
parms->RSSD_LOG_filter = NUL;
|
||||
parms->paneltype_mask = 0;
|
||||
#if defined AQ_ONETOUCH || defined AQ_IAQTOUCH
|
||||
parms->extended_device_id = NUL;
|
||||
parms->extended_device_id_programming = false;
|
||||
#endif
|
||||
//sscanf(DEFAULT_DEVICE_ID, "0x%x", &parms->device_id);
|
||||
parms->override_freeze_protect = FALSE;
|
||||
|
||||
parms->mqtt_dz_sub_topic = DEFAULT_MQTT_DZ_OUT;
|
||||
parms->mqtt_dz_pub_topic = DEFAULT_MQTT_DZ_IN;
|
||||
parms->mqtt_aq_topic = DEFAULT_MQTT_AQ_TP;
|
||||
parms->mqtt_server = DEFAULT_MQTT_SERVER;
|
||||
parms->mqtt_user = DEFAULT_MQTT_USER;
|
||||
parms->mqtt_passwd = DEFAULT_MQTT_PASSWD;
|
||||
|
||||
parms->dzidx_air_temp = TEMP_UNKNOWN;
|
||||
parms->dzidx_pool_water_temp = TEMP_UNKNOWN;
|
||||
parms->dzidx_spa_water_temp = TEMP_UNKNOWN;
|
||||
parms->dzidx_swg_percent = TEMP_UNKNOWN;
|
||||
parms->dzidx_swg_ppm = TEMP_UNKNOWN;
|
||||
//parms->dzidx_pool_thermostat = TEMP_UNKNOWN; // removed until domoticz has a better virtual thermostat
|
||||
//parms->dzidx_spa_thermostat = TEMP_UNKNOWN; // removed until domoticz has a better virtual thermostat
|
||||
parms->light_programming_mode = 0;
|
||||
parms->light_programming_initial_on = 15;
|
||||
parms->light_programming_initial_off = 12;
|
||||
//parms->light_programming_button_pool = TEMP_UNKNOWN;
|
||||
//parms->light_programming_button_spa = TEMP_UNKNOWN;
|
||||
parms->deamonize = true;
|
||||
parms->log_file = '\0';
|
||||
#ifdef AQ_PDA
|
||||
parms->pda_sleep_mode = false;
|
||||
#endif
|
||||
//parms->onetouch_mode = false;
|
||||
parms->convert_mqtt_temp = true;
|
||||
parms->convert_dz_temp = true;
|
||||
parms->report_zero_pool_temp = false;
|
||||
parms->report_zero_spa_temp = false;
|
||||
//parms->read_all_devices = true;
|
||||
//parms->read_pentair_packets = false;
|
||||
parms->read_RS485_devmask = 0;
|
||||
parms->use_panel_aux_labels = false;
|
||||
|
||||
parms->force_swg = false;
|
||||
parms->force_ps_setpoints = false;
|
||||
//parms->swg_pool_and_spa = false;
|
||||
parms->swg_zero_ignore = DEFAULT_SWG_ZERO_IGNORE_COUNT;
|
||||
parms->display_warnings_web = false;
|
||||
|
||||
parms->log_protocol_packets = false; // Read & Write as packets write to file
|
||||
parms->log_raw_bytes = false; // bytes read and write to file
|
||||
|
||||
parms->sync_panel_time = true;
|
||||
|
||||
// Default parameters for threading and USB blocking
|
||||
parms->readahead_b4_write = false;
|
||||
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
parms->rs_poll_speed = DEFAULT_POLL_SPEED;
|
||||
parms->thread_netservices = true;
|
||||
#endif
|
||||
|
||||
parms->enable_scheduler = true;
|
||||
parms->ftdi_low_latency = true;
|
||||
parms->prioritize_ack = false;
|
||||
|
||||
generate_mqtt_id(parms->mqtt_ID, MQTT_ID_LEN);
|
||||
}
|
||||
|
||||
char *cleanalloc(char*str)
|
||||
{
|
||||
if (str == NULL)
|
||||
return str;
|
||||
|
||||
char *result;
|
||||
str = cleanwhitespace(str);
|
||||
|
||||
result = (char*)malloc(strlen(str)+1);
|
||||
strcpy ( result, str );
|
||||
//printf("Result=%s\n",result);
|
||||
return result;
|
||||
}
|
||||
/*
|
||||
char *cleanallocindex(char*str, int index)
|
||||
{
|
||||
char *result;
|
||||
int i;
|
||||
int found = 1;
|
||||
int loc1=0;
|
||||
int loc2=strlen(str);
|
||||
|
||||
for(i=0;i<loc2;i++) {
|
||||
if ( str[i] == ';' ) {
|
||||
found++;
|
||||
if (found == index)
|
||||
loc1 = i;
|
||||
else if (found == (index+1))
|
||||
loc2 = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (found < index)
|
||||
return NULL;
|
||||
|
||||
// Trim leading & trailing spaces
|
||||
loc1++;
|
||||
while(isspace(str[loc1])) loc1++;
|
||||
loc2--;
|
||||
while(isspace(str[loc2])) loc2--;
|
||||
|
||||
// Allocate and copy
|
||||
result = (char*)malloc(loc2-loc1+2*sizeof(char));
|
||||
strncpy ( result, &str[loc1], loc2-loc1+1 );
|
||||
result[loc2-loc1+1] = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
// Find the first network interface with valid MAC and put mac address into buffer upto length
|
||||
bool mac(char *buf, int len)
|
||||
{
|
||||
struct ifreq s;
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
struct if_nameindex *if_nidxs, *intf;
|
||||
|
||||
if_nidxs = if_nameindex();
|
||||
if (if_nidxs != NULL)
|
||||
{
|
||||
for (intf = if_nidxs; intf->if_index != 0 || intf->if_name != NULL; intf++)
|
||||
{
|
||||
strcpy(s.ifr_name, intf->if_name);
|
||||
if (0 == ioctl(fd, SIOCGIFHWADDR, &s))
|
||||
{
|
||||
int i;
|
||||
if ( s.ifr_addr.sa_data[0] == 0 &&
|
||||
s.ifr_addr.sa_data[1] == 0 &&
|
||||
s.ifr_addr.sa_data[2] == 0 &&
|
||||
s.ifr_addr.sa_data[3] == 0 &&
|
||||
s.ifr_addr.sa_data[4] == 0 &&
|
||||
s.ifr_addr.sa_data[5] == 0 ) {
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < 6 && i * 2 < len; ++i)
|
||||
{
|
||||
sprintf(&buf[i * 2], "%02x", (unsigned char)s.ifr_addr.sa_data[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char *generate_mqtt_id(char *buf, int len) {
|
||||
extern char *__progname; // glibc populates this
|
||||
int i;
|
||||
strncpy(buf, basename(__progname), len);
|
||||
i = strlen(buf);
|
||||
|
||||
if (i < len) {
|
||||
buf[i++] = '_';
|
||||
// If we can't get MAC to pad mqtt id then use PID
|
||||
if (!mac(&buf[i], len - i)) {
|
||||
sprintf(&buf[i], "%.*d", (len-i), getpid());
|
||||
}
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
/*
|
||||
void readCfg_OLD (struct aqconfig *config_parameters, struct aqualinkdata *aqdata, char *cfgFile)
|
||||
{
|
||||
FILE * fp ;
|
||||
char bufr[MAXCFGLINE];
|
||||
//const char delim[2] = ";";
|
||||
//char *buf;
|
||||
//int line = 0;
|
||||
//int tokenindex = 0;
|
||||
char *b_ptr;
|
||||
|
||||
if( (fp = fopen(cfgFile, "r")) != NULL){
|
||||
while(! feof(fp)){
|
||||
if (fgets(bufr, MAXCFGLINE, fp) != NULL)
|
||||
{
|
||||
b_ptr = &bufr[0];
|
||||
char *indx;
|
||||
// Eat leading whitespace
|
||||
while(isspace(*b_ptr)) b_ptr++;
|
||||
if ( b_ptr[0] != '\0' && b_ptr[0] != '#')
|
||||
{
|
||||
indx = strchr(b_ptr, '=');
|
||||
if ( indx != NULL)
|
||||
{
|
||||
if (strncasecmp (b_ptr, "socket_port", 11) == 0) {
|
||||
//_aqconfig_.socket_port = cleanint(indx+1);
|
||||
_aqconfig_.socket_port = cleanalloc(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "serial_port", 11) == 0) {
|
||||
_aqconfig_.serial_port = cleanalloc(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "log_level", 9) == 0) {
|
||||
_aqconfig_.log_level = text2elevel(cleanalloc(indx+1));
|
||||
// should fee mem here
|
||||
} else if (strncasecmp (b_ptr, "device_id", 9) == 0) {
|
||||
_aqconfig_.device_id = strtoul(cleanalloc(indx+1), NULL, 16);
|
||||
// should fee mem here
|
||||
} else if (strncasecmp (b_ptr, "web_directory", 13) == 0) {
|
||||
_aqconfig_.web_directory = cleanalloc(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "log_file", 8) == 0) {
|
||||
_aqconfig_.log_file = cleanalloc(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "mqtt_address", 12) == 0) {
|
||||
_aqconfig_.mqtt_server = cleanalloc(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "mqtt_dz_sub_topic", 17) == 0) {
|
||||
_aqconfig_.mqtt_dz_sub_topic = cleanalloc(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "mqtt_dz_pub_topic", 17) == 0) {
|
||||
_aqconfig_.mqtt_dz_pub_topic = cleanalloc(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "mqtt_aq_topic", 13) == 0) {
|
||||
_aqconfig_.mqtt_aq_topic = cleanalloc(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "mqtt_user", 9) == 0) {
|
||||
_aqconfig_.mqtt_user = cleanalloc(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "mqtt_passwd", 11) == 0) {
|
||||
_aqconfig_.mqtt_passwd = cleanalloc(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "air_temp_dzidx", 14) == 0) {
|
||||
_aqconfig_.dzidx_air_temp = strtoul(indx+1, NULL, 10);
|
||||
} else if (strncasecmp (b_ptr, "pool_water_temp_dzidx", 21) == 0) {
|
||||
_aqconfig_.dzidx_pool_water_temp = strtoul(indx+1, NULL, 10);
|
||||
} else if (strncasecmp (b_ptr, "spa_water_temp_dzidx", 20) == 0) {
|
||||
_aqconfig_.dzidx_spa_water_temp = strtoul(indx+1, NULL, 10);
|
||||
} else if (strncasecmp (b_ptr, "light_programming_mode", 21) == 0) {
|
||||
_aqconfig_.light_programming_mode = atof(cleanalloc(indx+1)); // should free this
|
||||
} else if (strncasecmp (b_ptr, "light_programming_initial_on", 28) == 0) {
|
||||
_aqconfig_.light_programming_initial_on = strtoul(indx+1, NULL, 10);
|
||||
} else if (strncasecmp (b_ptr, "light_programming_initial_off", 29) == 0) {
|
||||
_aqconfig_.light_programming_initial_off = strtoul(indx+1, NULL, 10);
|
||||
} else if (strncasecmp (b_ptr, "light_programming_button", 21) == 0) {
|
||||
_aqconfig_.light_programming_button = strtoul(indx+1, NULL, 10) - 1;
|
||||
} else if (strncasecmp (b_ptr, "SWG_percent_dzidx", 17) == 0) {
|
||||
_aqconfig_.dzidx_swg_percent = strtoul(indx+1, NULL, 10);
|
||||
} else if (strncasecmp (b_ptr, "SWG_PPM_dzidx", 13) == 0) {
|
||||
_aqconfig_.dzidx_swg_ppm = strtoul(indx+1, NULL, 10);
|
||||
} else if (strncasecmp (b_ptr, "SWG_Status_dzidx", 14) == 0) {
|
||||
_aqconfig_.dzidx_swg_status = strtoul(indx+1, NULL, 10);
|
||||
} else if (strncasecmp (b_ptr, "override_freeze_protect", 23) == 0) {
|
||||
_aqconfig_.override_freeze_protect = text2bool(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "pda_mode", 8) == 0) {
|
||||
_aqconfig_.pda_mode = text2bool(indx+1);
|
||||
set_pda_mode(_aqconfig_.pda_mode);
|
||||
} else if (strncasecmp (b_ptr, "convert_mqtt_temp_to_c", 22) == 0) {
|
||||
_aqconfig_.convert_mqtt_temp = text2bool(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "convert_dz_temp_to_c", 21) == 0) {
|
||||
_aqconfig_.convert_dz_temp = text2bool(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "flash_mqtt_buttons", 18) == 0) {
|
||||
_aqconfig_.flash_mqtt_buttons = text2bool(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "report_zero_pool_temp", 21) == 0) {
|
||||
_aqconfig_.report_zero_pool_temp = text2bool(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "report_zero_spa_temp", 20) == 0) {
|
||||
_aqconfig_.report_zero_spa_temp = text2bool(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "report_zero_pool_temp", 21) == 0) {
|
||||
_aqconfig_.report_zero_pool_temp = text2bool(indx+1);
|
||||
} else if (strncasecmp (b_ptr, "button_", 7) == 0) {
|
||||
int num = strtoul(b_ptr+7, NULL, 10) - 1;
|
||||
//logMessage (LOG_DEBUG, "Button %d\n", strtoul(b_ptr+7, NULL, 10));
|
||||
if (strncasecmp (b_ptr+9, "_label", 6) == 0) {
|
||||
//logMessage (LOG_DEBUG, " Label %s\n", cleanalloc(indx+1));
|
||||
aqdata->aqbuttons[num].label = cleanalloc(indx+1);
|
||||
} else if (strncasecmp (b_ptr+9, "_dzidx", 6) == 0) {
|
||||
//logMessage (LOG_DEBUG, " dzidx %d\n", strtoul(indx+1, NULL, 10));
|
||||
aqdata->aqbuttons[num].dz_idx = strtoul(indx+1, NULL, 10);
|
||||
} else if (strncasecmp (b_ptr+9, "_PDA_label", 10) == 0) {
|
||||
//logMessage (LOG_DEBUG, " dzidx %d\n", strtoul(indx+1, NULL, 10));
|
||||
aqdata->aqbuttons[num].pda_label = cleanalloc(indx+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
//line++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
} else {
|
||||
|
||||
displayLastSystemError(cfgFile);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
|
||||
bool rtn = false;
|
||||
|
||||
if (strncasecmp(param, "debug_log_mask", 14) == 0) {
|
||||
addDebugLogMask(strtoul(value, NULL, 10));
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "socket_port", 11) == 0) {
|
||||
_aqconfig_.socket_port = cleanalloc(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "serial_port", 11) == 0) {
|
||||
_aqconfig_.serial_port = cleanalloc(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "log_level", 9) == 0) {
|
||||
_aqconfig_.log_level = text2elevel(cleanalloc(value));
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "device_id", 9) == 0) {
|
||||
_aqconfig_.device_id = strtoul(cleanalloc(value), NULL, 16);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "rssa_device_id", 14) == 0) {
|
||||
_aqconfig_.rssa_device_id = strtoul(cleanalloc(value), NULL, 16);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "RSSD_LOG_filter", 15) == 0) {
|
||||
_aqconfig_.RSSD_LOG_filter = strtoul(cleanalloc(value), NULL, 16);
|
||||
rtn=true;
|
||||
#if defined AQ_ONETOUCH || defined AQ_IAQTOUCH
|
||||
} else if (strncasecmp (param, "extended_device_id_programming", 30) == 0) {
|
||||
// Has to be before the below.
|
||||
_aqconfig_.extended_device_id_programming = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "extended_device_id", 9) == 0) {
|
||||
_aqconfig_.extended_device_id = strtoul(cleanalloc(value), NULL, 16);
|
||||
//_config_parameters.onetouch_device_id != 0x00
|
||||
rtn=true;
|
||||
#endif
|
||||
} else if (strncasecmp(param, "panel_type_size", 15) == 0) {
|
||||
_tmpPanel->size = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "panel_type_combo", 16) == 0) {
|
||||
_tmpPanel->combo = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "panel_type_dual", 15) == 0) {
|
||||
_tmpPanel->dual = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "panel_type_pda", 14) == 0) {
|
||||
_tmpPanel->rs = !text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "panel_type_rs", 13) == 0) {
|
||||
_tmpPanel->rs = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "panel_type", 10) == 0) { // This must be last so it doesn't get picked up by other settings
|
||||
setPanelByName(aqdata, cleanwhitespace(value));
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "rs_panel_size", 13) == 0) {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'rs_panel_size' no longer supported, please use 'panel_type'\n");
|
||||
_tmpPanel->size = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "web_directory", 13) == 0) {
|
||||
_aqconfig_.web_directory = cleanalloc(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "log_file", 8) == 0) {
|
||||
_aqconfig_.log_file = cleanalloc(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "mqtt_address", 12) == 0) {
|
||||
_aqconfig_.mqtt_server = cleanalloc(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "mqtt_dz_sub_topic", 17) == 0) {
|
||||
_aqconfig_.mqtt_dz_sub_topic = cleanalloc(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "mqtt_dz_pub_topic", 17) == 0) {
|
||||
_aqconfig_.mqtt_dz_pub_topic = cleanalloc(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "mqtt_aq_topic", 13) == 0) {
|
||||
_aqconfig_.mqtt_aq_topic = cleanalloc(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "mqtt_user", 9) == 0) {
|
||||
_aqconfig_.mqtt_user = cleanalloc(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "mqtt_passwd", 11) == 0) {
|
||||
_aqconfig_.mqtt_passwd = cleanalloc(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "air_temp_dzidx", 14) == 0) {
|
||||
_aqconfig_.dzidx_air_temp = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "pool_water_temp_dzidx", 21) == 0) {
|
||||
_aqconfig_.dzidx_pool_water_temp = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "spa_water_temp_dzidx", 20) == 0) {
|
||||
_aqconfig_.dzidx_spa_water_temp = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "light_programming_mode", 21) == 0) {
|
||||
_aqconfig_.light_programming_mode = atof(cleanalloc(value)); // should free this
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "light_programming_initial_on", 28) == 0) {
|
||||
_aqconfig_.light_programming_initial_on = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "light_programming_initial_off", 29) == 0) {
|
||||
_aqconfig_.light_programming_initial_off = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "light_programming_button_spa", 28) == 0) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, 'light_programming_button_spa' no longer supported\n");
|
||||
//_aqconfig_.light_programming_button_spa = strtoul(value, NULL, 10) - 1;
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "light_programming_button", 24) == 0 ||
|
||||
strncasecmp(param, "light_programming_button_pool", 29) == 0) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, 'light_programming_button' & 'light_programming_button_pool' are no longer supported\n");
|
||||
//_aqconfig_.light_programming_button_pool = strtoul(value, NULL, 10) - 1;
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "SWG_percent_dzidx", 17) == 0) {
|
||||
_aqconfig_.dzidx_swg_percent = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "SWG_PPM_dzidx", 13) == 0) {
|
||||
_aqconfig_.dzidx_swg_ppm = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "SWG_Status_dzidx", 14) == 0) {
|
||||
_aqconfig_.dzidx_swg_status = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "override_freeze_protect", 23) == 0) {
|
||||
_aqconfig_.override_freeze_protect = text2bool(value);
|
||||
rtn=true;
|
||||
#ifdef AQ_PDA
|
||||
} else if (strncasecmp(param, "pda_mode", 8) == 0) {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'pda_mode' is no longer supported, please use rs_panel_type\n");
|
||||
//_aqconfig_.pda_mode = text2bool(value);
|
||||
//set_pda_mode(_aqconfig_.pda_mode);
|
||||
_tmpPanel->rs = !text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "pda_sleep_mode", 8) == 0) {
|
||||
_aqconfig_.pda_sleep_mode = text2bool(value);
|
||||
rtn=true;
|
||||
#endif
|
||||
} else if (strncasecmp(param, "convert_mqtt_temp_to_c", 22) == 0) {
|
||||
_aqconfig_.convert_mqtt_temp = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "convert_dz_temp_to_c", 20) == 0) {
|
||||
_aqconfig_.convert_dz_temp = text2bool(value);
|
||||
rtn=true;
|
||||
/*
|
||||
} else if (strncasecmp(param, "flash_mqtt_buttons", 18) == 0) {
|
||||
_aqconfig_.flash_mqtt_buttons = text2bool(value);
|
||||
rtn=true;*/
|
||||
} else if (strncasecmp(param, "report_zero_spa_temp", 20) == 0) {
|
||||
_aqconfig_.report_zero_spa_temp = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "report_zero_pool_temp", 21) == 0) {
|
||||
_aqconfig_.report_zero_pool_temp = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "read_all_devices", 16) == 0) {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'read_all_devices' is no longer supported, please using one or all of 'read_RS485_swg','read_RS485_ePump','read_RS485_vsfPump'\n");
|
||||
if (text2bool(value)) {
|
||||
_aqconfig_.read_RS485_devmask |= READ_RS485_SWG;
|
||||
_aqconfig_.read_RS485_devmask |= READ_RS485_JAN_PUMP;
|
||||
} else {
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_SWG;
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_JAN_PUMP;
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "read_pentair_packets", 17) == 0) {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'read_all_devices' is no longer supported, please using 'read_pentair_pump'\n");
|
||||
if (text2bool(value))
|
||||
_aqconfig_.read_RS485_devmask |= READ_RS485_PEN_PUMP;
|
||||
else
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_PEN_PUMP;
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "read_RS485_swg", 14) == 0) {
|
||||
if (text2bool(value))
|
||||
_aqconfig_.read_RS485_devmask |= READ_RS485_SWG;
|
||||
else
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_SWG;
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "read_RS485_ePump", 16) == 0) {
|
||||
if (text2bool(value))
|
||||
_aqconfig_.read_RS485_devmask |= READ_RS485_JAN_PUMP;
|
||||
else
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_JAN_PUMP;
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "read_RS485_vsfPump", 16) == 0) {
|
||||
if (text2bool(value))
|
||||
_aqconfig_.read_RS485_devmask |= READ_RS485_PEN_PUMP;
|
||||
else
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_PEN_PUMP;
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "use_panel_aux_labels", 20) == 0) {
|
||||
_aqconfig_.use_panel_aux_labels = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "force_SWG", 9) == 0) {
|
||||
_aqconfig_.force_swg = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "force_ps_setpoints", 18) == 0) {
|
||||
_aqconfig_.force_ps_setpoints = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "debug_RSProtocol_bytes", 22) == 0) {
|
||||
_aqconfig_.log_raw_bytes = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "debug_RSProtocol_packets", 24) == 0) {
|
||||
_aqconfig_.log_protocol_packets = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "swg_zero_ignore_count", 21) == 0) {
|
||||
_aqconfig_.swg_zero_ignore = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "display_warnings_in_web", 23) == 0) {
|
||||
_aqconfig_.display_warnings_web = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "serial_readahead_b4_write", 25) == 0) {
|
||||
_aqconfig_.readahead_b4_write = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "mqtt_timed_update", 17) == 0) {
|
||||
_aqconfig_.mqtt_timed_update = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "keep_paneltime_synced", 21) == 0) {
|
||||
_aqconfig_.sync_panel_time = text2bool(value);
|
||||
rtn=true;
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
} else if (strncasecmp (param, "network_poll_speed", 18) == 0) {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'network_poll_speed' is no longer supported, using value for 'rs_poll_speed'\n");
|
||||
_aqconfig_.rs_poll_speed = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "rs_poll_speed", 13) == 0) {
|
||||
_aqconfig_.rs_poll_speed = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "thread_netservices", 18) == 0) {
|
||||
_aqconfig_.thread_netservices = text2bool(value);
|
||||
rtn=true;
|
||||
#endif
|
||||
} else if (strncasecmp (param, "enable_scheduler", 16) == 0) {
|
||||
_aqconfig_.enable_scheduler = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "ftdi_low_latency", 16) == 0) {
|
||||
_aqconfig_.ftdi_low_latency = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "prioritize_ack", 14) == 0) {
|
||||
_aqconfig_.prioritize_ack = text2bool(value);
|
||||
rtn=true;
|
||||
}
|
||||
else if (strncasecmp(param, "button_", 7) == 0) {
|
||||
// Check we have inichalized panel information, if not use any settings we may have
|
||||
if (_aqconfig_.paneltype_mask == 0)
|
||||
setPanel(aqdata, _tmpPanel->rs, _tmpPanel->size, _tmpPanel->combo, _tmpPanel->dual);
|
||||
|
||||
int num = strtoul(param + 7, NULL, 10) - 1;
|
||||
if (num > TOTAL_BUTTONS) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, button_%d is out of range\n",num+1);
|
||||
rtn=false;
|
||||
} else if (strncasecmp(param + 9, "_label", 6) == 0) {
|
||||
aqdata->aqbuttons[num].label = cleanalloc(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 9, "_dzidx", 6) == 0) {
|
||||
aqdata->aqbuttons[num].dz_idx = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
#ifdef AQ_PDA
|
||||
} else if (strncasecmp(param + 9, "_PDA_label", 10) == 0) {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'button_%d_PDA_label' is no longer supported, please use 'button_%d_label'\n",num,num);
|
||||
//aqdata->aqbuttons[num].pda_label = cleanalloc(value);
|
||||
aqdata->aqbuttons[num].label = cleanalloc(value);
|
||||
rtn=true;
|
||||
#endif
|
||||
} else if (strncasecmp(param + 9, "_lightMode", 10) == 0) {
|
||||
if (aqdata->num_lights < MAX_LIGHTS) {
|
||||
int type = strtoul(value, NULL, 10);
|
||||
if (type < LC_PROGRAMABLE || type > NUMBER_LIGHT_COLOR_TYPES) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, unknown light mode '%s'\n",type);
|
||||
} else {
|
||||
aqdata->lights[aqdata->num_lights].button = &aqdata->aqbuttons[num];
|
||||
aqdata->lights[aqdata->num_lights].lightType = type;
|
||||
aqdata->num_lights++;
|
||||
aqdata->aqbuttons[num].special_mask |= PROGRAM_LIGHT;
|
||||
}
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, (colored|programmable) Lights limited to %d, ignoring %s'\n",MAX_LIGHTS,param);
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 9, "_pumpID", 7) == 0) {
|
||||
pump_detail *pump = getpump(aqdata, num);
|
||||
if (pump != NULL) {
|
||||
pump->pumpID = strtoul(cleanalloc(value), NULL, 16);
|
||||
if ( (int)pump->pumpID <= PENTAIR_DEC_PUMP_MAX) {
|
||||
pump->prclType = PENTAIR;
|
||||
} else {
|
||||
pump->prclType = JANDY;
|
||||
//pump->pumpType = EPUMP; // For testing let the interface set this
|
||||
}
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 9, "_pumpIndex", 10) == 0) { //button_01_pumpIndex=1
|
||||
pump_detail *pump = getpump(aqdata, num);
|
||||
if (pump != NULL) {
|
||||
pump->pumpIndex = strtoul(value, NULL, 10);
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
|
||||
}
|
||||
rtn=true;
|
||||
}
|
||||
/*
|
||||
} else if (strncasecmp(param + 9, "_pumpID", 7) == 0) {
|
||||
//aqdata->aqbuttons[num].pda_label = cleanalloc(value);
|
||||
//96 to 111 = Pentair, 120 to 123 = Jandy
|
||||
if (pi < MAX_PUMPS) {
|
||||
aqdata->pumps[pi].button = &aqdata->aqbuttons[num];
|
||||
aqdata->pumps[pi].pumpID = strtoul(cleanalloc(value), NULL, 16);
|
||||
aqdata->pumps[pi].pumpIndex = pi+1;
|
||||
//aqdata->pumps[pi].buttonID = num;
|
||||
if (aqdata->pumps[pi].pumpID < 119)
|
||||
aqdata->pumps[pi].ptype = PENTAIR;
|
||||
else
|
||||
aqdata->pumps[pi].ptype = JANDY;
|
||||
pi++;
|
||||
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
|
||||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 9, "_pumpIndex", 10) == 0) { //button_01_pumpIndex=1
|
||||
}*/
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
pump_detail *getpump(struct aqualinkdata *aqdata, int button)
|
||||
{
|
||||
//static int _pumpindex = 0;
|
||||
//aqdata->num_pumps
|
||||
int pi;
|
||||
|
||||
// Does it exist
|
||||
for (pi=0; pi < aqdata->num_pumps; pi++) {
|
||||
if (aqdata->pumps[pi].button == &aqdata->aqbuttons[button]) {
|
||||
//printf ("Found pump %d\n",button);
|
||||
return &aqdata->pumps[pi];
|
||||
}
|
||||
}
|
||||
|
||||
// Create new entry
|
||||
if (aqdata->num_pumps < MAX_PUMPS) {
|
||||
//printf ("Creating pump %d\n",button);
|
||||
aqdata->aqbuttons[button].special_mask |= VS_PUMP;
|
||||
aqdata->pumps[aqdata->num_pumps].button = &aqdata->aqbuttons[button];
|
||||
aqdata->pumps[aqdata->num_pumps].pumpType = PT_UNKNOWN;
|
||||
aqdata->pumps[aqdata->num_pumps].rpm = TEMP_UNKNOWN;
|
||||
aqdata->pumps[aqdata->num_pumps].watts = TEMP_UNKNOWN;
|
||||
aqdata->pumps[aqdata->num_pumps].gpm = TEMP_UNKNOWN;
|
||||
aqdata->num_pumps++;
|
||||
return &aqdata->pumps[aqdata->num_pumps-1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
FILE * fp ;
|
||||
char bufr[MAXCFGLINE];
|
||||
//const char delim[2] = ";";
|
||||
//char *buf;
|
||||
//int line = 0;
|
||||
//int tokenindex = 0;
|
||||
char *b_ptr;
|
||||
|
||||
|
||||
|
||||
_aqconfig_.config_file = cleanalloc(cfgFile);
|
||||
|
||||
if( (fp = fopen(cfgFile, "r")) != NULL){
|
||||
while(! feof(fp)){
|
||||
if (fgets(bufr, MAXCFGLINE, fp) != NULL)
|
||||
{
|
||||
b_ptr = &bufr[0];
|
||||
char *indx;
|
||||
// Eat leading whitespace
|
||||
while(isspace(*b_ptr)) b_ptr++;
|
||||
if ( b_ptr[0] != '\0' && b_ptr[0] != '#')
|
||||
{
|
||||
indx = strchr(b_ptr, '=');
|
||||
if ( indx != NULL)
|
||||
{
|
||||
if ( ! setConfigValue(aqdata, b_ptr, indx+1))
|
||||
LOG(AQUA_LOG,LOG_ERR, "Unknown config parameter '%.*s'\n",strlen(b_ptr)-1, b_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
} else {
|
||||
/* error processing, couldn't open file */
|
||||
LOG(AQUA_LOG,LOG_ERR, "Error reading config file '%s'\n",cfgFile);
|
||||
errno = EBADF;
|
||||
displayLastSystemError("Error reading config file");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
free(_tmpPanel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//DEBUG_DERIAL, DEBUG, INFO, NOTICE, WARNING, ERROR
|
||||
char *errorlevel2text(int level)
|
||||
{
|
||||
switch(level) {
|
||||
case LOG_DEBUG_SERIAL:
|
||||
return "DEBUG_SERIAL";
|
||||
break;
|
||||
case LOG_DEBUG:
|
||||
return "DEBUG";
|
||||
break;
|
||||
case LOG_INFO:
|
||||
return "INFO";
|
||||
break;
|
||||
case LOG_NOTICE:
|
||||
return "NOTICE";
|
||||
break;
|
||||
case LOG_WARNING:
|
||||
return "WARNING";
|
||||
break;
|
||||
case LOG_ERR:
|
||||
default:
|
||||
return "ERROR";
|
||||
break;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
bool remount_root_ro(bool readonly) {
|
||||
// NSF Check if config is RO_ROOT set
|
||||
if (readonly) {} // Dummy to stop compile warnings.
|
||||
|
||||
if (readonly) {
|
||||
LOG(AQUA_LOG,LOG_INFO, "reMounting root RO\n");
|
||||
mount (NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
|
||||
return true;
|
||||
} else {
|
||||
struct statvfs fsinfo;
|
||||
statvfs("/", &fsinfo);
|
||||
if ((fsinfo.f_flag & ST_RDONLY) == 0) // We are readwrite, ignore
|
||||
return false;
|
||||
|
||||
LOG(AQUA_LOG,LOG_INFO, "reMounting root RW\n");
|
||||
mount (NULL, "/", NULL, MS_REMOUNT, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
void writeCharValue (FILE *fp, char *msg, char *value)
|
||||
{
|
||||
if (value == NULL)
|
||||
fprintf(fp, "#%s = \n",msg);
|
||||
else
|
||||
fprintf(fp, "%s = %s\n", msg, value);
|
||||
}
|
||||
void writeIntValue (FILE *fp, char *msg, int value)
|
||||
{
|
||||
if (value <= 0)
|
||||
fprintf(fp, "#%s = \n",msg);
|
||||
else
|
||||
fprintf(fp, "%s = %d\n", msg, value);
|
||||
}
|
||||
|
||||
|
||||
bool writeCfg (struct aqualinkdata *aqdata)
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_ERR, "writeCfg() not implimented\n");
|
||||
/*
|
||||
FILE *fp;
|
||||
int i;
|
||||
bool fs = remount_root_ro(false);
|
||||
|
||||
fp = fopen(_aqconfig_.config_file, "w");
|
||||
if (fp == NULL) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Open config file failed '%s'\n", _aqconfig_.config_file);
|
||||
remount_root_ro(true);
|
||||
//fprintf(stdout, "Open file failed 'sprinkler.cron'\n");
|
||||
return false;
|
||||
}
|
||||
fprintf(fp, "#***** AqualinkD configuration *****\n");
|
||||
|
||||
fprintf(fp, "socket_port = %s\n", _aqconfig_.socket_port);
|
||||
fprintf(fp, "serial_port = %s\n", _aqconfig_.serial_port);
|
||||
fprintf(fp, "device_id = 0x%02hhx\n", _aqconfig_.device_id);
|
||||
fprintf(fp, "read_all_devices = %s", bool2text(_aqconfig_.read_all_devices));
|
||||
writeCharValue(fp, "log_level", errorlevel2text(_aqconfig_.log_level));
|
||||
writeCharValue(fp, "web_directory", _aqconfig_.web_directory);
|
||||
writeCharValue(fp, "log_file", _aqconfig_.log_file);
|
||||
fprintf(fp, "pda_mode = %s\n", bool2text(_aqconfig_.pda_mode));
|
||||
|
||||
fprintf(fp, "\n#** MQTT Configuration **\n");
|
||||
writeCharValue(fp, "mqtt_address", _aqconfig_.mqtt_server);
|
||||
writeCharValue(fp, "mqtt_dz_sub_topic", _aqconfig_.mqtt_dz_sub_topic);
|
||||
writeCharValue(fp, "mqtt_dz_pub_topic", _aqconfig_.mqtt_dz_pub_topic);
|
||||
writeCharValue(fp, "mqtt_aq_topic", _aqconfig_.mqtt_aq_topic);
|
||||
writeCharValue(fp, "mqtt_user", _aqconfig_.mqtt_user);
|
||||
writeCharValue(fp, "mqtt_passwd", _aqconfig_.mqtt_passwd);
|
||||
|
||||
fprintf(fp, "\n#** General **\n");
|
||||
fprintf(fp, "convert_mqtt_temp_to_c = %s\n", bool2text(_aqconfig_.convert_mqtt_temp));
|
||||
fprintf(fp, "override_freeze_protect = %s\n", bool2text(_aqconfig_.override_freeze_protect));
|
||||
//fprintf(fp, "flash_mqtt_buttons = %s\n", bool2text(_aqconfig_.flash_mqtt_buttons));
|
||||
fprintf(fp, "report_zero_spa_temp = %s\n", bool2text(_aqconfig_.report_zero_spa_temp));
|
||||
fprintf(fp, "report_zero_pool_temp = %s\n", bool2text(_aqconfig_.report_zero_pool_temp));
|
||||
|
||||
fprintf(fp, "\n#** Programmable light **\n");
|
||||
//if (_aqconfig_.light_programming_button_pool <= 0) {
|
||||
// fprintf(fp, "#light_programming_button_pool = %d\n", _aqconfig_.light_programming_button_pool);
|
||||
// fprintf(fp, "#light_programming_mode = %f\n", _aqconfig_.light_programming_mode);
|
||||
// fprintf(fp, "#light_programming_initial_on = %d\n", _aqconfig_.light_programming_initial_on);
|
||||
// fprintf(fp, "#light_programming_initial_off = %d\n", _aqconfig_.light_programming_initial_off);
|
||||
//} else {
|
||||
fprintf(fp, "light_programming_button_pool = %d\n", _aqconfig_.light_programming_button_pool);
|
||||
fprintf(fp, "light_programming_button_spa = %d\n", _aqconfig_.light_programming_button_spa);
|
||||
fprintf(fp, "light_programming_mode = %f\n", _aqconfig_.light_programming_mode);
|
||||
fprintf(fp, "light_programming_initial_on = %d\n", _aqconfig_.light_programming_initial_on);
|
||||
fprintf(fp, "light_programming_initial_off = %d\n", _aqconfig_.light_programming_initial_off);
|
||||
//}
|
||||
|
||||
fprintf(fp, "\n#** Domoticz **\n");
|
||||
fprintf(fp, "convert_dz_temp_to_c = %s\n", bool2text(_aqconfig_.convert_dz_temp));
|
||||
writeIntValue(fp, "air_temp_dzidx", _aqconfig_.dzidx_air_temp);
|
||||
writeIntValue(fp, "pool_water_temp_dzidx", _aqconfig_.dzidx_pool_water_temp);
|
||||
writeIntValue(fp, "spa_water_temp_dzidx", _aqconfig_.dzidx_spa_water_temp);
|
||||
writeIntValue(fp, "SWG_percent_dzidx", _aqconfig_.dzidx_swg_percent);
|
||||
writeIntValue(fp, "SWG_PPM_dzidx", _aqconfig_.dzidx_swg_ppm);
|
||||
writeIntValue(fp, "SWG_Status_dzidx", _aqconfig_.dzidx_swg_status);
|
||||
|
||||
fprintf(fp, "\n#** Buttons **\n");
|
||||
for (i=0; i < TOTAL_BUTTONS; i++)
|
||||
{
|
||||
fprintf(fp, "button_%.2d_label = %s\n", i+1, aqdata->aqbuttons[i].label);
|
||||
if (aqdata->aqbuttons[i].dz_idx > 0)
|
||||
fprintf(fp, "button_%.2d_dzidx = %d\n", i+1, aqdata->aqbuttons[i].dz_idx);
|
||||
if (aqdata->aqbuttons[i].pda_label != NULL)
|
||||
fprintf(fp, "button_%.2d_PDA_label = %s\n", i+1, aqdata->aqbuttons[i].pda_label);
|
||||
}
|
||||
fclose(fp);
|
||||
remount_root_ro(fs);
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
131
config.h
131
config.h
|
@ -1,131 +0,0 @@
|
|||
|
||||
#ifndef CONFIG_H_
|
||||
#define CONFIG_H_
|
||||
|
||||
#include "utils.h"
|
||||
#include "aq_serial.h"
|
||||
#include "aqualink.h"
|
||||
|
||||
|
||||
//#define DEFAULT_LOG_LEVEL 10
|
||||
#define DEFAULT_LOG_LEVEL LOG_NOTICE
|
||||
#define DEFAULT_WEBPORT "6580"
|
||||
#define DEFAULT_WEBROOT "./"
|
||||
#define DEFAULT_SERIALPORT "/dev/ttyUSB0"
|
||||
#define DEFAULT_DEVICE_ID "0x0a"
|
||||
#define DEFAULT_MQTT_DZ_IN NULL
|
||||
#define DEFAULT_MQTT_DZ_OUT NULL
|
||||
#define DEFAULT_MQTT_AQ_TP NULL
|
||||
#define DEFAULT_MQTT_SERVER NULL
|
||||
#define DEFAULT_MQTT_USER NULL
|
||||
#define DEFAULT_MQTT_PASSWD NULL
|
||||
#define DEFAULT_SWG_ZERO_IGNORE_COUNT 0
|
||||
|
||||
#define MQTT_ID_LEN 18 // 20 seems to kill mosquitto 1.6
|
||||
|
||||
// For aqconfig.read_RS485_devmask
|
||||
#define READ_RS485_SWG (1 << 0) // 1 SWG
|
||||
#define READ_RS485_JAN_PUMP (1 << 1) // 2 Jandy Pump
|
||||
#define READ_RS485_PEN_PUMP (1 << 2) // 4 Pentair Pump
|
||||
|
||||
struct aqconfig
|
||||
{
|
||||
char *config_file;
|
||||
char *serial_port;
|
||||
unsigned int log_level;
|
||||
char *socket_port;
|
||||
char *web_directory;
|
||||
unsigned char device_id;
|
||||
unsigned char rssa_device_id;
|
||||
int16_t paneltype_mask;
|
||||
#if defined AQ_ONETOUCH || defined AQ_IAQTOUCH
|
||||
unsigned char extended_device_id;
|
||||
bool extended_device_id_programming;
|
||||
#endif
|
||||
bool deamonize;
|
||||
char *log_file;
|
||||
char *mqtt_dz_sub_topic;
|
||||
char *mqtt_dz_pub_topic;
|
||||
char *mqtt_aq_topic;
|
||||
char *mqtt_server;
|
||||
char *mqtt_user;
|
||||
char *mqtt_passwd;
|
||||
char mqtt_ID[MQTT_ID_LEN];
|
||||
int dzidx_air_temp;
|
||||
int dzidx_pool_water_temp;
|
||||
int dzidx_spa_water_temp;
|
||||
int dzidx_swg_percent;
|
||||
int dzidx_swg_ppm;
|
||||
int dzidx_swg_status;
|
||||
float light_programming_mode;
|
||||
int light_programming_initial_on;
|
||||
int light_programming_initial_off;
|
||||
bool override_freeze_protect;
|
||||
#ifdef AQ_PDA
|
||||
bool pda_sleep_mode;
|
||||
#endif
|
||||
bool convert_mqtt_temp;
|
||||
bool convert_dz_temp;
|
||||
bool report_zero_spa_temp;
|
||||
bool report_zero_pool_temp;
|
||||
//bool read_all_devices;
|
||||
//bool read_pentair_packets;
|
||||
uint8_t read_RS485_devmask;
|
||||
bool use_panel_aux_labels;
|
||||
bool force_swg;
|
||||
bool force_ps_setpoints;
|
||||
int swg_zero_ignore;
|
||||
bool display_warnings_web;
|
||||
bool log_protocol_packets; // Read & Write as packets
|
||||
bool log_raw_bytes; // Read as bytes
|
||||
unsigned char RSSD_LOG_filter;
|
||||
//bool log_raw_RS_bytes;
|
||||
bool readahead_b4_write;
|
||||
bool mqtt_timed_update;
|
||||
bool sync_panel_time;
|
||||
bool enable_scheduler;
|
||||
bool ftdi_low_latency;
|
||||
bool prioritize_ack;
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
int rs_poll_speed; // Need to remove
|
||||
bool thread_netservices; // Need to remove
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef CONFIG_C
|
||||
extern struct aqconfig _aqconfig_;
|
||||
#else
|
||||
struct aqconfig _aqconfig_;
|
||||
#endif
|
||||
|
||||
|
||||
#define READ_RSDEV_SWG ((_aqconfig_.read_RS485_devmask & READ_RS485_SWG) == READ_RS485_SWG)
|
||||
#define READ_RSDEV_ePUMP ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_PUMP) == READ_RS485_JAN_PUMP)
|
||||
#define READ_RSDEV_vsfPUMP ((_aqconfig_.read_RS485_devmask & READ_RS485_PEN_PUMP) == READ_RS485_PEN_PUMP)
|
||||
|
||||
//#define isPDA ((_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA)
|
||||
|
||||
|
||||
/*
|
||||
#ifndef CONFIG_C
|
||||
#ifdef AQUALINKD_C
|
||||
extern struct aqconfig _aqconfig_;
|
||||
#else
|
||||
extern const struct aqconfig _aqconfig_;
|
||||
#endif
|
||||
#endif
|
||||
*/
|
||||
|
||||
void init_parameters (struct aqconfig * parms);
|
||||
//bool parse_config (struct aqconfig * parms, char *cfgfile);
|
||||
//void readCfg (struct aqconfig *config_parameters, char *cfgFile);
|
||||
//void readCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqualink_data, char *cfgFile);
|
||||
void read_config(struct aqualinkdata *aqdata, char *cfgFile);
|
||||
void init_config();
|
||||
|
||||
bool writeCfg (struct aqualinkdata *aqdata);
|
||||
bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value);
|
||||
|
||||
char *cleanalloc(char*str);
|
||||
|
||||
#endif
|
482
devices_jandy.c
482
devices_jandy.c
|
@ -1,482 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Shaun Feakes - All rights reserved
|
||||
*
|
||||
* You may use redistribute and/or modify this code under the terms of
|
||||
* the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. For the terms of this license,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* https://github.com/sfeakes/aqualinkd
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "devices_jandy.h"
|
||||
#include "aq_serial.h"
|
||||
#include "aqualink.h"
|
||||
#include "utils.h"
|
||||
#include "aq_mqtt.h"
|
||||
#include "packetLogger.h"
|
||||
|
||||
/*
|
||||
All button errors
|
||||
'Check AQUAPURE No Flow'
|
||||
'Check AQUAPURE Low Salt'
|
||||
'Check AQUAPURE High Salt'
|
||||
'Check AQUAPURE General Fault'
|
||||
*/
|
||||
|
||||
static int _swg_noreply_cnt = 0;
|
||||
|
||||
bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
static rsDeviceType interestedInNextAck = DRS_NONE;
|
||||
static unsigned char previous_packet_to = NUL; // bad name, it's not previous, it's previous that we were interested in.
|
||||
int rtn = false;
|
||||
// We received the ack from a Jandy device we are interested in
|
||||
if (packet_buffer[PKT_DEST] == DEV_MASTER && interestedInNextAck != DRS_NONE)
|
||||
{
|
||||
if (interestedInNextAck == DRS_SWG)
|
||||
{
|
||||
rtn = processPacketFromSWG(packet_buffer, packet_length, aqdata);
|
||||
}
|
||||
else if (interestedInNextAck == DRS_EPUMP)
|
||||
{
|
||||
rtn = processPacketFromJandyPump(packet_buffer, packet_length, aqdata);
|
||||
}
|
||||
interestedInNextAck = DRS_NONE;
|
||||
previous_packet_to = NUL;
|
||||
}
|
||||
// We were expecting an ack from Jandy device but didn't receive it.
|
||||
else if (packet_buffer[PKT_DEST] != DEV_MASTER && interestedInNextAck != DRS_NONE)
|
||||
{
|
||||
if (interestedInNextAck == DRS_SWG && aqdata->ar_swg_device_status != SWG_STATUS_OFF)
|
||||
{ // SWG Offline
|
||||
processMissingAckPacketFromSWG(previous_packet_to, aqdata);
|
||||
}
|
||||
else if (interestedInNextAck == DRS_EPUMP)
|
||||
{ // ePump offline
|
||||
processMissingAckPacketFromJandyPump(previous_packet_to, aqdata);
|
||||
}
|
||||
interestedInNextAck = DRS_NONE;
|
||||
previous_packet_to = NUL;
|
||||
}
|
||||
else if (READ_RSDEV_SWG && packet_buffer[PKT_DEST] == SWG_DEV_ID)
|
||||
{
|
||||
interestedInNextAck = DRS_SWG;
|
||||
rtn = processPacketToSWG(packet_buffer, packet_length, aqdata, _aqconfig_.swg_zero_ignore);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
else if (READ_RSDEV_ePUMP && packet_buffer[PKT_DEST] >= JANDY_DEC_PUMP_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_PUMP_MAX)
|
||||
{
|
||||
interestedInNextAck = DRS_EPUMP;
|
||||
rtn = processPacketToJandyPump(packet_buffer, packet_length, aqdata);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
else
|
||||
{
|
||||
interestedInNextAck = DRS_NONE;
|
||||
previous_packet_to = NUL;
|
||||
}
|
||||
|
||||
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 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) {
|
||||
// In service or timeout mode SWG set % message is very strange. AR %% | HEX: 0x10|0x02|0x50|0x11|0xff|0x72|0x10|0x03|
|
||||
// Not really sure what to do with this, just ignore 0xff / 255 for the moment. (if statment above)
|
||||
|
||||
// SWG can get ~10 messages to set to 0 then go back again for some reason, so don't go to 0 until 10 messages are received
|
||||
if (swg_zero_cnt <= swg_zero_ignore && packet[4] == 0x00) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Ignoring SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n", (int)packet[4],
|
||||
swg_zero_cnt, swg_zero_ignore, packet[4], packet[5]);
|
||||
swg_zero_cnt++;
|
||||
} else if (swg_zero_cnt > swg_zero_ignore && packet[4] == 0x00) {
|
||||
if (aqdata->swg_percent != (int)packet[4]) {
|
||||
//aqdata->swg_percent = (int)packet[4];
|
||||
setSWGpercent(aqdata, (int)packet[4]);
|
||||
changedAnything = true;
|
||||
aqdata->updated = true;
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG %% to %d from reading control panel packet sent to SWG (received %d messages)\n", aqdata->swg_percent, swg_zero_cnt);
|
||||
}
|
||||
// LOG(DJAN_LOG, LOG_DEBUG, "SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n",
|
||||
// (int)packet[4],swg_zero_cnt,SWG_ZERO_IGNORE_COUNT,packet[4],packet[5]); swg_zero_cnt++;
|
||||
} else {
|
||||
swg_zero_cnt = 0;
|
||||
if (aqdata->swg_percent != (int)packet[4]) {
|
||||
//aqdata->swg_percent = (int)packet[4];
|
||||
setSWGpercent(aqdata, (int)packet[4]);
|
||||
changedAnything = true;
|
||||
aqdata->updated = true;
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG %% to %d from control panel packet to SWG\n", aqdata->swg_percent);
|
||||
}
|
||||
// LOG(DJAN_LOG, LOG_DEBUG, "SWG set to %d due to packet from control panel to SWG 0x%02hhx 0x%02hhx\n",
|
||||
// aqdata.swg_percent,packet[4],packet[5]);
|
||||
}
|
||||
|
||||
if (aqdata->swg_percent > 100)
|
||||
aqdata->boost = true;
|
||||
else
|
||||
aqdata->boost = false;
|
||||
}
|
||||
return changedAnything;
|
||||
}
|
||||
|
||||
bool processPacketFromSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata) {
|
||||
bool changedAnything = false;
|
||||
_swg_noreply_cnt = 0;
|
||||
|
||||
if (packet[PKT_CMD] == CMD_PPM) {
|
||||
//aqdata->ar_swg_device_status = packet[5];
|
||||
setSWGdeviceStatus(aqdata, JANDY_DEVICE, packet[5]);
|
||||
if (aqdata->swg_delayed_percent != TEMP_UNKNOWN && aqdata->ar_swg_device_status == SWG_STATUS_ON) { // We have a delayed % to set.
|
||||
char sval[10];
|
||||
snprintf(sval, 9, "%d", aqdata->swg_delayed_percent);
|
||||
aq_programmer(AQ_SET_SWG_PERCENT, sval, aqdata);
|
||||
LOG(DJAN_LOG, LOG_NOTICE, "Setting SWG %% to %d, from delayed message\n", aqdata->swg_delayed_percent);
|
||||
aqdata->swg_delayed_percent = TEMP_UNKNOWN;
|
||||
}
|
||||
|
||||
if ( (packet[4] * 100) != aqdata->swg_ppm ) {
|
||||
aqdata->swg_ppm = packet[4] * 100;
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG PPM to %d from SWG packet\n", aqdata->swg_ppm);
|
||||
changedAnything = true;
|
||||
aqdata->updated = true;
|
||||
}
|
||||
// logMessage(LOG_DEBUG, "Read SWG PPM %d from ID 0x%02hhx\n", aqdata.swg_ppm, SWG_DEV_ID);
|
||||
}
|
||||
|
||||
return changedAnything;
|
||||
}
|
||||
|
||||
void processMissingAckPacketFromSWG(unsigned char destination, struct aqualinkdata *aqdata)
|
||||
{
|
||||
// SWG_STATUS_UNKNOWN means we have never seen anything from SWG, so leave as is.
|
||||
// IAQTOUCH & ONETOUCH give us AQUAPURE=0 but ALLBUTTON doesn't, so only turn off if we are not in extra device mode.
|
||||
// NSF Need to check that we actually use 0 from IAQTOUCH & ONETOUCH
|
||||
if ( aqdata->ar_swg_device_status != SWG_STATUS_UNKNOWN && isIAQT_ENABLED == false && isONET_ENABLED == false )
|
||||
{
|
||||
if ( _swg_noreply_cnt < 3 ) {
|
||||
//_aqualink_data.ar_swg_device_status = SWG_STATUS_OFF;
|
||||
//_aqualink_data.updated = true;
|
||||
setSWGoff(aqdata);
|
||||
_swg_noreply_cnt++; // Don't put in if, as it'll go past size limit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isSWGDeviceErrorState(unsigned char status)
|
||||
{
|
||||
if (status == SWG_STATUS_NO_FLOW ||
|
||||
status == SWG_STATUS_CHECK_PCB ||
|
||||
status == SWG_STATUS_LOW_TEMP ||
|
||||
status == SWG_STATUS_HIGH_CURRENT ||
|
||||
status == SWG_STATUS_NO_FLOW)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void setSWGdeviceStatus(struct aqualinkdata *aqdata, emulation_type requester, unsigned char status) {
|
||||
if (aqdata->ar_swg_device_status == status)
|
||||
return;
|
||||
|
||||
// If we get (ALLBUTTON, SWG_STATUS_CHECK_PCB), it sends this for many status, like clean cell.
|
||||
// So if we are in one of those states, don't use it.
|
||||
|
||||
if (requester == ALLBUTTON && status == SWG_STATUS_CHECK_PCB ) {
|
||||
if (aqdata->ar_swg_device_status > SWG_STATUS_ON &&
|
||||
aqdata->ar_swg_device_status < SWG_STATUS_TURNING_OFF) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Ignoreing set SWG device state to '0x%02hhx', request from %d\n", aqdata->ar_swg_device_status, requester);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check validity of status and set as appropiate
|
||||
switch (status) {
|
||||
|
||||
case SWG_STATUS_ON:
|
||||
case SWG_STATUS_NO_FLOW:
|
||||
case SWG_STATUS_LOW_SALT:
|
||||
case SWG_STATUS_HI_SALT:
|
||||
case SWG_STATUS_HIGH_CURRENT:
|
||||
case SWG_STATUS_CLEAN_CELL:
|
||||
case SWG_STATUS_LOW_VOLTS:
|
||||
case SWG_STATUS_LOW_TEMP:
|
||||
case SWG_STATUS_CHECK_PCB:
|
||||
aqdata->ar_swg_device_status = status;
|
||||
aqdata->swg_led_state = isSWGDeviceErrorState(status)?ENABLE:ON;
|
||||
break;
|
||||
case SWG_STATUS_OFF: // THIS IS OUR OFF STATUS, NOT AQUAPURE
|
||||
case SWG_STATUS_TURNING_OFF:
|
||||
aqdata->ar_swg_device_status = status;
|
||||
aqdata->swg_led_state = OFF;
|
||||
break;
|
||||
default:
|
||||
LOG(DJAN_LOG, LOG_WARNING, "Ignoring set SWG device to state '0x%02hhx', state is unknown\n", status);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG device state to '0x%02hhx', request from %d, LED state = %d\n", aqdata->ar_swg_device_status, requester, aqdata->swg_led_state);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
bool updateSWG(struct aqualinkdata *aqdata, emulation_type requester, aqledstate state, int percent)
|
||||
{
|
||||
switch (requester) {
|
||||
case ALLBUTTON: // no insight into 0% (just blank)
|
||||
break;
|
||||
case ONETOUCH:
|
||||
break;
|
||||
case IAQTOUCH:
|
||||
break;
|
||||
case AQUAPDA:
|
||||
break;
|
||||
case JANDY_DEVICE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
bool setSWGboost(struct aqualinkdata *aqdata, bool on) {
|
||||
if (!on) {
|
||||
aqdata->boost = false;
|
||||
aqdata->boost_msg[0] = '\0';
|
||||
aqdata->swg_percent = 0;
|
||||
} else {
|
||||
aqdata->boost = true;
|
||||
aqdata->swg_percent = 101;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only change SWG percent if we are not in SWG programming
|
||||
bool changeSWGpercent(struct aqualinkdata *aqdata, int percent) {
|
||||
|
||||
if (in_swg_programming_mode(aqdata)) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Ignoring set SWG %% to %d due to programming SWG\n", aqdata->swg_percent);
|
||||
return false;
|
||||
}
|
||||
|
||||
setSWGpercent(aqdata, percent);
|
||||
return true;
|
||||
}
|
||||
|
||||
void setSWGoff(struct aqualinkdata *aqdata) {
|
||||
if (aqdata->ar_swg_device_status != SWG_STATUS_OFF || aqdata->swg_led_state != OFF)
|
||||
aqdata->updated = true;
|
||||
|
||||
aqdata->ar_swg_device_status = SWG_STATUS_OFF;
|
||||
aqdata->swg_led_state = OFF;
|
||||
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG to off\n");
|
||||
}
|
||||
|
||||
void setSWGenabled(struct aqualinkdata *aqdata) {
|
||||
if (aqdata->swg_led_state != ENABLE) {
|
||||
aqdata->updated = true;
|
||||
aqdata->swg_led_state = ENABLE;
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG to Enable\n");
|
||||
}
|
||||
}
|
||||
|
||||
// force a Change SWG percent.
|
||||
void setSWGpercent(struct aqualinkdata *aqdata, int percent) {
|
||||
|
||||
aqdata->swg_percent = percent;
|
||||
aqdata->updated = true;
|
||||
|
||||
if (aqdata->swg_percent > 0) {
|
||||
//LOG(DJAN_LOG, LOG_DEBUG, "swg_led_state=%d, swg_led_state=%d, isSWGDeviceErrorState=%d, ar_swg_device_status=%d\n",aqdata->swg_led_state, aqdata->swg_led_state, isSWGDeviceErrorState(aqdata->ar_swg_device_status),aqdata->ar_swg_device_status);
|
||||
if (aqdata->swg_led_state == OFF || (aqdata->swg_led_state == ENABLE && ! isSWGDeviceErrorState(aqdata->ar_swg_device_status)) ) // Don't change ENABLE / FLASH
|
||||
aqdata->swg_led_state = ON;
|
||||
|
||||
if (aqdata->ar_swg_device_status == SWG_STATUS_UNKNOWN)
|
||||
aqdata->ar_swg_device_status = SWG_STATUS_ON;
|
||||
|
||||
} if ( aqdata->swg_percent == 0 ) {
|
||||
if (aqdata->swg_led_state == ON)
|
||||
aqdata->swg_led_state = ENABLE; // Don't change OFF
|
||||
|
||||
if (aqdata->ar_swg_device_status == SWG_STATUS_UNKNOWN)
|
||||
aqdata->ar_swg_device_status = SWG_STATUS_ON; // Maybe this should be off
|
||||
}
|
||||
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG %% to %d, LED=%d, FullStatus=0x%02hhx\n", aqdata->swg_percent, aqdata->swg_led_state, aqdata->ar_swg_device_status);
|
||||
}
|
||||
|
||||
aqledstate get_swg_led_state(struct aqualinkdata *aqdata)
|
||||
{
|
||||
switch (aqdata->ar_swg_device_status) {
|
||||
|
||||
case SWG_STATUS_ON:
|
||||
return (aqdata->swg_percent > 0?ON:ENABLE);
|
||||
break;
|
||||
case SWG_STATUS_NO_FLOW:
|
||||
return ENABLE;
|
||||
break;
|
||||
case SWG_STATUS_LOW_SALT:
|
||||
return (aqdata->swg_percent > 0?ON:ENABLE);
|
||||
break;
|
||||
case SWG_STATUS_HI_SALT:
|
||||
return (aqdata->swg_percent > 0?ON:ENABLE);
|
||||
break;
|
||||
case SWG_STATUS_HIGH_CURRENT:
|
||||
return (aqdata->swg_percent > 0?ON:ENABLE);
|
||||
break;
|
||||
case SWG_STATUS_TURNING_OFF:
|
||||
return OFF;
|
||||
break;
|
||||
case SWG_STATUS_CLEAN_CELL:
|
||||
return (aqdata->swg_percent > 0?ON:ENABLE);
|
||||
return ENABLE;
|
||||
break;
|
||||
case SWG_STATUS_LOW_VOLTS:
|
||||
return ENABLE;
|
||||
break;
|
||||
case SWG_STATUS_LOW_TEMP:
|
||||
return ENABLE;
|
||||
break;
|
||||
case SWG_STATUS_CHECK_PCB:
|
||||
return ENABLE;
|
||||
break;
|
||||
case SWG_STATUS_OFF: // THIS IS OUR OFF STATUS, NOT AQUAPURE
|
||||
return OFF;
|
||||
break;
|
||||
default:
|
||||
return (aqdata->swg_percent > 0?ON:ENABLE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void get_swg_status_msg(struct aqualinkdata *aqdata, char *message)
|
||||
{
|
||||
int tmp1;
|
||||
int tmp2;
|
||||
|
||||
return get_swg_status_mqtt(aqdata, message, &tmp1, &tmp2);
|
||||
}
|
||||
|
||||
void get_swg_status_mqtt(struct aqualinkdata *aqdata, char *message, int *status, int *dzalert)
|
||||
{
|
||||
switch (aqdata->ar_swg_device_status) {
|
||||
// Level = (0=gray, 1=green, 2=yellow, 3=orange, 4=red)
|
||||
case SWG_STATUS_ON:
|
||||
*status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
|
||||
sprintf(message, "AQUAPURE GENERATING CHLORINE");
|
||||
*dzalert = 1;
|
||||
break;
|
||||
case SWG_STATUS_NO_FLOW:
|
||||
*status = SWG_OFF;
|
||||
sprintf(message, "AQUAPURE NO FLOW");
|
||||
*dzalert = 2;
|
||||
break;
|
||||
case SWG_STATUS_LOW_SALT:
|
||||
*status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
|
||||
sprintf(message, "AQUAPURE LOW SALT");
|
||||
*dzalert = 2;
|
||||
break;
|
||||
case SWG_STATUS_HI_SALT:
|
||||
*status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
|
||||
sprintf(message, "AQUAPURE HIGH SALT");
|
||||
*dzalert = 3;
|
||||
break;
|
||||
case SWG_STATUS_HIGH_CURRENT:
|
||||
*status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
|
||||
sprintf(message, "AQUAPURE HIGH CURRENT");
|
||||
*dzalert = 4;
|
||||
break;
|
||||
case SWG_STATUS_TURNING_OFF:
|
||||
*status = SWG_OFF;
|
||||
sprintf(message, "AQUAPURE TURNING OFF");
|
||||
*dzalert = 0;
|
||||
break;
|
||||
case SWG_STATUS_CLEAN_CELL:
|
||||
*status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
|
||||
sprintf(message, "AQUAPURE CLEAN CELL");
|
||||
*dzalert = 2;
|
||||
break;
|
||||
case SWG_STATUS_LOW_VOLTS:
|
||||
*status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
|
||||
sprintf(message, "AQUAPURE LOW VOLTAGE");
|
||||
*dzalert = 3;
|
||||
break;
|
||||
case SWG_STATUS_LOW_TEMP:
|
||||
*status = SWG_OFF;
|
||||
sprintf(message, "AQUAPURE WATER TEMP LOW");
|
||||
*dzalert = 2;
|
||||
break;
|
||||
case SWG_STATUS_CHECK_PCB:
|
||||
*status = SWG_OFF;
|
||||
sprintf(message, "AQUAPURE CHECK PCB");
|
||||
*dzalert = 4;
|
||||
break;
|
||||
case SWG_STATUS_OFF: // THIS IS OUR OFF STATUS, NOT AQUAPURE
|
||||
*status = SWG_OFF;
|
||||
sprintf(message, "AQUAPURE OFF");
|
||||
*dzalert = 0;
|
||||
break;
|
||||
default:
|
||||
*status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
|
||||
sprintf(message, "AQUAPURE UNKNOWN STATUS");
|
||||
*dzalert = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool processPacketToJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
char msg[1000];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "To ePump: %s\n", msg);
|
||||
|
||||
//find pump for message
|
||||
if ( 1 == 0 /*SOME_DEBUG_TEST*/) {
|
||||
int i;
|
||||
for (i=0; i < aqdata->num_pumps; i++) {
|
||||
if (aqdata->pumps[i].pumpID == packet_buffer[PKT_DEST]) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Last panel info RPM:%d GPM:%d WATTS:%d\n", aqdata->pumps[i].rpm, aqdata->pumps[i].gpm, aqdata->pumps[i].watts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
char msg[1000];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "From ePump: %s\n", msg);
|
||||
return false;
|
||||
}
|
||||
void processMissingAckPacketFromJandyPump(unsigned char destination, struct aqualinkdata *aqdata)
|
||||
{
|
||||
// Do nothing for the moment.
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Messages to ePump so far.
|
||||
Debug: To ePump: Jandy Packet | HEX: 0x10|0x02|0x78|0x42|0xcc|0x10|0x03|
|
||||
Debug: To ePump: Jandy Packet | HEX: 0x10|0x02|0x78|0x44|0x00|0x10|0x27|0x05|0x10|0x03|
|
||||
Debug: To ePump: Jandy Packet | HEX: 0x10|0x02|0x78|0x44|0x00|0x58|0x1b|0x41|0x10|0x03|
|
||||
Debug: To ePump: Jandy Packet | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Debug: To ePump: Jandy Packet | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Debug: To ePump: Jandy Packet | HEX: 0x10|0x02|0x78|0x46|0x00|0x04|0x00|0xd4|0x10|0x03|
|
||||
*/
|
|
@ -1,27 +0,0 @@
|
|||
#ifndef AQUAPURE_H_
|
||||
#define AQUAPURE_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "aqualink.h"
|
||||
|
||||
bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
|
||||
bool processPacketToSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata, int swg_zero_ignore);
|
||||
bool processPacketFromSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata);
|
||||
bool processPacketToJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
void processMissingAckPacketFromSWG(unsigned char destination, struct aqualinkdata *aqdata);
|
||||
void processMissingAckPacketFromJandyPump(unsigned char destination, struct aqualinkdata *aqdata);
|
||||
|
||||
void get_swg_status_mqtt(struct aqualinkdata *aqdata, char *message, int *status, int *dzalert);
|
||||
aqledstate get_swg_led_state(struct aqualinkdata *aqdata);
|
||||
|
||||
bool changeSWGpercent(struct aqualinkdata *aqdata, int percent);
|
||||
void setSWGpercent(struct aqualinkdata *aqdata, int percent);
|
||||
void setSWGoff(struct aqualinkdata *aqdata);
|
||||
void setSWGenabled(struct aqualinkdata *aqdata);
|
||||
bool setSWGboost(struct aqualinkdata *aqdata, bool on);
|
||||
void setSWGdeviceStatus(struct aqualinkdata *aqdata, emulation_type requester, unsigned char status);
|
||||
|
||||
#endif // AQUAPURE_H_
|
|
@ -1,139 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2017 Shaun Feakes - All rights reserved
|
||||
*
|
||||
* You may use redistribute and/or modify this code under the terms of
|
||||
* the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. For the terms of this license,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* https://github.com/sfeakes/aqualinkd
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aqualink.h"
|
||||
#include "aq_serial.h"
|
||||
#include "devices_pentair.h"
|
||||
#include "utils.h"
|
||||
|
||||
bool processPentairPacket(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
bool changedAnything = false;
|
||||
int i;
|
||||
//ID's 96 to 111 = Pentair (or 0x60 to 0x6F)
|
||||
|
||||
// Need to find a better way to support pump index
|
||||
|
||||
//static int pumpIndex = 1;
|
||||
|
||||
if ( packet[PEN_PKT_CMD] == PEN_CMD_STATUS && packet[PEN_PKT_FROM] >= PENTAIR_DEC_PUMP_MIN && packet[PEN_PKT_FROM] <= PENTAIR_DEC_PUMP_MAX ){
|
||||
// We have Pentair Pump packet, let's see if it's configured.
|
||||
//printf("PUMP\n");
|
||||
|
||||
for (i = 0; i < MAX_PUMPS; i++) {
|
||||
if ( aqdata->pumps[i].prclType == PENTAIR && aqdata->pumps[i].pumpID == packet[PEN_PKT_FROM] ) {
|
||||
// We found the pump.
|
||||
LOG(DPEN_LOG, LOG_INFO, "Pentair Pump Status message = RPM %d | WATTS %d\n",
|
||||
(packet[PEN_HI_B_RPM] * 256) + packet[PEN_LO_B_RPM],
|
||||
(packet[PEN_HI_B_WAT] * 256) + packet[PEN_LO_B_WAT]);
|
||||
|
||||
aqdata->pumps[i].rpm = (packet[PEN_HI_B_RPM] * 256) + packet[PEN_LO_B_RPM];
|
||||
aqdata->pumps[i].watts = (packet[PEN_HI_B_WAT] * 256) + packet[PEN_LO_B_WAT];
|
||||
|
||||
changedAnything = true;
|
||||
break;
|
||||
}
|
||||
if (changedAnything != true)
|
||||
LOG(DPEN_LOG, LOG_NOTICE, "Pentair Pump found at ID 0x%02hhx with RPM %d | WATTS %d, but not configured, information ignored!\n",
|
||||
packet[PEN_PKT_FROM],
|
||||
(packet[PEN_HI_B_RPM] * 256) + packet[PEN_LO_B_RPM],
|
||||
(packet[PEN_HI_B_WAT] * 256) + packet[PEN_LO_B_WAT]);
|
||||
}
|
||||
//
|
||||
}
|
||||
|
||||
return changedAnything;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Removed as iAqualink has a sleep mode, Keeping code to use as stub for other devices.
|
||||
|
||||
*/
|
||||
#ifdef DO_NOT_COMPILE
|
||||
|
||||
bool processiAqualinkMsg(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
bool changedAnything = false;
|
||||
static char lastmessage[AQ_MSGLONGLEN];
|
||||
|
||||
//static char message[AQ_MSGLONGLEN + 1];
|
||||
static int pumpIndex = 1;
|
||||
|
||||
/*
|
||||
|
||||
Jandy ePumpTM DC,
|
||||
Jandy ePumpTM AC,
|
||||
IntelliFlo 1 VF,
|
||||
IntelliFlo VS
|
||||
|
||||
Pump type are like // Not sure how to read this accuratly.
|
||||
"Jandy ePUMP 1"
|
||||
"Intelliflo VS 1"
|
||||
|
||||
RPM message always comes after the above, so maybe saving last string
|
||||
then when see RPM go back to get pump number.
|
||||
|
||||
' RPM: 2950'
|
||||
' Watts: 1028'
|
||||
' GPM: 1028'
|
||||
*/
|
||||
|
||||
if (packet_buffer[9] == 'R' && packet_buffer[10] == 'P' && packet_buffer[11] == 'M' && packet_buffer[12] == ':') {
|
||||
|
||||
pumpIndex = atoi((char *) &lastmessage[14]);
|
||||
|
||||
if ( pumpIndex < aqdata->num_pumps && pumpIndex < 0) {
|
||||
pumpIndex = 1;
|
||||
logMessage(LOG_ERR, "Can't find pump index for messsage '%.*s' in string '%.*s' using %d\n",AQ_MSGLEN, packet_buffer+4, AQ_MSGLEN, lastmessage, pumpIndex);
|
||||
}
|
||||
|
||||
aqdata->pumps[pumpIndex-1].rpm = atoi((char *) &packet_buffer[13]);
|
||||
|
||||
logMessage(LOG_DEBUG, "Read message '%.*s' from iAqualink device\n",AQ_MSGLEN, packet_buffer+4);
|
||||
changedAnything = true;
|
||||
}
|
||||
else if (packet_buffer[9] == 'G' && packet_buffer[10] == 'P' && packet_buffer[11] == 'H' && packet_buffer[12] == ':') {
|
||||
aqdata->pumps[pumpIndex-1].gph = atoi((char *) &packet_buffer[13]);
|
||||
logMessage(LOG_DEBUG, "Read message '%.*s' from iAqualink device\n",AQ_MSGLEN, packet_buffer+4);
|
||||
changedAnything = true;
|
||||
}
|
||||
else if (packet_buffer[7] == 'W' && packet_buffer[8] == 'a' && packet_buffer[9] == 't' && packet_buffer[10] == 't' && packet_buffer[11] == 's' && packet_buffer[12] == ':') {
|
||||
//printf("Punp %d, Watts = %d\n", pumpIndex, atoi((char *) &packet_buffer[13]));
|
||||
aqdata->pumps[pumpIndex-1].watts = atoi((char *) &packet_buffer[13]);
|
||||
logMessage(LOG_DEBUG, "Read message '%.*s' from iAqualink device\n",AQ_MSGLEN, packet_buffer+4);
|
||||
changedAnything = true;
|
||||
}
|
||||
|
||||
//printf("Message : '");
|
||||
//fwrite(packet_buffer + 4, 1, packet_length-7, stdout);
|
||||
//printf("'\n");
|
||||
|
||||
strncpy(lastmessage, (char *)&packet_buffer[4], packet_length-7);
|
||||
|
||||
return changedAnything;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,66 @@
|
|||
#####################################
|
||||
#
|
||||
# Build container
|
||||
# The most basic build for aqualinkd
|
||||
#
|
||||
# env AQUALINKD_VERSION must be passed to this
|
||||
#
|
||||
#####################################
|
||||
|
||||
FROM debian:bookworm AS aqualinkd-build
|
||||
|
||||
#VOLUME ["/aqualinkd-build"]
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install curl make gcc libsystemd-dev
|
||||
|
||||
# Seup working dir
|
||||
RUN mkdir /home/AqualinkD
|
||||
WORKDIR /home/AqualinkD
|
||||
|
||||
ARG AQUALINKD_VERSION
|
||||
RUN curl -sL "https://github.com/aqualinkd/AqualinkD/archive/refs/tags/$AQUALINKD_VERSION.tar.gz" | tar xz --strip-components=1
|
||||
# Get latest release
|
||||
#RUN curl -sL $(curl -s https://api.github.com/repos/aqualinkd/AqualinkD/releases/latest | grep "tarball_url" | cut -d'"' -f4) | tar xz --strip-components=1
|
||||
|
||||
# Build aqualinkd
|
||||
RUN make clean && \
|
||||
make container
|
||||
|
||||
#####################################
|
||||
#
|
||||
# Runtime container
|
||||
#
|
||||
#####################################
|
||||
|
||||
FROM debian:bookworm-slim AS aqualinkd
|
||||
|
||||
ARG AQUALINKD_VERSION
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y cron curl socat && \
|
||||
apt-get clean
|
||||
|
||||
# Set cron to read local.d
|
||||
RUN sed -i '/EXTRA_OPTS=.-l./s/^#//g' /etc/default/cron
|
||||
|
||||
# Add Open Container Initiative (OCI) annotations.
|
||||
# See: https://github.com/opencontainers/image-spec/blob/main/annotations.md
|
||||
|
||||
LABEL org.opencontainers.image.title="AqualinkD"
|
||||
LABEL org.opencontainers.image.url="https://hub.docker.com/repository/docker/aqualinkd/aqualinkd/general"
|
||||
LABEL org.opencontainers.image.source="https://github.com/aqualinkd/AqualinkD"
|
||||
LABEL org.opencontainers.image.documentation="https://github.com/aqualinkd/AqualinkD"
|
||||
LABEL org.opencontainers.image.version=$AQUALINKD_VERSION
|
||||
|
||||
|
||||
COPY --from=aqualinkd-build /home/AqualinkD/release/aqualinkd /usr/local/bin/aqualinkd
|
||||
COPY --from=aqualinkd-build /home/AqualinkD/release/serial_logger /usr/local/bin/serial_logger
|
||||
COPY --from=aqualinkd-build /home/AqualinkD/web/ /var/www/aqualinkd/
|
||||
COPY --from=aqualinkd-build /home/AqualinkD/release/aqualinkd.conf /etc/aqualinkd.conf
|
||||
|
||||
#COPY --from=aqualinkd-build /home/AqualinkD/docker/aqualinkd-docker.cmd /usr/local/bin/aqualinkd-docker
|
||||
RUN curl -s -o /usr/local/bin/aqualinkd-docker https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/docker/aqualinkd-docker.cmd && \
|
||||
chmod +x /usr/local/bin/aqualinkd-docker
|
||||
|
||||
CMD ["sh", "-c", "/usr/local/bin/aqualinkd-docker"]
|
|
@ -0,0 +1,105 @@
|
|||
#####################################
|
||||
#
|
||||
# Create AqualinkD container for release (includes AMD64 and ARM64 for >Pi4 with 64 bit os and Linux PC)
|
||||
# Build container for buildx
|
||||
# This should support building on any host platform, but only supports output platform of amd64 & arm64
|
||||
#
|
||||
# Enable multi platform
|
||||
# docker buildx create --use --platform=linux/arm64,linux/amd64 --name multi-platform-builder
|
||||
# docker buildx inspect --bootstrap
|
||||
#
|
||||
# Build
|
||||
# docker buildx build --platform=linux/amd64,linux/arm64 --output=./crap --file /Dockerfile.test -t aqualinkd-test .
|
||||
# docker buildx build --platform=linux/amd64,linux/arm64 --file Dockerfile.test --output type=docker -t aqualinkd-test .
|
||||
# docker build --file Dockerfile.test --progress=plain -t aqualinkd-test .
|
||||
#
|
||||
# adding --progress=plain helps with debug
|
||||
#
|
||||
# Clean the build env and start again
|
||||
# docker buildx prune
|
||||
#
|
||||
#
|
||||
# docker build -f ./Dockerfile.buildrelease .
|
||||
#
|
||||
#####################################
|
||||
|
||||
|
||||
# Starting with base debian:bookworm and installing build-essential seems to be quicker than starting with gcc:bookworm
|
||||
#FROM --platform=$BUILDPLATFORM gcc:12-bookworm AS aqualinkd-build
|
||||
FROM --platform=$BUILDPLATFORM debian:bookworm AS aqualinkd-build
|
||||
|
||||
ARG BUILDARCH
|
||||
ARG TARGETARCH
|
||||
|
||||
# Print all buildx variables
|
||||
RUN echo "Build Arch $BUILDARCH" && \
|
||||
echo "Tagert OS $TARGETOS"
|
||||
|
||||
# Setup build env, using toolchain for all builds, even native, since make this Dockerfile cleaner
|
||||
# and no need to use bash if statments.
|
||||
# Need to be careful on install order, so using two commands
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
make \
|
||||
curl \
|
||||
gcc-aarch64-linux-gnu \
|
||||
gcc-x86-64-linux-gnu
|
||||
|
||||
RUN dpkg --add-architecture arm64 && \
|
||||
dpkg --add-architecture amd64 && \
|
||||
apt-get update && \
|
||||
apt-get install -y \
|
||||
libsystemd-dev:arm64 \
|
||||
libsystemd-dev:amd64
|
||||
|
||||
|
||||
RUN mkdir /home/AqualinkD
|
||||
WORKDIR /home/AqualinkD
|
||||
|
||||
|
||||
ARG AQUALINKD_VERSION
|
||||
RUN curl -sL "https://github.com/aqualinkd/AqualinkD/archive/refs/tags/$AQUALINKD_VERSION.tar.gz" | tar xz --strip-components=1
|
||||
# Get latest release
|
||||
#RUN curl -sL $(curl -s https://api.github.com/repos/aqualinkd/AqualinkD/releases/latest | grep "tarball_url" | cut -d'"' -f4) | tar xz --strip-components=1
|
||||
|
||||
|
||||
# Make AqualinkD
|
||||
RUN make clean && \
|
||||
make container-$TARGETARCH;
|
||||
|
||||
#####################################
|
||||
#
|
||||
# Runtime container(s)
|
||||
#
|
||||
#####################################
|
||||
|
||||
FROM debian:bookworm-slim AS aqualinkd
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y cron curl socat
|
||||
|
||||
# Set cron to read local.d
|
||||
RUN sed -i '/EXTRA_OPTS=.-l./s/^#//g' /etc/default/cron
|
||||
|
||||
#Add Open Container Initiative (OCI) annotations.
|
||||
#See: https://github.com/opencontainers/image-spec/blob/main/annotations.md
|
||||
|
||||
LABEL org.opencontainers.image.title="AqualinkD"
|
||||
LABEL org.opencontainers.image.url="https://hub.docker.com/repository/docker/sfeakes/aqualinkd/general"
|
||||
LABEL org.opencontainers.image.source="https://github.com/aqualinkd/AqualinkD"
|
||||
LABEL org.opencontainers.image.documentation="https://github.com/aqualinkd/AqualinkD"
|
||||
LABEL org.opencontainers.image.version=$AQUALINKD_VERSION
|
||||
|
||||
EXPOSE 80/tcp
|
||||
|
||||
COPY --from=aqualinkd-build /home/AqualinkD/release/aqualinkd /usr/local/bin/aqualinkd
|
||||
COPY --from=aqualinkd-build /home/AqualinkD/release/serial_logger /usr/local/bin/serial_logger
|
||||
COPY --from=aqualinkd-build /home/AqualinkD/web/ /var/www/aqualinkd/
|
||||
COPY --from=aqualinkd-build /home/AqualinkD/release/aqualinkd.conf /etc/aqualinkd.conf
|
||||
|
||||
COPY --from=aqualinkd-build /home/AqualinkD/docker/aqualinkd-docker.cmd /usr/local/bin/aqualinkd-docker
|
||||
|
||||
RUN chmod +x /usr/local/bin/aqualinkd-docker
|
||||
|
||||
CMD ["sh", "-c", "/usr/local/bin/aqualinkd-docker"]
|
|
@ -0,0 +1,286 @@
|
|||
|
||||
#####################################
|
||||
#
|
||||
# Build container to compile AqualnkD Release binaries (armhf and arm64)
|
||||
#
|
||||
# armhf is 32 bit armv6l (armhf) stretch and newer - work on all Pi's running 32bit (Pi1 to Pi4)
|
||||
# arm64 is 64 bit aarch64 buster and newer - work on Pi3/Pi4/2w running 64bit os
|
||||
#
|
||||
# docker build -f Dockerfile.releaseBinaries -t aqualinkd-releasebin .
|
||||
# docker run -it --mount type=bind,source=./build,target=/build aqualinkd-releasebin bash
|
||||
#
|
||||
# clean method
|
||||
# docker system prune
|
||||
#
|
||||
# armhf =
|
||||
# COLLECT_GCC=arm-linux-gnueabihf-gcc
|
||||
# COLLECT_LTO_WRAPPER=/opt/cross-pi-gcc/libexec/gcc/arm-linux-gnueabihf/6.3.0/lto-wrapper
|
||||
# Target: arm-linux-gnueabihf
|
||||
# Configured with: ../gcc-6.3.0/configure --prefix=/opt/cross-pi-gcc --target=arm-linux-gnueabihf --enable-languages=c,c++,fortran --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-multilib --enable-linker-build-id
|
||||
# Thread model: posix
|
||||
# gcc version 6.3.0 (GCC)
|
||||
# GLIBC version 2.24
|
||||
#
|
||||
# arm64 =
|
||||
# COLLECT_GCC=aarch64-linux-gnu-gcc
|
||||
# COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/aarch64-linux-gnu/8/lto-wrapper
|
||||
# Target: aarch64-linux-gnu
|
||||
# Configured with: ../src/configure -v --with-pkgversion='Debian 8.3.0-2' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --disable-libphobos --enable-multiarch --enable-fix-cortex-a53-843419 --disable-werror --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=aarch64-linux-gnu --program-prefix=aarch64-linux-gnu- --includedir=/usr/aarch64-linux-gnu/include
|
||||
# Thread model: posix
|
||||
# gcc version 8.3.0 (Debian 8.3.0-2)
|
||||
# GLIBC 2.28-10+deb10u3
|
||||
#####################################
|
||||
|
||||
FROM debian:buster
|
||||
|
||||
# ############
|
||||
# Get arm64 build environment.
|
||||
#
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
build-essential \
|
||||
gcc-aarch64-linux-gnu \
|
||||
binutils-arm-linux-gnueabi \
|
||||
file
|
||||
|
||||
RUN dpkg --add-architecture arm64
|
||||
RUN apt-get update && \
|
||||
apt-get install -y libsystemd-dev:arm64
|
||||
|
||||
# ############
|
||||
# Get armhf build environment
|
||||
# prebuilt armhf doesn't support hard float, (or something that causes it to fail on armhf machines)
|
||||
#RUN apt-get install -y \
|
||||
# gcc-arm-linux-gnueabihf \
|
||||
# binutils-arm-linux-gnueabihf
|
||||
|
||||
#RUN dpkg --add-architecture armhf
|
||||
#RUN apt-get update && \
|
||||
# apt-get install -y libsystemd-dev:armhf
|
||||
|
||||
# So we need to build arnhf our selves. Since we are doing that, using debian/rasbian stretch versions of
|
||||
# everthing for best compatibality
|
||||
|
||||
ENV GCC_VERSION gcc-6.3.0
|
||||
ENV GLIBC_VERSION glibc-2.24
|
||||
ENV BINUTILS_VERSION binutils-2.28
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install some tools and compilers + clean up
|
||||
RUN apt-get update && \
|
||||
#apt-get install -y rsync git wget gcc-6 g++-6 cmake gdb gdbserver bzip2 && \
|
||||
apt-get install -y rsync git wget cmake gdb gdbserver bzip2 && \
|
||||
apt-get clean autoclean && \
|
||||
apt-get autoremove -y && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
# Use GCC 6 as the default
|
||||
#RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-6 999 \
|
||||
# && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-6 999 \
|
||||
# && update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-6 999 \
|
||||
# && update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-6 999
|
||||
|
||||
# Add a user called `develop`
|
||||
RUN useradd -ms /bin/bash develop
|
||||
RUN echo "develop ALL=(ALL:ALL) ALL" >> /etc/sudoers
|
||||
|
||||
WORKDIR /home/develop
|
||||
|
||||
# Download and extract GCC
|
||||
RUN wget https://ftp.gnu.org/gnu/gcc/${GCC_VERSION}/${GCC_VERSION}.tar.gz && \
|
||||
tar xf ${GCC_VERSION}.tar.gz && \
|
||||
rm ${GCC_VERSION}.tar.gz
|
||||
# Download and extract LibC
|
||||
RUN wget https://ftp.gnu.org/gnu/libc/${GLIBC_VERSION}.tar.bz2 && \
|
||||
tar xjf ${GLIBC_VERSION}.tar.bz2 && \
|
||||
rm ${GLIBC_VERSION}.tar.bz2
|
||||
# Download and extract BinUtils
|
||||
RUN wget https://ftp.gnu.org/gnu/binutils/${BINUTILS_VERSION}.tar.bz2 && \
|
||||
tar xjf ${BINUTILS_VERSION}.tar.bz2 && \
|
||||
rm ${BINUTILS_VERSION}.tar.bz2
|
||||
# Download the GCC prerequisites
|
||||
RUN cd ${GCC_VERSION} && contrib/download_prerequisites && rm *.tar.*
|
||||
#RUN cd gcc-9.2.0 && contrib/download_prerequisites && rm *.tar.*
|
||||
|
||||
# Build BinUtils
|
||||
RUN mkdir -p /opt/cross-pi-gcc
|
||||
WORKDIR /home/develop/build-binutils
|
||||
RUN ../${BINUTILS_VERSION}/configure \
|
||||
--prefix=/opt/cross-pi-gcc --target=arm-linux-gnueabihf \
|
||||
--with-arch=armv6 --with-fpu=vfp --with-float=hard \
|
||||
--disable-multilib
|
||||
RUN make -j$(nproc)
|
||||
RUN make install
|
||||
|
||||
|
||||
# Apply batch to GCC
|
||||
# https://github.com/qca/open-ath9k-htc-firmware/issues/135
|
||||
WORKDIR /home/develop
|
||||
RUN sed -i '1474s/file ==/file[0] ==/' gcc-6.3.0/gcc/ubsan.c
|
||||
|
||||
# Build the first part of GCC
|
||||
WORKDIR /home/develop/build-gcc
|
||||
RUN ../${GCC_VERSION}/configure \
|
||||
--prefix=/opt/cross-pi-gcc \
|
||||
--target=arm-linux-gnueabihf \
|
||||
--enable-languages=c,c++,fortran \
|
||||
--with-arch=armv6 --with-fpu=vfp --with-float=hard \
|
||||
--disable-multilib \
|
||||
--enable-linker-build-id
|
||||
RUN make -j$(nproc) 'LIMITS_H_TEST=true' all-gcc
|
||||
RUN make install-gcc
|
||||
ENV PATH=/opt/cross-pi-gcc/bin:${PATH}
|
||||
|
||||
# Install dependencies
|
||||
RUN apt-get update && \
|
||||
apt-get install -y gawk bison python3 && \
|
||||
apt-get clean autoclean && \
|
||||
apt-get autoremove -y && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Download and install the Linux headers
|
||||
WORKDIR /home/develop
|
||||
RUN git clone --depth=1 https://github.com/raspberrypi/linux
|
||||
WORKDIR /home/develop/linux
|
||||
ENV KERNEL=kernel7
|
||||
RUN make ARCH=arm INSTALL_HDR_PATH=/opt/cross-pi-gcc/arm-linux-gnueabihf headers_install
|
||||
|
||||
# Build GLIBC
|
||||
WORKDIR /home/develop/build-glibc
|
||||
RUN ../${GLIBC_VERSION}/configure \
|
||||
--prefix=/opt/cross-pi-gcc/arm-linux-gnueabihf \
|
||||
--build=$MACHTYPE --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf \
|
||||
--with-arch=armv6 --with-fpu=vfp --with-float=hard \
|
||||
--with-headers=/opt/cross-pi-gcc/arm-linux-gnueabihf/include \
|
||||
--disable-multilib libc_cv_forced_unwind=yes
|
||||
RUN make install-bootstrap-headers=yes install-headers
|
||||
RUN make -j8 csu/subdir_lib
|
||||
RUN install csu/crt1.o csu/crti.o csu/crtn.o /opt/cross-pi-gcc/arm-linux-gnueabihf/lib
|
||||
RUN arm-linux-gnueabihf-gcc -nostdlib -nostartfiles -shared -x c /dev/null \
|
||||
-o /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/libc.so
|
||||
RUN touch /opt/cross-pi-gcc/arm-linux-gnueabihf/include/gnu/stubs.h
|
||||
|
||||
# Continue building GCC
|
||||
WORKDIR /home/develop/build-gcc
|
||||
RUN make -j$(nproc) all-target-libgcc
|
||||
RUN make install-target-libgcc
|
||||
|
||||
# Finish building GLIBC
|
||||
WORKDIR /home/develop/build-glibc
|
||||
RUN make -j$(nproc)
|
||||
RUN make install
|
||||
|
||||
# Finish building GCC
|
||||
WORKDIR /home/develop/build-gcc
|
||||
RUN make -j$(nproc)
|
||||
RUN make install
|
||||
|
||||
|
||||
# Download systemd and it's dependancys.
|
||||
RUN mkdir -p /home/develop/packages
|
||||
WORKDIR /home/develop/packages
|
||||
|
||||
|
||||
####################
|
||||
# Manually libsystemd-dev and all it's depandancys
|
||||
# Commented out ones are what I really want, but couldn;t find.
|
||||
#####RUN wget https://archive.debian.org/debian/pool/main/s/systemd/libsystemd-dev_232-25+deb9u14_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/s/systemd/libsystemd-dev_232-25+deb9u12_armhf.deb
|
||||
#####RUN wget https://archive.debian.org/debian/pool/main/s/systemd/libsystemd0_232-25+deb9u14_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/s/systemd/libsystemd0_232-25+deb9u12_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/g/glibc/libc6_2.24-11+deb9u4_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/libg/libgpg-error/libgpg-error0_1.26-2_armhf.deb
|
||||
#####RUN wget https://archive.debian.org/debian/pool/main/x/xz-utils/liblzma5_5.2.2-1.2+deb9u1_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/x/xz-utils/liblzma5_5.2.2-1.2+b1_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/libs/libselinux/libselinux1_2.6-3+b3_armhf.deb
|
||||
#####RUN wget https://archive.debian.org/debian/pool/main/libg/libgcrypt20//libgcrypt20_1.7.6-2+deb9u4_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/libg/libgcrypt20//libgcrypt20_1.7.6-2+deb9u3_armhf.deb
|
||||
#####RUN wget https://archive.debian.org/debian/pool/main/l/lz4/liblz4-1_0.0~r131-2+deb9u1_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/l/lz4/liblz4-1_0.0~r131-2+b1_armhf.deb
|
||||
#####RUN wget https://archive.debian.org/debian/pool/main/p/pcre3/libpcre3_2%3a8.39-3_armhf.deb
|
||||
#RUN wget https://archive.debian.org/debian/pool/main/p/pcre3/libpcre3_8.39-3_armhf.deb
|
||||
#
|
||||
# Now we have all packaged, let's unpack them.
|
||||
#
|
||||
# Install all packages into /opt/cross-pi-gcc/arm-linux-gnueabihf
|
||||
#RUN for file in *; do dpkg-deb -x $file /opt/cross-pi-gcc/arm-linux-gnueabihf; done
|
||||
#
|
||||
|
||||
####################
|
||||
# Rather than manually, Let's do some modifications to apt and get that working (kinda)
|
||||
|
||||
# Get just enough for apt-get and dpk to run. apt-get doesn't actually work, just enough to download
|
||||
ENV APT_ROOT=/opt/cross-pi-gcc/apt-armhf
|
||||
RUN mkdir -p $APT_ROOT
|
||||
#RUN APT_ROOT=/opt/cross-pi-gcc/apt-armhf; export APT_ROOT
|
||||
|
||||
RUN mkdir -p $APT_ROOT/etc/apt/sources.list.d/
|
||||
RUN mkdir -p $APT_ROOT/var/lib/dpkg/updates/
|
||||
RUN mkdir -p $APT_ROOT/var/lib/dpkg/info
|
||||
RUN mkdir -p $APT_ROOT/var/cache/apt/archives/partial
|
||||
RUN mkdir -p $APT_ROOT/var/log/apt/
|
||||
#mkdir -p $APT_ROOT/usr/share/
|
||||
|
||||
RUN echo "deb http://archive.debian.org/debian/ stretch main contrib non-free" > $APT_ROOT/etc/apt/sources.list
|
||||
RUN echo "deb http://archive.debian.org/debian/ stretch-proposed-updates main contrib non-free" >> $APT_ROOT/etc/apt/sources.list
|
||||
RUN echo "deb http://archive.debian.org/debian-security stretch/updates main contrib non-free" >> $APT_ROOT/etc/apt/sources.list
|
||||
|
||||
RUN touch $APT_ROOT/var/lib/dpkg/status
|
||||
|
||||
RUN ln -s /etc/apt/trusted.gpg.d $APT_ROOT/etc/apt/
|
||||
RUN ln -s /etc/apt/preferences.d $APT_ROOT/etc/apt/
|
||||
RUN ln -s /etc/apt/auth.conf.d $APT_ROOT/etc/apt/
|
||||
|
||||
# needed for download
|
||||
RUN dpkg --add-architecture armhf
|
||||
# needed for install
|
||||
RUN dpkg --root=$APT_ROOT --add-architecture armhf
|
||||
|
||||
RUN apt -o Dir=$APT_ROOT update
|
||||
|
||||
RUN apt -o Dir=$APT_ROOT download libsystemd-dev:armhf \
|
||||
libsystemd0:armhf \
|
||||
libc6:armhf \
|
||||
libgcrypt20:armhf \
|
||||
liblz4-1:armhf \
|
||||
liblzma5:armhf \
|
||||
libselinux1:armhf \
|
||||
libpcre3:armhf \
|
||||
libgpg-error0:armhf
|
||||
|
||||
############
|
||||
# Now we have all packaged, let's unpack them.
|
||||
|
||||
# Install all packages into /opt/cross-pi-gcc/arm-linux-gnueabihf
|
||||
# Could use `dpkg --root=$APT_ROOT --force-all -i` in below, but extract works without any warnings.
|
||||
RUN for file in *; do dpkg -x $file /opt/cross-pi-gcc/arm-linux-gnueabihf; done
|
||||
|
||||
# the above will ge installed in /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/arm-linux-gnueabihf,
|
||||
# and we need them in /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/, so make come links.
|
||||
WORKDIR /opt/cross-pi-gcc/arm-linux-gnueabihf/lib
|
||||
RUN for file in ./arm-linux-gnueabihf/*; do ln -s $file ./`basename $file` 2> /dev/null; done; exit 0
|
||||
|
||||
# liblz4.so.1 is installed in a different directory, so link that as well.
|
||||
RUN ln -s /opt/cross-pi-gcc/arm-linux-gnueabihf/usr/lib/arm-linux-gnueabihf/liblz4.so.1 /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/liblz4.so.1
|
||||
|
||||
|
||||
ENV C_INCLUDE_PATH=/opt/cross-pi-gcc/arm-linux-gnueabihf/usr/include
|
||||
|
||||
ENV PATH=$PATH:/opt/cross-pi-gcc/bin:/opt/cross-pi-gcc/libexec/gcc/arm-linux-gnueabihf/6.3.0/
|
||||
|
||||
RUN mkdir /build
|
||||
WORKDIR /build
|
||||
|
||||
# Add a user called `build` uid 1001 & gid 10000
|
||||
# You chould change RB_UID & RB_GID to what works on your build setup
|
||||
ENV RB_USER=build
|
||||
ENV RB_UID=1001
|
||||
ENV RB_GID=1000
|
||||
RUN groupadd -g $RB_GID $RB_USER 2> /dev/null; exit 0
|
||||
RUN useradd $RB_USER -u $RB_UID -g $RB_GID -m -s /bin/bash
|
||||
RUN echo "$RB_USER ALL=(ALL:ALL) ALL" >> /etc/sudoers
|
||||
|
||||
USER $RB_USER
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Example file that will start SOCAT before AqualinkD in a docker
|
||||
# to support EW-11 WIFI module for RS485 connection
|
||||
#
|
||||
# This file should be placed in the config aqualinkd directory defined
|
||||
# in your docker-compose.yml (or equiv)
|
||||
#
|
||||
# MAKE SURE TO CHAGE THE IP BELOW (1.1.1.1)
|
||||
# aqualinkd.cong should have serial_port=/dev/ttyEW11
|
||||
|
||||
echo "Starting SOCAT port binding....."
|
||||
socat -d -d pty,link=/dev/ttyEW11,raw,ignoreeof TCP4:1.1.1.1:8899,ignoreeof &
|
||||
sudo docker compose up
|
||||
echo "Sleeping for SOCAT start....."
|
||||
sleep 2s
|
|
@ -0,0 +1,50 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
# Script to start AqualinkD inside container.
|
||||
|
||||
CONFDIR=/aquadconf
|
||||
AQUA_CONF=$CONFDIR/aqualinkd.conf
|
||||
|
||||
# Check we have a config directory
|
||||
if [ -d "$CONFDIR" ]; then
|
||||
|
||||
# Check we have config file, if not copy default
|
||||
if [ ! -f "$AQUA_CONF" ]; then
|
||||
echo "Warning no aqualinkd.conf in $CONFDIR", using default
|
||||
cp /etc/aqualinkd.conf $CONFDIR
|
||||
fi
|
||||
|
||||
# Replace local filesystem config with mounted config
|
||||
ln -sf "$AQUA_CONF" /etc/aqualinkd.conf
|
||||
|
||||
# If we have a web config, replace the local filesystem with mounted
|
||||
if [ -f "$CONFDIR/config.js" ]; then
|
||||
ln -sf "$CONFDIR/config.js" /var/www/aqualinkd/config.js
|
||||
fi
|
||||
|
||||
# If don't have a cron file, create one
|
||||
if [ ! -f "$CONFDIR/aqualinkd.schedule" ]; then
|
||||
echo "#***** AUTO GENERATED DO NOT EDIT *****" > "$CONFDIR/aqualinkd.schedule"
|
||||
fi
|
||||
|
||||
# link mounted cron file to local filesystem.
|
||||
ln -sf "$CONFDIR/aqualinkd.schedule" /etc/cron.d/aqualinkd
|
||||
chmod 644 "$CONFDIR/aqualinkd.schedule"
|
||||
else
|
||||
# No conig dir, show warning
|
||||
echo "WARNING no config directory, AqualinkD starting with default config, no changes will be saved"
|
||||
AQUA_CONF="/etc/aqualinkd.conf"
|
||||
fi
|
||||
|
||||
# See if we have any execpre files to run.
|
||||
if [[ -x "$CONFDIR/aqexec-pre.sh" ]]; then
|
||||
"$CONFDIR/aqexec-pre.sh"
|
||||
fi
|
||||
|
||||
# Start cron
|
||||
service cron start
|
||||
|
||||
# Start AqualinkD not in daemon mode
|
||||
/usr/local/bin/aqualinkd -d -c $AQUA_CONF
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Script to build arm64 & amd64 containers that are published to docker.io
|
||||
#
|
||||
# This should never be used, unless you want to deploy AqualinkD docker containers to docer.io
|
||||
# It's here incase someone taked over this repo because I'm no longer around
|
||||
#
|
||||
|
||||
IMAGE=aqualinkd
|
||||
|
||||
DOCKER_HUB_NAME="docker.io/sfeakes"
|
||||
LATEST_TAG=""
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
# Below is safer, but not supported on all platforms.
|
||||
#VERSION=$(curl --silent "https://api.github.com/repos/sfeakes/AqualinkD/releases/latest" | grep -Po '"tag_name": "[^0-9|v|V]*\K.*?(?=")')
|
||||
VERSION=$(curl --silent "https://api.github.com/repos/sfeakes/AqualinkD/releases/latest" | grep "tag_name" | awk -F'"' '$0=$4')
|
||||
LATEST_TAG="-t ${DOCKER_HUB_NAME}/${IMAGE}:latest"
|
||||
else
|
||||
VERSION=$1
|
||||
fi
|
||||
|
||||
URL="https://github.com/sfeakes/AqualinkD/archive/refs/tags/"$VERSION".tar.gz"
|
||||
URL2="https://github.com/sfeakes/AqualinkD/archive/refs/tags/v"$VERSION".tar.gz"
|
||||
URL3="https://github.com/sfeakes/AqualinkD/archive/refs/tags/V"$VERSION".tar.gz"
|
||||
#BURL="https://github.com/sfeakes/AqualinkD/archive/refs/heads/"$VERSION".tar.gz"
|
||||
|
||||
# Check version is accurate before running docker build
|
||||
|
||||
if ! curl --output /dev/null --silent --location --head --fail "$URL"; then
|
||||
# Check if version tag has wrong case
|
||||
if curl --output /dev/null --silent --location --head --fail "$URL2"; then
|
||||
VERSION=v$VERSION
|
||||
else
|
||||
# Check if it's a branch
|
||||
if curl --output /dev/null --silent --location --head --fail "$URL3"; then
|
||||
VERSION=V$VERSION
|
||||
else
|
||||
echo "ERROR Can't build Docker container for $IMAGE $VERSION"
|
||||
echo -e "Neither Version or Branch URLs:- \n $URL \n $URL2 \n $URL3"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check we are building a version not already on docker hub
|
||||
|
||||
DOCKER_TAGS=$(wget -q -O - "https://hub.docker.com/v2/namespaces/sfeakes/repositories/aqualinkd/tags" | grep -o '"name": *"[^"]*' | grep -o '[^"]*$')
|
||||
|
||||
if echo $DOCKER_TAGS | grep -q $VERSION; then
|
||||
echo "AqualinkD version $VERSION already exists on docker.io, are you sure you want to overide"
|
||||
read -p "Are you sure? " -n 1 -r
|
||||
echo ""
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
# Login first Run as root not with sudo on my build machine.
|
||||
# cat ~/.docker.token | docker login --username sfeakes --password-stdin
|
||||
# any errors clean build env `docker buildx prune``
|
||||
|
||||
echo "Building Docker container for $IMAGE using branch $VERSION"
|
||||
docker buildx build --platform=linux/amd64,linux/arm64 \
|
||||
--file Dockerfile.buildx \
|
||||
-t ${DOCKER_HUB_NAME}/${IMAGE}:${VERSION} \
|
||||
$LATEST_TAG \
|
||||
--build-arg AQUALINKD_VERSION=${VERSION} \
|
||||
--push .
|
|
@ -0,0 +1,37 @@
|
|||
services:
|
||||
aqualinkd:
|
||||
image: sfeakes/aqualinkd:latest
|
||||
#build:
|
||||
# context: https://github.com/aqualinkd/AqualinkD.git#master:docker
|
||||
# args:
|
||||
# AQUALINKD_VERSION: v2.3.6 # Make sure to change to correct version
|
||||
# tags:
|
||||
# - aqualinkd:v2.3.6
|
||||
container_name: aqualinkd
|
||||
ports:
|
||||
- "6171:80"
|
||||
volumes:
|
||||
- type: bind # AqualinkD config directory
|
||||
source: ./config
|
||||
target: /aquadconf
|
||||
read_only: false
|
||||
- type: bind # systemd logging
|
||||
source: /var/run/systemd/journal/socket
|
||||
target: /var/run/systemd/journal/socket
|
||||
read_only: false
|
||||
- type: bind # systemd logging
|
||||
source: /var/log/journal
|
||||
target: /var/log/journal
|
||||
read_only: true
|
||||
- type: bind # time
|
||||
source: /etc/localtime
|
||||
target: /etc/localtime
|
||||
read_only: true
|
||||
- type: bind # timezone
|
||||
source: /etc/timezone
|
||||
target: /etc/timezone
|
||||
read_only: true
|
||||
devices: # Map
|
||||
- "/dev/ttyUSB0:/dev/ttyUSB0"
|
||||
logging:
|
||||
driver: journald
|
16
epump.h
16
epump.h
|
@ -1,16 +0,0 @@
|
|||
|
||||
/*
|
||||
Nothing seems to change these, need real pump to test
|
||||
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
|
||||
|
||||
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
|
||||
|
||||
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
|
||||
0x10|0x02|0x7a|0x41|0xcd|0x10|0x03|
|
||||
|
||||
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
|
||||
0x10|0x02|0x7a|0x41|0xcd|0x10|0x03|
|
||||
|
||||
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
|
||||
0x10|0x02|0x7a|0x41|0xcd|0x10|0x03|
|
||||
*/
|
|
@ -113,11 +113,11 @@ switch:
|
|||
retain: false
|
||||
icon: mdi:lightbulb
|
||||
- platform: mqtt
|
||||
unique_id: aqualink_spa_mode
|
||||
name: "Spa Mode"
|
||||
state_topic: "aqualinkd/Spa_Mode"
|
||||
command_topic: "aqualinkd/Spa_Mode/set"
|
||||
json_attributes_topic: "aqualinkd/Spa_Mode/delay"
|
||||
unique_id: aqualink_spa
|
||||
name: "Spa"
|
||||
state_topic: "aqualinkd/Spa"
|
||||
command_topic: "aqualinkd/Spa/set"
|
||||
json_attributes_topic: "aqualinkd/Spa/delay"
|
||||
json_attributes_template: "{{ {'delay': value|int} | tojson }}"
|
||||
qos: 1
|
||||
payload_on: "1"
|
||||
|
@ -318,9 +318,9 @@ binary_sensor:
|
|||
payload_on: "1"
|
||||
payload_off: "0"
|
||||
- platform: mqtt
|
||||
unique_id: spa_mode_delay
|
||||
state_topic: "aqualinkd/Spa_Mode/delay"
|
||||
name: "Spa Mode Delay"
|
||||
unique_id: spa_delay
|
||||
state_topic: "aqualinkd/Spa/delay"
|
||||
name: "Spa Delay"
|
||||
qos: 0
|
||||
payload_on: "1"
|
||||
payload_off: "0"
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 143 KiB |
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
|
@ -10,6 +10,25 @@
|
|||
# curl --silent "https://raw.githubusercontent.com/sfeakes/AqualinkD/master/version.h" | grep AQUALINKD_VERSION | cut -d '"' -f 2
|
||||
#
|
||||
|
||||
echo "This script has been updated!"
|
||||
echo "Please use 'curl -fsSL https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/release/remote_install.sh | sudo bash -s -- latest' to install AqualinkD"
|
||||
|
||||
while true; do
|
||||
read -p "Continue install with this script? (y/n): " response
|
||||
case $response in
|
||||
[yY] )
|
||||
echo "Continuing..."
|
||||
break
|
||||
;;
|
||||
[nN] )
|
||||
echo "Exiting..."
|
||||
exit 0
|
||||
;;
|
||||
* )
|
||||
echo "Invalid input. Please enter y or n."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
NAME="AqualinkD"
|
||||
SOURCE_LOCATION="/extras/aqua.sh"
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# * See the GNU General Public License for more details.
|
||||
# *
|
||||
# * https://github.com/sfeakes/aqualinkd
|
||||
# * https://github.com/aqualinkd/aqualinkd
|
||||
# */
|
||||
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -13,7 +13,7 @@
|
|||
# * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# * See the GNU General Public License for more details.
|
||||
# *
|
||||
# * https://github.com/sfeakes/aqualinkd
|
||||
# * https://github.com/aqualinkd/aqualinkd
|
||||
# */
|
||||
|
||||
MAX_TEMP=78
|
||||
|
|
|
@ -4,6 +4,13 @@
|
|||
PROCESSNAME=aqualinkd
|
||||
MYPID=`pidof $PROCESSNAME`
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
MYPID=$(pidof "$PROCESSNAME-arm64")
|
||||
if [ $? -ne 0 ]; then
|
||||
MYPID=$(pidof "$PROCESSNAME-armhf")
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root"
|
||||
exit 1
|
||||
|
|
|
@ -4,6 +4,13 @@
|
|||
PROCESSNAME=aqualinkd
|
||||
MYPID=`pidof $PROCESSNAME`
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
MYPID=$(pidof "$PROCESSNAME-arm64")
|
||||
if [ $? -ne 0 ]; then
|
||||
MYPID=$(pidof "$PROCESSNAME-armhf")
|
||||
fi
|
||||
fi
|
||||
|
||||
#if [[ $EUID -ne 0 ]]; then
|
||||
# echo "This script must be run as root"
|
||||
# exit 1
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Pass time between as #1 and #2 using 24 hour
|
||||
|
||||
# example crontab entry to start pump if system boots is between 6am and 11pm
|
||||
#
|
||||
# @reboot /path/start_pump_reboot 6 23
|
||||
#
|
||||
|
||||
startAfter=$1
|
||||
startBefore=$2
|
||||
|
||||
SLEEP_BETWEEN_TRIES=5 # 5 seconds
|
||||
TRIES=5 # 5 tries
|
||||
|
||||
# Wait for AqualinkD to come up and connect to panel
|
||||
sleep 30
|
||||
|
||||
hour=$(date +%H)
|
||||
|
||||
|
||||
function turn_on() {
|
||||
curl -s -S -o /dev/null http://localhost:80/api/Filter_Pump/set -d value=1 -X PUT --fail
|
||||
rtn=$?
|
||||
echo $rtn
|
||||
return $rtn
|
||||
}
|
||||
|
||||
#echo "Hour=$hour Ater=$startAfter Before=$startBefore"
|
||||
|
||||
# Remember 11:45 is 11, so don't use <= for startBefore
|
||||
if (($hour >= $startAfter && $hour < $startBefore )); then
|
||||
x=1
|
||||
while [ $x -le $TRIES ] && [ $(turn_on) -gt 0 ]; do
|
||||
sleep $SLEEP_BETWEEN_TRIES
|
||||
x=$(( $x + 1 ))
|
||||
done
|
||||
fi
|
924
iaqtouch.c
924
iaqtouch.c
|
@ -1,924 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Shaun Feakes - All rights reserved
|
||||
*
|
||||
* You may use redistribute and/or modify this code under the terms of
|
||||
* the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. For the terms of this license,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* https://github.com/sfeakes/aqualinkd
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aq_serial.h"
|
||||
#include "aqualink.h"
|
||||
#include "utils.h"
|
||||
#include "packetLogger.h"
|
||||
#include "iaqtouch.h"
|
||||
#include "iaqtouch_aq_programmer.h"
|
||||
#include "aq_programmer.h"
|
||||
#include "rs_msg_utils.h"
|
||||
#include "devices_jandy.h"
|
||||
|
||||
void temp_debugprintExtraInfo(unsigned char *pk, int length);
|
||||
|
||||
|
||||
#ifdef ATOUCH_TEST
|
||||
void set_iaq_cansend(bool yes) {}
|
||||
bool in_iaqt_programming_mode(struct aqualinkdata *aq_data) {return false;}
|
||||
bool iaqt_queue_cmd(unsigned char cmd) {}
|
||||
bool in_programming_mode(struct aqualinkdata *aq_data){return false;}
|
||||
void queueGetProgramData(emulation_type source_type, struct aqualinkdata *aq_data){}
|
||||
void kick_aq_program_thread(struct aqualinkdata *aq_data, emulation_type source_type){}
|
||||
void aq_programmer(program_type type, char *args, struct aqualinkdata *aq_data){}
|
||||
#endif
|
||||
|
||||
unsigned char _button_keys[] = { KEY_IAQTCH_KEY01,
|
||||
KEY_IAQTCH_KEY02,
|
||||
KEY_IAQTCH_KEY03,
|
||||
KEY_IAQTCH_KEY04,
|
||||
KEY_IAQTCH_KEY05,
|
||||
KEY_IAQTCH_KEY06,
|
||||
KEY_IAQTCH_KEY07,
|
||||
KEY_IAQTCH_KEY08,
|
||||
KEY_IAQTCH_KEY09,
|
||||
KEY_IAQTCH_KEY10,
|
||||
KEY_IAQTCH_KEY11,
|
||||
KEY_IAQTCH_KEY12,
|
||||
KEY_IAQTCH_KEY13,
|
||||
KEY_IAQTCH_KEY14,
|
||||
KEY_IAQTCH_KEY15};
|
||||
|
||||
|
||||
#define IAQ_STATUS_PAGE_LINES 18
|
||||
#define IAQ_PAGE_BUTTONS 24
|
||||
#define IAQ_MSG_TABLE_LINES IAQ_STATUS_PAGE_LINES // No idea actual size, so just use this until figured out.
|
||||
#define IAQT_TABLE_MSGLEN 32
|
||||
|
||||
unsigned char _currentPageLoading;
|
||||
unsigned char _currentPage;
|
||||
|
||||
unsigned char _lastMsgType = 0x00;
|
||||
//unsigned char _last_kick_type = -1;
|
||||
|
||||
int _deviceStatusLines = 0;
|
||||
char _deviceStatus[IAQ_STATUS_PAGE_LINES][AQ_MSGLEN+1];
|
||||
char _tableInformation[IAQ_MSG_TABLE_LINES][IAQT_TABLE_MSGLEN+1];
|
||||
struct iaqt_page_button _pageButtons[IAQ_PAGE_BUTTONS];
|
||||
|
||||
// Need to cache these two pages, as only get updates after initial load.
|
||||
struct iaqt_page_button _devicePageButtons[IAQ_PAGE_BUTTONS];
|
||||
struct iaqt_page_button _devicePage2Buttons[IAQ_PAGE_BUTTONS];
|
||||
struct iaqt_page_button _deviceSystemSetupButtons[IAQ_PAGE_BUTTONS];
|
||||
|
||||
unsigned char iaqtLastMsg()
|
||||
{
|
||||
return _lastMsgType;
|
||||
}
|
||||
|
||||
void set_iaqtouch_lastmsg(unsigned char msgtype)
|
||||
{
|
||||
_lastMsgType = msgtype;
|
||||
}
|
||||
|
||||
bool wasiaqtThreadKickTypePage()
|
||||
{
|
||||
switch(_lastMsgType) {
|
||||
//case CMD_IAQ_PAGE_MSG:
|
||||
//case CMD_IAQ_PAGE_BUTTON:
|
||||
//case CMD_IAQ_PAGE_START:
|
||||
case CMD_IAQ_PAGE_END:
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
unsigned char iaqtCurrentPage()
|
||||
{
|
||||
return _currentPage;
|
||||
}
|
||||
|
||||
const char *iaqtGetMessageLine(int index) {
|
||||
if (index < IAQ_STATUS_PAGE_LINES)
|
||||
return _deviceStatus[index];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
const char *iaqtGetTableInfoLine(int index) {
|
||||
if (index < IAQ_MSG_TABLE_LINES)
|
||||
return _tableInformation[index];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct iaqt_page_button *iaqtFindButtonByIndex(int index) {
|
||||
//int i;
|
||||
struct iaqt_page_button *buttons;
|
||||
|
||||
// NSF Need to merge this from iaqtFindButtonByLabel function
|
||||
if (_currentPage == IAQ_PAGE_DEVICES )
|
||||
buttons = _devicePageButtons;
|
||||
else if (_currentPage == IAQ_PAGE_DEVICES2 )
|
||||
buttons = _devicePage2Buttons;
|
||||
else if (_currentPage == IAQ_PAGE_SYSTEM_SETUP )
|
||||
buttons = _deviceSystemSetupButtons;
|
||||
else
|
||||
buttons = _pageButtons;
|
||||
|
||||
if (index>=0 && index < IAQ_PAGE_BUTTONS) {
|
||||
return &buttons[index];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct iaqt_page_button *iaqtFindButtonByLabel(char *label) {
|
||||
int i;
|
||||
struct iaqt_page_button *buttons;
|
||||
|
||||
if (_currentPage == IAQ_PAGE_DEVICES )
|
||||
buttons = _devicePageButtons;
|
||||
else if (_currentPage == IAQ_PAGE_DEVICES2 )
|
||||
buttons = _devicePage2Buttons;
|
||||
else if (_currentPage == IAQ_PAGE_SYSTEM_SETUP )
|
||||
buttons = _deviceSystemSetupButtons;
|
||||
else
|
||||
buttons = _pageButtons;
|
||||
|
||||
for (i=0; i < IAQ_PAGE_BUTTONS; i++) {
|
||||
//if (_pageButtons[i].state != 0 || _pageButtons[i].type != 0 || _pageButtons[i].unknownByte != 0)
|
||||
if (rsm_strcmp((char *)buttons[i].name,label) == 0)
|
||||
return &buttons[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int num2iaqtRSset (unsigned char* packetbuffer, int num, bool pad4unknownreason)
|
||||
{
|
||||
//unsigned int score = 42; // Works for score in [0, UINT_MAX]
|
||||
//unsigned char tmp;
|
||||
//printf ("num via printf: %u\n", num); // For validation
|
||||
|
||||
int bcnt = 0;
|
||||
int digits = 0;
|
||||
unsigned int div = 1;
|
||||
unsigned int digit_count = 1;
|
||||
while ( div <= num / 10 ) {
|
||||
digit_count++;
|
||||
div *= 10;
|
||||
}
|
||||
while ( digit_count > 0 ) {
|
||||
packetbuffer[bcnt] = (num / div + 0x30); // 48 = 0x30 base number for some reason. (ie 48=0)
|
||||
num %= div;
|
||||
div /= 10;
|
||||
digit_count--;
|
||||
bcnt++;
|
||||
}
|
||||
|
||||
for (digits = bcnt; bcnt < 6; bcnt++) { // Note setting digits to bcnt is correct. Saving current count to different int
|
||||
if (bcnt == 4 && digits <= 3 ) // Less than 4 digits (<1000), need to add a 0x30
|
||||
packetbuffer[bcnt] = 0x30;
|
||||
else
|
||||
packetbuffer[bcnt] = NUL;
|
||||
}
|
||||
|
||||
return bcnt;
|
||||
}
|
||||
|
||||
int char2iaqtRSset(unsigned char* packetbuffer, char *msg, int msg_len)
|
||||
{
|
||||
int bcnt=0;
|
||||
|
||||
for (bcnt=0; bcnt < msg_len; bcnt++ ){
|
||||
packetbuffer[bcnt] = msg[bcnt];
|
||||
}
|
||||
|
||||
packetbuffer[bcnt] = 0x00;
|
||||
|
||||
return ++bcnt;
|
||||
}
|
||||
|
||||
|
||||
void createDeviceUpdatePacket() {
|
||||
unsigned char packets[AQ_MAXPKTLEN];
|
||||
int cnt;
|
||||
|
||||
packets[0] = DEV_MASTER;
|
||||
packets[1] = 0x24;
|
||||
packets[2] = 0x31;
|
||||
|
||||
cnt = num2iaqtRSset(&packets[3], 1000, true);
|
||||
|
||||
for(cnt = cnt+3; cnt <= 18; cnt++)
|
||||
packets[cnt] = 0xcd;
|
||||
|
||||
//printHex(packets, 19);
|
||||
//printf("\n");
|
||||
|
||||
//send_jandy_command(NULL, packets, cnt);
|
||||
}
|
||||
|
||||
void processPageMessage(unsigned char *message, int length)
|
||||
{
|
||||
if ( (int)message[PKT_IAQT_MSGINDX] >= IAQ_STATUS_PAGE_LINES ) {
|
||||
LOG(IAQT_LOG,LOG_ERR, "Run out of IAQT message buffer, need %d have %d\n",(int)message[PKT_IAQT_MSGINDX],IAQ_STATUS_PAGE_LINES);
|
||||
return;
|
||||
}
|
||||
// 2nd page of device status doesn;t gine us new page message
|
||||
if (_currentPageLoading == IAQ_PAGE_STATUS || _currentPage == IAQ_PAGE_STATUS) {
|
||||
//sprintf(_deviceStatus[(int)message[4]], message[5], AQ_MSGLEN);
|
||||
//strncpy(_deviceStatus[(int)message[PKT_IAQT_MSGINDX]], (char *)message + PKT_IAQT_MSGDATA, AQ_MSGLEN);
|
||||
rsm_strncpy(_deviceStatus[(int)message[PKT_IAQT_MSGINDX]], &message[PKT_IAQT_MSGDATA], AQ_MSGLEN, length-PKT_IAQT_MSGDATA-3);
|
||||
} else {
|
||||
//strncpy(_deviceStatus[(int)message[PKT_IAQT_MSGINDX]], (char *)message + PKT_IAQT_MSGDATA, AQ_MSGLEN);
|
||||
rsm_strncpy(_deviceStatus[(int)message[PKT_IAQT_MSGINDX]], &message[PKT_IAQT_MSGDATA], AQ_MSGLEN, length-PKT_IAQT_MSGDATA-3);
|
||||
//LOG(IAQT_LOG,LOG_ERR, "Request to assign message to unknown page,'%.*s'\n",AQ_MSGLEN,(char *)message + PKT_IAQT_MSGDATA);
|
||||
}
|
||||
|
||||
//LOG(IAQT_LOG,LOG_DEBUG, "Message :- '%d' '%.*s'\n",(int)message[PKT_IAQT_MSGINDX], length-PKT_IAQT_MSGDATA-3, &message[PKT_IAQT_MSGDATA]);
|
||||
}
|
||||
|
||||
void processTableMessage(unsigned char *message, int length)
|
||||
{
|
||||
if ( (int)message[5] < IAQ_MSG_TABLE_LINES )
|
||||
rsm_strncpy(_tableInformation[(int)message[5]], &message[6], IAQT_TABLE_MSGLEN, length-PKT_IAQT_MSGDATA-3);
|
||||
else
|
||||
LOG(IAQT_LOG,LOG_ERR, "Run out of IAQT table buffer, need %d have %d\n",(int)message[5],IAQ_MSG_TABLE_LINES);
|
||||
}
|
||||
|
||||
void processPageButton(unsigned char *message, int length)
|
||||
{
|
||||
struct iaqt_page_button *button;
|
||||
int index = (int)message[PKT_IAQT_BUTINDX];
|
||||
|
||||
if (_currentPageLoading == IAQ_PAGE_DEVICES )
|
||||
button = &_devicePageButtons[index];
|
||||
else if (_currentPageLoading == IAQ_PAGE_DEVICES2 )
|
||||
button = &_devicePage2Buttons[index];
|
||||
else if (_currentPageLoading == IAQ_PAGE_SYSTEM_SETUP )
|
||||
button = &_deviceSystemSetupButtons[index];
|
||||
else
|
||||
button = &_pageButtons[index];
|
||||
|
||||
button->state = message[PKT_IAQT_BUTSTATE];
|
||||
button->type = message[PKT_IAQT_BUTTYPE];
|
||||
button->unknownByte = message[PKT_IAQT_BUTUNKNOWN];
|
||||
|
||||
if (message[PKT_IAQT_BUTSTATE] == 0x0d)
|
||||
button->keycode = message[PKT_IAQT_BUTTYPE];
|
||||
else if (index < 15) {
|
||||
button->keycode = _button_keys[index];
|
||||
}
|
||||
// This doesn't work with return which is 0x00
|
||||
|
||||
//strncpy(&button->name, (char *)message + PKT_IAQT_BUTDATA, AQ_MSGLEN);
|
||||
rsm_strncpy_nul2sp((char *)button->name, &message[PKT_IAQT_BUTDATA], IAQT_MSGLEN, length-PKT_IAQT_BUTDATA-3);
|
||||
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Added Button %d %s\n",index,button->name);
|
||||
|
||||
/*
|
||||
_pageButtons[index].state = (int)message[5];
|
||||
_pageButtons[index].type = (int)message[7];
|
||||
_pageButtons[index].unknownByte = (int)message[6];
|
||||
// This doesn't work with return which is 0x00
|
||||
strncpy(&_pageButtons[index].name, (char *)message + 8, AQ_MSGLEN);
|
||||
|
||||
LOG(IAQT_LOG,LOG_NOTICE, "Added Button %d %s\n",index,_pageButtons[index].name);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Log if we saw a pump in a device page cycle.
|
||||
void iaqt_pump_update(struct aqualinkdata *aq_data, int updated) {
|
||||
const int bitmask[MAX_PUMPS] = {1,2,4,8};
|
||||
static unsigned char updates = '\0';
|
||||
int i;
|
||||
|
||||
if (updated == -1) {
|
||||
for(i=0; i < MAX_PUMPS; i++) {
|
||||
if ((updates & bitmask[i]) != bitmask[i]) {
|
||||
aq_data->pumps[i].rpm = PUMP_OFF_RPM;
|
||||
aq_data->pumps[i].gpm = PUMP_OFF_GPM;
|
||||
aq_data->pumps[i].watts = PUMP_OFF_WAT;
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Clearing pump %d\n",i);
|
||||
aq_data->updated =true;
|
||||
}
|
||||
}
|
||||
updates = '\0';
|
||||
} else if (updated >=0 && updated < MAX_PUMPS) {
|
||||
updates |= bitmask[updated];
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Got pump update message for pump %d\n",updated);
|
||||
}
|
||||
}
|
||||
|
||||
void passDeviceStatusPage(struct aqualinkdata *aq_data)
|
||||
{
|
||||
int i;
|
||||
int pi;
|
||||
pump_detail *pump = NULL;
|
||||
//bool found_swg = false;
|
||||
//int pump_index = 0;
|
||||
|
||||
for (i=0; i <IAQ_STATUS_PAGE_LINES; i++ ) {
|
||||
//LOG(IAQT_LOG,LOG_NOTICE, "Passing message %.2d| %s\n",i,_deviceStatus[i]);
|
||||
if (rsm_strcmp(_deviceStatus[i],"Intelliflo VS") == 0 ||
|
||||
rsm_strcmp(_deviceStatus[i],"Intelliflo VF") == 0 ||
|
||||
rsm_strcmp(_deviceStatus[i],"Jandy ePUMP") == 0 ||
|
||||
rsm_strcmp(_deviceStatus[i],"ePump AC") == 0)
|
||||
{
|
||||
int pump_index = rsm_atoi(&_deviceStatus[i][14]);
|
||||
if (pump_index <= 0)
|
||||
pump_index = rsm_atoi(&_deviceStatus[i][10]); // ePump AC seems to display index in different position
|
||||
for (pi=0; pi < aq_data->num_pumps; pi++) {
|
||||
if (aq_data->pumps[pi].pumpIndex == pump_index) {
|
||||
iaqt_pump_update(aq_data, pi); // Log that we saw a pump
|
||||
pump = &aq_data->pumps[pi];
|
||||
aq_data->updated =true;
|
||||
if (pump->pumpType == PT_UNKNOWN){
|
||||
if (rsm_strcmp(_deviceStatus[i],"Intelliflo VS") == 0)
|
||||
pump->pumpType = VSPUMP;
|
||||
else if (rsm_strcmp(_deviceStatus[i],"Intelliflo VF") == 0)
|
||||
pump->pumpType = VFPUMP;
|
||||
else if (rsm_strcmp(_deviceStatus[i],"Jandy ePUMP") == 0 ||
|
||||
rsm_strcmp(_deviceStatus[i],"ePump AC") == 0)
|
||||
pump->pumpType = EPUMP;
|
||||
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Pump %d set to type %s\n",pump->pumpIndex, (pump->pumpType==EPUMP?"Jandy ePUMP":(pump->pumpType==VFPUMP?"Intelliflo VF":"Intelliflo VS")) );
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pump == NULL)
|
||||
LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump at index %d\n",_deviceStatus[i],pump_index);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (rsm_strcmp(_deviceStatus[i],"RPM:") == 0) {
|
||||
if (pump != NULL)
|
||||
pump->rpm = rsm_atoi(&_deviceStatus[i][9]);
|
||||
else
|
||||
LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
|
||||
continue;
|
||||
} else if (rsm_strcmp(_deviceStatus[i],"GPM:") == 0) {
|
||||
if (pump != NULL)
|
||||
pump->gpm = rsm_atoi(&_deviceStatus[i][9]);
|
||||
else
|
||||
LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
|
||||
continue;
|
||||
} else if (rsm_strcmp(_deviceStatus[i],"Watts:") == 0) {
|
||||
if (pump != NULL)
|
||||
pump->watts = rsm_atoi(&_deviceStatus[i][9]);
|
||||
else
|
||||
LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
|
||||
continue;
|
||||
} else if (rsm_strcmp(_deviceStatus[i],"*** Priming ***") == 0) {
|
||||
if (pump != NULL)
|
||||
pump->rpm = PUMP_PRIMING;
|
||||
else
|
||||
LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
|
||||
continue;
|
||||
} else if (rsm_strcmp(_deviceStatus[i],"(Offline)") == 0) {
|
||||
if (pump != NULL)
|
||||
pump->rpm = PUMP_OFFLINE;
|
||||
else
|
||||
LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
|
||||
continue;
|
||||
} else if (rsm_strcmp(_deviceStatus[i],"(Priming Error)") == 0) {
|
||||
if (pump != NULL)
|
||||
pump->rpm = PUMP_ERROR;
|
||||
else
|
||||
LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
|
||||
continue;
|
||||
// Need to catch messages like
|
||||
// *** Priming ***
|
||||
// (Priming Error)
|
||||
// (Offline)
|
||||
} else {
|
||||
pump = NULL;
|
||||
}
|
||||
|
||||
if (rsm_strcmp(_deviceStatus[i],"Chemlink") == 0) {
|
||||
/* Info: = Chemlink 1
|
||||
Info: = ORP 750/PH 7.0 */
|
||||
i++;
|
||||
if (rsm_strcmp(_deviceStatus[i],"ORP") == 0) {
|
||||
int orp = rsm_atoi(&_deviceStatus[i][4]);
|
||||
char *indx = strchr(_deviceStatus[i], '/');
|
||||
float ph = rsm_atof(indx+3);
|
||||
if (aq_data->ph != ph || aq_data->orp != orp) {
|
||||
aq_data->ph = ph;
|
||||
aq_data->orp = orp;
|
||||
}
|
||||
LOG(IAQT_LOG,LOG_INFO, "Set Cemlink ORP = %d PH = %f from message '%s'\n",orp,ph,_deviceStatus[i]);
|
||||
}
|
||||
}
|
||||
#ifdef READ_SWG_FROM_EXTENDED_ID
|
||||
else if (rsm_strcmp(_deviceStatus[i],"AQUAPURE") == 0) {
|
||||
//aq_data->swg_percent = rsm_atoi(&_deviceStatus[i][9]);
|
||||
if (changeSWGpercent(aq_data, rsm_atoi(&_deviceStatus[i][9])))
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Set swg %% to %d from message'%s'\n",aq_data->swg_percent,_deviceStatus[i]);
|
||||
} else if (rsm_strcmp(_deviceStatus[i],"salt") == 0) {
|
||||
aq_data->swg_ppm = rsm_atoi(&_deviceStatus[i][5]);
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Set swg PPM to %d from message'%s'\n",aq_data->swg_ppm,_deviceStatus[i]);
|
||||
} else if (rsm_strcmp(_deviceStatus[i],"Boost Pool") == 0) {
|
||||
aq_data->boost = true;
|
||||
// Let RS pickup time remaing message.
|
||||
}
|
||||
#endif
|
||||
|
||||
} // for
|
||||
}
|
||||
|
||||
void debugPrintButtons(struct iaqt_page_button buttons[])
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < IAQ_PAGE_BUTTONS; i++) {
|
||||
if (buttons[i].state != 0 || buttons[i].type != 0 || buttons[i].unknownByte != 0 || buttons[i].keycode != 0)
|
||||
LOG(IAQT_LOG,LOG_INFO, "Button %.2d| %21.21s | type=0x%02hhx | state=0x%02hhx | unknown=0x%02hhx | keycode=0x%02hhx\n",i,buttons[i].name,buttons[i].type,buttons[i].state,buttons[i].unknownByte,buttons[i].keycode);
|
||||
}
|
||||
}
|
||||
|
||||
void processPage(struct aqualinkdata *aq_data)
|
||||
{
|
||||
int i;
|
||||
|
||||
LOG(IAQT_LOG,LOG_INFO, "Page: %s | 0x%02hhx\n",iaqt_page_name(_currentPage),_currentPage);
|
||||
|
||||
switch(_currentPage) {
|
||||
case IAQ_PAGE_STATUS:
|
||||
case IAQ_PAGE_STATUS2:
|
||||
//LOG(IAQT_LOG,LOG_INFO, "Status Page:-\n");
|
||||
for (i=0; i <IAQ_STATUS_PAGE_LINES; i++ )
|
||||
if (strlen(_deviceStatus[i]) > 1)
|
||||
LOG(IAQT_LOG,LOG_INFO, "Status page %.2d| %s\n",i,_deviceStatus[i]);
|
||||
|
||||
debugPrintButtons(_pageButtons);
|
||||
passDeviceStatusPage(aq_data);
|
||||
// If button 1 is type 0x02 then there is a next page. Since status page isn't used for programming, hit the next page button.
|
||||
if (_pageButtons[1].type == 0x02)
|
||||
iaqt_queue_cmd(KEY_IAQTCH_KEY02);
|
||||
else
|
||||
iaqt_pump_update(aq_data, -1); // Reset pumps.
|
||||
break;
|
||||
case IAQ_PAGE_DEVICES:
|
||||
//LOG(IAQT_LOG,LOG_INFO, "Devices Page #1:-\n");
|
||||
debugPrintButtons(_devicePageButtons);
|
||||
break;
|
||||
case IAQ_PAGE_DEVICES2:
|
||||
//LOG(IAQT_LOG,LOG_INFO, "Devices Page #2:-\n");
|
||||
debugPrintButtons(_devicePage2Buttons);
|
||||
break;
|
||||
case IAQ_PAGE_COLOR_LIGHT:
|
||||
//LOG(IAQT_LOG,LOG_INFO, "Color Light Page :-\n");
|
||||
debugPrintButtons(_pageButtons);
|
||||
break;
|
||||
case IAQ_PAGE_HOME:
|
||||
//LOG(IAQT_LOG,LOG_INFO, "Home Page :-\n");
|
||||
for (i=0; i <IAQ_STATUS_PAGE_LINES; i++ )
|
||||
if (_deviceStatus[i][0] != 0)
|
||||
LOG(IAQT_LOG,LOG_INFO, "Status page %.2d| %s\n",i,_deviceStatus[i]);
|
||||
|
||||
debugPrintButtons(_pageButtons);
|
||||
break;
|
||||
case IAQ_PAGE_SYSTEM_SETUP:
|
||||
//LOG(IAQT_LOG,LOG_INFO, "System Setup :-\n");
|
||||
debugPrintButtons(_deviceSystemSetupButtons);
|
||||
break;
|
||||
case IAQ_PAGE_SET_VSP:
|
||||
debugPrintButtons(_pageButtons);
|
||||
break;
|
||||
|
||||
default:
|
||||
//LOG(IAQT_LOG,LOG_INFO, "** UNKNOWN PAGE 0x%02hhx **\n",_currentPage);
|
||||
for (i=0; i <IAQ_STATUS_PAGE_LINES; i++ )
|
||||
if (_deviceStatus[i][0] != 0)
|
||||
LOG(IAQT_LOG,LOG_INFO, "Page %.2d| %s\n",i,_deviceStatus[i]);
|
||||
|
||||
debugPrintButtons(_pageButtons);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i=0; i < IAQ_MSG_TABLE_LINES; i++) {
|
||||
if (strlen((char *)_tableInformation[i]) > 0)
|
||||
LOG(IAQT_LOG,LOG_INFO, "Table Messages %.2d| %s\n",i,_tableInformation[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#define REQUEST_STATUS_POLL_COUNT 50
|
||||
|
||||
bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data)
|
||||
{
|
||||
static int cnt = 0;
|
||||
static bool gotStatus = true;
|
||||
//char buff[1024];
|
||||
|
||||
if (packet[PKT_CMD] == CMD_IAQ_PAGE_START) {
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Turning IAQ SEND off\n");
|
||||
set_iaq_cansend(false);
|
||||
_currentPageLoading = packet[PKT_IAQT_PAGTYPE];
|
||||
_currentPage = NUL;
|
||||
memset(_pageButtons, 0, IAQ_PAGE_BUTTONS * sizeof(struct iaqt_page_button));
|
||||
memset(_deviceStatus, 0, sizeof(char) * IAQ_STATUS_PAGE_LINES * AQ_MSGLEN+1 );
|
||||
memset(_tableInformation, 0, sizeof(char) * IAQ_MSG_TABLE_LINES * AQ_MSGLEN+1 );
|
||||
// Fix bug with control panel where after a few hours status page disapears and you need to hit menu.
|
||||
if (gotStatus == false)
|
||||
gotStatus = true;
|
||||
//[IAQ_STATUS_PAGE_LINES][AQ_MSGLEN+1];
|
||||
} else if (packet[PKT_CMD] == CMD_IAQ_PAGE_END) {
|
||||
set_iaq_cansend(true);
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Turning IAQ SEND on\n");
|
||||
if (_currentPageLoading != NUL) {
|
||||
_currentPage = _currentPageLoading;
|
||||
_currentPageLoading = NUL;
|
||||
} else {
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Page end message without proceding page start, ignoring!\n");
|
||||
}
|
||||
processPage(aq_data);
|
||||
} else if (packet[PKT_CMD] == CMD_IAQ_TABLE_MSG) {
|
||||
processTableMessage(packet, length);
|
||||
} else if (packet[PKT_CMD] == CMD_IAQ_PAGE_MSG) {
|
||||
processPageMessage(packet, length);
|
||||
} else if (packet[PKT_CMD] == CMD_IAQ_PAGE_BUTTON) {
|
||||
processPageButton(packet, length);
|
||||
// Second page on status doesn't send start & end, but button is message, so use that to kick off next page.
|
||||
if (_currentPage == IAQ_PAGE_STATUS) {
|
||||
/* Notice: Added Button 1
|
||||
* Notice: To 0x33 of type iAq pBut | HEX: 0x10|0x02|0x33|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x6a|0x10|0x03|
|
||||
* Button | 1 | 0x00 | |-| |-| -off-
|
||||
*
|
||||
* SHOULD PROBABLY USE ABOVE TO CHECK.
|
||||
*/
|
||||
//if (packet[PKT_IAQT_BUTTYPE] == 0x02 )
|
||||
processPage(aq_data);
|
||||
}
|
||||
|
||||
// if we get a button with 0x00 state on Light Page, that's the end of page.
|
||||
if (_currentPageLoading == IAQ_PAGE_COLOR_LIGHT) {
|
||||
if (packet[7] == 0x00) {
|
||||
//printf("** MANUAL PAGE END\n");
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "MANUAL PAGE END\n");
|
||||
_currentPage = _currentPageLoading;
|
||||
_currentPageLoading = NUL;
|
||||
processPage(aq_data);
|
||||
set_iaq_cansend(true);
|
||||
// Also END page here, as you can send commands.
|
||||
// NEED to rethink this approach. ie, selecting light needs to hold open while showing page, no page end, then select light color, then message "please wait", the finally done
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (packet[3] == 0x29) {
|
||||
//printf("***** iAqualink Touch STARTUP Message ******* \n");
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "STARTUP Message\n");
|
||||
queueGetProgramData(IAQTOUCH, aq_data);
|
||||
|
||||
//aq_programmer(AQ_SET_IAQTOUCH_SET_TIME, NULL, aq_data);
|
||||
}
|
||||
// Standard ack/poll not interested in printing or kicking threads
|
||||
if (packet[3] == 0x30) {
|
||||
//LOG(IAQT_LOG,LOG_DEBUG, "poll count %d\n",cnt);
|
||||
// Load status page every 50 messages
|
||||
if (cnt++ > REQUEST_STATUS_POLL_COUNT && in_programming_mode(aq_data) == false ) {
|
||||
iaqt_queue_cmd(KEY_IAQTCH_STATUS);
|
||||
gotStatus = false; // Reset if we got status page, for fix panel bug.
|
||||
//aq_programmer(AQ_GET_IAQTOUCH_VSP_ASSIGNMENT, NULL, aq_data);
|
||||
cnt = 0;
|
||||
} else if (gotStatus == false && cnt > 3) {
|
||||
// Fix bug with control panel where after a few hours status page disapears and you need to hit menu.
|
||||
LOG(IAQT_LOG,LOG_INFO, "Overcomming Jandy control panel bug, (missing status, goto menu)\n",cnt);
|
||||
iaqt_queue_cmd(KEY_IAQTCH_HOME);
|
||||
iaqt_queue_cmd(KEY_IAQTCH_STATUS);
|
||||
} else if (in_programming_mode(aq_data) == true) {
|
||||
// Set count to something close to above, so we will pull latest info once programming has finished.
|
||||
// This is goot for VSP GPM programming as it takes number of seconds to register once finished programming.
|
||||
// -5 seems to be too quick for VSP/GPM so using 10
|
||||
cnt = REQUEST_STATUS_POLL_COUNT - 10;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//debuglogPacket(IAQT_LOG ,packet, length);
|
||||
|
||||
//_lastMsgType = packet[PKT_CMD];
|
||||
set_iaqtouch_lastmsg(packet[PKT_CMD]);
|
||||
//debuglogPacket(IAQT_LOG ,packet, length);
|
||||
//beautifyPacket(buff, packet, length);
|
||||
//LOG(IAQT_LOG,LOG_DEBUG, "%s", buff);
|
||||
|
||||
//temp_debugprintExtraInfo(packet, length);
|
||||
|
||||
kick_aq_program_thread(aq_data, IAQTOUCH);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const char *iaqt_page_name(const unsigned char page)
|
||||
{
|
||||
switch (page){
|
||||
case IAQ_PAGE_HOME:
|
||||
return "HOME";
|
||||
break;
|
||||
case IAQ_PAGE_STATUS:
|
||||
return "Status";
|
||||
break;
|
||||
case IAQ_PAGE_STATUS2:
|
||||
return "Status (diff ID)";
|
||||
break;
|
||||
case IAQ_PAGE_DEVICES:
|
||||
return "Devices #1";
|
||||
break;
|
||||
case IAQ_PAGE_DEVICES2:
|
||||
return "Devices #2";
|
||||
break;
|
||||
case IAQ_PAGE_SET_TEMP:
|
||||
return "Set Temp";
|
||||
break;
|
||||
case IAQ_PAGE_MENU:
|
||||
return "MENU";
|
||||
break;
|
||||
case IAQ_PAGE_SET_VSP:
|
||||
return "Set VSP";
|
||||
break;
|
||||
case IAQ_PAGE_SET_TIME:
|
||||
return "Set Time";
|
||||
break;
|
||||
case IAQ_PAGE_SET_DATE:
|
||||
return "Set Date";
|
||||
break;
|
||||
case IAQ_PAGE_SET_SWG:
|
||||
return "Set Aquapure";
|
||||
break;
|
||||
case IAQ_PAGE_SET_BOOST:
|
||||
return "Set Boost";
|
||||
break;
|
||||
case IAQ_PAGE_SET_QBOOST:
|
||||
return "Set Quick Boost";
|
||||
break;
|
||||
case IAQ_PAGE_ONETOUCH:
|
||||
return "OneTouch";
|
||||
break;
|
||||
case IAQ_PAGE_COLOR_LIGHT:
|
||||
return "Color Lights";
|
||||
break;
|
||||
case IAQ_PAGE_SYSTEM_SETUP:
|
||||
return "System Setup";
|
||||
break;
|
||||
case IAQ_PAGE_VSP_SETUP:
|
||||
return "VSP Setup";
|
||||
break;
|
||||
case IAQ_PAGE_FREEZE_PROTECT:
|
||||
return "Freeze Protect";
|
||||
break;
|
||||
case IAQ_PAGE_LABEL_AUX:
|
||||
return "Label Aux";
|
||||
break;
|
||||
default:
|
||||
return "** Unknown **";
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
void temp_debugprintExtraInfo(unsigned char *pk, int length)
|
||||
{
|
||||
if (pk[PKT_CMD] == CMD_IAQ_PAGE_MSG) {
|
||||
int i;
|
||||
printf(" Message | %d | ",(int)pk[4]);
|
||||
// Byte #4 is line index on status page at least
|
||||
// 1 bytes unknown #4.
|
||||
// Message starts at 5
|
||||
for (i=5;i<length-3;i++)
|
||||
printf("%c",pk[i]);
|
||||
printf("\n");
|
||||
}
|
||||
else if (pk[PKT_CMD] == CMD_IAQ_TABLE_MSG) {
|
||||
int i;
|
||||
printf(" Table Msg | %d | ",(int)pk[5]);
|
||||
for (i=6;i<length-3;i++)
|
||||
printf("%c",pk[i]);
|
||||
printf("\n");
|
||||
}
|
||||
else if (pk[PKT_CMD] == CMD_IAQ_PAGE_BUTTON) {
|
||||
int i;
|
||||
printf(" Button | %d | 0x%02hhx | ",(int)pk[4],pk[7]);
|
||||
// byte 4 is button index.
|
||||
// byte 5 is status 0x00 off (0x01, 0x02, 0x03)
|
||||
// byte 6
|
||||
// byte 7
|
||||
// 6 & 7 0x01|0x00 for normal stuff
|
||||
// 6 & 7 0x00|0x0c for lights with 7 incrementing.
|
||||
// 7 = Key to send in ACK to select, at least for Light modes.
|
||||
// (Might also be in pk5=0x0d) Think if pk6 = 0x01, pk7 not used, if pk=0x00 then pk7 is keycode to send if you select that option.
|
||||
// Byte 7 0x03 PAGE DOWN / 0x02 PAGE UP
|
||||
// 2 bytes unknown #5 and #6.
|
||||
// Message starts at 8
|
||||
// if pk[5] == 0x0d start at 8
|
||||
for (i=8;i<length-3;i++) {
|
||||
// If we get a 0x00 looks like a return.
|
||||
if (pk[i] == 0x00)
|
||||
printf(" |-| ");
|
||||
|
||||
printf("%c",pk[i]);
|
||||
}
|
||||
|
||||
if (pk[5] == 0x00)
|
||||
printf(" -off- ");
|
||||
else if (pk[5] == 0xff)
|
||||
printf(" -blank/unknown- ");
|
||||
else if (pk[5] == 0x03)
|
||||
printf(" -Enabeled- ");
|
||||
else if (pk[5] == 0x01)
|
||||
printf(" -on- ");
|
||||
else if (pk[5] == 0x0d)
|
||||
printf(" -Light something 0x0d|0x%02hhx|0x%02hhx %d - ",pk[6],pk[7],(int)pk[7]);
|
||||
else
|
||||
printf(" -?- 0x%02hhx ",pk[5]);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
else if (pk[PKT_CMD] == CMD_IAQ_PAGE_START) {
|
||||
if (pk[4] == IAQ_PAGE_STATUS)
|
||||
printf(" New Page | Status\n");
|
||||
else if (pk[4] == IAQ_PAGE_HOME)
|
||||
printf(" New Page | Home\n");
|
||||
else if (pk[4] == IAQ_PAGE_DEVICES)
|
||||
printf(" New Page | Other Devices\n");
|
||||
else if (pk[4] == IAQ_PAGE_DEVICES2)
|
||||
printf(" New Page | Other Devices page 2\n");
|
||||
else if (pk[4] == IAQ_PAGE_SET_TEMP)
|
||||
printf(" New Page | Set Temp\n");
|
||||
else if (pk[4] == IAQ_PAGE_MENU)
|
||||
printf(" New Page | MENU\n");
|
||||
else if (pk[4] == IAQ_PAGE_SET_VSP)
|
||||
printf(" New Page | VSP Adjust\n");
|
||||
else if (pk[4] == IAQ_PAGE_SET_TIME)
|
||||
printf(" New Page | Set Time\n");
|
||||
else if (pk[4] == IAQ_PAGE_SET_DATE)
|
||||
printf(" New Page | Set Date\n");
|
||||
else if (pk[4] == IAQ_PAGE_SET_SWG)
|
||||
printf(" New Page | Set Aquapure\n");
|
||||
else if (pk[4] == IAQ_PAGE_SET_BOOST)
|
||||
printf(" New Page | Set BOOST\n");
|
||||
else if (pk[4] == IAQ_PAGE_SET_QBOOST)
|
||||
printf(" New Page | Set Quick BOOST\n");
|
||||
else if (pk[4] == IAQ_PAGE_ONETOUCH)
|
||||
printf(" New Page | One Touch\n");
|
||||
else if (pk[4] == IAQ_PAGE_COLOR_LIGHT)
|
||||
printf(" New Page | Color Light\n");
|
||||
else
|
||||
printf(" New Page | unknown 0x%02hhx\n",pk[4]);
|
||||
}
|
||||
else if (pk[PKT_CMD] == CMD_IAQ_PAGE_END) {
|
||||
printf(" New Page | Finished\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
Notice: Turning IAQ SEND off
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x23|0x5b|0xc1|0x10|0x03|
|
||||
New Page | Status
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x2d|0x45|0x71|0x75|0x69|0x70|0x6d|0x65|0x6e|0x74|0x20|0x53|0x74|0x61|0x74|0x75|0x73|0x00|0xcc|0x10|0x03|
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x00|0x46|0x69|0x6c|0x74|0x65|0x72|0x20|0x50|0x75|0x6d|0x70|0x00|0x90|0x10|0x03|
|
||||
Message | 0 | Filter Pump
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x01|0x53|0x6f|0x6c|0x61|0x72|0x20|0x48|0x65|0x61|0x74|0x20|0x45|0x4e|0x41|0x00|0x00|0x10|0x03|
|
||||
Message | 1 | Solar Heat ENA
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x02|0x41|0x75|0x78|0x31|0x00|0xc9|0x10|0x03|
|
||||
Message | 2 | Aux1
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x03|0x41|0x75|0x78|0x32|0x00|0xcb|0x10|0x03|
|
||||
Message | 3 | Aux2
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x04|0x50|0x6f|0x6f|0x6c|0x20|0x4c|0x69|0x67|0x68|0x74|0x00|0x1e|0x10|0x03|
|
||||
Message | 4 | Pool Light
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x05|0x41|0x75|0x78|0x36|0x00|0xd1|0x10|0x03|
|
||||
Message | 5 | Aux6
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x06|0x4a|0x61|0x6e|0x64|0x79|0x20|0x65|0x50|0x55|0x4d|0x50|0x20|0x20|0x20|0x31|0x00|0xbc|0x10|0x03|
|
||||
Message | 6 | Jandy ePUMP 1
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x07|0x20|0x20|0x20|0x20|0x52|0x50|0x4d|0x3a|0x20|0x32|0x37|0x35|0x30|0x00|0x06|0x10|0x03|
|
||||
Message | 7 | RPM: 2750
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x08|0x20|0x20|0x57|0x61|0x74|0x74|0x73|0x3a|0x20|0x30|0x00|0x4d|0x10|0x03|
|
||||
Message | 8 | Watts: 0
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x09|0x49|0x6e|0x74|0x65|0x6c|0x6c|0x69|0x66|0x6c|0x6f|0x20|0x56|0x46|0x20|0x32|0x00|0x91|0x10|0x03|
|
||||
Message | 9 | Intelliflo VF 2
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0a|0x20|0x20|0x20|0x20|0x52|0x50|0x4d|0x3a|0x20|0x32|0x32|0x35|0x30|0x00|0x04|0x10|0x03|
|
||||
Message | 10 | RPM: 2250
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0b|0x20|0x20|0x57|0x61|0x74|0x74|0x73|0x3a|0x20|0x31|0x30|0x30|0x00|0xb1|0x10|0x03|
|
||||
Message | 11 | Watts: 100
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0c|0x20|0x20|0x20|0x20|0x47|0x50|0x4d|0x3a|0x20|0x31|0x30|0x30|0x00|0xc3|0x10|0x03|
|
||||
Message | 12 | GPM: 100
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0d|0x49|0x6e|0x74|0x65|0x6c|0x6c|0x69|0x66|0x6c|0x6f|0x20|0x56|0x53|0x20|0x33|0x00|0xa3|0x10|0x03|
|
||||
Message | 13 | Intelliflo VS 3
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0e|0x28|0x4f|0x66|0x66|0x6c|0x69|0x6e|0x65|0x29|0x00|0x8a|0x10|0x03|
|
||||
Message | 14 | (Offline)
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0f|0x20|0x00|0x97|0x10|0x03|
|
||||
Message | 15 |
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x10|0x20|0x00|0x98|0x10|0x03|
|
||||
Message | 16 |
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x11|0x20|0x00|0x99|0x10|0x03|
|
||||
Message | 17 |
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x68|0x10|0x03|
|
||||
Button | 1 | |-| |-| |-| -off-
|
||||
Notice: Turning IAQ SEND on
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Notice: Turning IAQ SEND off
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x23|0x5b|0xc1|0x10|0x03|
|
||||
New Page | Status
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x2d|0x45|0x71|0x75|0x69|0x70|0x6d|0x65|0x6e|0x74|0x20|0x53|0x74|0x61|0x74|0x75|0x73|0x00|0xcc|0x10|0x03|
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x00|0x46|0x69|0x6c|0x74|0x65|0x72|0x20|0x50|0x75|0x6d|0x70|0x00|0x90|0x10|0x03|
|
||||
Message | 0 | Filter Pump
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x01|0x41|0x75|0x78|0x31|0x00|0xc8|0x10|0x03|
|
||||
Message | 1 | Aux1
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x02|0x41|0x75|0x78|0x32|0x00|0xca|0x10|0x03|
|
||||
Message | 2 | Aux2
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x03|0x50|0x6f|0x6f|0x6c|0x20|0x4c|0x69|0x67|0x68|0x74|0x00|0x1d|0x10|0x03|
|
||||
Message | 3 | Pool Light
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x04|0x41|0x75|0x78|0x36|0x00|0xd0|0x10|0x03|
|
||||
Message | 4 | Aux6
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x05|0x4a|0x61|0x6e|0x64|0x79|0x20|0x65|0x50|0x55|0x4d|0x50|0x20|0x20|0x20|0x31|0x00|0xbb|0x10|0x03|
|
||||
Message | 5 | Jandy ePUMP 1
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x06|0x20|0x20|0x20|0x20|0x52|0x50|0x4d|0x3a|0x20|0x32|0x37|0x35|0x30|0x00|0x05|0x10|0x03|
|
||||
Message | 6 | RPM: 2750
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x07|0x20|0x20|0x57|0x61|0x74|0x74|0x73|0x3a|0x20|0x30|0x00|0x4c|0x10|0x03|
|
||||
Message | 7 | Watts: 0
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x08|0x49|0x6e|0x74|0x65|0x6c|0x6c|0x69|0x66|0x6c|0x6f|0x20|0x56|0x46|0x20|0x32|0x00|0x90|0x10|0x03|
|
||||
Message | 8 | Intelliflo VF 2
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x09|0x20|0x20|0x20|0x20|0x52|0x50|0x4d|0x3a|0x20|0x32|0x32|0x35|0x30|0x00|0x03|0x10|0x03|
|
||||
Message | 9 | RPM: 2250
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0a|0x20|0x20|0x57|0x61|0x74|0x74|0x73|0x3a|0x20|0x31|0x30|0x33|0x00|0xb3|0x10|0x03|
|
||||
Message | 10 | Watts: 103
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0b|0x20|0x20|0x20|0x20|0x47|0x50|0x4d|0x3a|0x20|0x31|0x30|0x30|0x00|0xc2|0x10|0x03|
|
||||
Message | 11 | GPM: 100
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0c|0x49|0x6e|0x74|0x65|0x6c|0x6c|0x69|0x66|0x6c|0x6f|0x20|0x56|0x53|0x20|0x33|0x00|0xa2|0x10|0x03|
|
||||
Message | 12 | Intelliflo VS 3
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0d|0x20|0x20|0x20|0x20|0x52|0x50|0x4d|0x3a|0x20|0x31|0x37|0x35|0x30|0x00|0x0b|0x10|0x03|
|
||||
Message | 13 | RPM: 1750
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0e|0x20|0x20|0x57|0x61|0x74|0x74|0x73|0x3a|0x20|0x33|0x34|0x00|0x8a|0x10|0x03|
|
||||
Message | 14 | Watts: 34
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0f|0x41|0x51|0x55|0x41|0x50|0x55|0x52|0x45|0x20|0x33|0x30|0x25|0x00|0x83|0x10|0x03|
|
||||
Message | 15 | AQUAPURE 30%
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x10|0x53|0x61|0x6c|0x74|0x20|0x33|0x38|0x30|0x30|0x20|0x50|0x50|0x4d|0x00|0x04|0x10|0x03|
|
||||
Message | 16 | Salt 3800 PPM
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x11|0x20|0x00|0x99|0x10|0x03|
|
||||
Message | 17 |
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x68|0x10|0x03|
|
||||
Button | 1 | |-| |-| |-| -off-
|
||||
Notice: Turning IAQ SEND on
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x68|0x10|0x03|
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x02|0x00|0x00|0x6a|0x10|0x03|
|
||||
|
||||
|
||||
No next page
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x68|0x10|0x03|
|
||||
Button | 1 | 0x00 | |-| |-| -off-
|
||||
|
||||
Get next page
|
||||
Debug: To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x12|0x25|0x10|0x03|
|
||||
|
||||
Has next page
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x02|0x00|0x00|0x6a|0x10|0x03|
|
||||
Button | 1 | 0x02 | |-| |-| -off-
|
||||
|
||||
Can go up
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x68|0x10|0x03|
|
||||
Button | 1 | 0x00 | |-| |-| -off-
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
No Next page
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x68|0x10|0x03|
|
||||
Button | 1 | 0x00 | |-| |-| -off-
|
||||
Next Page
|
||||
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x02|0x00|0x00|0x6a|0x10|0x03|
|
||||
Button | 1 | 0x02 | |-| |-| -off-
|
||||
|
||||
|
||||
*/
|
164
packetLogger.c
164
packetLogger.c
|
@ -1,164 +0,0 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "packetLogger.h"
|
||||
#include "aq_serial.h"
|
||||
#include "utils.h"
|
||||
#include "config.h"
|
||||
|
||||
static FILE *_packetLogFile = NULL;
|
||||
static FILE *_byteLogFile = NULL;
|
||||
static bool _logfile_raw = false;
|
||||
static bool _logfile_packets = false;
|
||||
//static bool _includePentair = false;
|
||||
static unsigned char _lastReadFrom = NUL;
|
||||
|
||||
void _logPacket(int16_t from, unsigned char *packet_buffer, int packet_length, bool error, bool force, bool is_read);
|
||||
int _beautifyPacket(char *buff, unsigned char *packet_buffer, int packet_length, bool error, bool is_read);
|
||||
|
||||
//void startPacketLogger(bool debug_RSProtocol_packets) {
|
||||
void startPacketLogger() {
|
||||
// Make local copy of variables so we can turn on/off as needed.
|
||||
_logfile_raw = _aqconfig_.log_raw_bytes;
|
||||
_logfile_packets = _aqconfig_.log_protocol_packets;
|
||||
}
|
||||
|
||||
void startPacketLogging(bool log_protocol_packets, bool log_raw_bytes)
|
||||
{
|
||||
_logfile_raw = log_raw_bytes;
|
||||
_logfile_packets = log_protocol_packets;
|
||||
}
|
||||
|
||||
void stopPacketLogger() {
|
||||
if (_packetLogFile != NULL)
|
||||
fclose(_packetLogFile);
|
||||
|
||||
if (_byteLogFile != NULL)
|
||||
fclose(_byteLogFile);
|
||||
|
||||
_logfile_raw = false;
|
||||
_logfile_packets = false;
|
||||
}
|
||||
|
||||
// Log passed packets
|
||||
void writePacketLog(char *buffer) {
|
||||
if (!_logfile_packets)
|
||||
return;
|
||||
|
||||
if (_packetLogFile == NULL)
|
||||
_packetLogFile = fopen(RS485LOGFILE, "w");
|
||||
|
||||
if (_packetLogFile != NULL) {
|
||||
fputs(buffer, _packetLogFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Log Raw Bytes
|
||||
void logPacketByte(unsigned char *byte)
|
||||
{
|
||||
if (!_logfile_raw)
|
||||
return;
|
||||
|
||||
char buff[10];
|
||||
if (_byteLogFile == NULL)
|
||||
_byteLogFile = fopen(RS485BYTELOGFILE, "w");
|
||||
|
||||
if (_byteLogFile != NULL) {
|
||||
sprintf(buff, "0x%02hhx|",*byte);
|
||||
fputs( buff, _byteLogFile);
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
/*
|
||||
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) {
|
||||
_logPacket(RSSD_LOG, packet_buffer, packet_length, false, false, true);
|
||||
}
|
||||
void logPacketWrite(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) {
|
||||
_logPacket(RSSD_LOG, packet_buffer, packet_length, true, false, true);
|
||||
}
|
||||
|
||||
void debuglogPacket(int16_t from, unsigned char *packet_buffer, int packet_length, bool is_read) {
|
||||
if ( getLogLevel(from) >= LOG_DEBUG )
|
||||
_logPacket(from, packet_buffer, packet_length, false, true, is_read);
|
||||
}
|
||||
|
||||
void _logPacket(int16_t from, unsigned char *packet_buffer, int packet_length, bool error, bool force, bool is_read)
|
||||
{
|
||||
// No point in continuing if loglevel is < debug_serial and not writing to file
|
||||
if ( force == false &&
|
||||
error == false &&
|
||||
getLogLevel(from) < LOG_DEBUG_SERIAL &&
|
||||
/*_logfile_raw == false &&*/
|
||||
_logfile_packets == false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( _aqconfig_.RSSD_LOG_filter != NUL ) {
|
||||
if (is_read) {
|
||||
_lastReadFrom = packet_buffer[PKT_DEST];
|
||||
if ( is_read && _aqconfig_.RSSD_LOG_filter != packet_buffer[PKT_DEST]) {
|
||||
return;
|
||||
}
|
||||
} else if (!is_read && _lastReadFrom != _aqconfig_.RSSD_LOG_filter) // Must be write
|
||||
return;
|
||||
/*
|
||||
if ( is_read && _aqconfig_.RSSD_LOG_filter != packet_buffer[PKT_DEST]) {
|
||||
return;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
char buff[1000];
|
||||
|
||||
_beautifyPacket(buff, packet_buffer, packet_length, error, is_read);
|
||||
|
||||
if (_logfile_packets)
|
||||
writePacketLog(buff);
|
||||
|
||||
if (error == true)
|
||||
LOG(from,LOG_WARNING, "%s", buff);
|
||||
else {
|
||||
if (force)
|
||||
LOG(from,LOG_DEBUG, "%s", buff);
|
||||
//else if (is_read && _aqconfig_.serial_debug_filter != NUL && _aqconfig_.serial_debug_filter == packet_buffer[PKT_DEST])
|
||||
// LOG(from,LOG_NOTICE, "%s", buff);
|
||||
else
|
||||
LOG(from,LOG_DEBUG_SERIAL, "%s", buff);
|
||||
}
|
||||
}
|
||||
|
||||
int beautifyPacket(char *buff, unsigned char *packet_buffer, int packet_length, bool is_read)
|
||||
{
|
||||
return _beautifyPacket(buff, packet_buffer, packet_length, false, is_read);
|
||||
}
|
||||
int _beautifyPacket(char *buff, unsigned char *packet_buffer, int packet_length, bool error, bool is_read)
|
||||
{
|
||||
int i = 0;
|
||||
int cnt = 0;
|
||||
|
||||
if (getProtocolType(packet_buffer)==PENTAIR) {
|
||||
// Listing Jandy below if redundant. need to clean this up.
|
||||
cnt = sprintf(buff, "%5.5s %s%8.8s Packet | HEX: ",(is_read?"Read":"Write"),(error?"BAD PACKET ":""),getProtocolType(packet_buffer)==PENTAIR?"Pentair":"Jandy");
|
||||
} else {
|
||||
cnt = sprintf(buff, "%5.5s %sTo 0x%02hhx of type %16.16s | HEX: ",(is_read?"Read":"Write"),(error?"BAD PACKET ":""), packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length));
|
||||
}
|
||||
|
||||
for (i = 0; i < packet_length; i++)
|
||||
cnt += sprintf(buff + cnt, "0x%02hhx|", packet_buffer[i]);
|
||||
|
||||
cnt += sprintf(buff + cnt, "\n");
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
|
||||
#ifndef PDA_AQ_PROGRAMMER_H_
|
||||
#define PDA_AQ_PROGRAMMER_H_
|
||||
|
||||
typedef enum pda_type {
|
||||
AQUAPALM,
|
||||
PDA
|
||||
} pda_type;
|
||||
|
||||
void *get_aqualink_PDA_device_status( void *ptr );
|
||||
void *set_aqualink_PDA_device_on_off( void *ptr );
|
||||
void *set_aqualink_PDA_wakeinit( void *ptr );
|
||||
void *set_aqualink_PDA_init( void *ptr );
|
||||
|
||||
bool set_PDA_aqualink_heater_setpoint(struct aqualinkdata *aq_data, int val, bool isPool);
|
||||
bool set_PDA_aqualink_SWG_setpoint(struct aqualinkdata *aq_data, int val);
|
||||
bool set_PDA_aqualink_freezeprotect_setpoint(struct aqualinkdata *aq_data, int val);
|
||||
|
||||
bool get_PDA_aqualink_pool_spa_heater_temps(struct aqualinkdata *aq_data);
|
||||
bool get_PDA_freeze_protect_temp(struct aqualinkdata *aq_data);
|
||||
|
||||
bool get_PDA_aqualink_aux_labels(struct aqualinkdata *aq_data);
|
||||
|
||||
bool set_PDA_aqualink_boost(struct aqualinkdata *aq_data, bool val);
|
||||
bool set_PDA_aqualink_time(struct aqualinkdata *aq_data);
|
||||
|
||||
|
||||
// These are from aq_programmer.c , exposed here for PDA AQ PROGRAMMER
|
||||
void send_cmd(unsigned char cmd);
|
||||
bool push_aq_cmd(unsigned char cmd);
|
||||
bool waitForMessage(struct aqualinkdata *aq_data, char* message, int numMessageReceived);
|
||||
void waitfor_queue2empty();
|
||||
void longwaitfor_queue2empty();
|
||||
|
||||
//void pda_programming_thread_check(struct aqualinkdata *aq_data);
|
||||
|
||||
#endif // AQ_PDA_PROGRAMMER_H_
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
./aqualinkd-armhf
|
Binary file not shown.
Binary file not shown.
|
@ -1,12 +1,13 @@
|
|||
# aqualinkd.conf
|
||||
#
|
||||
|
||||
# The directory where the web files are stored
|
||||
|
||||
web_directory=/var/www/aqualinkd/
|
||||
# The socket port that the daemon listens to
|
||||
# If you change this from 80, remember to update aqualink.service.avahi
|
||||
socket_port=80
|
||||
|
||||
# Log to file, comment out if you do not want to log to file
|
||||
#log_file=/var/log/aqualinkd.log
|
||||
# The serial port the daemon access to read the Aqualink RS8
|
||||
serial_port=/dev/ttyUSB0
|
||||
|
||||
# The log level. [DEBUG_DERIAL, DEBUG, INFO, NOTICE, WARNING, ERROR]
|
||||
# Pick the highest level, and all levels below will be sent to syslog.
|
||||
|
@ -21,15 +22,9 @@ web_directory=/var/www/aqualinkd/
|
|||
log_level=NOTICE
|
||||
#log_level=WARNING
|
||||
|
||||
# Display any ERROR & Warning messages in web interface.
|
||||
display_warnings_in_web=true
|
||||
# The directory where the web files are stored
|
||||
web_directory=/var/www/aqualinkd/
|
||||
|
||||
# The socket port that the daemon listens to
|
||||
# If you change this from 80, remember to update aqualink.service.avahi
|
||||
socket_port=80
|
||||
|
||||
# The serial port the daemon access to read the Aqualink RS8
|
||||
serial_port=/dev/ttyUSB0
|
||||
|
||||
# Your RS panel size. ie 4, 6, 8, 12 or 16 relates to RS4, RS6, RS8, RS12 or RS16.
|
||||
# VERY important that you select 12 or 16, if you have either of those size panels.
|
||||
|
@ -59,7 +54,8 @@ panel_type = RS-8 Combo
|
|||
# Working RS ID's are 0x0a 0x0b 0x09 0x08 <- 0x08 is usually taken
|
||||
# If your panel is a PDA only model, then PDA device ID's are 0x60, 0x61, 0x62, 0x63.
|
||||
# (These are NOT recomended to use unless you absolutly have no other option)
|
||||
device_id=0x0a
|
||||
# Use 0xFF to let Aqualink auto configure all the ID's device_id, rssa_device_id, extended_device_id
|
||||
device_id=0xFF
|
||||
|
||||
|
||||
# The ID of Jandy SerialInterface device. These is only one usable ID, if serial_logger
|
||||
|
@ -73,73 +69,37 @@ device_id=0x0a
|
|||
# Valid ID's are 0x30, 0x31, 0x32 & 0x33. for Aqualink Touch
|
||||
#extended_device_id=0x31
|
||||
|
||||
# If using 0x30 to 0x33 for extended_device_id, then enable below if you want to use virtual buttons
|
||||
#enable_iaqualink=yes
|
||||
|
||||
# If you have extended_device_id set, then you can also use that ID for programming some features.
|
||||
# This means that you can turn things on/off while AqualinkD is programming certian features.
|
||||
# If you are using Aqualink Touch protocol for extended_device_id then this is highly recomended
|
||||
# as it will speed up programming substantially. if One Touch it's 50/50.
|
||||
#extended_device_id_programming = yes
|
||||
|
||||
# Read information from these devices directly from the RS485 bus as well as control panel.
|
||||
# Read information from these devices directly from the RS485 bus as well as control panel. This will
|
||||
# give you quicker updates and more information.
|
||||
# swg = Salt Water Generator
|
||||
# ePump = Jandy ePump or ePump AC
|
||||
# vsfPump = Pentair VS,VF,VSF pump
|
||||
# JXi = Jandy JXi heater (might also be LXi heaters)
|
||||
# LX = Jandy LX & LT heaters
|
||||
# Chem = Jandy Chemical Feeder
|
||||
# iAqualink = Read iAqualink2 (wifi device). Only relevant in PDA mode IF you have iAqualink2/3 device
|
||||
# HeatPump = Heatpumps.
|
||||
#read_RS485_swg = yes
|
||||
#read_RS485_ePump = yes
|
||||
#read_RS485_vsfPump = yes
|
||||
#read_RS485_JXi = yes
|
||||
#read_RS485_LX = yes
|
||||
#read_RS485_Chem = yes
|
||||
#read_RS485_iAqualink = yes
|
||||
#read_RS485_HeatPump = yes
|
||||
|
||||
# Keep the panel time synced with systemtime. Make sure to set systemtime / NTP correctly.
|
||||
keep_paneltime_synced = yes
|
||||
|
||||
# If equiptment is in freeze protect mode some commands like pump_off / spa_on are
|
||||
# ignored. You can force these to work by setting the below.
|
||||
override_freeze_protect = no
|
||||
|
||||
# Convert Deg F to Deg C when posting to Domoticz or MQTT.
|
||||
# If using homebridge-aqualinkd convert_mqtt_temp_to_c must be set to yes.
|
||||
convert_mqtt_temp_to_c = yes
|
||||
convert_dz_temp_to_c = yes
|
||||
|
||||
# default is to use pool water temp as spa water temp when spa is off (and there for not able to report water temp)
|
||||
# enable below to report 0 as the spa temp when spa is off.
|
||||
# This is for MQTT cnnections only, WEB socket and WEB API always report TEMP_UNKNOWN (-999) allowing the consumer to
|
||||
# decide how to report.
|
||||
report_zero_spa_temp = yes
|
||||
|
||||
# default is to not report changes to pool temp when the filter pump is off or in spa mode
|
||||
# enable below to report 0 as the pool temp when the filter pump is off or when in spa mode.
|
||||
# This is for MQTT cnnections only, WEB socket and WEB API always report TEMP_UNKNOWN (-999) allowing the consumer to
|
||||
# decide how to report.
|
||||
report_zero_pool_temp = no
|
||||
|
||||
# mqtt stuff
|
||||
#mqtt_address = localhost:1883
|
||||
#mqtt_user = someusername
|
||||
#mqtt_passwd = somepassword
|
||||
#mqtt_dz_pub_topic = domoticz/in
|
||||
#mqtt_dz_sub_topic = domoticz/out
|
||||
#mqtt_aq_topic = aqualinkd
|
||||
|
||||
# MQTT will only post updated information, this option AqualinkD will re-post all MQTT information every ~5 minutes.
|
||||
#mqtt_timed_update = no
|
||||
|
||||
# Please see forum for this, only set to yes when logging information to support new devices. (or debugging protocol)
|
||||
# Information will be written to /tmp/RS485.log & /tmp/RS485_raw.log respectively
|
||||
#debug_RSProtocol_packets = no
|
||||
#debug_RSProtocol_bytes = no
|
||||
|
||||
# Log any packets from this device.
|
||||
#serial_debug_filter = 0x00
|
||||
|
||||
# Not documented. These are experimental. Will change how RS485 / Serial works, Only use if asked to for problem solving purposes.
|
||||
#serial_readahead_b4_write = yes
|
||||
#prioritize_ack = yes
|
||||
|
||||
# Get rid of the startup warning message about no low latency. BETTER option is to buy a better adapter.
|
||||
#ftdi_low_latency = no
|
||||
|
||||
# Stop the SWG bounce from displaying when using VSP.
|
||||
#swg_zero_ignore_count = 20
|
||||
# AqualinkD will start with no extra devices by default, and once it notices the device it will add it.
|
||||
# This is not so good for automation hubs (Homekit / HomeAssistant etc), these options will force AqualinkD
|
||||
# to start with these devides.
|
||||
#force_swg = yes
|
||||
#force_ps_setpoints = yes
|
||||
#force_frzprotect_setpoints = yes
|
||||
#force_chem_feeder = yes
|
||||
#force_chiller = yes
|
||||
|
||||
|
||||
# Enable AqualinkD scheduler.
|
||||
|
@ -147,61 +107,107 @@ report_zero_pool_temp = no
|
|||
# If you used the install script and didn;t receive any cron warnings, you should be good to go.
|
||||
enable_scheduler = yes
|
||||
|
||||
# Check if button_01 (usually Pump) is scheduled to run after an event that may have turned it off, and set it to run.
|
||||
# Only for RS panels, Will not work for PDA panles.
|
||||
# Example below is if pump is off due to power reset, freezeprotect or swg boots is turned off between 6am and 11pm then turn the pump on.
|
||||
# You can leave scheduler_check_pumpon_hour & scheduler_check_pumpoff_hour commented out and AqualinkD will try to find the hours from the actual schedule
|
||||
# that's been set in scheduler. This only works if you have the same schedule for every day of the week.
|
||||
#event_check_use_scheduler_times = NO
|
||||
#event_poweron_check_pump = YES
|
||||
#event_freezeprotectoff_check_pump = YES
|
||||
#event_boostoff_check_pump = YES
|
||||
#event_check_pumpon_hour = 6
|
||||
#event_check_pumpoff_hour = 24
|
||||
|
||||
# This last one will link a button to SWG boost mode. When in boost mode, you usually have a problem that warrants running the pump faster.
|
||||
# So you can assign a virtual/one touch button to a particular pump RMP, and then turn it on with this option. (it will also turn it off when boost is finished)
|
||||
#event_booston_check_device = Fast Pump
|
||||
|
||||
# Set the RS485 adapter into low latency mode (of supported)
|
||||
ftdi_low_latency=YES
|
||||
|
||||
# Will change how RS485 / Serial works, Only use if asked to for problem solving purposes.
|
||||
# Delay between RS485 frame (set or packets that make up a command), reply too quickly can
|
||||
# cause slow panels (like PDA only) issues, reply too slowly and the control panel will think we are
|
||||
# dead.
|
||||
# ~40 and we will be replying too slowley, so keep below that.
|
||||
# 10~20 is about what most device reply in. But 0-4 works well.
|
||||
# Recomended to set to at least 4 for PDA panels.
|
||||
#rs485_frame_delay=10
|
||||
|
||||
# Keep the panel time synced with systemtime. Make sure to set systemtime / NTP correctly.
|
||||
sync_panel_time = yes
|
||||
|
||||
# Display any warnings in web UI
|
||||
display_warnings_in_web = yes
|
||||
|
||||
# If equiptment is in freeze protect mode some commands like pump_off / spa_on are
|
||||
# ignored. You can force these to work by setting the below.
|
||||
#override_freeze_protect = yes
|
||||
|
||||
# default is to use pool water temp as spa water temp when spa is off (and there for not able to report water temp)
|
||||
# enable below to report 0 as the spa temp when spa is off.
|
||||
# This is for MQTT cnnections only, WEB socket and WEB API always report TEMP_UNKNOWN (-999) allowing the consumer to
|
||||
# decide how to report.
|
||||
report_zero_spa_temp = yes
|
||||
# When pool or spa is off, report 0deg for water temp. If set to no, last known value will be used.
|
||||
report_zero_pool_temp = yes
|
||||
|
||||
# Put AqualinkD to sleep when in PDA mode after inactivity.
|
||||
# Ignore if you are not using PDA mode.
|
||||
# If you have Jandy PDA then this MUST be set to yes as the controller can only support one PDA.
|
||||
# If you don't have a Jandy PDA leave this at no as AqualinkD will be a lot quicker.
|
||||
#pda_sleep_mode = yes
|
||||
|
||||
# If you have a SWG connected to the control panel, set this to yes.
|
||||
# AqualinkD can only detect a SWG if it's on, so after a restart you will not see/access a SWG until the the next time the pump is on.
|
||||
force_SWG = no
|
||||
|
||||
# AqualinkD can take sime time to find heater setpoints (if they exist), This will force the pool & spa
|
||||
# heaters to be listed as thermostats vs switches on startup, helps with homekit.
|
||||
force_PS_setpoints = no
|
||||
|
||||
# Lights can be programmed by control panel or AqualinkD (if controlpanel doesn;t support specific light or light mode you want)
|
||||
# Lights can be programmed by control panel or AqualinkD (if controlpanel doesn't support specific light or light mode you want)
|
||||
# IF YOU WANT AQUALINKD TO PROGRAM THE LIGHT, IT MUST NOT BE CONFIGURED AS A COLOR LIGHT IN THE JANDY CONTROL PANEL.
|
||||
# Light probramming mode. 0=safe mode, but slow.
|
||||
# any number greater is seconds to wait between button presses.
|
||||
# 0.4 seems to be the minimum. (workd for light modes below 10 presses)
|
||||
# 0.6 seems to work about 95% of the time, but above 20 presses can be hit or miss.
|
||||
# 0 will simply wait for the controler to send the response back before sending the next, so is equivelent to about 1.2
|
||||
light_programming_mode=0
|
||||
#light_programming_mode=0
|
||||
|
||||
# Light programming assumes light needs to be on before sending pulse (above setting)
|
||||
# If the light is off when request is made to change "light show", then the below value are used
|
||||
light_programming_initial_on=15
|
||||
#light_programming_initial_on=15
|
||||
|
||||
# Turn the light off for below time before start programmig puleses.
|
||||
light_programming_initial_off=12
|
||||
#light_programming_initial_off=12
|
||||
|
||||
# If AqualinkD is programming the lights (and not control panel), set the light names / modes below/.
|
||||
#light_program_01=Voodoo Lounge - show
|
||||
#light_program_02=Blue Sea
|
||||
#light_program_03=Royal Blue
|
||||
#light_program_04=Afternoon Skies
|
||||
#light_program_05=Aqua Green
|
||||
#light_program_06=Emerald
|
||||
#light_program_07=Cloud White
|
||||
#light_program_08=Warm Red
|
||||
#light_program_09=Flamingo
|
||||
#light_program_10=Vivid Violet
|
||||
#light_program_11=Sangria
|
||||
#light_program_12=Twilight - show
|
||||
#light_program_13=Tranquility - show
|
||||
#light_program_14=Gemstone - show
|
||||
#light_program_15=USA - show
|
||||
#light_program_16=Mardi Gras - show
|
||||
#light_program_17=Cool Cabaret - show
|
||||
|
||||
# Everything below here, if it ends with dzidx, then that's the ID for domoticz,
|
||||
# so not needed if you are not suing dooticz.
|
||||
# Domoticz ID's for temps.
|
||||
# All below are Virtual Sensors
|
||||
#air_temp_dzidx=0
|
||||
#pool_water_temp_dzidx=0
|
||||
#spa_water_temp_dzidx=0
|
||||
#SWG_percent_dzidx=0
|
||||
#SWG_PPM_dzidx=0
|
||||
# Must be Virtual Alert Sensor
|
||||
#SWG_Status_dzidx=0
|
||||
|
||||
|
||||
# Use/find labels from Control Panel, these will overwrite the button_xx_label below,
|
||||
# it noes NOT work in PDA mode, and it also considerable slows down AqualinkD startup process.
|
||||
use_panel_aux_labels=no
|
||||
|
||||
# These are all the button labels / options / pump and light configurations you want to use.
|
||||
# Simply change these to your setup, valid options for wach button are :-
|
||||
# None of these are mandatory unless you have PDA or RS16 panel, then _label is mandatory
|
||||
# button_??_label=Filter Pump <Label you want to see>
|
||||
# button_??_dzidx=37 <Domoticz IDX>
|
||||
# button_??_pumpID=0x60 <RS485 ID of VSP>
|
||||
# button_??_pumpIndex=1 <Pump index Jandy panel is configured to use>
|
||||
# button_??_lightMode=4 <Color light mode>
|
||||
# button_??_label=Filter Pump <Label you want to see>
|
||||
# button_??_dzidx=37 <Domoticz IDX>
|
||||
# button_??_pumpID=0x60 <RS485 ID of VSP>
|
||||
# button_??_pumpIndex=1 <Pump index Jandy panel is configured to use>
|
||||
# button_??_pumpType=Pentair VF <Pump Type, one of the folowing :- JANDY ePUMP, Pentair VF, Pentair VS>
|
||||
# button_??_pumpName=My Pump <Panel Rev Y supports renaming VSP, use the name here>
|
||||
# button_??_lightMode=4 <Color light mode>
|
||||
#
|
||||
# In most cases the label is just what you want to see in web UI/MQTT/API. ie you don't need to use Jandy's labeling. There are 2 exaeptions to the labeling listed below
|
||||
# 1) If using PDA mode, The Labels below are of the utmost importance, the labels MUST exactly match the labels in the "EQUIPTMENT ON/OFF" menu of the PDA device.
|
||||
|
@ -210,28 +216,28 @@ use_panel_aux_labels=no
|
|||
#
|
||||
# Below is an example of how different Panels map into the buttons.
|
||||
#
|
||||
# | RS-6 Combo | RS-6 Only | RS-8 Combo | RS-2/6 Dual | RS-2/10 Dual | RS-16 Combo |
|
||||
# --------------------------------------------------------------------------------------------
|
||||
# Button_01 | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump |
|
||||
# Button_02 | Spa | Aux_1 | Spa | Spa | Spa | Spa |
|
||||
# Button_03 | Aux 1 | Aux 2 | Aux 1 | Aux 1 | Aux 1 | Aux 1 |
|
||||
# Button_04 | Aux 2 | Aux 3 | Aux 2 | Aux 2 | Aux 2 | Aux 2 |
|
||||
# Button_05 | Aux 3 | Aux 4 | Aux 3 | Aux 3 | Aux 3 | Aux 3 |
|
||||
# Button_06 | Aux 4 | Aux 5 | Aux 4 | Aux 4 | Aux 4 | Aux 4 |
|
||||
# Button_07 | Aux 5 | Temp 1 | Aux 5 | Aux 5 | Aux 5 | Aux 5 |
|
||||
# Button_08 | Pool Heater | Temp 2 | Aux 6 | Aux 6 | Aux 6 | Aux 6 |
|
||||
# Button_09 | Spa Heater | Solar Heater | Aux 7 | Pool Heater | Aux B1 | Aux 7 |
|
||||
# Button_10 | Solar Heater | | Pool Heater | Spa Heater | Aux B2 | Aux B1 |
|
||||
# Button_11 | | | Spa Heater | Solar Heater | Aux B3 | Aux B2 |
|
||||
# Button_12 | | | Solar Heater | | Aux B4 | Aux B3 |
|
||||
# Button_13 | | | | | Pool Heater | Aux B4 |
|
||||
# Button_14 | | | | | Spa Heater | Aux B5 |
|
||||
# Button_15 | | | | | Solar Heater | Aux B6 |
|
||||
# Button_16 | | | | | | Aux B7 |
|
||||
# Button_17 | | | | | | Aux B8 |
|
||||
# Button_18 | | | | | | Pool Heater |
|
||||
# Button_19 | | | | | | Spa Heater |
|
||||
# Button_20 | | | | | | Solar Heater |
|
||||
# | RS-4 Combo | RS-6 Combo | RS-6 Only | RS-8 Combo | RS-2/6 Dual | RS-2/10 Dual | RS-16 Combo |
|
||||
# ----------------------------------------------------------------------------------------------------------
|
||||
# Button_01 | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump |
|
||||
# Button_02 | Spa | Spa | Aux_1 | Spa | Spa | Spa | Spa |
|
||||
# Button_03 | Aux 1 | Aux 1 | Aux 2 | Aux 1 | Aux 1 | Aux 1 | Aux 1 |
|
||||
# Button_04 | Aux 2 | Aux 2 | Aux 3 | Aux 2 | Aux 2 | Aux 2 | Aux 2 |
|
||||
# Button_05 | Aux 3 | Aux 3 | Aux 4 | Aux 3 | Aux 3 | Aux 3 | Aux 3 |
|
||||
# Button_06 | Pool Heater | Aux 4 | Aux 5 | Aux 4 | Aux 4 | Aux 4 | Aux 4 |
|
||||
# Button_07 | Spa Heater | Aux 5 | Temp 1 | Aux 5 | Aux 5 | Aux 5 | Aux 5 |
|
||||
# Button_08 | Solar Heater | Pool Heater | Temp 2 | Aux 6 | Aux 6 | Aux 6 | Aux 6 |
|
||||
# Button_09 | | Spa Heater | Solar Heater | Aux 7 | Pool Heater | Aux B1 | Aux 7 |
|
||||
# Button_10 | | Solar Heater | | Pool Heater | Spa Heater | Aux B2 | Aux B1 |
|
||||
# Button_11 | | | | Spa Heater | Solar Heater | Aux B3 | Aux B2 |
|
||||
# Button_12 | | | | Solar Heater | | Aux B4 | Aux B3 |
|
||||
# Button_13 | | | | | | Pool Heater | Aux B4 |
|
||||
# Button_14 | | | | | | Spa Heater | Aux B5 |
|
||||
# Button_15 | | | | | | Solar Heater | Aux B6 |
|
||||
# Button_16 | | | | | | | Aux B7 |
|
||||
# Button_17 | | | | | | | Aux B8 |
|
||||
# Button_18 | | | | | | | Pool Heater |
|
||||
# Button_19 | | | | | | | Spa Heater |
|
||||
# Button_20 | | | | | | | Solar Heater |
|
||||
|
||||
#
|
||||
# Optional, ( button_01_pumpID & button_01_pumpIndex )
|
||||
|
@ -245,32 +251,60 @@ use_panel_aux_labels=no
|
|||
# button_01_pumpIndex=1
|
||||
# If you have assigned this pump an index number in your Aqualink control panel, (Between 1 & 4), put it here for VSP, RPM, Primp information to be captured.
|
||||
#
|
||||
# button_xx_lightMode = (0=Aqualink program, 1=Jandy, 2=Jandy LED, 3=SAm/SAL, 4=Color Logic, 5=Intellibrite, 6=Dimmer)
|
||||
#
|
||||
# button_xx_lightMode = (0=Aqualink program, 1=Jandy, 2=Jandy LED, 3=SAm/SAL, 4=Color Logic, 5=Intellibrite, 6=Hayw Univ Color, 7,8,9(future), 10=Dimmer, 11=Full Range Dimmer)
|
||||
#
|
||||
# Below are settings for standard buttons on RS-8 Combo panel used as example.
|
||||
button_01_label=Filter Pump
|
||||
#
|
||||
#button_01_label=Filter Pump
|
||||
#button_01_pumpIndex=1
|
||||
#button_01_pumpID=0x78
|
||||
#button_01_pumpName=Intelliflo VS 1
|
||||
#button_01_pumpType=Pentair VS
|
||||
|
||||
button_02_label=Spa Mode
|
||||
#button_02_label=Spa
|
||||
#button_03_label=Cleaner
|
||||
#button_04_label=Waterfall
|
||||
#button_05_label=Spa Blower
|
||||
|
||||
button_03_label=Cleaner
|
||||
#button_06_label=Pool Light
|
||||
#button_06_lightMode=2
|
||||
|
||||
button_04_label=Waterfall
|
||||
#button_07_label=Spa Light
|
||||
#button_07_lightMode=2
|
||||
|
||||
button_05_label=Spa Blower
|
||||
#button_08_label=NONE\
|
||||
#button_09_label=NONE
|
||||
#button_10_label=Pool Heater
|
||||
#button_11_label=Spa Heater
|
||||
#button_12_label=Solar Heater
|
||||
|
||||
button_06_label=Pool Light
|
||||
#button_05_lightMode=0
|
||||
# Virtual buttons.
|
||||
# To use these you must have extended_device_id set to AqualnkTouch protocol, ie 0x31, 0x31, 0x32, 0x33
|
||||
# These are the One Touch buttons. By default below are the labels
|
||||
# Panels rev Yg and newer support custom virtual buttons as well, simply add these here
|
||||
# Add the ones you would like to use below, making sure to
|
||||
# a) Sequential order of the button number starting 01
|
||||
# b) Label must be IDENTICAL to how it's displayed on a AqualinkTouch device (or web)
|
||||
#
|
||||
#virtual_button_01_label=Spa Mode
|
||||
#virtual_button_02_label=Clean Mode
|
||||
#virtual_button_03_label = OneTouch 4
|
||||
#virtual_button_04_label = OneTouch 5
|
||||
#virtual_button_05_label = OneTouch 6
|
||||
|
||||
button_07_label=Spa Light
|
||||
#button_05_lightMode=0
|
||||
# Sensors.
|
||||
# All Raspberry Pi's (and most other SBC) report CPU temp. Most report to /sys/class/thermal/thermal_zone0/temp,
|
||||
# you can monitor these and AqualinkD will post the information to MQTT.
|
||||
# These will depend a lot on the board & OS you are running.
|
||||
# the "factor" is the number the sensor is multiplied by to get an accurate result. example below is (millidegrees Celsius to Celsius)
|
||||
|
||||
button_08_label=NONE
|
||||
#sensor_01_path = /sys/class/thermal/thermal_zone0/temp
|
||||
#sensor_01_label = CPU
|
||||
#sensor_01_factor = 0.001
|
||||
|
||||
button_09_label=NONE
|
||||
# Boards like Radxa Zero3 have others sensors like below.
|
||||
#sensor_02_path = /sys/class/thermal/thermal_zone1/temp
|
||||
#sensor_02_label = GPU
|
||||
#sensor_02_factor = 0.001
|
||||
|
||||
button_10_label=Pool Heater
|
||||
|
||||
button_11_label=Spa Heater
|
||||
|
||||
button_12_label=Solar Heater
|
||||
|
||||
|
|
|
@ -1,282 +0,0 @@
|
|||
# aqualinkd.conf
|
||||
#
|
||||
|
||||
# The directory where the web files are stored
|
||||
#web_directory=/var/www/aqualinkd/
|
||||
web_directory=/nas/data/Development/Raspberry/AqualinkD/web
|
||||
|
||||
# Log to file, comment out if you do not want to log to file
|
||||
log_file=/var/log/aqualinkd.log
|
||||
|
||||
# The log level. [DEBUG, INFO, NOTICE, WARNING, ERROR]
|
||||
# Pick the highest level, and all levels below will be sent to syslog.
|
||||
# your syslog settings may be set to only display messages above a certian level
|
||||
# in which case make sure you use the log_file settings to capture everything
|
||||
# you want when debugging
|
||||
# so, NOTICE also prints WARNING & ERROR
|
||||
# DEBUG would print everything possible
|
||||
|
||||
#log_level=DEBUG_SERIAL
|
||||
#log_level=DEBUG
|
||||
log_level=INFO
|
||||
#log_level=NOTICE
|
||||
|
||||
# AQUA_LOG 1
|
||||
# NET_LOG 2
|
||||
# AQRS_LOG 4
|
||||
# ONET_LOG 8
|
||||
# IAQT_LOG 16
|
||||
# PDA_LOG 32
|
||||
# RSSA_LOG 64
|
||||
# DJAN_LOG 128
|
||||
# DPEN_LOG 256
|
||||
# RSSD_LOG 512 // Serial connection
|
||||
# PROG_LOG 1024
|
||||
# DBGT_LOG 2048
|
||||
# TIMR_LOG 4096
|
||||
|
||||
|
||||
#debug_log_mask = 1
|
||||
#debug_log_mask = 2
|
||||
#debug_log_mask = 4
|
||||
#debug_log_mask = 8
|
||||
#debug_log_mask = 16
|
||||
#debug_log_mask = 32
|
||||
#debug_log_mask = 64
|
||||
#debug_log_mask = 256
|
||||
#debug_log_mask = 512
|
||||
#debug_log_mask = 1024
|
||||
#debug_log_mask = 2048
|
||||
#debug_log_mask = 4096
|
||||
|
||||
display_warnings_in_web = yes
|
||||
|
||||
# The socket port that the daemon listens to
|
||||
# If you change this from 80, remember to update aqualink.service.avahi
|
||||
socket_port = 80
|
||||
|
||||
# The serial port the daemon access to read the Aqualink RS8
|
||||
serial_port=/dev/ttyUSB0
|
||||
#serial_port=/dev/ttyUSB1
|
||||
#serial_port=/dev/null
|
||||
|
||||
override_freeze_protect = no
|
||||
|
||||
# mqtt stuff
|
||||
mqtt_address = trident:1883
|
||||
#mqtt_user = someusername
|
||||
#mqtt_passwd = somepassword
|
||||
|
||||
#mqtt_dz_pub_topic = domoticz/in
|
||||
#mqtt_dz_sub_topic = domoticz/out
|
||||
mqtt_aq_topic = aqualinkd-test
|
||||
|
||||
# The id of the Aqualink terminal device. Devices probed by RS8 master are:
|
||||
# 08-0b, 10-13, 18-1b, 20-23, 28-2b, 30-33, 38-3b, 40-43
|
||||
#
|
||||
# Working RS 0x0a 0x0b 0x09 0x08
|
||||
|
||||
#device_id=0x0a
|
||||
#device_id=0xFF # For testing one touch, don't use kaypad
|
||||
#device_id=0x00
|
||||
device_id=0x60
|
||||
|
||||
#rssa_device_id=0x48
|
||||
|
||||
# The ID for extended settings, These are ONE TOUCH MACROS & VARIABLE SPEED PUMP RPM
|
||||
# Do not enable this if you don't use either, you'll just waste memory and cpu cycles
|
||||
# Valid ID's are 0x40, 0x41, 0x42 & 0x43.
|
||||
# If you have a one touch remote do not use Ox40
|
||||
#extended_device_id=0x43
|
||||
#extended_device_id=0x31
|
||||
|
||||
# If you have extended_device_id set, then you can also use that ID for programming some features.
|
||||
# This means that you can turn things on/off while AqualinkD is programming certian features.
|
||||
# At the moment only heater setpoints & swg boost is on the extended device programming
|
||||
#extended_device_id_programming = yes
|
||||
#extended_device_id_programming = no
|
||||
|
||||
# Not documented
|
||||
serial_readahead_b4_write = yes
|
||||
mqtt_timed_update = no
|
||||
thread_netservices = yes
|
||||
rs_poll_speed = -1
|
||||
#rs_poll_speed = 1
|
||||
|
||||
# Your RS panel size. ie 4, 6, 8, 12 or 16 relates to RS4, RS6, RS8, RS12 or RS16.
|
||||
# VERY important that you select 12 or 16, if you have either of those size panels.
|
||||
# Also don't think setting a 12 when you have a 8 will give you 4 more accessories to control, it won't the
|
||||
# panel information is needed as different panels use different bits within the RS protocol for status and key
|
||||
# presses.
|
||||
#rs_panel_size = 12
|
||||
#panel_type = RS-2/6 Dual
|
||||
#panel_type = RS-4 Only
|
||||
#panel_type = RS-4 Combo
|
||||
#panel_type = RS-6 Only
|
||||
#panel_type = RS-8 Combo
|
||||
panel_type = PD-8 Combo
|
||||
#panel_type = RS-16 Combo
|
||||
#panel_type = RS-2/14 Dual
|
||||
|
||||
#panel_type = RS-8 Only
|
||||
#panel_type_size = 8
|
||||
#panel_type_combo = yes
|
||||
#panel_type_dual = no
|
||||
#panel_type_pda = no
|
||||
#panel_type_rs = yes
|
||||
|
||||
#network_poll_speed = 1
|
||||
|
||||
keep_paneltime_synced = yes
|
||||
|
||||
#pda_mode = yes
|
||||
|
||||
#use_PDA_auxiliary = yes
|
||||
|
||||
# Read information from these devices directly from the RS485 bus as well as control panel.
|
||||
#read_RS485_swg = yes
|
||||
#read_RS485_ePump = no
|
||||
#read_RS485_vsfPump = no
|
||||
|
||||
|
||||
# F to C conversions
|
||||
convert_mqtt_temp_to_c = yes
|
||||
convert_dz_temp_to_c = yes
|
||||
|
||||
# by default use pool temp as spa temp when spa is off, enable below to report 0 as spa temp when off.
|
||||
report_zero_spa_temp = yes
|
||||
report_zero_pool_temp = no
|
||||
|
||||
# Light probramming mode. 0=safe mode, but slow.
|
||||
# any number greater is seconds to wait between button presses.
|
||||
# 0.4 seems to be the minimum. (workd for light modes below 10 presses)
|
||||
# 0.6 seems to work about 95% of the time, but above 20 presses can be hit or miss.
|
||||
# 0 will simply wait for the controler to send the response back before sending the next, so is equivelent to about 1.2
|
||||
light_programming_mode=0
|
||||
|
||||
# Light programming assumes light needs to be on before sending pulse (above setting)
|
||||
# If the light is off when request is made to change "light show", then the below value are used
|
||||
light_programming_initial_on=15
|
||||
|
||||
# Turn the light off for below time before start programmig puleses.
|
||||
light_programming_initial_off=12
|
||||
|
||||
# Try to use labels from Control Panel.
|
||||
#use_panel_aux_labels=yes
|
||||
|
||||
# If you have a SWG, set this to yes. AqualinkD can only detect a SWG if it's on, so after a restart
|
||||
# you will not see/access a SWG until the the next time the pump is on.
|
||||
force_SWG = yes
|
||||
|
||||
# Please see forum for this, only set to yes when logging information to support
|
||||
# new devices. Inflrmation will be written to /tmp/RS485.log & /tmp/RS485_raw.log respectively
|
||||
debug_RSProtocol_packets = no
|
||||
debug_RSProtocol_bytes = no
|
||||
|
||||
|
||||
# Domoticz ID's for temps.
|
||||
#air_temp_dzidx=13
|
||||
#pool_water_temp_dzidx=14
|
||||
#spa_water_temp_dzidx=15
|
||||
#SWG_percent_dzidx=998
|
||||
#SWG_PPM_dzidx=999
|
||||
#SWG_percent_dzidx=153
|
||||
#SWG_PPM_dzidx=152
|
||||
#SWG_Status_dzidx=157
|
||||
|
||||
#
|
||||
# | RS-6 Combo | RS-6 Only | RS-8 Combo | RS-2/6 Dual | RS-2/10 Dual | RS-16 Combo |
|
||||
# --------------------------------------------------------------------------------------------
|
||||
# Button_01 | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump |
|
||||
# Button_02 | Spa | Aux_1 | Spa | Spa | Spa | Spa |
|
||||
# Button_03 | Aux 1 | Aux 2 | Aux 1 | Aux 1 | Aux 1 | Aux 1 |
|
||||
# Button_04 | Aux 2 | Aux 3 | Aux 2 | Aux 2 | Aux 2 | Aux 2 |
|
||||
# Button_05 | Aux 3 | Aux 4 | Aux 3 | Aux 3 | Aux 3 | Aux 3 |
|
||||
# Button_06 | Aux 4 | Aux 5 | Aux 4 | Aux 4 | Aux 4 | Aux 4 |
|
||||
# Button_07 | Aux 5 | Temp 1 | Aux 5 | Aux 5 | Aux 5 | Aux 5 |
|
||||
# Button_08 | Pool Heater | Temp 2 | Aux 6 | Aux 6 | Aux 6 | Aux 6 |
|
||||
# Button_09 | Spa Heater | Solar Heater | Aux 7 | Pool Heater | Aux B1 | Aux 7 |
|
||||
# Button_10 | Solar Heater | | Pool Heater | Spa Heater | Aux B2 | Aux B1 |
|
||||
# Button_11 | | | Spa Heater | Solar Heater | Aux B3 | Aux B2 |
|
||||
# Button_12 | | | Solar Heater | | Aux B4 | Aux B3 |
|
||||
# Button_13 | | | | | Pool Heater | Aux B4 |
|
||||
# Button_14 | | | | | Spa Heater | Aux B5 |
|
||||
# Button_15 | | | | | Solar Heater | Aux B6 |
|
||||
# Button_16 | | | | | | Aux B7 |
|
||||
# Button_17 | | | | | | Aux B8 |
|
||||
# Button_18 | | | | | | Pool Heater |
|
||||
# Button_19 | | | | | | Spa Heater |
|
||||
# Button_20 | | | | | | Solar Heater |
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Pentair pump ID's
|
||||
# 0x60 to 0x6F (0x60, 0x61 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F)
|
||||
# Jandy pump ID's
|
||||
# 0x78, 0x79, 0x7A, 0x7B
|
||||
|
||||
# button_xx_lightMode = (0=Aqualink program, 1=Jandy, 2=Jandy LED, 3=SAm/SAL, 4=Color Logic, 5=Intellibrite)
|
||||
|
||||
# Labels for standard butons (shown in web UI), and domoticz idx's
|
||||
button_01_label=Filter Pump
|
||||
#button_01_dzidx=37
|
||||
button_01_pumpID=0x78
|
||||
#button_01_PDA_label=FILTER PUMP
|
||||
button_01_pumpIndex=1
|
||||
|
||||
button_02_label=Spa Mode
|
||||
#button_02_dzidx=38
|
||||
#button_02_pumpID= 0x78
|
||||
#button_02_pumpIndex=3
|
||||
#button_02_PDA_label=SPA
|
||||
|
||||
button_03_label=Aux1
|
||||
#button_03_dzidx=39
|
||||
button_03_pumpID=0x61
|
||||
button_03_pumpIndex=3
|
||||
|
||||
button_04_label=Aux2
|
||||
#button_04_dzidx=40
|
||||
button_04_pumpID=0x60
|
||||
button_04_pumpIndex=2
|
||||
|
||||
button_05_label=Aux3
|
||||
#button_05_dzidx=41
|
||||
button_05_lightMode=4
|
||||
|
||||
button_06_label=Aux4
|
||||
#button_06_dzidx=42
|
||||
#button_06_lightMode=1
|
||||
#button_06_pumpIndex=4
|
||||
|
||||
button_07_label=Aux5
|
||||
#button_07_label=NONE
|
||||
#button_07_dzidx=43
|
||||
#button_07_lightMode=0
|
||||
|
||||
button_08_label=Aux6
|
||||
|
||||
#button_09_label=Fountain
|
||||
|
||||
button_10_label=Pool Heat
|
||||
#button_10_dzidx=44
|
||||
|
||||
button_11_label=Spa Heat
|
||||
#button_11_dzidx=56
|
||||
|
||||
#button_12_label=Solar Heater
|
||||
#button_12_label=Solar Heater
|
||||
#button_12_dzidx=NONE
|
||||
|
||||
# RS-8 & RS-6 STOP HERE
|
||||
# This is for RS-12 & RS-16 only.
|
||||
|
||||
#button_12_label=Aux B1
|
||||
#button_13_label=
|
||||
#button_14_label=
|
||||
#button_15_label=
|
||||
#button_16_label=
|
||||
#button_17_label=Pool Heater
|
||||
#button_18_label=Spa Heater
|
||||
#button_19_label=Solar Heater
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
|
||||
BUILD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
PARENT_COMMAND=$(ps -o comm= $PPID)
|
||||
|
||||
SERVICE="aqualinkd"
|
||||
|
||||
|
@ -21,18 +22,95 @@ DEFLocation="/etc/default"
|
|||
WEBLocation="/var/www/aqualinkd/"
|
||||
MDNSLocation="/etc/avahi/services/"
|
||||
|
||||
SOURCEBIN=$BIN
|
||||
|
||||
LOG_SYSTEMD=1 # 1=false in bash, 0=true
|
||||
REMOUNT_RO=1
|
||||
|
||||
log()
|
||||
{
|
||||
echo "$*"
|
||||
|
||||
if [[ $LOG_SYSTEMD -eq 0 ]]; then
|
||||
logger -p local0.notice -t aqualinkd "Upgrade: $*"
|
||||
# Below is same as above but will only wotrk on journald (leaving it here if we use that rater then file)
|
||||
#echo $* | systemd-cat -t aqualinkd_upgrade -p info
|
||||
#echo "$*" >> "$OUTPUT"
|
||||
fi
|
||||
}
|
||||
|
||||
if ! tty > /dev/null 2>&1 || [ "$1" = "syslog" ]; then
|
||||
# No stdin, probably called from upgrade script
|
||||
LOG_SYSTEMD=0 # Set logger to systemd
|
||||
fi
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root"
|
||||
log "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $(mount | grep " / " | grep "(ro,") ]]; then
|
||||
echo "Root filesystem is readonly, can't install"
|
||||
if mount / -o remount,rw &>/dev/null; then
|
||||
# can mount RW.
|
||||
#mount / -o remount,rw &>/dev/null
|
||||
log "Root filesystem is readonly, remounted RW"
|
||||
REMOUNT_RO=0;
|
||||
else
|
||||
log "Root filesystem is readonly, can't install"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Figure out what system we are on and set correct binary.
|
||||
# If we have been called from make, this is a custom build and install, so ignore check.
|
||||
if [ "$PARENT_COMMAND" != "make" ] && [ "$1" != "from-make" ] && [ "$1" != "ignorearch" ]; then
|
||||
# Use arch or uname -a to get above.
|
||||
# dpkg --print-architecture
|
||||
|
||||
# Exit if we can't find systemctl
|
||||
command -v dpkg >/dev/null 2>&1 || { log -e "Can't detect system architecture, Please check path to 'dpkg' or install manually.\n"\
|
||||
"Or run '$0 ignorearch'" >&2; exit 1; }
|
||||
|
||||
ARCH=$(dpkg --print-architecture)
|
||||
BINEXT=""
|
||||
|
||||
case $ARCH in
|
||||
arm64)
|
||||
log "Arch is $ARCH, Using 64bit AqualinkD"
|
||||
BINEXT="-arm64"
|
||||
;;
|
||||
armhf)
|
||||
log "Arch is $ARCH, Using 32bit AqualinkD"
|
||||
BINEXT="-armhf"
|
||||
;;
|
||||
*)
|
||||
if [ -f $BUILD/$SOURCEBIN-$ARCH ]; then
|
||||
log "Arch $ARCH is not officially supported, but we found a suitable binary"
|
||||
BINEXT="-$ARCH"
|
||||
else
|
||||
log "Arch $ARCH is unknown, Default to using 32bit HF AqualinkD, you may need to manually try ./release/aqualnkd_arm64"
|
||||
BINEXT=""
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# Need to check BINEXISTS
|
||||
if [ -f $BUILD/$SOURCEBIN$BINEXT ]; then
|
||||
SOURCEBIN=$BIN$BINEXT
|
||||
elif [ -f $BUILD/$SOURCEBIN ]; then
|
||||
# Not good
|
||||
log "Can't find correct aqualnkd binary for $ARCH, '$BUILD/$SOURCEBIN$BINEXT' using '$BUILD/$SOURCEBIN' ";
|
||||
fi
|
||||
fi
|
||||
|
||||
# Exit if we can't find binary
|
||||
if [ ! -f $BUILD/$SOURCEBIN ]; then
|
||||
log "Can't find aqualnkd binary `$BUILD/$SOURCEBIN` ";
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Exit if we can't find systemctl
|
||||
command -v systemctl >/dev/null 2>&1 || { echo "This script needs systemd's systemctl manager, Please check path or install manually" >&2; exit 1; }
|
||||
command -v systemctl >/dev/null 2>&1 || { log "This script needs systemd's systemctl manager, Please check path or install manually" >&2; exit 1; }
|
||||
|
||||
# stop service, hide any error, as the service may not be installed yet
|
||||
systemctl stop $SERVICE > /dev/null 2>&1
|
||||
|
@ -40,7 +118,7 @@ SERVICE_EXISTS=$(echo $?)
|
|||
|
||||
# Clean everything if requested.
|
||||
if [ "$1" == "clean" ]; then
|
||||
echo "Deleting install"
|
||||
log "Deleting install"
|
||||
systemctl disable $SERVICE > /dev/null 2>&1
|
||||
if [ -f $BINLocation/$BIN ]; then
|
||||
rm -f $BINLocation/$BIN
|
||||
|
@ -54,6 +132,9 @@ if [ "$1" == "clean" ]; then
|
|||
if [ -f $DEFLocation/$DEF ]; then
|
||||
rm -f $DEFLocation/$DEF
|
||||
fi
|
||||
if [ -f /etc/cron.d/aqualinkd ]; then
|
||||
rm -f /etc/cron.d/aqualinkd
|
||||
fi
|
||||
if [ -d $WEBLocation ]; then
|
||||
rm -rf $WEBLocation
|
||||
fi
|
||||
|
@ -64,44 +145,62 @@ fi
|
|||
|
||||
# Check cron.d options
|
||||
if [ ! -d "/etc/cron.d" ]; then
|
||||
echo "The version of Cron may not support chron.d, if so AqualinkD Scheduler will not work"
|
||||
echo "Please check before starting"
|
||||
log "The version of Cron may not support chron.d, if so AqualinkD Scheduler will not work"
|
||||
log "Please check before starting"
|
||||
else
|
||||
if [ -f "/etc/default/cron" ]; then
|
||||
CD=$(cat /etc/default/cron | grep -v ^# | grep "\-l")
|
||||
if [ -z "$CD" ]; then
|
||||
echo "Please enabled cron.d support, if not AqualinkD Scheduler will not work"
|
||||
echo "Edit /etc/default/cron and look for the -l option, usually in EXTRA_OPTS"
|
||||
log "Please enabled cron.d support, if not AqualinkD Scheduler will not work"
|
||||
log "Edit /etc/default/cron and look for the -l option, usually in EXTRA_OPTS"
|
||||
fi
|
||||
else
|
||||
echo "Please make sure the version if Cron supports chron.d, if not the AqualinkD Scheduler will not work"
|
||||
log "Please make sure the version if Cron supports chron.d, if not the AqualinkD Scheduler will not work"
|
||||
fi
|
||||
fi
|
||||
|
||||
# V2.3.9 & V2.6.0 has kind-a breaking change for config.js, so check existing and rename if needed
|
||||
# we added Aux_V? to the button list
|
||||
if [ -f "$WEBLocation/config.js" ]; then
|
||||
# Test is if has AUX_V1 in file AND "Spa" is in file (Spa_mode changed to Spa)
|
||||
# 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
|
||||
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"
|
||||
mv $WEBLocation/config.js $WEBLocation/config.js.$dateext
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# copy files to locations, but only copy cfg if it doesn;t already exist
|
||||
|
||||
cp $BUILD/$BIN $BINLocation/$BIN
|
||||
cp $BUILD/$SOURCEBIN $BINLocation/$BIN
|
||||
cp $BUILD/$SRV $SRVLocation/$SRV
|
||||
|
||||
if [ -f $CFGLocation/$CFG ]; then
|
||||
echo "AqualinkD config exists, did not copy new config, you may need to edit existing! $CFGLocation/$CFG"
|
||||
log "AqualinkD config exists, did not copy new config, you may need to edit existing! $CFGLocation/$CFG"
|
||||
else
|
||||
cp $BUILD/$CFG $CFGLocation/$CFG
|
||||
fi
|
||||
|
||||
if [ -f $DEFLocation/$DEF ]; then
|
||||
echo "AqualinkD defaults exists, did not copy new defaults to $DEFLocation/$DEF"
|
||||
log "AqualinkD defaults exists, did not copy new defaults to $DEFLocation/$DEF"
|
||||
else
|
||||
|
||||
cp $BUILD/$DEF.defaults $DEFLocation/$DEF
|
||||
fi
|
||||
|
||||
if [ -f $MDNSLocation/$MDNS ]; then
|
||||
echo "Avahi/mDNS defaults exists, did not copy new defaults to $MDNSLocation/$MDNS"
|
||||
log "Avahi/mDNS defaults exists, did not copy new defaults to $MDNSLocation/$MDNS"
|
||||
else
|
||||
if [ -d "$MDNSLocation" ]; then
|
||||
cp $BUILD/$MDNS.avahi $MDNSLocation/$MDNS
|
||||
else
|
||||
echo "Avahi/mDNS may not be installed, not copying $MDNSLocation/$MDNS"
|
||||
log "Avahi/mDNS may not be installed, not copying $MDNSLocation/$MDNS"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@ -110,20 +209,38 @@ if [ ! -d "$WEBLocation" ]; then
|
|||
fi
|
||||
|
||||
if [ -f "$WEBLocation/config.js" ]; then
|
||||
echo "AqualinkD web config exists, did not copy new config, you may need to edit existing $WEBLocation/config.js "
|
||||
rsync -avq --exclude='config.js' $BUILD/../web/* $WEBLocation
|
||||
log "AqualinkD web config exists, did not copy new config, you may need to edit existing $WEBLocation/config.js "
|
||||
if command -v "rsync" &>/dev/null; then
|
||||
rsync -avq --exclude='config.js' $BUILD/../web/* $WEBLocation
|
||||
else
|
||||
# This isn;t the right way to do it, but seems to work.
|
||||
shopt -s extglob
|
||||
`cp -r "$BUILD/../web/"!(*config.js) "$WEBLocation"`
|
||||
shopt -u extglob
|
||||
# Below should work, but doesn't.
|
||||
#shopt -s extglob
|
||||
#cp -r "$BUILD/../web/"!(*config.js) "$WEBLocation"
|
||||
#shopt -u extglob
|
||||
fi
|
||||
else
|
||||
cp -r $BUILD/../web/* $WEBLocation
|
||||
fi
|
||||
|
||||
# remount root ro
|
||||
if [[ $REMOUNT_RO -eq 0 ]]; then
|
||||
mount / -o remount,ro &>/dev/null
|
||||
fi
|
||||
|
||||
systemctl enable $SERVICE
|
||||
systemctl daemon-reload
|
||||
|
||||
if [ $SERVICE_EXISTS -eq 0 ]; then
|
||||
echo "Starting daemon $SERVICE"
|
||||
log "Starting daemon $SERVICE"
|
||||
systemctl start $SERVICE
|
||||
else
|
||||
echo "Please edit $CFGLocation/$CFG, then start AqualinkD service"
|
||||
log "Please edit $CFGLocation/$CFG, then start AqualinkD service with `sudo systemctl start aqualinkd`"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,332 @@
|
|||
#!/bin/bash
|
||||
|
||||
#
|
||||
# run from curl or local will give different results.
|
||||
# curl -fsSL https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/release/remote_install.sh | sudo bash -s -- latest
|
||||
# ./upgrade.sh latest
|
||||
#
|
||||
# To get good / bad exit code from both curl and bash, use below. It will exit current term so be careful.
|
||||
# curl -fsSL "https://raw.githubusercontent.com/aqualinkd/AqualinkD/master/release/remote_install.sh" | ( sudo bash && exit 0 ) || exit $?
|
||||
|
||||
REQUIRED_SPACE_MB=18 # Need 17MB, use 18
|
||||
|
||||
TRUE=0
|
||||
FALSE=1
|
||||
|
||||
REPO="https://api.github.com/repos/AqualinkD/AqualinkD"
|
||||
#REPO="https://api.github.com/repos/sfeakes/AqualinkD"
|
||||
|
||||
INSTALLED_BINARY="/usr/local/bin/aqualinkd"
|
||||
|
||||
# Can't use $0 since this script is usually piped into bash
|
||||
SELF="remote_install.sh"
|
||||
|
||||
REL_VERSION=""
|
||||
DEV_VERSION=""
|
||||
INSTALLED_VERSION=""
|
||||
|
||||
TEMP_INSTALL="/tmp/aqualinkd"
|
||||
OUTPUT="/tmp/aqualinkd_upgrade.log"
|
||||
|
||||
FROM_CURL=$FASE
|
||||
|
||||
# Remember not to use (check for terminal, as it may not exist when pipe to bash)
|
||||
# ie. if [ -t 0 ]; then
|
||||
|
||||
if command -v "systemd-cat" &>/dev/null; then SYSTEMD_LOG=$TRUE;fi
|
||||
|
||||
log()
|
||||
{
|
||||
echo "$*"
|
||||
if [[ $SYSTEMD_LOG -eq $TRUE ]]; then
|
||||
echo "Upgrade: $*" | systemd-cat -t aqualinkd -p info
|
||||
else
|
||||
logger -p local0.notice -t aqualinkd "Upgrade: $*"
|
||||
fi
|
||||
echo "$*" 2>/dev/null >> "$OUTPUT"
|
||||
}
|
||||
|
||||
logerr()
|
||||
{
|
||||
echo "Error: $*" >&2
|
||||
|
||||
if [[ $SYSTEMD_LOG -eq $TRUE ]]; then
|
||||
echo "Upgrade: $*" | systemd-cat -t aqualinkd -p err
|
||||
else
|
||||
logger -p local0.error -t aqualinkd "Upgrade: $*"
|
||||
fi
|
||||
|
||||
echo "ERROR: $*" 2>/dev/null >> "$OUTPUT"
|
||||
}
|
||||
|
||||
|
||||
function check_tool() {
|
||||
cmd=$1
|
||||
if ! command -v "$cmd" &>/dev/null
|
||||
then
|
||||
log "Command '$cmd' could not be found!"
|
||||
return "$FALSE"
|
||||
fi
|
||||
|
||||
return "$TRUE"
|
||||
}
|
||||
|
||||
function latest_release_version {
|
||||
REL_VERSION=$(curl -fsSL "$REPO/releases/latest" | grep -Po '"tag_name": "\K.*?(?=")')
|
||||
if [[ "$REL_VERSION" != "" ]]; then
|
||||
return "$TRUE"
|
||||
else
|
||||
return "$FALSE"
|
||||
fi
|
||||
}
|
||||
|
||||
function latest_development_version {
|
||||
#DEV_VERSION=$(curl --silent -L "https://raw.githubusercontent.com/sfeakes/AqualinkD/master/version.h" | grep AQUALINKD_VERSION | cut -d '"' -f 2)
|
||||
DEV_VERSION=$(curl -fsSL -H "Accept: application/vnd.github.raw" "$REPO/contents/source/version.h" | grep AQUALINKD_VERSION | cut -d '"' -f 2)
|
||||
if [[ "$DEV_VERSION" != "" ]]; then
|
||||
return "$TRUE"
|
||||
else
|
||||
return "$FALSE"
|
||||
fi
|
||||
}
|
||||
|
||||
function installed_version {
|
||||
if [ -f "$INSTALLED_BINARY" ]; then
|
||||
if check_tool strings &&
|
||||
check_tool grep &&
|
||||
check_tool awk &&
|
||||
check_tool tr; then
|
||||
INSTALLED_VERSION=$(strings "$INSTALLED_BINARY" | grep sw_version | awk -v RS="," -v FS=":" '/sw_version/{print $2;exit;}' | tr -d ' "' )
|
||||
log "Current installed version $INSTALLED_VERSION"
|
||||
fi
|
||||
else
|
||||
log "AqualinkD is not installed"
|
||||
fi
|
||||
|
||||
if [[ "$INSTALLED_VERSION" != "" ]]; then
|
||||
return "$TRUE"
|
||||
else
|
||||
return "$FALSE"
|
||||
fi
|
||||
}
|
||||
|
||||
function check_system_arch {
|
||||
ARCH=$(dpkg --print-architecture)
|
||||
|
||||
case $ARCH in
|
||||
arm64 |\
|
||||
armhf)
|
||||
return "$TRUE"
|
||||
;;
|
||||
*)
|
||||
logerr "System arch is $ARCH, this is not supported by AqualinkD"
|
||||
return "$FALSE";
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
function check_can_upgrade {
|
||||
#version=$1
|
||||
output=""
|
||||
# Check we have needed commands.
|
||||
# curl, dpkg, systemctl
|
||||
if ! command -v curl &>/dev/null; then output+="Command 'curl' not found, please check it's installed and in path\n"; fi
|
||||
if ! command -v dpkg &>/dev/null; then output+="Command 'dpkg' not found, please check it's installed and in path\n"; fi
|
||||
if ! command -v systemctl &>/dev/null; then output+="Command 'systemctl' not found, please check it's installed and in path\n"; fi
|
||||
|
||||
# Check root is rw
|
||||
if mount | grep " / " | grep -q "(ro,"; then
|
||||
# check if can remount rw.
|
||||
if mount / -o remount,rw &>/dev/null; then
|
||||
# can mount RW.
|
||||
mount / -o remount,ro &>/dev/null
|
||||
else
|
||||
output+="Root filesystem is readonly & failed to remount read write, can't upgrade";
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check we can get the latest version
|
||||
if ! latest_release_version; then output+="Couldn't find latest version on github"; fi
|
||||
|
||||
# Check we can get the latest version
|
||||
if command -v dpkg &>/dev/null; then
|
||||
if ! check_system_arch; then output+="System Architecture not supported!"; fi
|
||||
fi
|
||||
|
||||
# Check free diskspace
|
||||
mkdir -p "$TEMP_INSTALL"
|
||||
free_space_mb=$(df -mP "$TEMP_INSTALL" 2>/dev/null | awk 'NR==2{print $4}' )
|
||||
|
||||
# Check if the df command was successful and if free_space_mb is a number
|
||||
if [ -z "$free_space_mb" ] || ! [[ "$free_space_mb" =~ ^[0-9]+$ ]]; then
|
||||
output+="Could not retrieve free space for directory: $TEMP_INSTALL"
|
||||
else
|
||||
if [ "$free_space_mb" -lt "$REQUIRED_SPACE_MB" ]; then
|
||||
output+="Not enough disk space on directory: $TEMP_INSTALL! (Required $REQUIRED_SPACE_MB MB)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$output" == "" ]] && [[ "$REL_VERSION" != "" ]]; then
|
||||
return "$TRUE"
|
||||
else [[ "$output" != "" ]]
|
||||
logerr "$output";
|
||||
return "$FALSE"
|
||||
fi
|
||||
|
||||
return "$TRUE"
|
||||
}
|
||||
|
||||
|
||||
function download_latest_release {
|
||||
mkdir -p "$TEMP_INSTALL"
|
||||
tar_url=$(curl -fsSL "$REPO/releases/latest" | grep -Po '"tarball_url": "\K.*?(?=")')
|
||||
if [[ "$tar_url" == "" ]]; then return "$FALSE"; fi
|
||||
|
||||
curl -fsSL "$tar_url" | tar xz --strip-components=1 --directory="$TEMP_INSTALL"
|
||||
if [ $? -ne 0 ]; then return "$FALSE"; fi
|
||||
|
||||
return "$TRUE";
|
||||
}
|
||||
|
||||
function download_latest_development {
|
||||
mkdir -p "$TEMP_INSTALL"
|
||||
tar_url="$REPO/tarball/master"
|
||||
curl -fsSL "$tar_url" | tar xz --strip-components=1 --directory="$TEMP_INSTALL"
|
||||
if [ $? -ne 0 ]; then return "$FALSE"; fi
|
||||
|
||||
return "$TRUE";
|
||||
}
|
||||
|
||||
function download_version {
|
||||
tar_url=$(curl -fsSL "$REPO/releases" | awk 'match($0,/.*"tarball_url": "(.*\/tarball\/.*)".*/)' | grep $1\" | awk -F '"' '{print $4}')
|
||||
if [[ ! -n "$tar_url" ]]; then
|
||||
return $"$FALSE"
|
||||
fi
|
||||
|
||||
mkdir -p "$TEMP_INSTALL"
|
||||
curl -fsSL "$tar_url" | tar xz --strip-components=1 --directory="$TEMP_INSTALL"
|
||||
if [ $? -ne 0 ]; then return "$FALSE"; fi
|
||||
|
||||
return "$TRUE";
|
||||
}
|
||||
|
||||
function get_all_versions {
|
||||
curl -fsSL "$REPO/releases" | awk 'match($0,/.*"tarball_url": "(.*\/tarball\/.*)".*/)' | awk -F '/' '{split($NF,a,"\""); print a[1]}'
|
||||
}
|
||||
|
||||
function run_install_script {
|
||||
if [ ! -f "$TEMP_INSTALL/release/install.sh" ]; then
|
||||
logerr "Can not find install script $TEMP_INSTALL/release/install.sh"
|
||||
return "$FALSE"
|
||||
fi
|
||||
|
||||
log "Installing AqualinkD $1"
|
||||
|
||||
# Can't run in background as it'll cleanup / delete files before install.
|
||||
nohup "$TEMP_INSTALL/release/install.sh" >> "$OUTPUT" 2>&1
|
||||
#source "/nas/data/Development/Raspberry/AqualinkD/release/install.sh" &>> "$OUTPUT"
|
||||
|
||||
#nohup "/nas/data/Development/Raspberry/AqualinkD/release/install.sh" >> "$OUTPUT" 2>&1 &
|
||||
#nohup "$TEMP_INSTALL/release/install.sh" >> "$OUTPUT" 2>&1 &
|
||||
}
|
||||
|
||||
function remove_install {
|
||||
curl -fsSL -H "Accept: application/vnd.github.raw+json" "$REPO/contents/install/install.sh" | sudo bash clean
|
||||
}
|
||||
|
||||
function cleanup {
|
||||
rm -rf "$TEMP_INSTALL"
|
||||
}
|
||||
|
||||
|
||||
####################################################
|
||||
#
|
||||
# Main
|
||||
#
|
||||
|
||||
|
||||
# See if we are called from curl ot local dir.
|
||||
# with curl no tty input and script name wil be blank.
|
||||
if ! tty > /dev/null 2>&1; then
|
||||
script=$(basename "$0")
|
||||
if [ "$script" == "bash" ] || [ "$script" == "" ]; then
|
||||
#echo "$(basename "$0") Script is likely running from curl"
|
||||
# We don't actualy use this, but may in the future to leave it here
|
||||
FROM_CURL=$TRUE
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
logerr "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#if [ ! -t 0 ]; then
|
||||
#Don't use log function here as we will cleanout the file if it exists.
|
||||
# Can't use $0 below as this script might be piped into bash from curl
|
||||
echo "$SELF - $(date) " 2>/dev/null > "$OUTPUT"
|
||||
#fi
|
||||
|
||||
if check_can_upgrade; then
|
||||
installed_version
|
||||
if [[ "$INSTALLED_VERSION" != "" ]]; then
|
||||
log "Current AqualinkD installation $INSTALLED_VERSION"
|
||||
log "System OK to upgrade AqualinkD to $REL_VERSION"
|
||||
else
|
||||
log "System OK to install AqualinkD $REL_VERSION"
|
||||
fi
|
||||
|
||||
#exit $TRUE;
|
||||
else
|
||||
logerr "Can not upgrade, Please fix error(s)!"
|
||||
exit $FALSE;
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
check|checkupgradable)
|
||||
# We have already done the check, and returned false at this point, so return true.
|
||||
exit $TRUE
|
||||
;;
|
||||
development)
|
||||
if ! latest_development_version; then logerr "getting development version";exit "$FALSE"; fi
|
||||
if ! download_latest_development; then logerr "downloading latest development";exit "$FALSE"; fi
|
||||
run_install_script "$REL_VERSION"
|
||||
cleanup
|
||||
;;
|
||||
# Add Delete / remove / clean.
|
||||
clean|delete|remove)
|
||||
if ! remove_install; then logerr "Removing install";exit "$FALSE"; fi
|
||||
log "Removed install"
|
||||
;;
|
||||
list|versions)
|
||||
get_all_versions
|
||||
;;
|
||||
v*)
|
||||
if ! download_version $1; then logerr "downloading version $1";exit "$FALSE"; fi
|
||||
run_install_script "$REL_VERSION"
|
||||
cleanup
|
||||
;;
|
||||
-h|help|h)
|
||||
echo "AqualinkD Installation script"
|
||||
echo "$SELF <- download and install latest AqualinkD version"
|
||||
echo "$SELF latest <- download and install latest AqualinkD version"
|
||||
echo "$SELF development <- download and install latest AqualinkD development version"
|
||||
echo "$SELF clean <- Remove AqualinkD"
|
||||
echo "$SELF list <- List available versions to install"
|
||||
echo "$SELF v1.0.0 <- install AqualinkD v1.0.0 (use list option to see available versions)"
|
||||
;;
|
||||
latest|*)
|
||||
if ! download_latest_release; then logerr "downloading latest"; exit "$FALSE"; fi
|
||||
run_install_script "$REL_VERSION"
|
||||
cleanup
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
exit
|
||||
|
||||
|
||||
# List all versions
|
||||
# curl -fsSL https://api.github.com/repos/sfeakes/aqualinkd/releases | awk 'match($0,/.*"html_url": "(.*\/releases\/tag\/.*)".*/)'
|
||||
# curl -fsSL "https://api.github.com/repos/sfeakes/AqualinkD/releases" | awk 'match($0,/.*"tarball_url": "(.*\/tarball\/.*)".*/)' | awk -F '"' '{print $4}'
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
./serial_logger-armhf
|
Binary file not shown.
Binary file not shown.
211
rs_msg_utils.c
211
rs_msg_utils.c
|
@ -1,211 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Shaun Feakes - All rights reserved
|
||||
*
|
||||
* You may use redistribute and/or modify this code under the terms of
|
||||
* the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. For the terms of this license,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* https://github.com/sfeakes/aqualinkd
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE 1 // for strcasestr
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
/*
|
||||
int check_panel_conf(char *panel)
|
||||
{
|
||||
"RS-16 Combo"
|
||||
"PD-8 Only"
|
||||
"PD-8 Combo"
|
||||
"RS-2/14 Dual"
|
||||
"RS-2/10 Dual"
|
||||
"RS-16 Only"
|
||||
"RS-12 Only"
|
||||
"RS-16 Combo"
|
||||
"RS-12 Combo"
|
||||
"RS-2/6 Dual"
|
||||
"RS-4 Only"
|
||||
"RS-6 Only"
|
||||
"RS-8 Only"
|
||||
"RS-4 Combo"
|
||||
"RS-6 Combo"
|
||||
"RS-8 Combo"
|
||||
}
|
||||
*/
|
||||
char *rsm_strstr(const char *haystack, const char *needle)
|
||||
{
|
||||
char *sp1 = (char *)haystack;
|
||||
char *sp2 = (char *)needle;
|
||||
//int i=0;
|
||||
// Get rid of all padding
|
||||
while(isspace(*sp1)) sp1++;
|
||||
while(isspace(*sp2)) sp2++;
|
||||
|
||||
if (strlen(sp1) == 0 || strlen(sp2) == 0)
|
||||
return NULL;
|
||||
// Need to write this myself for speed
|
||||
// Maybe use stristr from utils.c in the future. Needs a lot of testing.
|
||||
//LOG(AQUA_LOG,LOG_DEBUG, "Compare (reset)%d chars of '%s' to '%s'\n",strlen(sp2),sp1,sp2);
|
||||
return strcasestr(sp1, sp2);
|
||||
}
|
||||
char *rsm_strnstr(const char *haystack, const char *needle, int length)
|
||||
{
|
||||
// NEED TO WRITE THIS MYSELF. Same as below but limit length
|
||||
return strcasestr(haystack, needle);
|
||||
}
|
||||
|
||||
// Check s2 exists in s1
|
||||
int rsm_strcmp(const char *haystack, const char *needle)
|
||||
{
|
||||
char *sp1 = (char *)haystack;
|
||||
char *sp2 = (char *)needle;
|
||||
//int i=0;
|
||||
// Get rid of all padding
|
||||
while(isspace(*sp1)) sp1++;
|
||||
while(isspace(*sp2)) sp2++;
|
||||
|
||||
if (strlen(sp1) == 0 || strlen(sp2) == 0)
|
||||
return -1;
|
||||
// Need to write this myself for speed
|
||||
//LOG(AQUA_LOG,LOG_DEBUG, "Compare (reset)%d chars of '%s' to '%s'\n",strlen(sp2),sp1,sp2);
|
||||
return strncasecmp(sp1, sp2, strlen(sp2));
|
||||
}
|
||||
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
int rsm_strncmp(const char *haystack, const char *needle, int length)
|
||||
{
|
||||
char *sp1 = (char *)haystack;
|
||||
char *sp2 = (char *)needle;
|
||||
char *ep1 = (sp1+length);
|
||||
//int i=0;
|
||||
// Get rid of all padding
|
||||
while(isspace(*sp1)) sp1++;
|
||||
while(isspace(*sp2)) sp2++;
|
||||
|
||||
if (strlen(sp1) == 0 || strlen(sp2) == 0)
|
||||
return -1;
|
||||
|
||||
// Work out last char in haystack
|
||||
while(isspace(*ep1)) ep1--;
|
||||
|
||||
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "CHECK haystack SP1='%c' EP1='%c' SP2='%c' '%.*s' for '%s' length=%d\n",*sp1,*ep1,*sp2,(ep1-sp1)+1,sp1,sp2,(ep1-sp1)+1);
|
||||
// Need to write this myself for speed
|
||||
// Need to check if full length string (no space on end), that the +1 is accurate. MIN should do it
|
||||
return strncasecmp(sp1, sp2, MIN((ep1-sp1)+1,length));
|
||||
}
|
||||
|
||||
// NSF Check is this works correctly.
|
||||
char *rsm_strncpycut(char *dest, const char *src, int dest_len, int src_len)
|
||||
{
|
||||
char *sp = (char *)src;
|
||||
char *ep = (sp+dest_len);
|
||||
|
||||
while(isspace(*sp)) sp++;
|
||||
while(isspace(*ep)) ep--;
|
||||
|
||||
int length=MIN((ep-sp)+1,dest_len);
|
||||
|
||||
memset(dest, '\0',dest_len);
|
||||
return strncpy(dest, sp, length);
|
||||
//dest[length] = '\0';
|
||||
}
|
||||
|
||||
int _rsm_strncpy(char *dest, const unsigned char *src, int dest_len, int src_len, bool nulspace)
|
||||
{
|
||||
int i;
|
||||
int end = dest_len < src_len ? dest_len:src_len;
|
||||
//0x09 is Tab and means next field on table.
|
||||
for(i=0; i < end; i++) {
|
||||
//0x00 on button is space
|
||||
//0x00 on message is end
|
||||
if (src[i] == 0x00 && nulspace)
|
||||
dest[i] = ' ';
|
||||
else if (src[i] == 0x00 && !nulspace)
|
||||
{
|
||||
dest[i] = '\0';
|
||||
break;
|
||||
}
|
||||
else if ( (src[i] < 32 || src[i] > 126) && src[1] != 10 ) // only printable chars
|
||||
dest[i] = ' ';
|
||||
else
|
||||
dest[i] = src[i];
|
||||
|
||||
//printf("Char %c to %c\n",src[i],dest[i]);
|
||||
}
|
||||
|
||||
//printf("--'%s'--\n",dest);
|
||||
|
||||
if (dest[i] != '\0') {
|
||||
if (i < (dest_len-1))
|
||||
i++;
|
||||
|
||||
dest[i] = '\0';
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int rsm_strncpy(char *dest, const unsigned char *src, int dest_len, int src_len)
|
||||
{
|
||||
return _rsm_strncpy(dest, src, dest_len, src_len, false);
|
||||
}
|
||||
int rsm_strncpy_nul2sp(char *dest, const unsigned char *src, int dest_len, int src_len)
|
||||
{
|
||||
return _rsm_strncpy(dest, src, dest_len, src_len, true);
|
||||
}
|
||||
|
||||
#define INT_MAX +2147483647
|
||||
#define INT_MIN -2147483647
|
||||
|
||||
// atoi that can have blank start
|
||||
int rsm_atoi(const char* str)
|
||||
{
|
||||
int sign = 1, base = 0, i = 0;
|
||||
// if whitespaces then ignore.
|
||||
if (str == NULL)
|
||||
return -1;
|
||||
|
||||
while (str[i] == ' ') {
|
||||
i++;
|
||||
}
|
||||
|
||||
// checking for valid input
|
||||
while (str[i] >= '0' && str[i] <= '9') {
|
||||
// handling overflow test case
|
||||
if (base > INT_MAX / 10 || (base == INT_MAX / 10 && str[i] - '0' > 7)) {
|
||||
if (sign == 1)
|
||||
return INT_MAX;
|
||||
else
|
||||
return INT_MIN;
|
||||
}
|
||||
base = 10 * base + (str[i++] - '0');
|
||||
}
|
||||
return base * sign;
|
||||
}
|
||||
|
||||
// atof that can have blank start
|
||||
float rsm_atof(const char* str)
|
||||
{
|
||||
int i=0;
|
||||
|
||||
while (str[i] == ' ') {
|
||||
i++;
|
||||
}
|
||||
|
||||
return atof(&str[i]);
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef RS_MSG_UTILS_H_
|
||||
#define RS_MSG_UTILS_H_
|
||||
|
||||
char *rsm_strstr(const char *haystack, const char *needle);
|
||||
char *rsm_strnstr(const char *haystack, const char *needle, int length);
|
||||
int rsm_strncpy(char *dest, const unsigned char *src, int dest_len, int src_len);
|
||||
int rsm_strcmp(const char *s1, const char *s2);
|
||||
int rsm_strncmp(const char *haystack, const char *needle, int length);
|
||||
int rsm_strncpy_nul2sp(char *dest, const unsigned char *src, int dest_len, int src_len);
|
||||
int rsm_atoi(const char* str);
|
||||
float rsm_atof(const char* str);
|
||||
char *rsm_strncpycut(char *dest, const char *src, int dest_len, int src_len);
|
||||
|
||||
#endif //RS_MSG_UTILS_H_
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
#ifndef SERIAL_LOGGER_H_
|
||||
#define SERIAL_LOGGER_H_
|
||||
|
||||
/*
|
||||
int logPackets = PACKET_MAX;
|
||||
int logLevel = LOG_NOTICE;
|
||||
bool panleProbe = true;
|
||||
bool rsSerialSpeedTest = false;
|
||||
//bool serialBlocking = true;
|
||||
bool errorMonitor = false;
|
||||
*/
|
||||
//int serial_logger(int rs_fd, char *port_name);
|
||||
int serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, bool panleProbe, bool rsSerialSpeedTest, bool errorMonitor);
|
||||
|
||||
#endif // SERIAL_LOGGER_H_
|
|
@ -0,0 +1,783 @@
|
|||
#define _GNU_SOURCE 1 // for strcasestr & strptime
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aqualink.h"
|
||||
#include "allbutton.h"
|
||||
#include "rs_msg_utils.h"
|
||||
#include "devices_jandy.h"
|
||||
#include "allbutton_aq_programmer.h"
|
||||
#include "color_lights.h"
|
||||
#include "aq_scheduler.h"
|
||||
|
||||
/* Below can also be called from serialadapter.c */
|
||||
void processLEDstate(struct aqualinkdata *aq_data, unsigned char *packet, logmask_t from)
|
||||
{
|
||||
|
||||
int i = 0;
|
||||
int byte;
|
||||
int bit;
|
||||
|
||||
if (memcmp(aq_data->raw_status, packet + 4, AQ_PSTLEN) != 0) {
|
||||
aq_data->updated = true;
|
||||
LOG(from,LOG_DEBUG, "Processing LEDs status CHANGED\n");
|
||||
} else {
|
||||
LOG(from,LOG_DEBUG, "Processing LEDs status\n");
|
||||
// Their is no point in continuing here, so we could return if wanted.
|
||||
// But for the moment, we don't need to speed up anything.
|
||||
}
|
||||
|
||||
memcpy(aq_data->raw_status, packet + 4, AQ_PSTLEN);
|
||||
|
||||
//debuglogPacket(ALLB_LOG, );
|
||||
|
||||
|
||||
for (byte = 0; byte < 5; byte++)
|
||||
{
|
||||
for (bit = 0; bit < 8; bit += 2)
|
||||
{
|
||||
if (((aq_data->raw_status[byte] >> (bit + 1)) & 1) == 1)
|
||||
aq_data->aqualinkleds[i].state = FLASH;
|
||||
else if (((aq_data->raw_status[byte] >> bit) & 1) == 1)
|
||||
aq_data->aqualinkleds[i].state = ON;
|
||||
else
|
||||
aq_data->aqualinkleds[i].state = OFF;
|
||||
|
||||
//LOG(from,LOG_DEBUG,"Led %d state %d",i+1,aq_data->aqualinkleds[i].state);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// Reset enabled state for heaters, as they take 2 led states
|
||||
if (aq_data->aqualinkleds[POOL_HTR_LED_INDEX - 1].state == OFF && aq_data->aqualinkleds[POOL_HTR_LED_INDEX].state == ON)
|
||||
aq_data->aqualinkleds[POOL_HTR_LED_INDEX - 1].state = ENABLE;
|
||||
|
||||
if (aq_data->aqualinkleds[SPA_HTR_LED_INDEX - 1].state == OFF && aq_data->aqualinkleds[SPA_HTR_LED_INDEX].state == ON)
|
||||
aq_data->aqualinkleds[SPA_HTR_LED_INDEX - 1].state = ENABLE;
|
||||
|
||||
if (aq_data->aqualinkleds[SOLAR_HTR_LED_INDEX - 1].state == OFF && aq_data->aqualinkleds[SOLAR_HTR_LED_INDEX].state == ON)
|
||||
aq_data->aqualinkleds[SOLAR_HTR_LED_INDEX - 1].state = ENABLE;
|
||||
/*
|
||||
for (i=0; i < TOTAL_BUTTONS; i++) {
|
||||
LOG(from,LOG_NOTICE, "%s = %d", aq_data->aqbuttons[i].name, aq_data->aqualinkleds[i].state);
|
||||
}
|
||||
*/
|
||||
#ifdef CLIGHT_PANEL_FIX // Use state from RSSD protocol for color light if it's on.
|
||||
for (int i=0; i < aq_data->num_lights; i++) {
|
||||
if ( aq_data->lights[i].RSSDstate == ON && aq_data->lights[i].button->led->state != ON ) {
|
||||
aq_data->lights[i].button->led->state = aq_data->lights[i].RSSDstate;
|
||||
//LOG(from,LOG_WARNING,"Fix Jandy bug, color light '%s' is on, setting status to match!\n", aq_data->lights[i].button->label);
|
||||
}
|
||||
|
||||
// Below is for aqualinkd programmable light, set color mode to last if something else turns it on or off.
|
||||
if (aq_data->lights[i].lightType == LC_PROGRAMABLE && ! in_light_programming_mode(aq_data)) {
|
||||
if (aq_data->lights[i].button->led->state == OFF && aq_data->lights[i].currentValue != 0) {
|
||||
set_currentlight_value(&aq_data->lights[i], 0);
|
||||
//LOG(ALLB_LOG,LOG_NOTICE,"****** SET LIGHT MODE 0 ******\n");
|
||||
} else if (aq_data->lights[i].button->led->state == ON && aq_data->lights[i].currentValue == 0 && aq_data->lights[i].lastValue != 0) {
|
||||
set_currentlight_value(&aq_data->lights[i], aq_data->lights[i].lastValue);
|
||||
//LOG(ALLB_LOG,LOG_NOTICE,"****** SET LIGHT MODE %d ******\n",aq_data->lights[i].lastValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void setUnits(char *msg, struct aqualinkdata *aq_data)
|
||||
{
|
||||
char buf[AQ_MSGLEN*3];
|
||||
|
||||
rsm_strncpy(buf, (unsigned char *)msg, AQ_MSGLEN*3, AQ_MSGLONGLEN);
|
||||
|
||||
//ascii(buf, msg);
|
||||
LOG(ALLB_LOG,LOG_DEBUG, "Getting temp units from message '%s', looking at '%c'\n", buf, buf[strlen(buf) - 1]);
|
||||
|
||||
if (msg[strlen(msg) - 1] == 'F')
|
||||
aq_data->temp_units = FAHRENHEIT;
|
||||
else if (msg[strlen(msg) - 1] == 'C')
|
||||
aq_data->temp_units = CELSIUS;
|
||||
else
|
||||
aq_data->temp_units = UNKNOWN;
|
||||
|
||||
LOG(ALLB_LOG,LOG_INFO, "Temp Units set to %d (F=0, C=1, Unknown=2)\n", aq_data->temp_units);
|
||||
}
|
||||
|
||||
// Defined as int16_t so 16 bits to mask
|
||||
#define MSG_FREEZE (1 << 0) // 1
|
||||
#define MSG_SERVICE (1 << 1) // 1
|
||||
#define MSG_SWG (1 << 2)
|
||||
#define MSG_BOOST (1 << 3)
|
||||
#define MSG_TIMEOUT (1 << 4)
|
||||
#define MSG_RS13BUTTON (1 << 5)
|
||||
#define MSG_RS14BUTTON (1 << 6)
|
||||
#define MSG_RS15BUTTON (1 << 7)
|
||||
#define MSG_RS16BUTTON (1 << 8)
|
||||
#define MSG_BATTERY_LOW (1 << 9)
|
||||
#define MSG_SWG_DEVICE (1 << 10)
|
||||
#define MSG_LOOP_POOL_TEMP (1 << 11)
|
||||
#define MSG_LOOP_SPA_TEMP (1 << 12)
|
||||
|
||||
|
||||
int16_t RS16_endswithLEDstate(char *msg, struct aqualinkdata *aq_data)
|
||||
{
|
||||
char *sp;
|
||||
int i;
|
||||
aqledstate state = LED_S_UNKNOWN;
|
||||
|
||||
//if (_aqconfig_.rs_panel_size < 16)
|
||||
if (PANEL_SIZE() < 16)
|
||||
return false;
|
||||
|
||||
sp = strrchr(msg, ' ');
|
||||
|
||||
if( sp == NULL )
|
||||
return false;
|
||||
|
||||
if (strncasecmp(sp, " on", 3) == 0)
|
||||
state = ON;
|
||||
else if (strncasecmp(sp, " off", 4) == 0)
|
||||
state = OFF;
|
||||
else if (strncasecmp(sp, " enabled", 8) == 0) // Total guess, need to check
|
||||
state = ENABLE;
|
||||
else if (strncasecmp(sp, " no idea", 8) == 0) // need to figure out these states
|
||||
state = FLASH;
|
||||
|
||||
if (state == LED_S_UNKNOWN)
|
||||
return false;
|
||||
|
||||
// Only need to start at Aux B5->B8 (12-15)
|
||||
// Loop over only aqdata->aqbuttons[13] to aqdata->aqbuttons[16]
|
||||
for (i = aq_data->rs16_vbutton_start; i <= aq_data->rs16_vbutton_end; i++) {
|
||||
//TOTAL_BUTTONS
|
||||
if ( stristr(msg, aq_data->aqbuttons[i].label) != NULL) {
|
||||
aq_data->aqbuttons[i].led->state = state;
|
||||
LOG(ALLB_LOG,LOG_INFO, "Set %s to %d\n", aq_data->aqbuttons[i].label, aq_data->aqbuttons[i].led->state);
|
||||
// Return true should be the result, but in the if we want to continue to display message
|
||||
//return true;
|
||||
if (i == 13)
|
||||
return MSG_RS13BUTTON;
|
||||
else if (i == 14)
|
||||
return MSG_RS14BUTTON;
|
||||
else if (i == 15)
|
||||
return MSG_RS15BUTTON;
|
||||
else if (i == 16)
|
||||
return MSG_RS16BUTTON;
|
||||
else
|
||||
{
|
||||
LOG(ALLB_LOG,LOG_ERR, "RS16 Button Set error %s to %d, %d is out of scope\n", aq_data->aqbuttons[i].label, aq_data->aqbuttons[i].led->state, i);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void _processMessage(char *message, struct aqualinkdata *aq_data, bool reset);
|
||||
|
||||
void processMessage(char *message, struct aqualinkdata *aq_data)
|
||||
{
|
||||
_processMessage(message, aq_data, false);
|
||||
}
|
||||
void processMessageReset(struct aqualinkdata *aq_data)
|
||||
{
|
||||
_processMessage(NULL, aq_data, true);
|
||||
}
|
||||
void _processMessage(char *message, struct aqualinkdata *aq_data, bool reset)
|
||||
{
|
||||
char *msg;
|
||||
static bool _initWithRS = false;
|
||||
//static bool _gotREV = false;
|
||||
//static int freeze_msg_count = 0;
|
||||
//static int service_msg_count = 0;
|
||||
//static int swg_msg_count = 0;
|
||||
//static int boost_msg_count = 0;
|
||||
static int16_t msg_loop = 0;
|
||||
static aqledstate default_frz_protect_state = OFF;
|
||||
static bool boostInLastLoop = false;
|
||||
// NSF replace message with msg
|
||||
|
||||
int16_t rs16;
|
||||
|
||||
|
||||
//msg = stripwhitespace(message);
|
||||
//strcpy(aq_data->last_message, msg);
|
||||
//LOG(ALLB_LOG,LOG_INFO, "RS Message :- '%s'\n", msg);
|
||||
|
||||
|
||||
|
||||
// Check long messages in this if/elseif block first, as some messages are similar.
|
||||
// ie "POOL TEMP" and "POOL TEMP IS SET TO" so want correct match first.
|
||||
//
|
||||
|
||||
//if (stristr(msg, "JANDY AquaLinkRS") != NULL) {
|
||||
if (!reset) {
|
||||
msg = stripwhitespace(message);
|
||||
strcpy(aq_data->last_message, msg);
|
||||
LOG(ALLB_LOG,LOG_INFO, "RS Message :- '%s'\n", msg);
|
||||
// Just set this to off, it will re-set since it'll be the only message we get if on
|
||||
aq_data->service_mode_state = OFF;
|
||||
} else {
|
||||
//aq_data->display_message = NULL;
|
||||
aq_data->last_display_message[0] = ' ';
|
||||
aq_data->last_display_message[1] = '\0';
|
||||
|
||||
// Anything that wasn't on during the last set of messages, turn off
|
||||
if ((msg_loop & MSG_FREEZE) != MSG_FREEZE) {
|
||||
if (aq_data->frz_protect_state != default_frz_protect_state) {
|
||||
LOG(ALLB_LOG,LOG_INFO, "Freeze protect turned off\n");
|
||||
event_happened_set_device_state(AQS_FRZ_PROTECT_OFF, aq_data);
|
||||
// Add code to check Pump if to turn it on (was scheduled) ie time now is inbetween ON / OFF schedule
|
||||
}
|
||||
aq_data->frz_protect_state = default_frz_protect_state;
|
||||
}
|
||||
|
||||
if ((msg_loop & MSG_SERVICE) != MSG_SERVICE &&
|
||||
(msg_loop & MSG_TIMEOUT) != MSG_TIMEOUT ) {
|
||||
aq_data->service_mode_state = OFF; // IF we get this message then Service / Timeout is off
|
||||
}
|
||||
|
||||
if ( ((msg_loop & MSG_SWG_DEVICE) != MSG_SWG_DEVICE) && aq_data->swg_led_state != LED_S_UNKNOWN) {
|
||||
// No Additional SWG devices messages like "no flow"
|
||||
if ((msg_loop & MSG_SWG) != MSG_SWG && aq_data->aqbuttons[PUMP_INDEX].led->state == OFF )
|
||||
setSWGdeviceStatus(aq_data, ALLBUTTON, SWG_STATUS_OFF);
|
||||
else
|
||||
setSWGdeviceStatus(aq_data, ALLBUTTON, SWG_STATUS_ON);
|
||||
}
|
||||
|
||||
// If no AQUAPURE message, either (no SWG, it's set 0, or it's off).
|
||||
if ((msg_loop & MSG_SWG) != MSG_SWG && aq_data->swg_led_state != LED_S_UNKNOWN ) {
|
||||
if (aq_data->swg_percent != 0 || aq_data->swg_led_state == ON) {
|
||||
// Something is wrong here. Let's check pump, if on set SWG to 0, if off turn SWE off
|
||||
if ( aq_data->aqbuttons[PUMP_INDEX].led->state == OFF) {
|
||||
LOG(ALLB_LOG,LOG_INFO, "No AQUAPURE message in cycle, pump is off so setting SWG to off\n");
|
||||
setSWGoff(aq_data);
|
||||
} else {
|
||||
LOG(ALLB_LOG,LOG_INFO, "No AQUAPURE message in cycle, pump is on so setting SWG to 0%%\n");
|
||||
changeSWGpercent(aq_data, 0);
|
||||
}
|
||||
} else if (isIAQT_ENABLED == false && isONET_ENABLED == false && READ_RSDEV_SWG == false ) {
|
||||
//We have no other way to read SWG %=0, so turn SWG on with pump
|
||||
if ( aq_data->aqbuttons[PUMP_INDEX].led->state == ON) {
|
||||
LOG(ALLB_LOG,LOG_INFO, "No AQUAPURE message in cycle, pump is off so setting SWG to off\n");
|
||||
//changeSWGpercent(aq_data, 0);
|
||||
setSWGenabled(aq_data);
|
||||
}
|
||||
}
|
||||
// NSF Need something to catch startup when SWG=0 so we set it to enabeled.
|
||||
// when other ways/protocols to detect SWG=0 are turned off.
|
||||
}
|
||||
|
||||
if ((msg_loop & MSG_LOOP_POOL_TEMP) != MSG_LOOP_POOL_TEMP && aq_data->pool_temp != TEMP_UNKNOWN ) {
|
||||
aq_data->pool_temp = TEMP_UNKNOWN;
|
||||
}
|
||||
if ((msg_loop & MSG_LOOP_SPA_TEMP) != MSG_LOOP_SPA_TEMP && aq_data->spa_temp != TEMP_UNKNOWN ) {
|
||||
aq_data->spa_temp = TEMP_UNKNOWN;
|
||||
}
|
||||
|
||||
/*
|
||||
// AQUAPURE=0 we never get that message on ALLBUTTON so don't turn off unless filter pump if off
|
||||
if ((msg_loop & MSG_SWG) != MSG_SWG && aq_data->aqbuttons[PUMP_INDEX].led->state == OFF ) {
|
||||
//aq_data->ar_swg_status = SWG_STATUS_OFF;
|
||||
setSWGoff(aq_data);
|
||||
}
|
||||
*/
|
||||
if ((msg_loop & MSG_BOOST) != MSG_BOOST) {
|
||||
if (aq_data->boost == true || boostInLastLoop == true) {
|
||||
LOG(ALLB_LOG,LOG_INFO, "Boost turned off\n");
|
||||
event_happened_set_device_state(AQS_BOOST_OFF, aq_data);
|
||||
// Add code to check Pump if to turn it on (was scheduled) ie time now is inbetween ON / OFF schedule
|
||||
}
|
||||
aq_data->boost = false;
|
||||
aq_data->boost_msg[0] = '\0';
|
||||
aq_data->boost_duration = 0;
|
||||
boostInLastLoop = false;
|
||||
//if (aq_data->swg_percent >= 101)
|
||||
// aq_data->swg_percent = 0;
|
||||
}
|
||||
|
||||
if ((msg_loop & MSG_BATTERY_LOW) != MSG_BATTERY_LOW)
|
||||
aq_data->battery = OK;
|
||||
|
||||
|
||||
//if ( _aqconfig_.rs_panel_size >= 16) {
|
||||
//if ( (int)PANEL_SIZE >= 16) { // NSF No idea why this fails on RS-4, but it does. Come back and find out why
|
||||
if ( PANEL_SIZE() >= 16 ) {
|
||||
//printf("Panel size %d What the fuck am I doing here\n",PANEL_SIZE());
|
||||
if ((msg_loop & MSG_RS13BUTTON) != MSG_RS13BUTTON)
|
||||
aq_data->aqbuttons[13].led->state = OFF;
|
||||
if ((msg_loop & MSG_RS14BUTTON) != MSG_RS14BUTTON)
|
||||
aq_data->aqbuttons[14].led->state = OFF;
|
||||
if ((msg_loop & MSG_RS15BUTTON) != MSG_RS15BUTTON)
|
||||
aq_data->aqbuttons[15].led->state = OFF;
|
||||
if ((msg_loop & MSG_RS16BUTTON) != MSG_RS16BUTTON)
|
||||
aq_data->aqbuttons[16].led->state = OFF;
|
||||
}
|
||||
|
||||
msg_loop = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (stristr(msg, LNG_MSG_BATTERY_LOW) != NULL)
|
||||
{
|
||||
aq_data->battery = LOW;
|
||||
msg_loop |= MSG_BATTERY_LOW;
|
||||
strcpy(aq_data->last_display_message, msg); // Also display the message on web UI
|
||||
}
|
||||
else if (stristr(msg, LNG_MSG_POOL_TEMP_SET) != NULL)
|
||||
{
|
||||
//LOG(ALLB_LOG,LOG_DEBUG, "**************** pool htr long message: %s", &message[20]);
|
||||
aq_data->pool_htr_set_point = atoi(message + 20);
|
||||
|
||||
if (aq_data->temp_units == UNKNOWN)
|
||||
setUnits(msg, aq_data);
|
||||
}
|
||||
else if (stristr(msg, LNG_MSG_SPA_TEMP_SET) != NULL)
|
||||
{
|
||||
//LOG(ALLB_LOG,LOG_DEBUG, "spa htr long message: %s", &message[19]);
|
||||
aq_data->spa_htr_set_point = atoi(message + 19);
|
||||
|
||||
if (aq_data->temp_units == UNKNOWN)
|
||||
setUnits(msg, aq_data);
|
||||
}
|
||||
else if (stristr(msg, LNG_MSG_FREEZE_PROTECTION_SET) != NULL)
|
||||
{
|
||||
//LOG(ALLB_LOG,LOG_DEBUG, "frz protect long message: %s", &message[28]);
|
||||
aq_data->frz_protect_set_point = atoi(message + 28);
|
||||
aq_data->frz_protect_state = ENABLE;
|
||||
default_frz_protect_state = ENABLE;
|
||||
|
||||
if (aq_data->temp_units == UNKNOWN)
|
||||
setUnits(msg, aq_data);
|
||||
}
|
||||
else if (strncasecmp(msg, MSG_AIR_TEMP, MSG_AIR_TEMP_LEN) == 0)
|
||||
{
|
||||
aq_data->air_temp = atoi(msg + MSG_AIR_TEMP_LEN);
|
||||
|
||||
if (aq_data->temp_units == UNKNOWN)
|
||||
setUnits(msg, aq_data);
|
||||
}
|
||||
else if (strncasecmp(msg, MSG_POOL_TEMP, MSG_POOL_TEMP_LEN) == 0)
|
||||
{
|
||||
msg_loop |= MSG_LOOP_POOL_TEMP;
|
||||
aq_data->pool_temp = atoi(msg + MSG_POOL_TEMP_LEN);
|
||||
|
||||
if (aq_data->temp_units == UNKNOWN)
|
||||
setUnits(msg, aq_data);
|
||||
}
|
||||
else if (strncasecmp(msg, MSG_SPA_TEMP, MSG_SPA_TEMP_LEN) == 0)
|
||||
{
|
||||
msg_loop |= MSG_LOOP_SPA_TEMP;
|
||||
aq_data->spa_temp = atoi(msg + MSG_SPA_TEMP_LEN);
|
||||
|
||||
if (aq_data->temp_units == UNKNOWN)
|
||||
setUnits(msg, aq_data);
|
||||
}
|
||||
// NSF If get water temp rather than pool or spa in some cases, then we are in Pool OR Spa ONLY mode
|
||||
else if (strncasecmp(msg, MSG_WATER_TEMP, MSG_WATER_TEMP_LEN) == 0)
|
||||
{
|
||||
aq_data->pool_temp = atoi(msg + MSG_WATER_TEMP_LEN);
|
||||
aq_data->spa_temp = atoi(msg + MSG_WATER_TEMP_LEN);
|
||||
if (aq_data->temp_units == UNKNOWN)
|
||||
setUnits(msg, aq_data);
|
||||
|
||||
if (isSINGLE_DEV_PANEL != true)
|
||||
{
|
||||
changePanelToMode_Only();
|
||||
LOG(ALLB_LOG,LOG_ERR, "AqualinkD set to 'Combo Pool & Spa' but detected 'Only Pool OR Spa' panel, please change config\n");
|
||||
}
|
||||
}
|
||||
else if (stristr(msg, LNG_MSG_WATER_TEMP1_SET) != NULL)
|
||||
{
|
||||
aq_data->pool_htr_set_point = atoi(message + 28);
|
||||
|
||||
if (aq_data->temp_units == UNKNOWN)
|
||||
setUnits(msg, aq_data);
|
||||
|
||||
if (isSINGLE_DEV_PANEL != true)
|
||||
{
|
||||
changePanelToMode_Only();
|
||||
LOG(ALLB_LOG,LOG_ERR, "AqualinkD set to 'Combo Pool & Spa' but detected 'Only Pool OR Spa' panel, please change config\n");
|
||||
}
|
||||
}
|
||||
else if (stristr(msg, LNG_MSG_WATER_TEMP2_SET) != NULL)
|
||||
{
|
||||
aq_data->spa_htr_set_point = atoi(message + 27);
|
||||
|
||||
if (aq_data->temp_units == UNKNOWN)
|
||||
setUnits(msg, aq_data);
|
||||
|
||||
if (isSINGLE_DEV_PANEL != true)
|
||||
{
|
||||
changePanelToMode_Only();
|
||||
LOG(ALLB_LOG,LOG_ERR, "AqualinkD set to 'Combo Pool & Spa' but detected 'Only Pool OR Spa' panel, please change config\n");
|
||||
}
|
||||
}
|
||||
else if (stristr(msg, LNG_MSG_SERVICE_ACTIVE) != NULL)
|
||||
{
|
||||
if (aq_data->service_mode_state == OFF)
|
||||
LOG(ALLB_LOG,LOG_NOTICE, "AqualinkD set to Service Mode\n");
|
||||
aq_data->service_mode_state = ON;
|
||||
msg_loop |= MSG_SERVICE;
|
||||
//service_msg_count = 0;
|
||||
}
|
||||
else if (stristr(msg, LNG_MSG_TIMEOUT_ACTIVE) != NULL)
|
||||
{
|
||||
if (aq_data->service_mode_state == OFF)
|
||||
LOG(ALLB_LOG,LOG_NOTICE, "AqualinkD set to Timeout Mode\n");
|
||||
aq_data->service_mode_state = FLASH;
|
||||
msg_loop |= MSG_TIMEOUT;
|
||||
//service_msg_count = 0;
|
||||
}
|
||||
else if (stristr(msg, LNG_MSG_FREEZE_PROTECTION_ACTIVATED) != NULL)
|
||||
{
|
||||
msg_loop |= MSG_FREEZE;
|
||||
//aq_data->frz_protect_state = default_frz_protect_state;
|
||||
aq_data->frz_protect_state = ON;
|
||||
//freeze_msg_count = 0;
|
||||
strcpy(aq_data->last_display_message, msg); // Also display the message on web UI
|
||||
}
|
||||
|
||||
else if (ENABLE_CHILLER && (stristr(msg,"Chiller") != NULL || stristr(msg,"Heat Pump") != NULL)) {
|
||||
processHeatPumpDisplayMessage(msg, aq_data); // This doesn;t exist yet
|
||||
}
|
||||
|
||||
/* // Not sure when to do with these for the moment, so no need to compile in the test.
|
||||
else if (stristr(msg, LNG_MSG_CHEM_FEED_ON) != NULL) {
|
||||
}
|
||||
else if (stristr(msg, LNG_MSG_CHEM_FEED_OFF) != NULL) {
|
||||
}
|
||||
*/
|
||||
else if (msg[2] == '/' && msg[5] == '/' && msg[8] == ' ')
|
||||
{ // date in format '08/29/16 MON'
|
||||
strcpy(aq_data->date, msg);
|
||||
}
|
||||
else if (stristr(msg, MSG_SWG_PCT) != NULL)
|
||||
{
|
||||
if (strncasecmp(msg, MSG_SWG_PCT, MSG_SWG_PCT_LEN) == 0 && strncasecmp(msg, "AQUAPURE HRS", 12) != 0) {
|
||||
changeSWGpercent(aq_data, atoi(msg + MSG_SWG_PCT_LEN));
|
||||
}
|
||||
else if (strncasecmp(msg, "AQUAPURE HRS", 12) != 0 && strncasecmp(msg, "SET AQUAPURE", 12) != 0)
|
||||
{
|
||||
if (strcasestr(msg, MSG_SWG_NO_FLOW) != NULL)
|
||||
setSWGdeviceStatus(aq_data, ALLBUTTON, SWG_STATUS_NO_FLOW);
|
||||
else if (strcasestr(msg, MSG_SWG_LOW_SALT) != NULL)
|
||||
setSWGdeviceStatus(aq_data, ALLBUTTON, SWG_STATUS_LOW_SALT);
|
||||
else if (strcasestr(msg, MSG_SWG_HIGH_SALT) != NULL)
|
||||
setSWGdeviceStatus(aq_data, ALLBUTTON, SWG_STATUS_HI_SALT);
|
||||
else if (strcasestr(msg, MSG_SWG_FAULT) != NULL)
|
||||
setSWGdeviceStatus(aq_data, ALLBUTTON, SWG_STATUS_GENFAULT);
|
||||
//setSWGdeviceStatus(aq_data, ALLBUTTON, SWG_STATUS_CHECK_PCB);
|
||||
|
||||
// Any of these messages want to display.
|
||||
strcpy(aq_data->last_display_message, msg);
|
||||
|
||||
msg_loop |= MSG_SWG_DEVICE;
|
||||
}
|
||||
msg_loop |= MSG_SWG;
|
||||
}
|
||||
else if (strncasecmp(msg, MSG_SWG_PPM, MSG_SWG_PPM_LEN) == 0)
|
||||
{
|
||||
aq_data->swg_ppm = atoi(msg + MSG_SWG_PPM_LEN);
|
||||
msg_loop |= MSG_SWG;
|
||||
}
|
||||
else if ((msg[1] == ':' || msg[2] == ':') && msg[strlen(msg) - 1] == 'M')
|
||||
{ // time in format '9:45 AM'
|
||||
strcpy(aq_data->time, msg);
|
||||
// Setting time takes a long time, so don't try until we have all other programmed data.
|
||||
if (_initWithRS == true && strlen(aq_data->date) > 1 && checkAqualinkTime() != true)
|
||||
{
|
||||
LOG(ALLB_LOG,LOG_NOTICE, "RS time is NOT accurate '%s %s', re-setting on controller!\n", aq_data->time, aq_data->date);
|
||||
aq_programmer(AQ_SET_TIME, NULL, aq_data);
|
||||
}
|
||||
else if (_initWithRS == false || _aqconfig_.sync_panel_time == false)
|
||||
{
|
||||
LOG(ALLB_LOG,LOG_DEBUG, "RS time '%s %s' not checking\n", aq_data->time, aq_data->date);
|
||||
}
|
||||
else if (_initWithRS == true)
|
||||
{
|
||||
LOG(ALLB_LOG,LOG_DEBUG, "RS time is accurate '%s %s'\n", aq_data->time, aq_data->date);
|
||||
}
|
||||
// If we get a time message before REV, the controller didn't see us as we started too quickly.
|
||||
/* Don't need to check this anymore with the check for probe before startup.
|
||||
if (_gotREV == false)
|
||||
{
|
||||
LOG(ALLB_LOG,LOG_NOTICE, "Getting control panel information\n", msg);
|
||||
aq_programmer(AQ_GET_DIAGNOSTICS_MODEL, NULL, aq_data);
|
||||
_gotREV = true; // Force it to true just incase we don't understand the model#
|
||||
}
|
||||
*/
|
||||
}
|
||||
else if (strstr(msg, " REV ") != NULL || strstr(msg, " REV. ") != NULL)
|
||||
{ // '8157 REV MMM'
|
||||
// A master firmware revision message.
|
||||
strcpy(aq_data->version, msg);
|
||||
rsm_get_revision(aq_data->revision, aq_data->version, strlen(aq_data->version));
|
||||
setPanelInformationFromPanelMsg(aq_data, msg, PANEL_CPU | PANEL_REV, ALLBUTTON);
|
||||
//setBoardCPURevision(aq_data, aq_data->version, strlen(aq_data->version), ALLB_LOG);
|
||||
//_gotREV = true;
|
||||
LOG(ALLB_LOG,LOG_DEBUG, "Control Panel version %s\n", aq_data->version);
|
||||
LOG(ALLB_LOG,LOG_DEBUG, "Control Panel revision %s\n", aq_data->revision);
|
||||
if (_initWithRS == false)
|
||||
{
|
||||
//LOG(ALLBUTTON,LOG_NOTICE, "Standard protocol initialization complete\n");
|
||||
queueGetProgramData(ALLBUTTON, aq_data);
|
||||
event_happened_set_device_state(AQS_POWER_ON, aq_data);
|
||||
//queueGetExtendedProgramData(ALLBUTTON, aq_data, _aqconfig_.use_panel_aux_labels);
|
||||
_initWithRS = true;
|
||||
}
|
||||
}
|
||||
else if (stristr(msg, " TURNS ON") != NULL)
|
||||
{
|
||||
LOG(ALLB_LOG,LOG_NOTICE, "Program data '%s'\n", msg);
|
||||
}
|
||||
else if (_aqconfig_.override_freeze_protect == TRUE && strncasecmp(msg, "Press Enter* to override Freeze Protection with", 47) == 0)
|
||||
{
|
||||
//send_cmd(KEY_ENTER, aq_data);
|
||||
//aq_programmer(AQ_SEND_CMD, (char *)KEY_ENTER, aq_data);
|
||||
aq_send_allb_cmd(KEY_ENTER);
|
||||
}
|
||||
// Process any button states (fake LED) for RS12 and above keypads
|
||||
// Text will be button label on or off ie Aux_B2 off or WaterFall off
|
||||
|
||||
|
||||
//else if ( _aqconfig_.rs_panel_size >= 16 && (rs16 = RS16_endswithLEDstate(msg)) != 0 )
|
||||
else if (PANEL_SIZE() >= 16 && (rs16 = RS16_endswithLEDstate(msg, aq_data)) != 0 )
|
||||
{
|
||||
msg_loop |= rs16;
|
||||
// Do nothing, just stop other else if statments executing
|
||||
// make sure we also display the message.
|
||||
// Note we only get ON messages here, Off messages will not be sent if something else turned it off
|
||||
// use the Onetouch or iAqua equiptment page for off.
|
||||
strcpy(aq_data->last_display_message, msg);
|
||||
}
|
||||
|
||||
else if (((msg[4] == ':') || (msg[6] == ':')) && (strncasecmp(msg, "AUX", 3) == 0) )
|
||||
{ // Should probable check we are in programming mode.
|
||||
// 'Aux3: No Label'
|
||||
// 'Aux B1: No Label'
|
||||
int labelid;
|
||||
int ni = 3;
|
||||
if (msg[4] == 'B') { ni = 5; }
|
||||
labelid = atoi(msg + ni);
|
||||
if (labelid > 0 && _aqconfig_.use_panel_aux_labels == true)
|
||||
{
|
||||
if (ni == 5)
|
||||
labelid = labelid + 8;
|
||||
else
|
||||
labelid = labelid + 1;
|
||||
// Aux1: on panel = Button 3 in aqualinkd (button 2 in array)
|
||||
if (strncasecmp(msg+ni+3, "No Label", 8) != 0) {
|
||||
aq_data->aqbuttons[labelid].label = prittyString(cleanalloc(msg+ni+2));
|
||||
LOG(ALLB_LOG,LOG_NOTICE, "AUX ID %s label set to '%s'\n", aq_data->aqbuttons[labelid].name, aq_data->aqbuttons[labelid].label);
|
||||
} else {
|
||||
LOG(ALLB_LOG,LOG_NOTICE, "AUX ID %s has no control panel label using '%s'\n", aq_data->aqbuttons[labelid].name, aq_data->aqbuttons[labelid].label);
|
||||
}
|
||||
//aq_data->aqbuttons[labelid + 1].label = cleanalloc(msg + 5);
|
||||
}
|
||||
}
|
||||
// BOOST POOL 23:59 REMAINING
|
||||
else if ( (strncasecmp(msg, "BOOST POOL", 10) == 0) && (strcasestr(msg, "REMAINING") != NULL) ) {
|
||||
// Ignore messages if in programming mode. We get one of these turning off for some strange reason.
|
||||
if (in_programming_mode(aq_data) == false) {
|
||||
|
||||
if (aq_data->boost == false || boostInLastLoop == false) {
|
||||
event_happened_set_device_state(AQS_BOOST_ON, aq_data);
|
||||
}
|
||||
|
||||
snprintf(aq_data->boost_msg, 6, "%s", &msg[11]);
|
||||
aq_data->boost_duration = rsm_HHMM2min(aq_data->boost_msg);
|
||||
aq_data->boost = true;
|
||||
msg_loop |= MSG_BOOST;
|
||||
msg_loop |= MSG_SWG;
|
||||
boostInLastLoop = true;
|
||||
//convert_boost_to_duration(aq_data->boost_msg)
|
||||
//if (aq_data->ar_swg_status != SWG_STATUS_ON) {aq_data->ar_swg_status = SWG_STATUS_ON;}
|
||||
if (aq_data->swg_percent != 101) {changeSWGpercent(aq_data, 101);}
|
||||
//boost_msg_count = 0;
|
||||
//if (aq_data->active_thread.thread_id == 0)
|
||||
strcpy(aq_data->last_display_message, msg); // Also display the message on web UI if not in programming mode
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(ALLB_LOG,LOG_DEBUG_SERIAL, "Ignoring '%s'\n", msg);
|
||||
//aq_data->display_message = msg;
|
||||
//if (in_programming_mode(aq_data) == false && aq_data->simulate_panel == false &&
|
||||
if (in_programming_mode(aq_data) == false &&
|
||||
stristr(msg, "JANDY AquaLinkRS") == NULL &&
|
||||
//stristr(msg, "PUMP O") == NULL &&// Catch 'PUMP ON' and 'PUMP OFF' but not 'PUMP WILL TURN ON'
|
||||
strncasecmp(msg, "PUMP O", 6) != 0 &&// Catch 'PUMP ON' and 'PUMP OFF' but not 'PUMP WILL TURN ON'
|
||||
stristr(msg, "MAINTAIN") == NULL && // Catch 'MAINTAIN TEMP IS OFF'
|
||||
stristr(msg, "0 PSI") == NULL /* // Catch some erronious message on test harness
|
||||
stristr(msg, "CLEANER O") == NULL &&
|
||||
stristr(msg, "SPA O") == NULL &&
|
||||
stristr(msg, "AUX") == NULL*/
|
||||
)
|
||||
{ // Catch all AUX1 AUX5 messages
|
||||
//aq_data->display_last_message = true;
|
||||
strcpy(aq_data->last_display_message, msg);
|
||||
//rsm_strncpy(aq_data->last_display_message, (unsigned char *)msg, AQ_MSGLONGLEN, AQ_MSGLONGLEN);
|
||||
}
|
||||
}
|
||||
|
||||
// Send every message if we are in simulate panel mode
|
||||
//if (aq_data->simulate_panel)
|
||||
// strcpy(aq_data->last_display_message, msg);
|
||||
//rsm_strncpy(aq_data->last_display_message, (unsigned char *)msg, AQ_MSGLONGLEN, AQ_MSGLONGLEN);
|
||||
//ascii(aq_data->last_display_message, msg);
|
||||
|
||||
|
||||
//LOG(ALLB_LOG,LOG_INFO, "RS Message loop :- '%d'\n", msg_loop);
|
||||
|
||||
// We processed the next message, kick any threads waiting on the message.
|
||||
//printf ("Message kicking\n");
|
||||
|
||||
|
||||
kick_aq_program_thread(aq_data, ALLBUTTON);
|
||||
}
|
||||
|
||||
bool process_allbutton_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data)
|
||||
{
|
||||
bool rtn = false;
|
||||
//static unsigned char last_packet[AQ_MAXPKTLEN];
|
||||
static unsigned char last_checksum;
|
||||
static char message[AQ_MSGLONGLEN + 1];
|
||||
static int processing_long_msg = 0;
|
||||
|
||||
// Check packet against last check if different.
|
||||
// Should only use the checksum, not whole packet since it's status messages.
|
||||
/*
|
||||
if ( packet[PKT_CMD] == CMD_STATUS && (memcmp(packet, last_packet, length) == 0))
|
||||
{
|
||||
LOG(ALLB_LOG,LOG_DEBUG_SERIAL, "RS Received duplicate, ignoring.\n", length);
|
||||
return rtn;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(last_packet, packet, length);
|
||||
aq_data->last_packet_type = packet[PKT_CMD];
|
||||
rtn = true;
|
||||
}
|
||||
*/
|
||||
|
||||
aq_data->last_packet_type = packet[PKT_CMD];
|
||||
|
||||
|
||||
if ( packet[PKT_CMD] == CMD_STATUS && packet[length-3] == last_checksum && ! in_programming_mode(aq_data) )
|
||||
{
|
||||
LOG(ALLB_LOG,LOG_DEBUG_SERIAL, "RS Received duplicate, ignoring.\n", length);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_checksum = packet[length-3];
|
||||
rtn = true;
|
||||
}
|
||||
|
||||
if (processing_long_msg > 0 && packet[PKT_CMD] != CMD_MSG_LONG)
|
||||
{
|
||||
processing_long_msg = 0;
|
||||
//LOG(ALLB_LOG,LOG_ERR, "RS failed to receive complete long message, received '%s'\n",message);
|
||||
//LOG(ALLB_LOG,LOG_DEBUG, "RS didn't finished receiving of MSG_LONG '%s'\n",message);
|
||||
processMessage(message, aq_data);
|
||||
}
|
||||
|
||||
LOG(ALLB_LOG,LOG_DEBUG_SERIAL, "RS Received packet type 0x%02hhx length %d.\n", packet[PKT_CMD], length);
|
||||
|
||||
switch (packet[PKT_CMD])
|
||||
{
|
||||
case CMD_ACK:
|
||||
//LOG(ALLB_LOG,LOG_DEBUG_SERIAL, "RS Received ACK length %d.\n", length);
|
||||
break;
|
||||
case CMD_STATUS:
|
||||
//LOG(ALLB_LOG,LOG_DEBUG, "RS Received STATUS length %d.\n", length);
|
||||
//debuglogPacket(ALLB_LOG, packet, length, true, true);
|
||||
|
||||
//memcpy(aq_data->raw_status, packet + 4, AQ_PSTLEN);
|
||||
//processLEDstate(aq_data);
|
||||
processLEDstate(aq_data, packet, ALLB_LOG);
|
||||
|
||||
/* NSF Take this out, and use the ALLButton loop cycle to determin if we get spa/pool temp
|
||||
messages. Works better for dual equiptment when both pool & spa pumps and dual temp sensors */
|
||||
/*
|
||||
if (aq_data->aqbuttons[PUMP_INDEX].led->state == OFF)
|
||||
{
|
||||
aq_data->pool_temp = TEMP_UNKNOWN;
|
||||
aq_data->spa_temp = TEMP_UNKNOWN;
|
||||
//aq_data->spa_temp = _aqconfig_.report_zero_spa_temp?-18:TEMP_UNKNOWN;
|
||||
}
|
||||
else if (aq_data->aqbuttons[SPA_INDEX].led->state == OFF && isSINGLE_DEV_PANEL != true)
|
||||
{
|
||||
//aq_data->spa_temp = _aqconfig_.report_zero_spa_temp?-18:TEMP_UNKNOWN;
|
||||
aq_data->spa_temp = TEMP_UNKNOWN;
|
||||
}
|
||||
else if (aq_data->aqbuttons[SPA_INDEX].led->state == ON && isSINGLE_DEV_PANEL != true)
|
||||
{
|
||||
aq_data->pool_temp = TEMP_UNKNOWN;
|
||||
}
|
||||
*/
|
||||
|
||||
// COLOR MODE programming relies on state changes, so let any threads know
|
||||
//if (aq_data->active_thread.ptype == AQ_SET_LIGHTPROGRAM_MODE) {
|
||||
if ( in_light_programming_mode(aq_data) ) {
|
||||
kick_aq_program_thread(aq_data, ALLBUTTON);
|
||||
}
|
||||
break;
|
||||
case CMD_MSG:
|
||||
case CMD_MSG_LONG:
|
||||
{
|
||||
int index = packet[PKT_DATA]; // Will get 0x00 for complete message, 0x01 for start on long message 0x05 last of long message
|
||||
//printf("RSM received message at index %d '%.*s'\n",index,AQ_MSGLEN,(char *)packet + PKT_DATA + 1);
|
||||
if (index <= 1){
|
||||
memset(message, 0, AQ_MSGLONGLEN + 1);
|
||||
//strncpy(message, (char *)packet + PKT_DATA + 1, AQ_MSGLEN);
|
||||
rsm_strncpy(message, packet + PKT_DATA + 1, AQ_MSGLONGLEN, AQ_MSGLEN);
|
||||
processing_long_msg = index;
|
||||
//LOG(ALLB_LOG,LOG_ERR, "Message %s\n",message);
|
||||
} else {
|
||||
//strncpy(&message[(processing_long_msg * AQ_MSGLEN)], (char *)packet + PKT_DATA + 1, AQ_MSGLEN);
|
||||
//rsm_strncpy(&message[(processing_long_msg * AQ_MSGLEN)], (unsigned char *)packet + PKT_DATA + 1, AQ_MSGLONGLEN, AQ_MSGLEN);
|
||||
rsm_strncpy(&message[( (index-1) * AQ_MSGLEN)], (unsigned char *)packet + PKT_DATA + 1, AQ_MSGLONGLEN, AQ_MSGLEN);
|
||||
//LOG(ALLB_LOG,LOG_ERR, "Long Message %s\n",message);
|
||||
if (++processing_long_msg != index) {
|
||||
LOG(ALLB_LOG,LOG_DEBUG, "Long message index %d doesn't match buffer %d\n",index,processing_long_msg);
|
||||
//printf("RSM Long message index %d doesn't match buffer %d\n",index,processing_long_msg);
|
||||
}
|
||||
#ifdef PROCESS_INCOMPLETE_MESSAGES
|
||||
kick_aq_program_thread(aq_data, ALLBUTTON);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (index == 0 || index == 5) {
|
||||
//printf("RSM process message '%s'\n",message);
|
||||
|
||||
// MOVED FROM LINE 701 see if less errors
|
||||
//kick_aq_program_thread(aq_data, ALLBUTTON);
|
||||
|
||||
LOG(ALLB_LOG,LOG_DEBUG, "Processing Message - '%s'\n",message);
|
||||
processMessage(message, aq_data); // This will kick thread
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case CMD_PROBE:
|
||||
LOG(ALLB_LOG,LOG_DEBUG, "RS Received PROBE length %d.\n", length);
|
||||
//LOG(ALLB_LOG,LOG_INFO, "Synch'ing with Aqualink master device...\n");
|
||||
rtn = false;
|
||||
break;
|
||||
case CMD_MSG_LOOP_ST:
|
||||
LOG(ALLB_LOG,LOG_INFO, "RS Received message loop start\n");
|
||||
processMessageReset(aq_data);
|
||||
rtn = false;
|
||||
break;
|
||||
default:
|
||||
LOG(ALLB_LOG,LOG_INFO, "RS Received unknown packet, 0x%02hhx\n", packet[PKT_CMD]);
|
||||
rtn = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef ALLBUTTON_H_
|
||||
#define ALLBUTTON_H_
|
||||
|
||||
|
||||
void processLEDstate(struct aqualinkdata *aq_data, unsigned char *packet, logmask_t from);
|
||||
bool process_allbutton_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data);
|
||||
|
||||
#endif //ALLBUTTON_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,26 @@
|
|||
#ifndef ALLBUTTON_PROGRAMMER_H_
|
||||
#define ALLBUTTON_PROGRAMMER_H_
|
||||
|
||||
|
||||
void *set_allbutton_pool_heater_temps( void *ptr );
|
||||
void *set_allbutton_spa_heater_temps( void *ptr );
|
||||
void *set_allbutton_freeze_heater_temps( void *ptr );
|
||||
void *set_allbutton_time( void *ptr );
|
||||
void *get_allbutton_pool_spa_heater_temps( void *ptr );
|
||||
void *get_allbutton_programs( void *ptr );
|
||||
void *get_allbutton_freeze_protect_temp( void *ptr );
|
||||
void *get_allbutton_diag_model( void *ptr );
|
||||
void *get_allbutton_aux_labels( void *ptr );
|
||||
//void *threadded_send_cmd( void *ptr );
|
||||
void *set_allbutton_light_programmode( void *ptr );
|
||||
void *set_allbutton_light_colormode( void *ptr );
|
||||
void *set_allbutton_SWG( void *ptr );
|
||||
void *set_allbutton_boost( void *ptr );
|
||||
|
||||
unsigned char pop_allb_cmd(struct aqualinkdata *aq_data);
|
||||
|
||||
|
||||
|
||||
void aq_send_allb_cmd(unsigned char cmd);
|
||||
|
||||
#endif //ALLBUTTON_PROGRAMMER_H_
|
|
@ -23,6 +23,9 @@
|
|||
#define SWG_SETPOINT_TOPIC SWG_TOPIC "/setpoint"
|
||||
#define SWG_EXTENDED_TOPIC SWG_TOPIC "/fullstatus"
|
||||
#define SWG_BOOST_TOPIC SWG_TOPIC "/Boost"
|
||||
#define SWG_BOOST_DURATION_TOPIC SWG_BOOST_TOPIC "/duration"
|
||||
|
||||
#define SWG_STATUS_MSG_TOPIC SWG_TOPIC "/Display_Message"
|
||||
|
||||
#define CHEM_TOPIC "CHEM"
|
||||
#define CHEM_PH_TOPIC CHEM_TOPIC "/pH"
|
||||
|
@ -30,18 +33,36 @@
|
|||
#define CHEM_ORP_TOPIC CHEM_TOPIC "/ORP"
|
||||
#define CHRM_ORP_F_TOPIC CHEM_TOPIC "/ORP_f"
|
||||
|
||||
#define LXI_TOPIC "LXi"
|
||||
#define LXI_STATUS LXI_TOPIC "/Status"
|
||||
#define LXI_ERROR_CODE LXI_TOPIC "/Error"
|
||||
#define LXI_ERROR_MESSAGE LXI_TOPIC "/Error_Message"
|
||||
|
||||
#define FREEZE_PROTECT "Freeze_Protect"
|
||||
#define FREEZE_PROTECT_ENABELED FREEZE_PROTECT ENABELED_SUBT
|
||||
|
||||
#define CHILLER "Chiller"
|
||||
#define CHILLER_ENABELED CHILLER ENABELED_SUBT
|
||||
|
||||
#define BATTERY_STATE "Battery"
|
||||
|
||||
#define POOL_THERMO_TEMP_TOPIC BTN_POOL_HTR "/Temperature"
|
||||
#define SPA_THERMO_TEMP_TOPIC BTN_SPA_HTR "/Temperature"
|
||||
//#define POOL_THERMO_TEMP_TOPIC BTN_POOL_HTR "/Temperature"
|
||||
//#define SPA_THERMO_TEMP_TOPIC BTN_SPA_HTR "/Temperature"
|
||||
|
||||
//#define PUMP_TOPIC "Pump_"
|
||||
#define PUMP_RPM_TOPIC "/RPM"
|
||||
#define PUMP_GPM_TOPIC "/GPM"
|
||||
#define PUMP_WATTS_TOPIC "/Watts"
|
||||
#define PUMP_MODE_TOPIC "/Mode"
|
||||
#define PUMP_STATUS_TOPIC "/Status"
|
||||
#define PUMP_PPC_TOPIC "/PPC"
|
||||
#define PUMP_SPEED_TOPIC "/Speed"
|
||||
|
||||
#define LIGHT_PROGRAM_TOPIC "/program"
|
||||
#define LIGHT_DIMMER_VALUE_TOPIC "/brightness"
|
||||
|
||||
#define SENSOR_TOPIC "Sensor"
|
||||
|
||||
/*
|
||||
#define AIR_TEMPERATURE "Air"
|
||||
#define POOL_TEMPERATURE "Pool_Water"
|
||||
|
@ -58,6 +79,7 @@
|
|||
#define MQTT_FLASH "2"
|
||||
#define MQTT_ON "1"
|
||||
#define MQTT_OFF "0"
|
||||
#define MQTT_COOL MQTT_FLASH
|
||||
|
||||
#define MQTT_LWM_TOPIC "Alive"
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,142 @@
|
|||
|
||||
#ifndef AQ_PANEL_H_
|
||||
#define AQ_PANEL_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "aqualink.h"
|
||||
|
||||
#define PUMP_INDEX 0
|
||||
#define SPA_INDEX 1
|
||||
/*
|
||||
#define POOL_HEAT_INDEX 9
|
||||
#define SPA_HEAT_INDEX 10
|
||||
*/
|
||||
|
||||
//#define VBUTTON_ONETOUCH_RSSD 0xFF
|
||||
//#define VBUTTON_RSSD 0xFE
|
||||
|
||||
// Defined as int16_t so 16 bits to mask
|
||||
#define RSP_4 (1 << 0) // 1
|
||||
#define RSP_6 (1 << 1) // 16
|
||||
#define RSP_8 (1 << 2) // 4
|
||||
#define RSP_10 (1 << 3) // 2
|
||||
#define RSP_12 (1 << 4) // 32
|
||||
#define RSP_14 (1 << 5) // 8
|
||||
#define RSP_16 (1 << 6) // 64
|
||||
#define RSP_COMBO (1 << 7) // 128
|
||||
#define RSP_SINGLE (1 << 8) // 128
|
||||
#define RSP_DUAL_EQPT (1 << 9) // 128
|
||||
#define RSP_RS (1 << 10) // 128
|
||||
#define RSP_PDA (1 << 11) // 128
|
||||
#define RSP_ONET (1 << 12) // 128
|
||||
#define RSP_IAQT (1 << 13) // 128
|
||||
#define RSP_RSSA (1 << 14) // 128
|
||||
#define RSP_EXT_PROG (1 << 15) // 128
|
||||
// ....Remeber no more for int16_t.......
|
||||
|
||||
// Bitmask for pannel support against board rev
|
||||
// used in getPanelSupport()
|
||||
#define RSP_SUP_ONET (1 << 0) // OneTouch
|
||||
#define RSP_SUP_AQLT (1 << 1) // Aqualink Touch
|
||||
#define RSP_SUP_ONET_EARLY (1 << 14) // OneTouch REV O uses different tpage for VSP
|
||||
#define RSP_SUP_IAQL (1 << 2) // iAqualink Wifi (1.0/2.0)
|
||||
#define RSP_SUP_IAQL3 (1 << 15) // iAqualink WiFi (3.0)
|
||||
#define RSP_SUP_RSSA (1 << 3) // RS Serial Adapter
|
||||
#define RSP_SUP_VSP (1 << 4) // Variable Speed Pumps
|
||||
#define RSP_SUP_CHEM (1 << 5) // chem feeder
|
||||
#define RSP_SUP_TSCHEM (1 << 6) // true sense chem reader
|
||||
#define RSP_SUP_SWG (1 << 7) // Salt water generator
|
||||
#define RSP_SUP_CLIT (1 << 8) // color lights
|
||||
#define RSP_SUP_DLIT (1 << 9) // dimmer lights
|
||||
#define RSP_SUP_VBTN (1 << 10) // Virtual button
|
||||
#define RSP_SUP_PLAB (1 << 11) // Pump VSP by Label and not number
|
||||
#define RSP_SUP_HPCHIL (1 << 12) // Heat Pump chiller
|
||||
#define RSP_SUP_PCDOC (1 << 13) // PC Dock
|
||||
|
||||
|
||||
#define PANEL_CPU (1 << 0)
|
||||
#define PANEL_REV (1 << 1)
|
||||
#define PANEL_STRING (1 << 2)
|
||||
uint8_t setPanelInformationFromPanelMsg(struct aqualinkdata *aqdata, const char *input, uint8_t type, emulation_type source);
|
||||
//bool setPanelStringFromPanelMsg(struct aqualinkdata *aqdata, const char *src, int src_len, logmask_t from);
|
||||
//bool setBoardCPURevisionFromPanelMsg (struct aqualinkdata *aqdata, const char *src, int src_len, logmask_t from);
|
||||
//void initButtons(struct aqualinkdata *aqdata);
|
||||
void setPanelByName(struct aqualinkdata *aqdata, const char *str);
|
||||
void setPanel(struct aqualinkdata *aqdata, bool rs, int size, bool combo, bool dual);
|
||||
const char* getPanelString();
|
||||
const char* getShortPanelString();
|
||||
|
||||
bool panel_device_request(struct aqualinkdata *aqdata, action_type type, int deviceIndex, int value, request_source source);
|
||||
|
||||
void updateButtonLightProgram(struct aqualinkdata *aqdata, int value, int button);
|
||||
|
||||
int getWaterTemp(struct aqualinkdata *aqdata);
|
||||
|
||||
void changePanelToMode_Only();
|
||||
void addPanelOneTouchInterface();
|
||||
void addPanelIAQTouchInterface();
|
||||
void addPanelRSserialAdapterInterface();
|
||||
void changePanelToExtendedIDProgramming();
|
||||
|
||||
int getPumpSpeedAsPercent(pump_detail *pump);
|
||||
int convertPumpPercentToSpeed(pump_detail *pump, int value); // This is probable only needed internally
|
||||
|
||||
uint16_t getPanelSupport( char *rev_string, int rev_len);
|
||||
|
||||
aqkey *addVirtualButton(struct aqualinkdata *aqdata, char *label, int vindex);
|
||||
bool setVirtualButtonLabel(aqkey *button, const char *label);
|
||||
bool setVirtualButtonAltLabel(aqkey *button, const char *label);
|
||||
|
||||
clight_detail *getProgramableLight(struct aqualinkdata *aqdata, int button);
|
||||
pump_detail *getPumpDetail(struct aqualinkdata *aqdata, int button);
|
||||
|
||||
//void panneltest();
|
||||
|
||||
#define isPDA_PANEL ((_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA)
|
||||
#define isRS_PANEL ((_aqconfig_.paneltype_mask & RSP_RS) == RSP_RS)
|
||||
#define isCOMBO_PANEL ((_aqconfig_.paneltype_mask & RSP_COMBO) == RSP_COMBO)
|
||||
#define isSINGLE_DEV_PANEL ((_aqconfig_.paneltype_mask & RSP_SINGLE) == RSP_SINGLE)
|
||||
#define isDUAL_EQPT_PANEL ((_aqconfig_.paneltype_mask & RSP_DUAL_EQPT) == RSP_DUAL_EQPT)
|
||||
#define isONET_ENABLED ((_aqconfig_.paneltype_mask & RSP_ONET) == RSP_ONET)
|
||||
#define isIAQT_ENABLED ((_aqconfig_.paneltype_mask & RSP_IAQT) == RSP_IAQT)
|
||||
#define isRSSA_ENABLED ((_aqconfig_.paneltype_mask & RSP_RSSA) == RSP_RSSA)
|
||||
#define isEXTP_ENABLED ((_aqconfig_.paneltype_mask & RSP_EXT_PROG) == RSP_EXT_PROG)
|
||||
|
||||
#define isIAQL_ACTIVE ((_aqconfig_.extended_device_id2 != NUL))
|
||||
|
||||
#define isVS_PUMP(mask) ((mask & VS_PUMP) == VS_PUMP)
|
||||
#define isPLIGHT(mask) ((mask & PROGRAM_LIGHT) == PROGRAM_LIGHT)
|
||||
#define isVBUTTON(mask) ((mask & VIRTUAL_BUTTON) == VIRTUAL_BUTTON)
|
||||
#define isVBUTTON_ALTLABEL(mask) ((mask & VIRTUAL_BUTTON_ALT_LABEL) == VIRTUAL_BUTTON_ALT_LABEL)
|
||||
#define isVBUTTON_CHILLER(mask) ((mask & VIRTUAL_BUTTON_CHILLER) == VIRTUAL_BUTTON_CHILLER)
|
||||
|
||||
int PANEL_SIZE();
|
||||
//
|
||||
//#define PANEL_SIZE PANEL_SIZE()
|
||||
/*
|
||||
#define PANEL_SIZE ((_aqconfig_.paneltype_mask & RSP_4) == RSP_4)?4:(\
|
||||
((_aqconfig_.paneltype_mask & RSP_6) == RSP_6)?6:(\
|
||||
((_aqconfig_.paneltype_mask & RSP_8) == RSP_8)?8:(\
|
||||
((_aqconfig_.paneltype_mask & RSP_10) == RSP_10)?10:(\
|
||||
((_aqconfig_.paneltype_mask & RSP_12) == RSP_12)?12:(\
|
||||
((_aqconfig_.paneltype_mask & RSP_14) == RSP_14)?14:(\
|
||||
((_aqconfig_.paneltype_mask & RSP_16) == RSP_16)?16:0))))))
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// If we need to increase virtual buttons, then increase below.
|
||||
|
||||
// NEED TO FIX, IF WE CHANGE TO ANOTHING OTHER THAN 0 CORE DUMP (we also had "panel_type = RS-16 Combo" in config)
|
||||
// FIX IS PROBABLY MAKE SURE LEDS IS SAME OR MORE.
|
||||
#define VIRTUAL_BUTTONS 0
|
||||
|
||||
|
||||
//#define TOTAL_BUTTONS 12+VIRTUAL_BUTTONS
|
||||
|
||||
#define TOTAL_BUTTONS 20+VIRTUAL_BUTTONS // Biggest jandy panel
|
||||
// This needs to be called AFTER and as well as initButtons
|
||||
void initButtons_RS16(struct aqualinkdata *aqdata);
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -16,11 +16,15 @@
|
|||
#define HEATER_MIN_F 36
|
||||
#define FREEZE_PT_MAX_F 42
|
||||
#define FREEZE_PT_MIN_F 34
|
||||
#define CHILLER_MAX_F 104
|
||||
#define CHILLER_MIN_F 34
|
||||
|
||||
#define HEATER_MAX_C 40
|
||||
#define HEATER_MIN_C 0
|
||||
#define FREEZE_PT_MAX_C 5
|
||||
#define FREEZE_PT_MIN_C 1
|
||||
#define CHILLER_MAX_C 40
|
||||
#define CHILLER_MIN_C 0
|
||||
|
||||
#define SWG_PERCENT_MAX 101
|
||||
#define SWG_PERCENT_MIN 0
|
||||
|
@ -29,16 +33,20 @@
|
|||
#define LIGHT_MODE_BUFER PTHREAD_ARG
|
||||
|
||||
typedef enum emulation_type{
|
||||
SIM_NONE = -1,
|
||||
ALLBUTTON,
|
||||
RSSADAPTER,
|
||||
ONETOUCH,
|
||||
IAQTOUCH,
|
||||
AQUAPDA, // AQUAPALM and PDA are taken as specific type.
|
||||
JANDY_DEVICE // Very rarley used.
|
||||
IAQUALNK, // iAqualink (wifi extra ID)
|
||||
JANDY_DEVICE, // Very rarley used.
|
||||
SIMULATOR
|
||||
} emulation_type;
|
||||
|
||||
typedef enum {
|
||||
AQP_NULL = -1,
|
||||
// ********* Generic Programming options, these are Allbutton by Default
|
||||
AQ_GET_POOL_SPA_HEATER_TEMPS,
|
||||
AQ_GET_FREEZE_PROTECT_TEMP,
|
||||
AQ_SET_TIME,
|
||||
|
@ -46,19 +54,31 @@ typedef enum {
|
|||
AQ_SET_SPA_HEATER_TEMP,
|
||||
AQ_SET_FRZ_PROTECTION_TEMP,
|
||||
AQ_GET_DIAGNOSTICS_MODEL,
|
||||
//AQ_SEND_CMD,
|
||||
AQ_GET_PROGRAMS,
|
||||
AQ_SET_LIGHTPROGRAM_MODE,
|
||||
AQ_SET_LIGHTCOLOR_MODE,
|
||||
AQ_PDA_INIT,
|
||||
AQ_SET_SWG_PERCENT,
|
||||
AQ_PDA_DEVICE_STATUS,
|
||||
AQ_PDA_DEVICE_ON_OFF,
|
||||
AQ_GET_AUX_LABELS,
|
||||
AQ_PDA_WAKE_INIT,
|
||||
AQ_SET_BOOST,
|
||||
AQ_SET_PUMP_RPM,
|
||||
AQ_SET_PUMP_VS_PROGRAM,
|
||||
AQ_SET_CHILLER_TEMP,
|
||||
// ******** PDA Delimiter make sure to change MAX/MIN below
|
||||
AQ_PDA_INIT,
|
||||
AQ_PDA_WAKE_INIT,
|
||||
AQ_PDA_DEVICE_STATUS,
|
||||
AQ_PDA_DEVICE_ON_OFF,
|
||||
AQ_PDA_AUX_LABELS,
|
||||
AQ_PDA_SET_BOOST,
|
||||
AQ_PDA_SET_SWG_PERCENT,
|
||||
AQ_PDA_GET_AUX_LABELS,
|
||||
AQ_PDA_SET_POOL_HEATER_TEMPS,
|
||||
AQ_PDA_SET_SPA_HEATER_TEMPS,
|
||||
AQ_PDA_SET_FREEZE_PROTECT_TEMP,
|
||||
AQ_PDA_SET_TIME,
|
||||
AQ_PDA_GET_POOL_SPA_HEATER_TEMPS,
|
||||
AQ_PDA_GET_FREEZE_PROTECT_TEMP,
|
||||
// ******** OneTouch Delimiter make sure to change MAX/MIN below
|
||||
AQ_SET_ONETOUCH_PUMP_RPM,
|
||||
AQ_SET_ONETOUCH_MACRO,
|
||||
AQ_GET_ONETOUCH_SETPOINTS,
|
||||
|
@ -69,6 +89,7 @@ typedef enum {
|
|||
AQ_SET_ONETOUCH_TIME,
|
||||
AQ_SET_ONETOUCH_BOOST,
|
||||
AQ_SET_ONETOUCH_SWG_PERCENT,
|
||||
// ******** iAqalink Touch Delimiter make sure to change MAX/MIN below
|
||||
AQ_SET_IAQTOUCH_PUMP_RPM,
|
||||
AQ_SET_IAQTOUCH_PUMP_VS_PROGRAM,
|
||||
AQ_GET_IAQTOUCH_VSP_ASSIGNMENT,
|
||||
|
@ -78,17 +99,50 @@ typedef enum {
|
|||
AQ_GET_IAQTOUCH_AUX_LABELS,
|
||||
AQ_SET_IAQTOUCH_SWG_PERCENT,
|
||||
AQ_SET_IAQTOUCH_SWG_BOOST,
|
||||
AQ_SET_IAQTOUCH_SET_TIME,
|
||||
AQ_SET_IAQTOUCH_DEVICE_ON_OFF,
|
||||
AQ_SET_IAQTOUCH_ONETOUCH_ON_OFF,
|
||||
AQ_SET_IAQTOUCH_POOL_HEATER_TEMP,
|
||||
AQ_SET_IAQTOUCH_SPA_HEATER_TEMP,
|
||||
AQ_SET_IAQTOUCH_SET_TIME,
|
||||
AQ_SET_IAQTOUCH_CHILLER_TEMP,
|
||||
AQ_SET_IAQLINK_POOL_HEATER_TEMP, // Same as above but using iAqualink not AqualinkTouch
|
||||
AQ_SET_IAQLINK_SPA_HEATER_TEMP, // Same as above but using iAqualink not AqualinkTouch
|
||||
AQ_SET_IAQLINK_CHILLER_TEMP,
|
||||
AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE,
|
||||
// ******** RS Serial Adapter Delimiter make sure to change MAX/MIN below
|
||||
AQ_GET_RSSADAPTER_SETPOINTS,
|
||||
AQ_SET_RSSADAPTER_POOL_HEATER_TEMP,
|
||||
AQ_SET_RSSADAPTER_SPA_HEATER_TEMP,
|
||||
AQ_ADD_RSSADAPTER_POOL_HEATER_TEMP,
|
||||
AQ_ADD_RSSADAPTER_SPA_HEATER_TEMP
|
||||
AQ_ADD_RSSADAPTER_SPA_HEATER_TEMP,
|
||||
// ******** Delimiter make sure to change MAX/MIN below
|
||||
} program_type;
|
||||
|
||||
|
||||
|
||||
//#define AQ_SET_CHILLER_TEMP AQ_SET_IAQTOUCH_CHILLER_TEMP
|
||||
|
||||
|
||||
|
||||
#define AQP_GENERIC_MIN AQ_GET_POOL_SPA_HEATER_TEMPS
|
||||
#define AQP_GENERIC_MAX AQ_SET_PUMP_VS_PROGRAM
|
||||
|
||||
#define AQP_ALLBUTTON_MIN AQ_GET_POOL_SPA_HEATER_TEMPS
|
||||
#define AQP_ALLBUTTONL_MAX AQ_SET_BOOST
|
||||
|
||||
#define AQP_PDA_MIN AQ_PDA_INIT
|
||||
#define AQP_PDA_MAX AQ_SET_ONETOUCH_SWG_PERCENT
|
||||
|
||||
#define AQP_ONETOUCH_MIN AQ_SET_ONETOUCH_PUMP_RPM
|
||||
#define AQP_ONETOUCH_MAX AQ_SET_ONETOUCH_SWG_PERCENT
|
||||
|
||||
#define AQP_IAQTOUCH_MIN AQ_SET_IAQTOUCH_PUMP_RPM
|
||||
#define AQP_IAQTOUCH_MAX AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE
|
||||
|
||||
#define AQP_RSSADAPTER_MIN AQ_GET_RSSADAPTER_SETPOINTS
|
||||
#define AQP_RSSADAPTER_MAX AQ_ADD_RSSADAPTER_SPA_HEATER_TEMP
|
||||
|
||||
|
||||
struct programmingThreadCtrl {
|
||||
pthread_t thread_id;
|
||||
//void *thread_args;
|
||||
|
@ -96,11 +150,12 @@ struct programmingThreadCtrl {
|
|||
struct aqualinkdata *aq_data;
|
||||
};
|
||||
|
||||
|
||||
typedef enum pump_type {
|
||||
PT_UNKNOWN = -1,
|
||||
EPUMP,
|
||||
VSPUMP,
|
||||
VFPUMP
|
||||
EPUMP, // = ePump AC & Jandy ePUMP
|
||||
VSPUMP, // = Intelliflo VS
|
||||
VFPUMP // = Intelliflo VF (GPM)
|
||||
} pump_type;
|
||||
|
||||
|
||||
|
@ -114,15 +169,15 @@ bool in_iaqt_programming_mode(struct aqualinkdata *aq_data);
|
|||
bool in_swg_programming_mode(struct aqualinkdata *aq_data);
|
||||
bool in_light_programming_mode(struct aqualinkdata *aq_data);
|
||||
bool in_allb_programming_mode(struct aqualinkdata *aq_data);
|
||||
void aq_send_cmd(unsigned char cmd);
|
||||
//void aq_send_cmd(unsigned char cmd);
|
||||
void queueGetProgramData(emulation_type source_type, struct aqualinkdata *aq_data);
|
||||
//void queueGetExtendedProgramData(emulation_type source_type, struct aqualinkdata *aq_data, bool labels);
|
||||
unsigned char pop_aq_cmd(struct aqualinkdata *aq_data);
|
||||
//unsigned char pop_aq_cmd(struct aqualinkdata *aq_data);
|
||||
|
||||
void waitForSingleThreadOrTerminate(struct programmingThreadCtrl *threadCtrl, program_type type);
|
||||
void cleanAndTerminateThread(struct programmingThreadCtrl *threadCtrl);
|
||||
|
||||
//void force_queue_delete() // Yes I want compiler warning if this is used.
|
||||
void force_queue_delete(); // NSF This needs to be deleted (come back and fix)
|
||||
|
||||
|
||||
//bool push_aq_cmd(unsigned char cmd);
|
||||
|
@ -133,7 +188,7 @@ void cleanAndTerminateThread(struct programmingThreadCtrl *threadCtrl);
|
|||
//void *set_aqualink_time( void *ptr );
|
||||
//void *get_aqualink_pool_spa_heater_temps( void *ptr );
|
||||
|
||||
int get_aq_cmd_length();
|
||||
//int get_aq_cmd_length();
|
||||
int setpoint_check(int type, int value, struct aqualinkdata *aqdata);
|
||||
int RPM_check(pump_type type, int value, struct aqualinkdata *aqdata);
|
||||
//int RPM_check(int type, int value, struct aqualinkdata *aqdata);
|
|
@ -0,0 +1,406 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Shaun Feakes - All rights reserved
|
||||
*
|
||||
* You may use redistribute and/or modify this code under the terms of
|
||||
* the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. For the terms of this license,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* https://github.com/sfeakes/aqualinkd
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <regex.h>
|
||||
|
||||
|
||||
#include "mongoose.h"
|
||||
#include "aqualink.h"
|
||||
#include "aq_scheduler.h"
|
||||
#include "config.h"
|
||||
#include "aq_panel.h"
|
||||
//#include "utils.h"
|
||||
#include "aq_systemutils.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Example /etc/cron.d/aqualinkd
|
||||
|
||||
01 10 1 * * curl localhost:80/api/Filter_Pump/set -d value=2 -X PUT
|
||||
*/
|
||||
|
||||
|
||||
|
||||
bool passJson_scObj(const char* line, int length, aqs_cron *values)
|
||||
{
|
||||
int keystart=0;
|
||||
//int keyend=0;
|
||||
int valuestart=0;
|
||||
int captured=0;
|
||||
bool readingvalue=false;
|
||||
bool invalue=false;
|
||||
//char value;
|
||||
values->enabled = true;
|
||||
|
||||
//LOG(SCHD_LOG,LOG_DEBUG, "Obj body:'%.*s'\n", length, line);
|
||||
|
||||
for (int i=0; i < length; i++) {
|
||||
if (line[i] == '}') {
|
||||
return (captured >= 7)?true:false;
|
||||
} else if (line[i] == '"' && keystart==0 && invalue==false && readingvalue==false) {
|
||||
keystart=i+1;
|
||||
} else if (line[i] == '"' && keystart > 0 && invalue==false && readingvalue==false) {
|
||||
//keyend=i;
|
||||
} else if (line[i] == ':' && keystart > 0 ) {
|
||||
invalue=true;
|
||||
} else if (line[i] == '"' && invalue == true && readingvalue == false && keystart > 0 ) {
|
||||
readingvalue=true;
|
||||
valuestart=i+1;
|
||||
} else if (line[i] == '"' && readingvalue == true) {
|
||||
// i is end of key
|
||||
if ( strncmp(&line[keystart], "enabled", 7) == 0) {
|
||||
values->enabled = (line[valuestart]=='0'?false:true);
|
||||
captured++;
|
||||
} else if ( strncmp(&line[keystart], "min", 3) == 0) {
|
||||
strncpy(values->minute, &line[valuestart], (i-valuestart) );
|
||||
values->minute[i-valuestart] = '\0';
|
||||
captured++;
|
||||
} else if( strncmp(&line[keystart], "hour", 4) == 0) {
|
||||
strncpy(values->hour, &line[valuestart], (i-valuestart) );
|
||||
values->hour[i-valuestart] = '\0';
|
||||
captured++;
|
||||
} else if( strncmp(&line[keystart], "daym", 4) == 0) {
|
||||
strncpy(values->daym, &line[valuestart], (i-valuestart) );
|
||||
values->daym[i-valuestart] = '\0';
|
||||
captured++;
|
||||
} else if( strncmp(&line[keystart], "month", 5) == 0) {
|
||||
strncpy(values->month, &line[valuestart], (i-valuestart) );
|
||||
values->month[i-valuestart] = '\0';
|
||||
captured++;
|
||||
} else if( strncmp(&line[keystart], "dayw", 4) == 0) {
|
||||
strncpy(values->dayw, &line[valuestart], (i-valuestart) );
|
||||
values->dayw[i-valuestart] = '\0';
|
||||
captured++;
|
||||
} else if( strncmp(&line[keystart], "url", 3) == 0) {
|
||||
strncpy(values->url, &line[valuestart], (i-valuestart) );
|
||||
values->url[i-valuestart] = '\0';
|
||||
captured++;
|
||||
} else if( strncmp(&line[keystart], "value", 5) == 0) {
|
||||
strncpy(values->value, &line[valuestart], (i-valuestart) );
|
||||
values->value[i-valuestart] = '\0';
|
||||
captured++;
|
||||
}
|
||||
keystart=0;
|
||||
//keyend=0;
|
||||
valuestart=0;
|
||||
invalue=false;
|
||||
readingvalue=false;
|
||||
}
|
||||
}
|
||||
|
||||
return (captured >= 7)?true:false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int save_schedules_js(const char* inBuf, int inSize, char* outBuf, int outSize)
|
||||
{
|
||||
FILE *fp;
|
||||
int i;
|
||||
bool inarray = false;
|
||||
aqs_cron cline;
|
||||
bool fileexists = false;
|
||||
bool fs = false;
|
||||
|
||||
if ( !_aqconfig_.enable_scheduler) {
|
||||
LOG(SCHD_LOG,LOG_WARNING, "Schedules are disabled\n");
|
||||
return sprintf(outBuf, "{\"message\":\"Error Schedules disabled\"}");
|
||||
}
|
||||
|
||||
LOG(SCHD_LOG,LOG_NOTICE, "Saving Schedule:\n");
|
||||
|
||||
/*
|
||||
bool fs = remount_root_ro(false);
|
||||
if (access(CRON_FILE, F_OK) == 0)
|
||||
fileexists = true;
|
||||
fp = fopen(CRON_FILE, "w");
|
||||
*/
|
||||
|
||||
fp = aq_open_file( CRON_FILE, &fs, &fileexists);
|
||||
|
||||
if (fp == NULL) {
|
||||
LOG(SCHD_LOG,LOG_ERR, "Open file failed '%s'\n", CRON_FILE);
|
||||
//remount_root_ro(true);
|
||||
aq_close_file(fp, fs);
|
||||
return sprintf(outBuf, "{\"message\":\"Error Saving Schedules\"}");
|
||||
}
|
||||
|
||||
fprintf(fp, "#***** AUTO GENERATED DO NOT EDIT *****\n");
|
||||
fprintf(fp, "PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n");
|
||||
|
||||
LOG(SCHD_LOG,LOG_DEBUG, "Schedules Message body:\n'%.*s'\n", inSize, inBuf);
|
||||
|
||||
for (i=0; i < inSize; i++) {
|
||||
if ( inBuf[i] == '[' ) {
|
||||
inarray=true;
|
||||
} else if ( inBuf[i] == ']' ) {
|
||||
inarray=false;
|
||||
} else if ( inarray && inBuf[i] == '{') {
|
||||
passJson_scObj( &inBuf[i], (inSize-i), &cline);
|
||||
LOG(SCHD_LOG,LOG_DEBUG, "Write to cron Min:%s Hour:%s DayM:%s Month:%s DayW:%s URL:%s Value:%s\n",cline.minute,cline.hour,cline.daym,cline.month,cline.dayw,cline.url,cline.value);
|
||||
LOG(SCHD_LOG,LOG_INFO, "%s%s %s %s %s %s curl -s -S --show-error -o /dev/null localhost:%s%s -d value=%s -X PUT\n",(cline.enabled?"":"#"),cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, _aqconfig_.socket_port, cline.url, cline.value);
|
||||
fprintf(fp, "%s%s %s %s %s %s root curl -s -S --show-error -o /dev/null localhost:%s%s -d value=%s -X PUT\n",(cline.enabled?"":"#"),cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, _aqconfig_.socket_port, cline.url, cline.value);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fp, "#***** AUTO GENERATED DO NOT EDIT *****\n");
|
||||
|
||||
//fclose(fp);
|
||||
|
||||
// if we created file, change the permissions
|
||||
if (!fileexists)
|
||||
if ( chmod(CRON_FILE, S_IRUSR | S_IWUSR ) < 0 )
|
||||
LOG(SCHD_LOG,LOG_ERR, "Could not change permissions on cron file %s, scheduling may not work\n",CRON_FILE);
|
||||
|
||||
//remount_root_ro(fs);
|
||||
aq_close_file(fp, fs);
|
||||
|
||||
return sprintf(outBuf, "{\"message\":\"Saved Schedules\"}");
|
||||
}
|
||||
|
||||
int build_schedules_js(char* buffer, int size)
|
||||
{
|
||||
memset(&buffer[0], 0, size);
|
||||
FILE *fp;
|
||||
char *line = NULL;
|
||||
int length = 0;
|
||||
int rc;
|
||||
aqs_cron cline;
|
||||
size_t len = 0;
|
||||
ssize_t read_size;
|
||||
regex_t regexCompiled;
|
||||
|
||||
if ( !_aqconfig_.enable_scheduler) {
|
||||
LOG(SCHD_LOG,LOG_WARNING, "Schedules are disabled\n");
|
||||
if (size > 0)
|
||||
length += sprintf(buffer, "{\"message\":\"Error Schedules disabled\"}");
|
||||
return length;
|
||||
}
|
||||
|
||||
// Below works for curl but not /usr/bin/curl in command. NSF come back and fix the regexp
|
||||
//char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(/api/.*)\\s-d value=([^\\d]+)\\s(.*)";
|
||||
// \d doesn't seem to be supported, so using [0-9]+ instead
|
||||
//char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(\\/api\\/.*\\/set).* value=([0-9]+).*";
|
||||
|
||||
//char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(\\/api\\/.*\\/set).* value=([0-9]+).*";
|
||||
const char *regexString="(#{0,1})([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(\\/api\\/.*\\/set).* value=([0-9]+).*";
|
||||
|
||||
//char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(/api/.*/set).*value=([0-9]+).*";
|
||||
|
||||
|
||||
size_t maxGroups = 15;
|
||||
regmatch_t groupArray[maxGroups];
|
||||
//static char buf[100];
|
||||
|
||||
if (size > 0)
|
||||
length += sprintf(buffer+length,"{\"type\": \"schedules\",");
|
||||
|
||||
if (0 != (rc = regcomp(®exCompiled, regexString, REG_EXTENDED))) {
|
||||
LOG(SCHD_LOG,LOG_ERR, "regcomp() failed, returning nonzero (%d)\n", rc);
|
||||
if (size > 0)
|
||||
length += sprintf(buffer+length,"\"message\": \"Error reading schedules\"}");
|
||||
return length;
|
||||
}
|
||||
|
||||
fp = fopen(CRON_FILE, "r");
|
||||
if (fp == NULL) {
|
||||
LOG(SCHD_LOG,LOG_WARNING, "Open file failed '%s'\n", CRON_FILE);
|
||||
if (size > 0)
|
||||
length += sprintf(buffer+length,"\"message\": \"Error reading schedules\"}");
|
||||
return length;
|
||||
}
|
||||
|
||||
if (size > 0)
|
||||
length += sprintf(buffer+length,"\"schedules\": [ ");
|
||||
|
||||
while ((read_size = getline(&line, &len, fp)) != -1) {
|
||||
//printf("Read from cron:-\n %s", line);
|
||||
//lc++;
|
||||
//rc = regexec(®exCompiled, line, maxGroups, groupArray, 0);
|
||||
if (0 == (rc = regexec(®exCompiled, line, maxGroups, groupArray, REG_EXTENDED))) {
|
||||
// Group 1 is # (enable or not)
|
||||
// Group 2 is minute
|
||||
// Group 3 is hour
|
||||
// Group 4 is day of month
|
||||
// Group 5 is month
|
||||
// Group 6 is day of week
|
||||
// Group 7 is root
|
||||
// Group 8 is curl
|
||||
// Group 9 is URL
|
||||
// Group 10 is value
|
||||
if (groupArray[8].rm_so == (size_t)-1) {
|
||||
if (size > 0) {
|
||||
LOG(SCHD_LOG,LOG_ERR, "No matching information from cron file\n");
|
||||
}
|
||||
} else {
|
||||
cline.enabled = (line[groupArray[1].rm_so] == '#')?false:true;
|
||||
sprintf(cline.minute, "%.*s", (groupArray[2].rm_eo - groupArray[2].rm_so), (line + groupArray[2].rm_so));
|
||||
sprintf(cline.hour, "%.*s", (groupArray[3].rm_eo - groupArray[3].rm_so), (line + groupArray[3].rm_so));
|
||||
sprintf(cline.daym, "%.*s", (groupArray[4].rm_eo - groupArray[4].rm_so), (line + groupArray[4].rm_so));
|
||||
sprintf(cline.month, "%.*s", (groupArray[5].rm_eo - groupArray[5].rm_so), (line + groupArray[5].rm_so));
|
||||
sprintf(cline.dayw, "%.*s", (groupArray[6].rm_eo - groupArray[6].rm_so), (line + groupArray[6].rm_so));
|
||||
sprintf(cline.url, "%.*s", (groupArray[9].rm_eo - groupArray[9].rm_so), (line + groupArray[9].rm_so));
|
||||
sprintf(cline.value, "%.*s", (groupArray[10].rm_eo - groupArray[10].rm_so), (line + groupArray[10].rm_so));
|
||||
if (size > 0) {
|
||||
LOG(SCHD_LOG,LOG_INFO, "Read from cron. Enabled:%d Min:%s Hour:%s DayM:%s Month:%s DayW:%s URL:%s Value:%s\n",cline.enabled,cline.minute,cline.hour,cline.daym,cline.month,cline.dayw,cline.url,cline.value);
|
||||
length += sprintf(buffer+length, "{\"enabled\":\"%d\", \"min\":\"%s\",\"hour\":\"%s\",\"daym\":\"%s\",\"month\":\"%s\",\"dayw\":\"%s\",\"url\":\"%s\",\"value\":\"%s\"},",
|
||||
cline.enabled,
|
||||
cline.minute,
|
||||
cline.hour,
|
||||
cline.daym,
|
||||
cline.month,
|
||||
cline.dayw,
|
||||
cline.url,
|
||||
cline.value);
|
||||
}
|
||||
//LOG(SCHD_LOG,LOG_DEBUG, "Read from cron Day %d | Time %d:%d | Zone %d | Runtime %d\n",day,hour,minute,zone,runtime);
|
||||
|
||||
// Test / get for pump start and end time
|
||||
if (isAQS_USE_CRON_PUMP_TIME_ENABLED) {
|
||||
// Could also check that dayw is *
|
||||
if ( cline.enabled && strstr(cline.url, AQS_PUMP_URL ))
|
||||
{
|
||||
int value = strtoul(cline.value, NULL, 10);
|
||||
int hour = strtoul(cline.hour, NULL, 10);
|
||||
if (value == 0) {
|
||||
if (hour > _aqconfig_.sched_chk_pumpoff_hour) // NSF this picks up the greatest offhour, (do we want the smallest???)
|
||||
_aqconfig_.sched_chk_pumpoff_hour = hour;
|
||||
} else if (value == 1){
|
||||
if (hour < _aqconfig_.sched_chk_pumpon_hour || _aqconfig_.sched_chk_pumpon_hour == 0)
|
||||
_aqconfig_.sched_chk_pumpon_hour = hour;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (size > 0) {
|
||||
LOG(SCHD_LOG,LOG_DEBUG, "regexp no match (%d) %s", rc, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
buffer[--length] = '\0';
|
||||
length += sprintf(buffer+length,"]}\n");
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
regfree(®exCompiled);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void get_cron_pump_times()
|
||||
{
|
||||
build_schedules_js(NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool event_happened_set_device_state(reset_event_type type, struct aqualinkdata *aq_data)
|
||||
{
|
||||
if (! isAQS_START_PUMP_EVENT_ENABLED) {
|
||||
LOG(SCHD_LOG,LOG_DEBUG, "Event scheduler is not enabled\n");
|
||||
return false;
|
||||
}
|
||||
// Check time is between hours.
|
||||
bool scheduledOn = false;
|
||||
|
||||
if (isAQS_USE_CRON_PUMP_TIME_ENABLED) {
|
||||
get_cron_pump_times();
|
||||
LOG(SCHD_LOG,LOG_DEBUG, "Pump on times from scheduler are between hours %.2d & %.2d\n",_aqconfig_.sched_chk_pumpon_hour, _aqconfig_.sched_chk_pumpoff_hour);
|
||||
}
|
||||
/*
|
||||
if (_aqconfig_.sched_chk_pumpon_hour == AQ_UNKNOWN || _aqconfig_.sched_chk_pumpoff_hour == AQ_UNKNOWN ) {
|
||||
if ( CRON TURNED OFF ) {
|
||||
LOG(SCHD_LOG,LOG_ERR, "No pump on / off times configures and cron scheduler not enabled, can't action event!");
|
||||
return false;
|
||||
}
|
||||
get_cron_pump_times();
|
||||
LOG(SCHD_LOG,LOG_DEBUG, "Pump on times from scheduler are between hours %.2d & %.2d\n",_aqconfig_.sched_chk_pumpon_hour, _aqconfig_.sched_chk_pumpoff_hour);
|
||||
|
||||
}
|
||||
*/
|
||||
time_t now = time(NULL);
|
||||
struct tm *tm_struct = localtime(&now);
|
||||
|
||||
int hour = tm_struct->tm_hour;
|
||||
if (hour >= _aqconfig_.sched_chk_pumpon_hour && hour < _aqconfig_.sched_chk_pumpoff_hour ) {
|
||||
scheduledOn = true;
|
||||
}
|
||||
|
||||
// Check event type.
|
||||
switch(type){
|
||||
case AQS_POWER_ON:
|
||||
if (scheduledOn && isAQS_POWER_ON_ENABED && aq_data->aqbuttons[0].led->state == OFF) {
|
||||
LOG(SCHD_LOG,LOG_INFO, "Powered on, schedule is set for pump running and pump is off, turning pump on\n");
|
||||
panel_device_request(aq_data, ON_OFF, 0, true, NET_TIMER);
|
||||
} else {
|
||||
//LOG(SCHD_LOG,LOG_DEBUG, "Powered on, schedule is not set and/or pump is already on, leaving\n");
|
||||
LOG(SCHD_LOG,LOG_DEBUG, "Powered on, schedule Pump on is %sset, time is %sbetween scheduled hours, Pump is %s, (not changing)\n",(isAQS_POWER_ON_ENABED?"":"not "),(scheduledOn?"":" not"), (aq_data->aqbuttons[0].led->state ==OFF?"Off":"On"));
|
||||
}
|
||||
break;
|
||||
case AQS_FRZ_PROTECT_OFF:
|
||||
if (scheduledOn && isAQS_FRZ_PROTECT_OFF_ENABED && aq_data->aqbuttons[0].led->state == OFF) {
|
||||
LOG(SCHD_LOG,LOG_INFO, "Freeze Protect off, schedule is set for pump running and pump is off, turning pump on\n");
|
||||
panel_device_request(aq_data, ON_OFF, 0, true, NET_TIMER);
|
||||
} else {
|
||||
//LOG(SCHD_LOG,LOG_DEBUG, "Freeze Protect off, schedule is not set and/or pump is already on, leaving\n");
|
||||
LOG(SCHD_LOG,LOG_DEBUG, "Freeze Protect off, schedule Pump on is %sset, time is %sbetween scheduled hours, Pump is %s, (not changing)\n",(isAQS_FRZ_PROTECT_OFF_ENABED?"":"not "),(scheduledOn?"":" not"), (aq_data->aqbuttons[0].led->state ==OFF?"Off":"On"));
|
||||
}
|
||||
break;
|
||||
case AQS_BOOST_OFF:
|
||||
if (scheduledOn && isAQS_BOOST_OFF_ENABED && aq_data->aqbuttons[0].led->state == OFF) {
|
||||
LOG(SCHD_LOG,LOG_INFO, "Boost off, schedule is set for pump running and pump is off, turning pump on\n");
|
||||
panel_device_request(aq_data, ON_OFF, 0, true, NET_TIMER);
|
||||
} else {
|
||||
//LOG(SCHD_LOG,LOG_DEBUG, "Boost off, schedule is not set and/or pump is already on, leaving\n");
|
||||
LOG(SCHD_LOG,LOG_DEBUG, "Boost off, schedule Pump on is %sset, time is %sbetween scheduled hours, Pump is %s, (not changing)\n",(isAQS_BOOST_OFF_ENABED?"":"not "),(scheduledOn?"":" not"), (aq_data->aqbuttons[0].led->state ==OFF?"Off":"On"));
|
||||
}
|
||||
|
||||
if (aq_data->boost_linked_device != AQ_UNKNOWN && aq_data->boost_linked_device <= aq_data->total_buttons && aq_data->boost_linked_device >= 0) {
|
||||
//aq_data->aqbuttons[aq_data->boost_linked_device].code
|
||||
if (aq_data->aqbuttons[aq_data->boost_linked_device].led->state == OFF) {
|
||||
panel_device_request(aq_data, ON_OFF, aq_data->boost_linked_device, false, NET_TIMER);
|
||||
LOG(SCHD_LOG,LOG_INFO, "Boost off, Turing %s off\n",aq_data->aqbuttons[aq_data->boost_linked_device].label);
|
||||
} else {
|
||||
LOG(SCHD_LOG,LOG_INFO, "Boost off, %s is already off\n",aq_data->aqbuttons[aq_data->boost_linked_device].label);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AQS_BOOST_ON:
|
||||
if (aq_data->boost_linked_device != AQ_UNKNOWN && aq_data->boost_linked_device <= aq_data->total_buttons && aq_data->boost_linked_device >= 0) {
|
||||
//aq_data->aqbuttons[aq_data->boost_linked_device].code
|
||||
if (aq_data->aqbuttons[aq_data->boost_linked_device].led->state == OFF) {
|
||||
panel_device_request(aq_data, ON_OFF, aq_data->boost_linked_device, true, NET_TIMER);
|
||||
LOG(SCHD_LOG,LOG_INFO, "Boost on, Turing %s on\n",aq_data->aqbuttons[aq_data->boost_linked_device].label);
|
||||
} else {
|
||||
LOG(SCHD_LOG,LOG_INFO, "Boost on, %s is already on\n",aq_data->aqbuttons[aq_data->boost_linked_device].label);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
|
||||
|
||||
|
||||
#ifndef AQ_SCHEDULER_H_
|
||||
#define AQ_SCHEDULER_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define CRON_FILE "/etc/cron.d/aqualinkd"
|
||||
#define CURL "curl"
|
||||
|
||||
#define CV_SIZE 20
|
||||
|
||||
typedef struct aqs_cron
|
||||
{
|
||||
int enabled;
|
||||
char minute[CV_SIZE];
|
||||
char hour[CV_SIZE];
|
||||
char daym[CV_SIZE];
|
||||
char month[CV_SIZE];
|
||||
char dayw[CV_SIZE];
|
||||
char url[CV_SIZE * 2];
|
||||
char value[CV_SIZE];
|
||||
} aqs_cron;
|
||||
|
||||
int build_schedules_js(char* buffer, int size);
|
||||
int save_schedules_js(const char* inBuf, int inSize, char* outBuf, int outSize);
|
||||
void get_cron_pump_times();
|
||||
|
||||
|
||||
|
||||
|
||||
#define AQS_PUMP_URL BTN_PUMP "/set"
|
||||
|
||||
// All below AQS_ are the same mask, but don;t want CRON in the emum
|
||||
#define AQS_USE_CRON_PUMP_TIME (1 << 0)
|
||||
typedef enum reset_event_type{
|
||||
AQS_POWER_ON = (1 << 1),
|
||||
AQS_FRZ_PROTECT_OFF = (1 << 2),
|
||||
AQS_BOOST_OFF = (1 << 3),
|
||||
AQS_BOOST_ON = (1 << 4)
|
||||
} reset_event_type;
|
||||
|
||||
#define isAQS_START_PUMP_EVENT_ENABLED ( ((_aqconfig_.schedule_event_mask & AQS_POWER_ON) == AQS_POWER_ON) || \
|
||||
((_aqconfig_.schedule_event_mask & AQS_FRZ_PROTECT_OFF) == AQS_FRZ_PROTECT_OFF) || \
|
||||
((_aqconfig_.schedule_event_mask & AQS_BOOST_OFF) == AQS_BOOST_OFF) || \
|
||||
((_aqconfig_.schedule_event_mask & AQS_BOOST_ON) == AQS_BOOST_ON))
|
||||
|
||||
//#define isAQS_USE_PUMP_TIME_FROM_CRON_ENABLED !((_aqconfig_.schedule_event_mask & AQS_DONT_USE_CRON_PUMP_TIME) == AQS_DONT_USE_CRON_PUMP_TIME)
|
||||
#define isAQS_USE_CRON_PUMP_TIME_ENABLED ((_aqconfig_.schedule_event_mask & AQS_USE_CRON_PUMP_TIME) == AQS_USE_CRON_PUMP_TIME)
|
||||
#define isAQS_POWER_ON_ENABED ((_aqconfig_.schedule_event_mask & AQS_POWER_ON) == AQS_POWER_ON)
|
||||
#define isAQS_FRZ_PROTECT_OFF_ENABED ((_aqconfig_.schedule_event_mask & AQS_FRZ_PROTECT_OFF) == AQS_FRZ_PROTECT_OFF)
|
||||
#define isAQS_BOOST_OFF_ENABED ((_aqconfig_.schedule_event_mask & AQS_BOOST_OFF) == AQS_BOOST_OFF)
|
||||
/*
|
||||
typedef enum reset_event_type{
|
||||
POWER_ON,
|
||||
FREEZE_PROTECT_OFF,
|
||||
BOOST_OFF
|
||||
} reset_event_type;
|
||||
*/
|
||||
bool event_happened_set_device_state(reset_event_type type, struct aqualinkdata *aq_data);
|
||||
//void read_schedules();
|
||||
//void write_schedules();
|
||||
|
||||
#endif // AQ_SCHEDULER_H_
|
|
@ -30,6 +30,8 @@
|
|||
#include "utils.h"
|
||||
#include "config.h"
|
||||
#include "packetLogger.h"
|
||||
#include "timespec_subtract.h"
|
||||
#include "aqualink.h"
|
||||
|
||||
/*
|
||||
Notes for serial usb speed
|
||||
|
@ -45,6 +47,9 @@ ioctl(fd, TIOCSSERIAL, &serial);
|
|||
|
||||
*/
|
||||
|
||||
// Default to send command with leading NUL, this changes that
|
||||
//#define SEND_CMD_WITH_TRAILING_NUL
|
||||
|
||||
//#define BLOCKING_MODE
|
||||
|
||||
static bool _blocking_mode = false;
|
||||
|
@ -52,12 +57,115 @@ int _blocking_fds = -1;
|
|||
|
||||
static struct termios _oldtio;
|
||||
|
||||
static struct timespec _last_serial_read_time;
|
||||
|
||||
void send_packet(int fd, unsigned char *packet, int length);
|
||||
//unsigned char getProtocolType(unsigned char* packet);
|
||||
|
||||
emulation_type getJandyDeviceType(unsigned char ID) {
|
||||
|
||||
// Using emulation_type from aqprogrammer. At some point may merge into one
|
||||
// and call device type
|
||||
|
||||
if (ID >= 0x08 && ID <= 0x0B)
|
||||
return ALLBUTTON;
|
||||
if (ID >= 0x40 && ID <= 0x43)
|
||||
return ONETOUCH;
|
||||
if (ID >= 0x48 && ID <= 0x4B)
|
||||
return RSSADAPTER;
|
||||
if (ID >= 0x60 && ID <= 0x63)
|
||||
return AQUAPDA;
|
||||
if (ID >= 0x30 && ID <= 0x33)
|
||||
return IAQTOUCH;
|
||||
if (ID >= 0xa0 && ID <= 0xa3)
|
||||
return IAQUALNK;
|
||||
|
||||
const char* get_packet_type(unsigned char* packet , int length)
|
||||
/*
|
||||
if (ID >= 0x00 && ID <= 0x03)
|
||||
return MASTER;
|
||||
if (ID >= 0x50 && ID <= 0x53)
|
||||
return SWG;
|
||||
if (ID >= 0x20 && ID <= 0x23)
|
||||
return SPA_R;
|
||||
if (ID >= 0x38 && ID <= 0x3B)
|
||||
return LX_HEATER;
|
||||
if (ID >= 0x58 && ID <= 0x5B)
|
||||
return PC_DOCK;
|
||||
if (ID >= 0x68 && ID <= 0x6B)
|
||||
return JXI_HEATER;
|
||||
//if (ID >= 0x70 && ID <= 0x73)
|
||||
if (ID >= 0x78 && ID <= 0x7B)
|
||||
return EPUMP;
|
||||
if (ID >= 0x80 && ID <= 0x83)
|
||||
return CHEM;
|
||||
//if (ID == 0x08)
|
||||
// return KEYPAD;
|
||||
*/
|
||||
return SIM_NONE;
|
||||
}
|
||||
|
||||
const char *getJandyDeviceName(emulation_type etype) {
|
||||
switch(etype){
|
||||
case ALLBUTTON:
|
||||
return "AllButton";
|
||||
break;
|
||||
case ONETOUCH:
|
||||
return "OneTouch";
|
||||
break;
|
||||
case RSSADAPTER:
|
||||
return "RS SerialAdapter";
|
||||
break;
|
||||
case IAQTOUCH:
|
||||
return "iAqualinkTouch";
|
||||
break;
|
||||
case AQUAPDA:
|
||||
return "PDA";
|
||||
break;
|
||||
default:
|
||||
return "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char* get_pentair_packet_type(unsigned char* packet , int length)
|
||||
{
|
||||
static char buf[15];
|
||||
|
||||
if (length <= 0 )
|
||||
return "";
|
||||
|
||||
switch (packet[PEN_PKT_CMD]) {
|
||||
case PEN_CMD_SPEED:
|
||||
if (packet[PEN_PKT_DEST]== PEN_DEV_MASTER)
|
||||
return "VSP SetSpeed rtn";
|
||||
else
|
||||
return "VSP SetSpeed";
|
||||
break;
|
||||
case PEN_CMD_REMOTECTL:
|
||||
if (packet[PEN_PKT_DEST]== PEN_DEV_MASTER)
|
||||
return "VSP RemoteCtl rtn";
|
||||
else
|
||||
return "VSP RemoteCtl";
|
||||
break;
|
||||
case PEN_CMD_POWER:
|
||||
if (packet[PEN_PKT_DEST]== PEN_DEV_MASTER)
|
||||
return "VSP SetPower rtn";
|
||||
else
|
||||
return "VSP SetPower";
|
||||
break;
|
||||
case PEN_CMD_STATUS:
|
||||
if (packet[PEN_PKT_DEST]== PEN_DEV_MASTER)
|
||||
return "VSP Status";
|
||||
else
|
||||
return "VSP GetStatus";
|
||||
break;
|
||||
default:
|
||||
sprintf(buf, "Unknown '0x%02hhx'", packet[PEN_PKT_CMD]);
|
||||
return buf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const char* get_jandy_packet_type(unsigned char* packet , int length)
|
||||
{
|
||||
static char buf[15];
|
||||
|
||||
|
@ -117,7 +225,10 @@ const char* get_packet_type(unsigned char* packet , int length)
|
|||
return "iAq pMessage";
|
||||
break;
|
||||
case CMD_IAQ_PAGE_BUTTON:
|
||||
return "iAq pButton";
|
||||
if (packet[PKT_DEST] == 0x00) // To master is iAqualink2 send command
|
||||
return "iAqualnk sendCmd";
|
||||
else
|
||||
return "iAq pButton";
|
||||
break;
|
||||
case CMD_IAQ_POLL:
|
||||
return "iAq Poll";
|
||||
|
@ -137,6 +248,21 @@ const char* get_packet_type(unsigned char* packet , int length)
|
|||
case CMD_IAQ_STARTUP:
|
||||
return "iAq init";
|
||||
break;
|
||||
case CMD_IAQ_TITLE_MESSAGE:
|
||||
return "iAq ProductName";
|
||||
break;
|
||||
case CMD_IAQ_MSG_LONG:
|
||||
return "iAq Popup message";
|
||||
break;
|
||||
case CMD_IAQ_MAIN_STATUS:
|
||||
return "iAq Main status";
|
||||
break;
|
||||
case CMD_IAQ_1TOUCH_STATUS:
|
||||
return "iAq 1Tch status";
|
||||
break;
|
||||
case CMD_IAQ_AUX_STATUS:
|
||||
return "iAq AUX status";
|
||||
break;
|
||||
case RSSA_DEV_STATUS:
|
||||
// This is a fail reply 0x10|0x02|0x48|0x13|0x02|0x00|0x10|0x00|0x7f|0x10|0x03|
|
||||
// Rather than check all, just check 0x02 and checksum sin't I'm not sure 0x10 means faiure without 0x00 around it.
|
||||
|
@ -148,6 +274,44 @@ const char* get_packet_type(unsigned char* packet , int length)
|
|||
case RSSA_DEV_READY:
|
||||
return "RSSA SendCommand";
|
||||
break;
|
||||
case CMD_EPUMP_STATUS:
|
||||
if (packet[4] == CMD_EPUMP_RPM)
|
||||
return "ePump RPM";
|
||||
else if (packet[4] == CMD_EPUMP_WATTS)
|
||||
return "ePump Watts";
|
||||
else
|
||||
return "ePump (unknown)";
|
||||
break;
|
||||
case CMD_EPUMP_RPM:
|
||||
return "ePump set RPM";
|
||||
break;
|
||||
case CMD_EPUMP_WATTS:
|
||||
return "ePump get Watts";
|
||||
break;
|
||||
case CMD_JXI_PING:
|
||||
if (packet[4] == 0x19)
|
||||
return "LXi heater on";
|
||||
else // 0x11 is normal off
|
||||
return "LXi heater ping";
|
||||
break;
|
||||
case CMD_JXI_STATUS:
|
||||
if (packet[6] == 0x10)
|
||||
return "LXi error";
|
||||
else
|
||||
return "LXi status";
|
||||
break;
|
||||
|
||||
case 0x53:
|
||||
return "iAqalnk Poll";
|
||||
break;
|
||||
|
||||
case CMD_IAQ_CMD_READY:
|
||||
return "iAqalnk rec ready";
|
||||
break;
|
||||
case CMD_IAQ_CTRL_READY:
|
||||
return "iAq receive ready";
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf(buf, "Unknown '0x%02hhx'", packet[PKT_CMD]);
|
||||
return buf;
|
||||
|
@ -155,6 +319,16 @@ const char* get_packet_type(unsigned char* packet , int length)
|
|||
}
|
||||
}
|
||||
|
||||
const char* get_packet_type(unsigned char* packet , int length)
|
||||
{
|
||||
if (getProtocolType(packet)==PENTAIR) {
|
||||
return get_pentair_packet_type(packet, length);
|
||||
}
|
||||
|
||||
return get_jandy_packet_type(packet, length);
|
||||
}
|
||||
|
||||
|
||||
// Generate and return checksum of packet.
|
||||
int generate_checksum(unsigned char* packet, int length)
|
||||
{
|
||||
|
@ -181,7 +355,7 @@ bool check_jandy_checksum(unsigned char* packet, int length)
|
|||
LOG(RSSD_LOG,LOG_INFO, "Ignoring bad checksum, seems to be bug in Jandy protocol\n");
|
||||
if (getLogLevel(RSSD_LOG) >= LOG_DEBUG) {
|
||||
static char buf[1000];
|
||||
beautifyPacket(buf,packet,length,true);
|
||||
beautifyPacket(buf,1000, packet,length,true);
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Packetin question %s\n",buf);
|
||||
}
|
||||
return true;
|
||||
|
@ -319,24 +493,15 @@ int _init_serial_port(const char* tty, bool blocking, bool readahead);
|
|||
int init_serial_port(const char* tty)
|
||||
{
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
if (_aqconfig_.rs_poll_speed < 0)
|
||||
if (_aqconfig_.rs_poll_speed < 0) {
|
||||
return init_blocking_serial_port(_aqconfig_.serial_port);
|
||||
else if (_aqconfig_.readahead_b4_write)
|
||||
return init_readahead_serial_port(_aqconfig_.serial_port);
|
||||
else
|
||||
return init_serial_port(_aqconfig_.serial_port);
|
||||
}
|
||||
#else
|
||||
if (_aqconfig_.readahead_b4_write)
|
||||
return init_readahead_serial_port(_aqconfig_.serial_port);
|
||||
else
|
||||
return init_blocking_serial_port(_aqconfig_.serial_port);
|
||||
return init_blocking_serial_port(_aqconfig_.serial_port);
|
||||
#endif
|
||||
|
||||
}
|
||||
int init_readahead_serial_port(const char* tty)
|
||||
{
|
||||
return _init_serial_port(tty, false, true);
|
||||
}
|
||||
|
||||
int init_blocking_serial_port(const char* tty)
|
||||
{
|
||||
_blocking_fds = _init_serial_port(tty, true, false);
|
||||
|
@ -387,19 +552,28 @@ int lock_port(int fd, const char* tty)
|
|||
|
||||
int unlock_port(int fd)
|
||||
{
|
||||
if (ioctl(fd, TIOCNXCL) < 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Failed to remove into exclusive mode (%d): %s\n", errno, strerror( errno ));
|
||||
}
|
||||
|
||||
if (flock(fd, LOCK_UN) < 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Can't unlock serial port (%d): %s\n",errno, strerror( errno ));
|
||||
//if (!isAqualinkDStopping()) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Can't unlock serial port (%d): %s\n",errno, strerror( errno ));
|
||||
//}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_valid_port(int fd) {
|
||||
return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
|
||||
}
|
||||
|
||||
|
||||
// https://www.cmrr.umn.edu/~strupp/serial.html#2_5_2
|
||||
// http://unixwiz.net/techtips/termios-vmin-vtime.html
|
||||
//#define OLD_SERIAL_INIT
|
||||
#ifndef OLD_SERIAL_INIT
|
||||
|
||||
// Unless AQ_RS_EXTRA_OPTS is defined, blocking will always be true
|
||||
int _init_serial_port(const char* tty, bool blocking, bool readahead)
|
||||
{
|
||||
//B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400
|
||||
|
@ -409,7 +583,9 @@ int _init_serial_port(const char* tty, bool blocking, bool readahead)
|
|||
|
||||
_blocking_mode = blocking;
|
||||
|
||||
int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
|
||||
//int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
|
||||
int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY | O_CLOEXEC);
|
||||
|
||||
//int fd = open(tty, O_RDWR | O_NOCTTY | O_SYNC); // This is way to slow at reading
|
||||
if (fd < 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Unable to open port: %s, error %d\n", tty, errno);
|
||||
|
@ -484,60 +660,7 @@ int _init_serial_port(const char* tty, bool blocking, bool readahead)
|
|||
|
||||
return fd;
|
||||
}
|
||||
#else //OLD_SERIAL_INIT
|
||||
int _init_serial_port(const char* tty, bool blocking, bool readahead) // readahead ignored in this implimentation
|
||||
{
|
||||
|
||||
long BAUD = B9600;
|
||||
long DATABITS = CS8;
|
||||
long STOPBITS = 0;
|
||||
long PARITYON = 0;
|
||||
long PARITY = 0;
|
||||
|
||||
struct termios newtio; //place for old and new port settings for serial port
|
||||
|
||||
_blocking_mode = blocking;
|
||||
|
||||
//int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
|
||||
if (fd < 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Unable to open port: %s\n", tty);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Openeded serial port %s\n",tty);
|
||||
|
||||
if (_blocking_mode) {
|
||||
// http://unixwiz.net/techtips/termios-vmin-vtime.html
|
||||
// Not designed behaviour, but it's what we need.
|
||||
fcntl(fd, F_SETFL, 0);
|
||||
newtio.c_cc[VMIN]= 1;
|
||||
//newtio.c_cc[VTIME]= 0; // This will wait indefinatly. (not the best if panel / rs485 adapter is down)
|
||||
newtio.c_cc[VTIME]= 50; // (1 to 255) 1 = 0.1 sec, 255 = 25.5 sec
|
||||
LOG(RSSD_LOG,LOG_INFO, "Set serial port %s to blocking mode\n",tty);
|
||||
} else {
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK | O_NDELAY);
|
||||
newtio.c_cc[VMIN]= 0;
|
||||
newtio.c_cc[VTIME]= 1; // This should be 0 if we have readahead before write
|
||||
LOG(RSSD_LOG,LOG_INFO, "Set serial port %s to non blocking mode\n",tty);
|
||||
}
|
||||
|
||||
tcgetattr(fd, &_oldtio); // save current port settings
|
||||
// set new port settings for canonical input processing
|
||||
newtio.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
|
||||
newtio.c_iflag = IGNPAR;
|
||||
newtio.c_lflag = 0; // ICANON;
|
||||
newtio.c_oflag = 0;
|
||||
|
||||
tcflush(fd, TCIFLUSH);
|
||||
tcsetattr(fd, TCSANOW, &newtio);
|
||||
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Set serial port %s io attributes\n",tty);
|
||||
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void close_blocking_serial_port()
|
||||
|
@ -552,6 +675,11 @@ void close_blocking_serial_port()
|
|||
/* close tty port */
|
||||
void close_serial_port(int fd)
|
||||
{
|
||||
if ( fcntl(fd, F_GETFD, 0) == -1 || errno == EBADF ) {
|
||||
// Looks like bad fd or already closed. return with no error since we can get called twice
|
||||
return;
|
||||
}
|
||||
|
||||
unlock_port(fd);
|
||||
tcsetattr(fd, TCSANOW, &_oldtio);
|
||||
close(fd);
|
||||
|
@ -627,13 +755,15 @@ void send_pentair_command(int fd, unsigned char *packet_buffer, int size)
|
|||
packet[++i] = NUL; // Checksum
|
||||
packet[++i] = NUL; // Checksum
|
||||
generate_pentair_checksum(&packet[1], i);
|
||||
packet[++i] = NUL;
|
||||
//packet[++i] = NUL;
|
||||
|
||||
|
||||
//logPacket(packet, i);
|
||||
send_packet(fd,packet,i);
|
||||
send_packet(fd,packet,++i);
|
||||
}
|
||||
|
||||
#ifndef SEND_CMD_WITH_TRAILING_NUL
|
||||
|
||||
void send_jandy_command(int fd, unsigned char *packet_buffer, int size)
|
||||
{
|
||||
unsigned char packet[AQ_MAXPKTLEN];
|
||||
|
@ -648,6 +778,26 @@ void send_jandy_command(int fd, unsigned char *packet_buffer, int size)
|
|||
packet[i] = packet_buffer[i-3];
|
||||
}
|
||||
|
||||
packet[++i] = DLE;
|
||||
packet[++i] = ETX;
|
||||
|
||||
packet[i-2] = generate_checksum(packet, i+1);
|
||||
|
||||
send_packet(fd,packet,++i);
|
||||
}
|
||||
#else
|
||||
void send_jandy_command(int fd, unsigned char *packet_buffer, int size)
|
||||
{
|
||||
unsigned char packet[AQ_MAXPKTLEN];
|
||||
int i=0;
|
||||
|
||||
packet[0] = DLE;
|
||||
packet[1] = STX;
|
||||
|
||||
for (i=2; i-2 < size; i++) {
|
||||
packet[i] = packet_buffer[i-2];
|
||||
}
|
||||
|
||||
packet[++i] = DLE;
|
||||
packet[++i] = ETX;
|
||||
packet[++i] = NUL;
|
||||
|
@ -656,7 +806,7 @@ void send_jandy_command(int fd, unsigned char *packet_buffer, int size)
|
|||
|
||||
send_packet(fd,packet,++i);
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
unsigned char tp[] = {PCOL_PENTAIR, 0x07, 0x0F, 0x10, 0x08, 0x0D, 0x55, 0x55, 0x5B, 0x2A, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00};
|
||||
send_command(0, tp, 19);
|
||||
|
@ -712,6 +862,29 @@ void send_packet(int fd, unsigned char *packet, int length)
|
|||
{
|
||||
#endif
|
||||
|
||||
struct timespec elapsed_time;
|
||||
struct timespec now;
|
||||
|
||||
if (_aqconfig_.frame_delay > 0) {
|
||||
struct timespec min_frame_wait_time;
|
||||
struct timespec frame_wait_time;
|
||||
struct timespec remainder_time;
|
||||
//struct timespec diff;
|
||||
|
||||
min_frame_wait_time.tv_sec = 0;
|
||||
min_frame_wait_time.tv_nsec = _aqconfig_.frame_delay * 1000000;
|
||||
|
||||
do {
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
timespec_subtract(&elapsed_time, &now, &_last_serial_read_time);
|
||||
if (timespec_subtract(&frame_wait_time, &min_frame_wait_time, &elapsed_time)) {
|
||||
break;
|
||||
}
|
||||
} while (nanosleep(&frame_wait_time, &remainder_time) != 0);
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
|
||||
if (_blocking_mode) {
|
||||
//int nwrite = write(fd, packet, length);
|
||||
//LOG(RSSD_LOG,LOG_DEBUG, "Serial write %d bytes of %d\n",nwrite,length);
|
||||
|
@ -720,13 +893,6 @@ void send_packet(int fd, unsigned char *packet, int length)
|
|||
if (nwrite != length)
|
||||
LOG(RSSD_LOG, LOG_ERR, "write to serial port failed\n");
|
||||
} else {
|
||||
if (_aqconfig_.readahead_b4_write) {
|
||||
if (cleanOutSerial(fd, false) != 0x00) {
|
||||
LOG(RSSD_LOG, LOG_ERR, "ERROR on RS485, AqualinkD was too slow in replying to message! (please check for performance issues)\n");
|
||||
cleanOutSerial(fd, true);
|
||||
}
|
||||
}
|
||||
|
||||
int nwrite, i;
|
||||
for (i = 0; i < length; i += nwrite) {
|
||||
nwrite = write(fd, packet + i, length - i);
|
||||
|
@ -747,9 +913,10 @@ void send_packet(int fd, unsigned char *packet, int length)
|
|||
*/
|
||||
|
||||
// MAYBE Change this back to debug serial
|
||||
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial write %d bytes\n",length-2);
|
||||
//LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial write %d bytes\n",length-2);
|
||||
//LOG(RSSD_LOG,LOG_DEBUG, "Serial write %d bytes, type 0x%02hhx cmd 0x%02hhx\n",length-2,packet[5],packet[6]);
|
||||
logPacketWrite(&packet[1], length-2);
|
||||
if (_aqconfig_.log_protocol_packets || getLogLevel(RSSD_LOG) >= LOG_DEBUG_SERIAL)
|
||||
logPacketWrite(&packet[1], length-1);
|
||||
/*
|
||||
if (getLogLevel(PDA_LOG) == LOG_DEBUG) {
|
||||
char buff[1024];
|
||||
|
@ -769,33 +936,75 @@ void send_packet(int fd, unsigned char *packet, int length)
|
|||
}*/
|
||||
|
||||
tcdrain(fd); // Make sure buffer has been sent.
|
||||
//if (_aqconfig_.frame_delay > 0) {
|
||||
#ifndef SERIAL_LOGGER
|
||||
if (_aqconfig_.frame_delay > 0) {
|
||||
timespec_subtract(&elapsed_time, &now, &_last_serial_read_time);
|
||||
LOG(RSTM_LOG, LOG_DEBUG, "Time from recv to %s send is %.3f sec\n",
|
||||
(_blocking_mode?"blocking":"non-blocking"),
|
||||
roundf3(timespec2float(&elapsed_time)));
|
||||
}
|
||||
#endif
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
#ifndef SEND_CMD_WITH_TRAILING_NUL
|
||||
void _send_ack(int fd, unsigned char ack_type, unsigned char command)
|
||||
{
|
||||
const int length = 11;
|
||||
//const int length = 11;
|
||||
int length = 10;
|
||||
// Default null ack with checksum generated, don't mess with it, just over right
|
||||
unsigned char ackPacket[] = { NUL, DLE, STX, DEV_MASTER, CMD_ACK, NUL, NUL, 0x13, DLE, ETX, NUL };
|
||||
//unsigned char ackPacket[] = { NUL, DLE, STX, DEV_MASTER, CMD_ACK, NUL, NUL, 0x13, DLE, ETX };
|
||||
|
||||
// To overcome Pentair VSP bug in Jandy control panel, we need to NOT send trailing NUL on
|
||||
// a normal ACK, but sent the trailing NUL on in ack with command.
|
||||
// Always send trailing NUL causes VSP to loose connection
|
||||
// Never sending trailing NUL causes come commands to be missed.
|
||||
|
||||
// Update the packet and checksum if command argument is not NUL.
|
||||
if(command != NUL || ack_type != NUL) {
|
||||
//ackPacket[5] = 0x00 normal, 0x03 some pause, 0x01 some pause ending (0x01 = Screen Busy (also return from logn message))
|
||||
ackPacket[5] = ack_type;
|
||||
ackPacket[6] = command;
|
||||
ackPacket[7] = generate_checksum(ackPacket, length-1);
|
||||
ackPacket[7] = generate_checksum(ackPacket, length);
|
||||
if (command == DLE) { // We shuld probably also check the ack type as well, just for future proofing.
|
||||
// 0x10(DLE) that's not part of the headder or footer needs to be escaped AFTER with NUL, so shif everyting uo one
|
||||
ackPacket[8] = ackPacket[7]; // move the caculated checksum
|
||||
ackPacket[7] = NUL; // escape the DLE
|
||||
ackPacket[9] = DLE; // add new end sequence
|
||||
ackPacket[10] = ETX; // add new end sequence
|
||||
ackPacket[10] = ETX; // add new end sequence
|
||||
length = 11;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("***Send ACK (%s) ***\n",(ack_type==ACK_NORMAL?"Normal":(ack_type==ACK_SCREEN_BUSY?"ScreenBusy":"ScreenBusyDisplay")) );
|
||||
|
||||
send_packet(fd, ackPacket, length);
|
||||
}
|
||||
#else
|
||||
void _send_ack(int fd, unsigned char ack_type, unsigned char command)
|
||||
{
|
||||
//const int length = 11;
|
||||
int length = 9;
|
||||
// Default null ack with checksum generated, don't mess with it, just over right
|
||||
unsigned char ackPacket[] = { DLE, STX, DEV_MASTER, CMD_ACK, NUL, NUL, 0x13, DLE, ETX, NUL };
|
||||
|
||||
if(command != NUL || ack_type != NUL) {
|
||||
//ackPacket[5] = 0x00 normal, 0x03 some pause, 0x01 some pause ending (0x01 = Screen Busy (also return from logn message))
|
||||
ackPacket[4] = ack_type;
|
||||
ackPacket[5] = command;
|
||||
ackPacket[6] = generate_checksum(ackPacket, length);
|
||||
if (command == DLE) { // We shuld probably also check the ack type as well, just for future proofing.
|
||||
// 0x10(DLE) that's not part of the headder or footer needs to be escaped AFTER with NUL, so shif everyting uo one
|
||||
ackPacket[7] = ackPacket[7]; // move the caculated checksum
|
||||
ackPacket[6] = NUL; // escape the DLE
|
||||
ackPacket[8] = DLE; // add new end sequence
|
||||
ackPacket[9] = ETX; // add new end sequence
|
||||
length = 10;
|
||||
}
|
||||
}
|
||||
send_packet(fd, ackPacket, length);
|
||||
}
|
||||
#endif // SEND_CMD_WITH_TRAILING_NUL
|
||||
|
||||
void send_ack(int fd, unsigned char command)
|
||||
{
|
||||
|
@ -820,6 +1029,8 @@ int get_packet_lograw(int fd, unsigned char* packet)
|
|||
}
|
||||
int _get_packet(int fd, unsigned char* packet, bool rawlog)
|
||||
*/
|
||||
|
||||
|
||||
int get_packet(int fd, unsigned char* packet)
|
||||
{
|
||||
unsigned char byte = 0x00;
|
||||
|
@ -834,6 +1045,8 @@ int get_packet(int fd, unsigned char* packet)
|
|||
//bool lastByteDLE = false;
|
||||
int PentairPreCnt = 0;
|
||||
int PentairDataCnt = -1;
|
||||
struct timespec packet_elapsed;
|
||||
struct timespec packet_end_time;
|
||||
|
||||
memset(packet, 0, AQ_MAXPKTLEN);
|
||||
|
||||
|
@ -949,19 +1162,23 @@ int get_packet(int fd, unsigned char* packet)
|
|||
} else if(bytesRead < 0) {
|
||||
// Got a read error. Wait one millisecond for the next byte to
|
||||
// arrive.
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
|
||||
if(errno == 9) {
|
||||
if (! isAqualinkDStopping() ) {
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
|
||||
if(errno == 9) {
|
||||
// Bad file descriptor. Port has been disconnected for some reason.
|
||||
// Return a -1.
|
||||
return AQSERR_READ;
|
||||
return AQSERR_READ;
|
||||
}
|
||||
delay(100);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// Break out of the loop if we exceed maximum packet
|
||||
// length.
|
||||
if (index >= AQ_MAXPKTLEN) {
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial packet too large\n");
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial packet too large for buffer, stopped reading\n");
|
||||
logPacketError(packet, index);
|
||||
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
return AQSERR_2LARGE;
|
||||
|
@ -969,27 +1186,16 @@ int get_packet(int fd, unsigned char* packet)
|
|||
}
|
||||
}
|
||||
|
||||
// Clean out rest of buffer, make sure their is nothing else
|
||||
/* Doesn't work for shit due to probe message speed, need to come back and re-think
|
||||
if (_aqconfig_.readahead_b4_write) {
|
||||
if (endOfPacket == true) {
|
||||
do {
|
||||
bytesRead = read(fd, &byte, 1);
|
||||
//if (bytesRead==1) { LOG(RSSD_LOG,LOG_ERR, "Cleanout buffer read 0x%02hhx\n",byte); }
|
||||
if (bytesRead==1 && byte != 0x00) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "SERIOUS ERROR on RS485, AqualinkD caught packet collision on bus, ignoring!\n");
|
||||
LOG(RSSD_LOG,LOG_ERR, "Error Cleanout read 0x%02hhx\n",byte);
|
||||
// Run the buffer out
|
||||
do {
|
||||
bytesRead = read(fd, &byte, 1);
|
||||
if (bytesRead==1) { LOG(RSSD_LOG,LOG_ERR, "Error Cleanout read 0x%02hhx\n",byte); }
|
||||
} while (bytesRead==1);
|
||||
return 0;
|
||||
}
|
||||
} while (bytesRead==1);
|
||||
|
||||
// Report any unusual size packets.
|
||||
if (index >= AQ_MAXPKTLEN_WARNING) {
|
||||
// Aqualink2 packets 0x72 and 0x71 can be very large, so supress if it one of those.
|
||||
if (packet[PKT_CMD] != CMD_IAQ_AUX_STATUS && packet[PKT_CMD] != CMD_IAQ_1TOUCH_STATUS) {
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial packet seems too large at length %d\n", index);
|
||||
logPacketError(packet, index);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//LOG(RSSD_LOG,LOG_DEBUG, "Serial checksum, length %d got 0x%02hhx expected 0x%02hhx\n", index, packet[index-3], generate_checksum(packet, index));
|
||||
if (jandyPacketStarted) {
|
||||
if (check_jandy_checksum(packet, index) != true){
|
||||
|
@ -1006,25 +1212,50 @@ int get_packet(int fd, unsigned char* packet)
|
|||
return AQSERR_CHKSUM;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
if (generate_checksum(packet, index) != packet[index-3]){
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad checksum, ignoring\n");
|
||||
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
return 0;
|
||||
} else*/ if (index < AQ_MINPKTLEN && (jandyPacketStarted || pentairPacketStarted) ) { //NSF. Sometimes we get END sequence only, so just ignore.
|
||||
} else*/
|
||||
if (index < AQ_MINPKTLEN && (jandyPacketStarted || pentairPacketStarted) ) { //NSF. Sometimes we get END sequence only, so just ignore.
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial read too small\n");
|
||||
logPacketError(packet, index);
|
||||
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
return AQSERR_2SMALL;
|
||||
}
|
||||
|
||||
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
|
||||
|
||||
if (_aqconfig_.frame_delay > 0 || getLogLevel(RSTM_LOG) >= LOG_DEBUG) {
|
||||
clock_gettime(CLOCK_REALTIME, &packet_end_time);
|
||||
if (getLogLevel(RSTM_LOG) >= LOG_DEBUG) {
|
||||
timespec_subtract(&packet_elapsed, &packet_end_time, &_last_serial_read_time);
|
||||
/*
|
||||
LOG(RSTM_LOG, LOG_NOTICE, "Start sec=%ld nsec=%ld\n",_last_serial_read_time.tv_sec,_last_serial_read_time.tv_nsec);
|
||||
LOG(RSTM_LOG, LOG_NOTICE, "End sec=%ld nsec=%ld\n",packet_end_time.tv_sec,packet_end_time.tv_nsec);
|
||||
LOG(RSTM_LOG, LOG_NOTICE, "Elapsed sec=%ld nsec=%ld Time between packets (%.3f sec)\n",packet_elapsed.tv_sec,packet_elapsed.tv_nsec, roundf3(timespec2float(&packet_elapsed)) );
|
||||
*/
|
||||
LOG(RSTM_LOG, LOG_DEBUG, "Time between packets (%.3f sec)\n", roundf3(timespec2float(&packet_elapsed)) );
|
||||
|
||||
}
|
||||
//if (_aqconfig_.frame_delay > 0) {
|
||||
memcpy(&_last_serial_read_time, &packet_end_time, sizeof(struct timespec));
|
||||
//}
|
||||
}
|
||||
|
||||
//clock_gettime(CLOCK_REALTIME, &_last_serial_read_time);
|
||||
//}
|
||||
//LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
|
||||
if (_aqconfig_.log_protocol_packets || getLogLevel(RSSD_LOG) >= LOG_DEBUG_SERIAL)
|
||||
logPacketRead(packet, index);
|
||||
// Return the packet length.
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else // PLAYBACKMODE
|
||||
|
||||
// Need to re-write this if we ever use playback mode again. Pull info from aq_serial.old.c
|
|
@ -5,8 +5,14 @@
|
|||
#include <termios.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define CONNECTION_ERROR "ERROR No connection to RS control panel"
|
||||
#include "aq_programmer.h" // Need this for function getJandyDeviceType due to enum defined their.
|
||||
emulation_type getJandyDeviceType(unsigned char ID);
|
||||
const char *getJandyDeviceName(emulation_type etype);
|
||||
|
||||
#define CONNECTION_ERROR "ERROR No connection to RS control panel"
|
||||
#ifdef AQ_MANAGER
|
||||
#define CONNECTION_RUNNING_SLOG "Running serial_logger, this will take some time"
|
||||
#endif
|
||||
|
||||
#define SERIAL_BLOCKING_TIME 50 // (1 to 255) in 1/10th second so 1 = 0.1 sec, 255 = 25.5 sec
|
||||
|
||||
|
@ -34,11 +40,57 @@
|
|||
# Jandy pump ID's
|
||||
# 0x78, 0x79, 0x7A, 0x7B
|
||||
*/
|
||||
#define PENTAIR_DEC_PUMP_MIN 96
|
||||
#define PENTAIR_DEC_PUMP_MAX 111
|
||||
#define JANDY_DEC_PUMP_MIN 120
|
||||
#define JANDY_DEC_PUMP_MAX 123
|
||||
#define PENTAIR_DEC_PUMP_MIN 96 // 0x60
|
||||
#define PENTAIR_DEC_PUMP_MAX 111 // 0x6F
|
||||
#define JANDY_DEC_SWG_MIN 80 // 0x50
|
||||
#define JANDY_DEC_SWG_MAX 83 // 0x53
|
||||
#define JANDY_DEC_PUMP_MIN 120 // 0x78
|
||||
#define JANDY_DEC_PUMP_MAX 123 // 0x7b
|
||||
// Have also seen epump at 0xe0 with panel rev W that supports more pumps
|
||||
#define JANDY_DEC_PUMP2_MIN 224 // 0xe0
|
||||
#define JANDY_DEC_PUMP2_MAX 228 // 0xe3 // Their are probably more, but this is a guess
|
||||
|
||||
#define JANDY_DEC_JXI_MIN 104 // 0x68
|
||||
#define JANDY_DEC_JXI_MAX 107 // 0x6B
|
||||
#define JANDY_DEC_LX_MIN 56 // 0x38
|
||||
#define JANDY_DEC_LX_MAX 59 // 0x3B
|
||||
#define JANDY_DEC_CHEM_MIN 128 // 0x80
|
||||
#define JANDY_DEC_CHEM_MAX 131 // 0x83
|
||||
|
||||
#define JANDY_DEV_IAQLN_MIN 0xa0 //
|
||||
#define JANDY_DEV_IAQLN_MAX 0xa3 // 0
|
||||
|
||||
#define JANDY_DEV_AQLNK_MIN 0x30 //
|
||||
#define JANDY_DEV_AQLNK_MAX 0x33 // 0
|
||||
|
||||
#define JANDY_DEV_HPUMP_MIN 0x70
|
||||
#define JANDY_DEV_HPUMP_MAX 0x73
|
||||
/*
|
||||
//===== Device ID's =====//
|
||||
//=========================================================================//
|
||||
DEV_MASTER_MASK = 0x00; // MASTER(S???0 00-03 0b0 0000 0XX //
|
||||
DEV_CTL_MASK = 0x08; // HOME CONTROLLER (RS-8?) 08-0b 0b0 0001 0XX //
|
||||
// 0x10; // XXXXX DEVICE 10-13 0b0 0010 0XX //
|
||||
// 0x18; // XXXXX DEVICE 18-1b 0b0 0011 0XX //
|
||||
DEV_SPA_MASK = 0x20; // SPA DEVICE 20-23 0b0 0100 0XX //
|
||||
DEV_RPC_MASK = 0x28; // REMOTE POWER CENTER DEVICE 28-2b 0b0 0101 0XX //
|
||||
DEV_AQUALINK_MASK = 0x30; // AQUALINK DEVICE 30-33 0b0 0110 0XX //
|
||||
DEV_LX_HTR_MASK = 0x38; // LX HEATER 38-3b 0b0 0111 0XX //
|
||||
DEV_ONETOUCH_MASK = 0x40; // XXXXX ONE TOUCH DEVICE 40-43 0b0 1000 0XX //
|
||||
// 0x48; // XXXXX DEVICE 48-4b 0b0 1001 0XX //
|
||||
DEV_AQUARITE_MASK = 0x50; // AQUARITE DEVICE 50-53 0b0 1010 0XX //
|
||||
DEV_PCDOCK_MASK = 0x58; // PCDOCK DEVICE 58-5b 0b0 1011 0XX //
|
||||
DEV_PDA_JDA_MASK = 0x60; // AQUAPALM DEVICE 60-63 0b0 1100 0XX //
|
||||
DEV_LXI_LRZE_MASK = 0x68; // LXi/LZRE DEVICE 68-6b 0b0 1101 0XX //
|
||||
DEV_HEATPUMP_MASK = 0x70; // HEAT PUMP DEVICE 70-73 0b0 1110 0XX //
|
||||
JANDY_EPUMP_MASK = 0x78; // EPUMP DEVICE 78-7b 0b0 1111 0XX //
|
||||
DEV_CHEMLINK_MASK = 0x80; // CHEMLINK DEVICE 80-83 0b1 0000 0XX //
|
||||
Heater 0x88; // XXXXX DEVICE 88-8b 0b1 0001 0XX //
|
||||
// 0x90; // XXXXX DEVICE 90-93 0b1 0010 0XX //
|
||||
// 0x98; // XXXXX DEVICE 98-9b 0b1 0011 0XX //
|
||||
DEV_AQUALINK_2_MASK = 0xA0; // AQUALINK 2 A0-A3 0b1 0100 0XX //
|
||||
DEV_UNKNOWN_MASK = 0xF8; // Unknown mask, used to reset values
|
||||
*/
|
||||
|
||||
// PACKET DEFINES Jandy
|
||||
#define NUL 0x00
|
||||
|
@ -52,26 +104,48 @@
|
|||
#define PP3 0xFF
|
||||
#define PP4 0xA5
|
||||
|
||||
#define PEN_CMD_STATUS 0x07
|
||||
#define PEN_DEV_MASTER 0x10
|
||||
|
||||
#define PEN_CMD_SPEED 0x01
|
||||
#define PEN_CMD_REMOTECTL 0x04
|
||||
#define PEN_CMD_POWER 0x06
|
||||
#define PEN_CMD_STATUS 0x07
|
||||
|
||||
|
||||
|
||||
#define PEN_PKT_FROM 6
|
||||
#define PEN_PKT_DEST 5
|
||||
#define PEN_PKT_CMD 7
|
||||
|
||||
#define PEN_HI_B_RPM 14
|
||||
#define PEN_LO_B_RPM 15
|
||||
#define PEN_HI_B_WAT 12
|
||||
#define PEN_LO_B_WAT 13
|
||||
// Pentair VSP
|
||||
#define PEN_MODE 10
|
||||
#define PEN_DRIVE_STATE 11
|
||||
#define PEN_HI_B_WAT 12
|
||||
#define PEN_LO_B_WAT 13
|
||||
#define PEN_HI_B_RPM 14
|
||||
#define PEN_LO_B_RPM 15
|
||||
#define PEN_FLOW 16
|
||||
#define PEN_PPC 17 // Pump pressure curve
|
||||
#define PEN_HI_B_STATUS 20 // The current status value of the pump. following values: ok, filterWarning, overCurrent, priming, systemBlocked, generalAlarm, powerOutage, overCurrent2, overVoltage, commLost
|
||||
#define PEN_LO_B_STATUS 21
|
||||
// END Pentair
|
||||
|
||||
#define AQ_MINPKTLEN 5
|
||||
//#define AQ_MAXPKTLEN 64
|
||||
#define AQ_MAXPKTLEN 128 // Max 79 bytes so far, so 128 is a guess at the moment, just seen large packets from iAqualink
|
||||
//#define AQ_MAXPKTLEN 128 // Max 79 bytes so far, so 128 is a guess at the moment, just seen large packets from iAqualink
|
||||
//#define AQ_MAXPKTLEN 256 // Still getting this at 128, so temp increase to 256 and print message over 128 in aq_serial.c
|
||||
#define AQ_MAXPKTLEN 512 // Still getting this at 128, so temp increase to 256 and print message over 128 in aq_serial.c
|
||||
#define AQ_MAXPKTLEN_SEND 32 // Out biggest send buffer
|
||||
#define AQ_PSTLEN 5
|
||||
#define AQ_MSGLEN 16
|
||||
#define AQ_MSGLONGLEN 128
|
||||
#define AQ_TADLEN 13
|
||||
|
||||
// For printing warning & debug messages for packets.
|
||||
// The below are related to AQ_MAXPKTLEN
|
||||
#define AQ_MAXPKTLEN_WARNING 128 // Print warning message if over this
|
||||
//#define AQ_PACKET_PRINT_BUFFER 1400 // Must be at least AQ_MAXPKTLEN * 5 + 100
|
||||
|
||||
/* COMMANDS */
|
||||
#define CMD_PROBE 0x00
|
||||
#define CMD_ACK 0x01
|
||||
|
@ -119,6 +193,10 @@
|
|||
#define CMD_PERCENT 0x11 // Set Percent
|
||||
#define CMD_PPM 0x16 // Received PPM
|
||||
|
||||
/* LXi Heater commands */
|
||||
#define CMD_JXI_PING 0x0c
|
||||
#define CMD_JXI_STATUS 0x0d
|
||||
|
||||
/* PDA KEY CODES */ // Just plating at the moment
|
||||
#define KEY_PDA_UP 0x06
|
||||
#define KEY_PDA_DOWN 0x05
|
||||
|
@ -139,7 +217,8 @@
|
|||
#define KEY_AUX7 0x15
|
||||
#define KEY_POOL_HTR 0x12
|
||||
#define KEY_SPA_HTR 0x17
|
||||
#define KEY_SOLAR_HTR 0x1c
|
||||
//#define KEY_SOLAR_HTR 0x1c
|
||||
#define KEY_EXT_AUX 0x1c
|
||||
#define KEY_MENU 0x09
|
||||
#define KEY_CANCEL 0x0e
|
||||
#define KEY_LEFT 0x13
|
||||
|
@ -148,7 +227,7 @@
|
|||
#define KEY_OVERRIDE 0x1e
|
||||
#define KEY_ENTER 0x1d
|
||||
|
||||
#ifdef AQ_RS16
|
||||
|
||||
//RS 12 & 16 are different from Aux4 to Aux7
|
||||
#define KEY_RS16_AUX4 0x14
|
||||
#define KEY_RS16_AUX5 0x03
|
||||
|
@ -164,10 +243,10 @@
|
|||
#define KEY_AUXB7 0x0d
|
||||
#define KEY_AUXB8 0x0c
|
||||
// End diff in RS12
|
||||
#endif
|
||||
|
||||
|
||||
#define BTN_PUMP "Filter_Pump"
|
||||
#define BTN_SPA "Spa_Mode"
|
||||
#define BTN_SPA "Spa"
|
||||
#define BTN_AUX1 "Aux_1"
|
||||
#define BTN_AUX2 "Aux_2"
|
||||
#define BTN_AUX3 "Aux_3"
|
||||
|
@ -177,12 +256,15 @@
|
|||
#define BTN_AUX7 "Aux_7"
|
||||
#define BTN_POOL_HTR "Pool_Heater"
|
||||
#define BTN_SPA_HTR "Spa_Heater"
|
||||
#define BTN_SOLAR_HTR "Solar_Heater"
|
||||
//#define BTN_SOLAR_HTR "Solar_Heater"
|
||||
#define BTN_EXT_AUX "Extra_Aux"
|
||||
|
||||
#define BTN_TEMP1_HTR "Temp1_Heater"
|
||||
#define BTN_TEMP2_HTR "Temp2_Heater"
|
||||
|
||||
#ifdef AQ_RS16
|
||||
#define BTN_VAUX "Aux_V" // A number will be appended
|
||||
|
||||
|
||||
#define BTN_AUXB1 "Aux_B1"
|
||||
#define BTN_AUXB2 "Aux_B2"
|
||||
#define BTN_AUXB3 "Aux_B3"
|
||||
|
@ -191,7 +273,7 @@
|
|||
#define BTN_AUXB6 "Aux_B6"
|
||||
#define BTN_AUXB7 "Aux_B7"
|
||||
#define BTN_AUXB8 "Aux_B8"
|
||||
#endif
|
||||
|
||||
|
||||
#define BTN_PDA_PUMP "FILTER PUMP"
|
||||
#define BTN_PDA_SPA "SPA"
|
||||
|
@ -204,15 +286,15 @@
|
|||
#define BTN_PDA_AUX7 "AUX7"
|
||||
#define BTN_PDA_POOL_HTR "POOL HEAT"
|
||||
#define BTN_PDA_SPA_HTR "SPA HEAT"
|
||||
#define BTN_PDA_SOLAR_HTR "EXTRA AUX"
|
||||
//#define BTN_PDA_SOLAR_HTR "EXTRA AUX"
|
||||
#define BTN_PDA_EXT_AUX "EXTRA AUX"
|
||||
|
||||
#define BUTTON_LABEL_LENGTH 20
|
||||
|
||||
#ifndef AQ_RS16
|
||||
#define TOTAL_LEDS 20
|
||||
#else
|
||||
|
||||
//#define TOTAL_LEDS 20
|
||||
#define TOTAL_LEDS 24 // Only 20 exist in control panel, but need space for the extra buttons on RS16 panel
|
||||
#endif
|
||||
|
||||
|
||||
// Index starting at 1
|
||||
#define POOL_HTR_LED_INDEX 15
|
||||
|
@ -229,6 +311,10 @@
|
|||
//#define LNG_MSG_FREEZE_PROTECTION_ACTIVATED "FREEZE PROTECTION ACTIVATED"
|
||||
#define LNG_MSG_FREEZE_PROTECTION_ACTIVATED "FREEZE PROTECTION IS ACTIVATED"
|
||||
|
||||
// These are
|
||||
#define LNG_MSG_CHEM_FEED_ON "CHEM FEED ON"
|
||||
#define LNG_MSG_CHEM_FEED_OFF "CHEM FEED OFF"
|
||||
|
||||
|
||||
#define MSG_AIR_TEMP "AIR TEMP"
|
||||
#define MSG_POOL_TEMP "POOL TEMP"
|
||||
|
@ -284,8 +370,9 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
//#define SWG_STATUS_OFFLINE 0xFE
|
||||
|
||||
//#define SWG_STATUS_UNKNOWN -128 // Idiot. unsigned char....Derr.
|
||||
#define SWG_STATUS_OFF 0xFF // Documented this as off in API, so don't change.
|
||||
#define SWG_STATUS_UNKNOWN 0xFE
|
||||
#define SWG_STATUS_OFF 0xFF // Documented this as off in API, so don't change.
|
||||
#define SWG_STATUS_UNKNOWN 0xFE
|
||||
#define SWG_STATUS_GENFAULT 0xFD //This is displayed in the panel, so adding it
|
||||
// These are actual from RS485
|
||||
|
||||
#define SWG_STATUS_ON 0x00
|
||||
|
@ -309,6 +396,10 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
#define CMD_PDA_SHIFTLINES 0x0F
|
||||
#define CMD_PDA_HIGHLIGHTCHARS 0x10
|
||||
|
||||
/* ePump */
|
||||
#define CMD_EPUMP_STATUS 0x1F
|
||||
#define CMD_EPUMP_RPM 0x44
|
||||
#define CMD_EPUMP_WATTS 0x45
|
||||
// One Touch commands
|
||||
//#define CMD_PDA_0x04 0x04 // No idea, might be building menu
|
||||
|
||||
|
@ -323,9 +414,16 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
#define CMD_IAQ_POLL 0x30 // Poll message or ready to receive command
|
||||
#define CMD_IAQ_CTRL_READY 0x31 // Get this when we can send big control command
|
||||
#define CMD_IAQ_PAGE_CONTINUE 0x40 // Seems we get this on AUX device page when there is another page, keeps circuling through pages.
|
||||
|
||||
#define CMD_IAQ_TITLE_MESSAGE 0x2d // This is what the product name is set to (Jandy RS) usually
|
||||
//#define CMD_IAQ_VSP_ERROR 0x2c // Error when setting speed too high
|
||||
#define CMD_IAQ_MSG_LONG 0x2c // This this is display popup message. Next 2 bytes 0x00|0x01 = wait and then 0x00|0x00 clear
|
||||
|
||||
// If
|
||||
#define CMD_IAQ_MAIN_STATUS 0x70
|
||||
#define CMD_IAQ_1TOUCH_STATUS 0x71
|
||||
#define CMD_IAQ_AUX_STATUS 0x72 // Get this on AqualinkTouch protocol when iAqualink protocol sends 0x18 (get aux status I assume)
|
||||
|
||||
#define CMD_IAQ_CMD_READY 0x73 // iAqualink ready to receive command
|
||||
/*
|
||||
#define CMD_IAQ_MSG_3 0x2d // Equiptment status message??
|
||||
#define CMD_IAQ_0x31 0x31 // Some pump speed info
|
||||
|
@ -341,6 +439,10 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
#define KEY_IAQTCH_STATUS 0x06
|
||||
#define KEY_IAQTCH_PREV_PAGE 0x20
|
||||
#define KEY_IAQTCH_NEXT_PAGE 0x21
|
||||
#define KEY_IAQTCH_OK 0x01 //HEX: 0x10|0x02|0x00|0x01|0x00|0x01|0x14|0x10|0x03|. OK BUTTON
|
||||
|
||||
#define KEY_IAQTCH_PREV_PAGE_ALTERNATE 0x1d // System setup prev
|
||||
#define KEY_IAQTCH_NEXT_PAGE_ALTERNATE 0x1e // System setup next
|
||||
|
||||
// PAGE1 (Horosontal keys) (These are duplicate so probable delete)
|
||||
#define KEY_IAQTCH_HOMEP_KEY01 0x11
|
||||
|
@ -376,6 +478,7 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
#define IAQ_PAGE_STATUS2 0x2a // Something get this for Status rather than 0x5b
|
||||
#define IAQ_PAGE_DEVICES 0x36
|
||||
#define IAQ_PAGE_DEVICES2 0x35
|
||||
#define IAQ_PAGE_DEVICES3 0x51
|
||||
#define IAQ_PAGE_SET_TEMP 0x39
|
||||
#define IAQ_PAGE_MENU 0x0f
|
||||
#define IAQ_PAGE_SET_VSP 0x1e
|
||||
|
@ -387,10 +490,18 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
#define IAQ_PAGE_ONETOUCH 0x4d
|
||||
#define IAQ_PAGE_COLOR_LIGHT 0x48
|
||||
#define IAQ_PAGE_SYSTEM_SETUP 0x14
|
||||
#define IAQ_PAGE_SYSTEM_SETUP2 0x49
|
||||
#define IAQ_PAGE_SYSTEM_SETUP3 0x4a
|
||||
#define IAQ_PAGE_VSP_SETUP 0x2d
|
||||
#define IAQ_PAGE_FREEZE_PROTECT 0x11
|
||||
#define IAQ_PAGE_LABEL_AUX 0x32
|
||||
#define IAQ_PAGE_HELP 0x0c
|
||||
#define IAQ_PAGE_SERVICEMODE 0x5e // Also Timeout
|
||||
|
||||
#define IAQ_PAGE_DEVICES_REV_Yg 0x0a // Panel rev Yg (and maybe others use this)
|
||||
|
||||
//#define IAQ_PAGE_START_BOOST 0x3f
|
||||
//#define IAQ_PAGE_DEGREES 0xFF // Added this as never want to actually select the page, just go to it.
|
||||
|
||||
|
||||
|
||||
|
@ -411,7 +522,11 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
typedef enum {
|
||||
DRS_NONE,
|
||||
DRS_SWG,
|
||||
DRS_EPUMP
|
||||
DRS_EPUMP,
|
||||
DRS_JXI,
|
||||
DRS_LX,
|
||||
DRS_CHEM,
|
||||
DRS_HEATPUMP
|
||||
} rsDeviceType;
|
||||
|
||||
typedef enum {
|
||||
|
@ -443,7 +558,7 @@ typedef enum {
|
|||
|
||||
int init_serial_port(const char* tty);
|
||||
int init_blocking_serial_port(const char* tty);
|
||||
int init_readahead_serial_port(const char* tty);
|
||||
//int init_readahead_serial_port(const char* tty);
|
||||
|
||||
void close_serial_port(int file_descriptor);
|
||||
void close_blocking_serial_port();
|
||||
|
@ -462,6 +577,7 @@ void send_extended_ack(int fd, unsigned char ack_type, unsigned char command);
|
|||
//void send_cmd(int file_descriptor, unsigned char cmd, unsigned char args);
|
||||
int get_packet(int file_descriptor, unsigned char* packet);
|
||||
//int get_packet_lograw(int fd, unsigned char* packet);
|
||||
int is_valid_port(int fd);
|
||||
|
||||
//int get_packet_new(int fd, unsigned char* packet);
|
||||
//int get_packet_new_lograw(int fd, unsigned char* packet);
|
||||
|
@ -493,4 +609,4 @@ bool onetouch_mode();
|
|||
//void send_test_cmd(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3);
|
||||
//void send_command(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3);
|
||||
//void send_messaged(int fd, unsigned char destination, char *message);
|
||||
#endif // AQ_SERIAL_H_
|
||||
#endif // AQ_SERIAL_H_
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Shaun Feakes - All rights reserved
|
||||
*
|
||||
* You may use redistribute and/or modify this code under the terms of
|
||||
* the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. For the terms of this license,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* https://github.com/sfeakes/aqualinkd
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "aqualink.h"
|
||||
#include "aq_scheduler.h"
|
||||
|
||||
bool remount_root_ro(bool readonly)
|
||||
{
|
||||
|
||||
#ifdef AQ_CONTAINER
|
||||
// In container this is pointless
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (readonly)
|
||||
{
|
||||
LOG(AQUA_LOG, LOG_INFO, "reMounting root RO\n");
|
||||
mount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct statvfs fsinfo;
|
||||
statvfs("/", &fsinfo);
|
||||
if ((fsinfo.f_flag & ST_RDONLY) == 0) // We are readwrite, ignore
|
||||
return false;
|
||||
|
||||
LOG(AQUA_LOG, LOG_INFO, "reMounting root RW\n");
|
||||
mount(NULL, "/", NULL, MS_REMOUNT, NULL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
FILE *aq_open_file(char *filename, bool *ro_root, bool *created_file)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
*ro_root = remount_root_ro(false);
|
||||
|
||||
if (access(filename, F_OK) == 0)
|
||||
{
|
||||
*created_file = true;
|
||||
}
|
||||
|
||||
fp = fopen(filename, "w");
|
||||
if (fp == NULL)
|
||||
{
|
||||
remount_root_ro(*ro_root);
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
bool aq_close_file(FILE *file, bool ro_root)
|
||||
{
|
||||
if (file != NULL)
|
||||
fclose(file);
|
||||
|
||||
return remount_root_ro(ro_root);
|
||||
}
|
||||
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
bool copy_file(const char *source_path, const char *destination_path)
|
||||
{
|
||||
|
||||
bool ro_root = remount_root_ro(false);
|
||||
|
||||
FILE *source_file = fopen(source_path, "rb");
|
||||
if (source_file == NULL)
|
||||
{
|
||||
LOG(AQUA_LOG, LOG_ERR, "Error opening source file: %s\n", source_path);
|
||||
remount_root_ro(ro_root);
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE *destination_file = fopen(destination_path, "wb");
|
||||
if (destination_file == NULL)
|
||||
{
|
||||
LOG(AQUA_LOG, LOG_ERR, "Error opening source file: %s\n", destination_path);
|
||||
fclose(source_file);
|
||||
remount_root_ro(ro_root);
|
||||
return false;
|
||||
}
|
||||
|
||||
char buffer[BUFFER_SIZE];
|
||||
size_t bytes_read;
|
||||
|
||||
while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, source_file)) > 0)
|
||||
{
|
||||
if (fwrite(buffer, 1, bytes_read, destination_file) != bytes_read)
|
||||
{
|
||||
LOG(AQUA_LOG, LOG_ERR, "Error writing to destination file: %s\n", destination_path);
|
||||
fclose(source_file);
|
||||
fclose(destination_file);
|
||||
remount_root_ro(ro_root);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ferror(source_file))
|
||||
{
|
||||
LOG(AQUA_LOG, LOG_ERR, "Error reading from source: %s\n", source_path);
|
||||
fclose(source_file);
|
||||
fclose(destination_file);
|
||||
remount_root_ro(ro_root);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(source_file);
|
||||
fclose(destination_file);
|
||||
remount_root_ro(ro_root);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run_aqualinkd_upgrade(bool onlycheck)
|
||||
{
|
||||
int pipe_curl_to_bash[2];
|
||||
pid_t pid_curl, pid_bash;
|
||||
//char *curl_args[] = {"curl", "-fsSl", "http://tiger/scratch/remote_install.sh", NULL};
|
||||
//char *curl_args[] = {"curl", "-fsSl", "-H", "Accept: application/vnd.github.raw", "https://api.github.com/repos/sfeakes/AqualinkD/contents/release/remote_install.sh", NULL};
|
||||
char *curl_args[] = {"curl", "-fsSl", "-H", "Accept: application/vnd.github.raw", "https://api.github.com/repos/AqualinkD/AqualinkD/contents/release/remote_install.sh", NULL};
|
||||
char *bash_args[] = {"bash", "-s", "--", "check", NULL};
|
||||
int status_curl, status_bash;
|
||||
|
||||
if (!onlycheck) {
|
||||
bash_args[3] = NULL;
|
||||
}
|
||||
|
||||
if (pipe(pipe_curl_to_bash) == -1)
|
||||
{
|
||||
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, opening pipe");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fork for curl
|
||||
pid_curl = fork();
|
||||
if (pid_curl == -1)
|
||||
{
|
||||
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, fork (curl)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pid_curl == 0)
|
||||
{ // Child process (curl)
|
||||
close(pipe_curl_to_bash[0]);
|
||||
dup2(pipe_curl_to_bash[1], STDOUT_FILENO);
|
||||
close(pipe_curl_to_bash[1]);
|
||||
execvp("curl", curl_args);
|
||||
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, execvp (curl)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fork for bash
|
||||
pid_bash = fork();
|
||||
if (pid_bash == -1)
|
||||
{
|
||||
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, fork (bash)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pid_bash == 0)
|
||||
{ // Child process (bash)
|
||||
close(pipe_curl_to_bash[1]);
|
||||
dup2(pipe_curl_to_bash[0], STDIN_FILENO);
|
||||
close(pipe_curl_to_bash[0]);
|
||||
execvp("bash", bash_args);
|
||||
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, execvp (bash)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parent process
|
||||
close(pipe_curl_to_bash[0]);
|
||||
close(pipe_curl_to_bash[1]);
|
||||
|
||||
// Wait for curl and get its exit status
|
||||
if (waitpid(pid_curl, &status_curl, 0) == -1)
|
||||
{
|
||||
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, waitpid (curl)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for bash and get its exit status
|
||||
if (waitpid(pid_bash, &status_bash, 0) == -1)
|
||||
{
|
||||
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, waitpid (bash)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the exit status of curl
|
||||
if (WIFEXITED(status_curl))
|
||||
{
|
||||
//printf("curl exited with status: %d\n", WEXITSTATUS(status_curl));
|
||||
if (WEXITSTATUS(status_curl) != 0) {
|
||||
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, curl exited with status: %d\n", WEXITSTATUS(status_curl));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (WIFSIGNALED(status_curl))
|
||||
{
|
||||
//printf("curl terminated by signal: %d\n", WTERMSIG(status_curl));
|
||||
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, curl terminated by signal: %d\n", WTERMSIG(status_curl));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the exit status of bash
|
||||
if (WIFEXITED(status_bash))
|
||||
{
|
||||
//printf("bash exited with status: %d\n", WEXITSTATUS(status_bash));
|
||||
if (WEXITSTATUS(status_bash) != 0) {
|
||||
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, bash exited with status: %d\n", WEXITSTATUS(status_bash));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (WIFSIGNALED(status_bash))
|
||||
{
|
||||
//printf("bash terminated by signal: %d\n", WTERMSIG(status_bash));
|
||||
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, bash terminated by signal: %d\n", WTERMSIG(status_bash));
|
||||
return false;
|
||||
}
|
||||
|
||||
//printf("Command execution complete.\n");
|
||||
LOG(AQUA_LOG, LOG_NOTICE, "AqualinkD is upgrading!");
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef AQ_FILESYSTEM_H_
|
||||
#define AQ_FILESYSTEM_H_
|
||||
|
||||
|
||||
FILE *aq_open_file( char *filename, bool *ro_root, bool* created_file);
|
||||
bool aq_close_file(FILE *file, bool ro_root);
|
||||
bool copy_file(const char *source_path, const char *destination_path);
|
||||
bool run_aqualinkd_upgrade(bool onlycheck);
|
||||
|
||||
|
||||
|
||||
#endif //AQ_FILESYSTEM_H_
|
|
@ -16,6 +16,7 @@ struct timerthread {
|
|||
pthread_mutex_t thread_mutex;
|
||||
pthread_cond_t thread_cond;
|
||||
aqkey *button;
|
||||
int deviceIndex;
|
||||
struct aqualinkdata *aq_data;
|
||||
int duration_min;
|
||||
struct timespec timeout;
|
||||
|
@ -56,9 +57,10 @@ int get_timer_left(aqkey *button)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void clear_timer(struct aqualinkdata *aq_data, aqkey *button)
|
||||
void clear_timer(struct aqualinkdata *aq_data, /*aqkey *button,*/ int deviceIndex)
|
||||
{
|
||||
struct timerthread *t_ptr = find_timerthread(button);
|
||||
//struct timerthread *t_ptr = find_timerthread(button);
|
||||
struct timerthread *t_ptr = find_timerthread(&aq_data->aqbuttons[deviceIndex]);
|
||||
|
||||
if (t_ptr != NULL) {
|
||||
LOG(TIMR_LOG, LOG_INFO, "Clearing timer for '%s'\n",t_ptr->button->name);
|
||||
|
@ -67,8 +69,9 @@ void clear_timer(struct aqualinkdata *aq_data, aqkey *button)
|
|||
}
|
||||
}
|
||||
|
||||
void start_timer(struct aqualinkdata *aq_data, aqkey *button, int duration)
|
||||
void start_timer(struct aqualinkdata *aq_data, /*aqkey *button,*/ int deviceIndex, int duration)
|
||||
{
|
||||
aqkey *button = &aq_data->aqbuttons[deviceIndex];
|
||||
struct timerthread *t_ptr = find_timerthread(button);
|
||||
|
||||
if (t_ptr != NULL) {
|
||||
|
@ -77,26 +80,15 @@ void start_timer(struct aqualinkdata *aq_data, aqkey *button, int duration)
|
|||
pthread_cond_broadcast(&t_ptr->thread_cond);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
struct timerthread *t_ptr;
|
||||
|
||||
if (_timerthread_ll != NULL) {
|
||||
for (t_ptr = _timerthread_ll; t_ptr != NULL; t_ptr = t_ptr->next) {
|
||||
if (t_ptr->button == button) {
|
||||
LOG(TIMR_LOG, LOG_INFO, "already active for '%s', resetting\n",t_ptr->button->name);
|
||||
t_ptr->duration_min = duration;
|
||||
pthread_cond_broadcast(&t_ptr->thread_cond);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
struct timerthread *tmthread = calloc(1, sizeof(struct timerthread));
|
||||
tmthread->aq_data = aq_data;
|
||||
tmthread->button = button;
|
||||
tmthread->deviceIndex = deviceIndex;
|
||||
tmthread->thread_id = 0;
|
||||
tmthread->duration_min = duration;
|
||||
tmthread->next = NULL;
|
||||
tmthread->started_at = time(0); // This will get reset once we actually start. But need it here incase someone calls get_timer_left() before we start
|
||||
|
||||
if( pthread_create( &tmthread->thread_id , NULL , timer_worker, (void*)tmthread) < 0) {
|
||||
LOG(TIMR_LOG, LOG_ERR, "could not create timer thread for button '%s'\n",button->name);
|
||||
|
@ -122,19 +114,22 @@ void start_timer(struct aqualinkdata *aq_data, aqkey *button, int duration)
|
|||
}
|
||||
}
|
||||
|
||||
#define WAIT_TIME_BEFORE_ON_CHECK 1000 // 1 second
|
||||
#define WAIT_TIME_BEFORE_ON_CHECK 1000
|
||||
//#define WAIT_TIME_BEFORE_ON_CHECK 1000000 // 1 second
|
||||
|
||||
void *timer_worker( void *ptr )
|
||||
{
|
||||
struct timerthread *tmthread;
|
||||
tmthread = (struct timerthread *) ptr;
|
||||
int retval = 0;
|
||||
int cnt=0;
|
||||
|
||||
LOG(TIMR_LOG, LOG_NOTICE, "Start timer for '%s'\n",tmthread->button->name);
|
||||
|
||||
// Add mask so we know timer is active
|
||||
tmthread->button->special_mask |= TIMER_ACTIVE;
|
||||
|
||||
/*
|
||||
#ifndef PRESTATE_ONOFF
|
||||
delay(WAIT_TIME_BEFORE_ON_CHECK);
|
||||
LOG(TIMR_LOG, LOG_DEBUG, "wait finished for button state '%s'\n",tmthread->button->name);
|
||||
|
@ -145,9 +140,21 @@ void *timer_worker( void *ptr )
|
|||
if ((tmthread->button->special_mask & PROGRAM_LIGHT) == PROGRAM_LIGHT && in_light_programming_mode(tmthread->aq_data)) {
|
||||
LOG(TIMR_LOG, LOG_NOTICE, "Not turning on '%s' as programmer is\n",tmthread->button->name);
|
||||
} else {
|
||||
// crap way to do this, need to use net_service logic in teh future, but should never actually get here
|
||||
LOG(TIMR_LOG, LOG_NOTICE, "turning on '%s'\n",tmthread->button->name);
|
||||
aq_send_cmd(tmthread->button->code);
|
||||
panel_device_request(tmthread->aq_data, ON_OFF, tmthread->deviceIndex, false, NET_TIMER);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
while (tmthread->button->led->state == OFF) {
|
||||
LOG(TIMR_LOG, LOG_DEBUG, "waiting for button state '%s' to change\n",tmthread->button->name);
|
||||
delay(WAIT_TIME_BEFORE_ON_CHECK);
|
||||
if (cnt++ == 5 && !isPDA_PANEL) {
|
||||
LOG(TIMR_LOG, LOG_NOTICE, "turning on '%s'\n",tmthread->button->name);
|
||||
panel_device_request(tmthread->aq_data, ON_OFF, tmthread->deviceIndex, true, NET_TIMER);
|
||||
} else if (cnt == 10) {
|
||||
LOG(TIMR_LOG, LOG_ERR, "button state never turned on'%s'\n",tmthread->button->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,17 +179,24 @@ void *timer_worker( void *ptr )
|
|||
|
||||
LOG(TIMR_LOG, LOG_NOTICE, "End timer for '%s'\n",tmthread->button->name);
|
||||
|
||||
if (tmthread->button->led->state != OFF) {
|
||||
LOG(TIMR_LOG, LOG_INFO, "Timer waking turning '%s' off\n",tmthread->button->name);
|
||||
#ifdef AQ_PDA
|
||||
if (isPDA_PANEL)
|
||||
create_PDA_on_off_request(tmthread->button, false);
|
||||
else
|
||||
#endif
|
||||
aq_send_cmd(tmthread->button->code);
|
||||
} else {
|
||||
// We need to detect if we ended on time or were killed.
|
||||
// If killed the device is probable off (or being set to off), so we should probably poll a few times before turning off.
|
||||
// Either that of change ap_panel to not turn off device if timer is set.
|
||||
|
||||
//LOG(TIMR_LOG, LOG_NOTICE, "End timer duration '%d'\n",tmthread->duration_min);
|
||||
|
||||
// if duration_min is 0 we were killed, if not we got here on timeout, so turn off device.
|
||||
|
||||
if (tmthread->duration_min != 0 && tmthread->button->led->state != OFF) {
|
||||
LOG(TIMR_LOG, LOG_INFO, "Timer waking turning '%s' off\n",tmthread->button->name);
|
||||
panel_device_request(tmthread->aq_data, ON_OFF, tmthread->deviceIndex, false, NET_TIMER);
|
||||
} else if (tmthread->button->led->state == OFF) {
|
||||
LOG(TIMR_LOG, LOG_INFO, "Timer waking '%s' is already off\n",tmthread->button->name);
|
||||
}
|
||||
|
||||
if (tmthread->button->led->state != OFF) {
|
||||
// Need to wait
|
||||
}
|
||||
|
||||
// remove mask so we know timer is dead
|
||||
tmthread->button->special_mask &= ~ TIMER_ACTIVE;
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
#include "aqualink.h"
|
||||
|
||||
void start_timer(struct aqualinkdata *aq_data, aqkey *button, int duration);
|
||||
void start_timer(struct aqualinkdata *aq_data, /*aqkey *button,*/ int deviceIndex, int duration);
|
||||
int get_timer_left(aqkey *button);
|
||||
void clear_timer(struct aqualinkdata *aq_data, aqkey *button);
|
||||
void clear_timer(struct aqualinkdata *aq_data, /*aqkey *button,*/ int deviceIndex);
|
||||
// Not best place for this, but leave it here so all requests are in net services, this is forward decleration of function in net_services.c
|
||||
#ifdef AQ_PDA
|
||||
void create_PDA_on_off_request(aqkey *button, bool isON);
|
|
@ -7,10 +7,15 @@
|
|||
#include <stdint.h>
|
||||
#include "aq_serial.h"
|
||||
#include "aq_programmer.h"
|
||||
#include "sensors.h"
|
||||
//#include "aq_panel.h" // Moved to later in file to overcome circular dependancy. (crappy I know)
|
||||
|
||||
#define isMASK_SET(bitmask, mask) ((bitmask & mask) == mask)
|
||||
#define setMASK(bitmask, mask) (bitmask |= mask)
|
||||
#define removeMASK(bitmask, mask) (bitmask &= ~mask)
|
||||
|
||||
#define SIGRESTART SIGUSR1
|
||||
#define SIGRESTART SIGUSR1
|
||||
#define SIGRUPGRADE SIGUSR2
|
||||
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
#define DEFAULT_POLL_SPEED -1
|
||||
|
@ -18,6 +23,8 @@
|
|||
#endif
|
||||
|
||||
|
||||
#define CLIGHT_PANEL_FIX // Overcome bug in some jandy panels where color light status of on is not in LED status
|
||||
|
||||
#define TIME_CHECK_INTERVAL 3600
|
||||
//#define TIME_CHECK_INTERVAL 100 // DEBUG ONLY
|
||||
#define ACCEPTABLE_TIME_DIFF 120
|
||||
|
@ -33,16 +40,19 @@
|
|||
|
||||
// The below will change state of devices before that are actually set on the control panel, this helps
|
||||
// with duplicate messages that come in quick succession that can catch the state before it happens.
|
||||
#define PRESTATE_ONOFF
|
||||
//#define PRESTATE_ONOFF
|
||||
#define PRESTATE_SWG_SETPOINT
|
||||
//#define PRESTATE_HEATER_SETPOINT // This one is not implimented yet
|
||||
|
||||
void intHandler(int dummy);
|
||||
|
||||
bool isAqualinkDStopping();
|
||||
|
||||
#ifdef AQ_PDA
|
||||
bool checkAqualinkTime(); // Only need to externalise this for PDA
|
||||
#endif
|
||||
// There are cases where SWG will read 80% in allbutton and 0% in onetouch/aqualinktouch, this will compile that in or our
|
||||
|
||||
// There are cases where SWG will read 80% in allbutton and 0% in onetouch/aqualinktouch, this will compile that in or out
|
||||
//#define READ_SWG_FROM_EXTENDED_ID
|
||||
|
||||
//#define TOTAL_BUTTONS 12
|
||||
|
@ -57,11 +67,22 @@ bool checkAqualinkTime(); // Only need to externalise this for PDA
|
|||
*/
|
||||
#define TEMP_UNKNOWN -999
|
||||
#define TEMP_REFRESH -998
|
||||
|
||||
#define AQ_UNKNOWN TEMP_UNKNOWN
|
||||
//#define UNKNOWN TEMP_UNKNOWN
|
||||
#define DATE_STRING_LEN 30
|
||||
|
||||
#define MAX_PUMPS 4
|
||||
#define MAX_LIGHTS 4
|
||||
#define MAX_SENSORS 4
|
||||
|
||||
bool isVirtualButtonEnabled();
|
||||
|
||||
#define PUMP_RPM_MAX 3450
|
||||
#define PUMP_RPM_MIN 600
|
||||
#define PUMP_GPM_MAX 130
|
||||
#define PUMP_GPM_MIN 15
|
||||
|
||||
|
||||
enum {
|
||||
FAHRENHEIT,
|
||||
|
@ -80,16 +101,21 @@ typedef struct aqualinkkey
|
|||
// char *pda_label;
|
||||
//#endif
|
||||
unsigned char code;
|
||||
unsigned char rssd_code;
|
||||
int dz_idx;
|
||||
uint8_t special_mask;
|
||||
void *special_mask_ptr;
|
||||
} aqkey;
|
||||
|
||||
// special_mask for above aqualinkkey structure.
|
||||
#define VS_PUMP (1 << 0)
|
||||
#define PROGRAM_LIGHT (1 << 1)
|
||||
#define TIMER_ACTIVE (1 << 2)
|
||||
//#define DIMMER_LIGHT (1 << 3) // NOT USED YET
|
||||
|
||||
//#define DIMMER_LIGHT (1 << 3) // NOT USED (Use PROGRAM_LIGHT or type LC_DIMMER)
|
||||
#define VIRTUAL_BUTTON (1 << 4)
|
||||
// Below are types of VIRT_BUTTON, SO VIRT_BUTTON must also be set
|
||||
#define VIRTUAL_BUTTON_ALT_LABEL (1 << 5)
|
||||
#define VIRTUAL_BUTTON_CHILLER (1 << 6)
|
||||
//typedef struct ProgramThread ProgramThread; // Definition is later
|
||||
|
||||
struct programmingthread {
|
||||
|
@ -100,13 +126,24 @@ struct programmingthread {
|
|||
//void *thread_args;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
typedef enum panel_status {
|
||||
CONNECTED,
|
||||
CHECKING_CONFIG,
|
||||
CONECTING,
|
||||
LOOKING_IDS,
|
||||
STARTING,
|
||||
SERIAL_ERROR, // Errors that stop reading serial port should be below this line
|
||||
NO_IDS_ERROR,
|
||||
} panel_status;
|
||||
*/
|
||||
|
||||
typedef enum action_type {
|
||||
NO_ACTION = -1,
|
||||
POOL_HTR_SETOINT,
|
||||
SPA_HTR_SETOINT,
|
||||
POOL_HTR_SETPOINT,
|
||||
SPA_HTR_SETPOINT,
|
||||
FREEZE_SETPOINT,
|
||||
CHILLER_SETPOINT,
|
||||
SWG_SETPOINT,
|
||||
SWG_BOOST,
|
||||
PUMP_RPM,
|
||||
|
@ -116,6 +153,7 @@ typedef enum action_type {
|
|||
ON_OFF,
|
||||
TIMER,
|
||||
LIGHT_MODE,
|
||||
LIGHT_BRIGHTNESS,
|
||||
DATE_TIME
|
||||
} action_type;
|
||||
|
||||
|
@ -137,25 +175,78 @@ typedef enum pump_type {
|
|||
} pump_type;
|
||||
*/
|
||||
|
||||
#define PUMP_PRIMING -1
|
||||
#define PUMP_OFFLINE -2
|
||||
#define PUMP_ERROR -3
|
||||
/*
|
||||
typedef enum simulator_type {
|
||||
SIM_NONE,
|
||||
SIM_ALLB,
|
||||
SIM_ONET,
|
||||
SIM_PDA,
|
||||
SIM_IAQT
|
||||
} simulator_type;
|
||||
*/
|
||||
|
||||
// Set Point types
|
||||
typedef enum SP_TYPE{
|
||||
SP_POOL,
|
||||
SP_SPA,
|
||||
SP_CHILLER
|
||||
} SP_TYPE;
|
||||
|
||||
//#define PUMP_PRIMING -1
|
||||
//#define PUMP_OFFLINE -2
|
||||
//#define PUMP_ERROR -3
|
||||
#define PUMP_OFF_RPM 0
|
||||
#define PUMP_OFF_GPM PUMP_OFF_RPM
|
||||
#define PUMP_OFF_WAT PUMP_OFF_RPM
|
||||
|
||||
|
||||
// FUTURE VSP STATUS, keep panel status and RS485 status seperate
|
||||
|
||||
typedef enum panel_vsp_status
|
||||
{
|
||||
PS_OK = 0, // Start at 0 to match actual status from RS, but go down from their.
|
||||
PS_OFF = -1,
|
||||
PS_PRIMING = -2,
|
||||
PS_OFFLINE = -3,
|
||||
PS_ERROR = -4
|
||||
} panel_vsp_status;
|
||||
|
||||
#define PUMP_NAME_LENGTH 30
|
||||
|
||||
// Overall Status of Aqualinkd
|
||||
|
||||
#define CONNECTED ( 1 << 0 ) // All is good (every other mask should be cleared)
|
||||
#define NOT_CONNECTED ( 1 << 2 ) // Serial Error maybe rename
|
||||
#define AUTOCONFIGURE_ID ( 1 << 3 )
|
||||
#define AUTOCONFIGURE_PANEL ( 1 << 4 )
|
||||
#define CHECKING_CONFIG ( 1 << 5 )
|
||||
//#define LOOKING_IDS ( 1 << 6 )
|
||||
#define CONNECTING ( 1 << 7 )
|
||||
#define ERROR_NO_DEVICE_ID ( 1 << 8 ) // maybe covered in NOT_CONNECTED
|
||||
#define ERROR_SERIAL ( 1 << 9 )
|
||||
|
||||
typedef struct pumpd
|
||||
{
|
||||
int rpm;
|
||||
int gpm;
|
||||
int watts;
|
||||
int maxSpeed; // Max rpm or gpm depending on pump
|
||||
int minSpeed;
|
||||
unsigned char pumpID;
|
||||
int pumpIndex;
|
||||
char pumpName[PUMP_NAME_LENGTH];
|
||||
//char *pumpName;
|
||||
pump_type pumpType;
|
||||
//int buttonID;
|
||||
protocolType prclType;
|
||||
aqkey *button;
|
||||
//bool updated;
|
||||
// Other VSP values read directly from RS485
|
||||
int mode; // 0 local control, 1 remote control
|
||||
//int driveState; // Haven't figured out what this is yet
|
||||
int status;
|
||||
panel_vsp_status pStatus; // FUTURE VSP STATUS,
|
||||
int pressureCurve;
|
||||
} pump_detail;
|
||||
|
||||
// color light modes (Aqualink program, Jandy, Jandy LED, SAm/SAL, Color Logic, Intellibrite)
|
||||
|
@ -166,20 +257,47 @@ typedef enum clight_type {
|
|||
LC_SAL,
|
||||
LC_CLOGIG,
|
||||
LC_INTELLIB,
|
||||
LC_DIMMER,
|
||||
LC_HAYWCL,
|
||||
LC_SPARE_1,
|
||||
LC_SPARE_2,
|
||||
LC_SPARE_3,
|
||||
LC_DIMMER, // use 0, 25, 50, 100
|
||||
LC_DIMMER2, // use range 0 to 100
|
||||
NUMBER_LIGHT_COLOR_TYPES // This is used to size and count so add more prior to this
|
||||
} clight_type;
|
||||
|
||||
/*
|
||||
typedef enum {
|
||||
MD_CHILLER,
|
||||
MD_HEATPUMP
|
||||
} heatmump_mode;
|
||||
*/
|
||||
typedef struct vbuttond
|
||||
{
|
||||
char *altlabel;
|
||||
bool in_alt_mode; // Example if altlabel="chiller", if last seen was chiller message this is true.
|
||||
//heatmump_mode chiller_mode;
|
||||
// Add any other special params for virtual button
|
||||
} vbutton_detail;
|
||||
|
||||
typedef enum {
|
||||
NET_MQTT=0,
|
||||
NET_API,
|
||||
NET_WS,
|
||||
NET_DZMQTT} request_source;
|
||||
NET_DZMQTT,
|
||||
NET_TIMER, // Timer or Scheduler (eg poweron/freezeprotect check)
|
||||
UNACTION_TIMER
|
||||
} request_source;
|
||||
|
||||
|
||||
|
||||
typedef struct clightd
|
||||
{
|
||||
clight_type lightType;
|
||||
aqkey *button;
|
||||
int currentValue;
|
||||
int lastValue; // Used for AqualinkD self programming
|
||||
aqledstate RSSDstate; // state from rs serial adapter
|
||||
} clight_detail;
|
||||
|
||||
|
||||
|
@ -188,14 +306,26 @@ typedef struct clightd
|
|||
|
||||
struct aqualinkdata
|
||||
{
|
||||
char version[AQ_MSGLEN*2];
|
||||
//panel_status panelstatus;
|
||||
uint16_t status_mask;
|
||||
char version[AQ_MSGLEN*2]; // Will be replaced by below in future
|
||||
char revision[AQ_MSGLEN]; // Will be replaced by below in future
|
||||
|
||||
// The below 4 are set (sometimes) but not used yet
|
||||
char panel_rev[AQ_MSGLEN]; // From panel
|
||||
char panel_cpu[AQ_MSGLEN]; // From panel
|
||||
char panel_string[AQ_MSGLEN]; // This is from actual PANEL not aqualinkd's config
|
||||
uint16_t panel_support_options;
|
||||
|
||||
char date[AQ_MSGLEN];
|
||||
char time[AQ_MSGLEN];
|
||||
char last_message[AQ_MSGLONGLEN+1]; // Last ascii message from panel - allbutton (or PDA) protocol
|
||||
char last_display_message[AQ_MSGLONGLEN+1]; // Last message to display in web UI
|
||||
bool is_display_message_programming;
|
||||
aqled aqualinkleds[TOTAL_LEDS];
|
||||
aqkey aqbuttons[TOTAL_BUTTONS];
|
||||
unsigned short total_buttons;
|
||||
unsigned short virtual_button_start;
|
||||
int air_temp;
|
||||
int pool_temp;
|
||||
int spa_temp;
|
||||
|
@ -207,16 +337,23 @@ struct aqualinkdata
|
|||
int spa_htr_set_point;
|
||||
int swg_percent;
|
||||
int swg_ppm;
|
||||
int chiller_set_point;
|
||||
aqkey *chiller_button;
|
||||
//heatmump_mode chiller_mode;
|
||||
unsigned char ar_swg_device_status; // Actual state
|
||||
unsigned char heater_err_status;
|
||||
aqledstate swg_led_state; // Display state for UI's
|
||||
aqledstate service_mode_state;
|
||||
aqledstate frz_protect_state;
|
||||
//aqledstate chiller_state;
|
||||
int num_pumps;
|
||||
pump_detail pumps[MAX_PUMPS];
|
||||
int num_lights;
|
||||
clight_detail lights[MAX_LIGHTS];
|
||||
bool boost;
|
||||
char boost_msg[10];
|
||||
int boost_duration; // need to remove boost message and use this
|
||||
int boost_linked_device;
|
||||
float ph;
|
||||
int orp;
|
||||
|
||||
|
@ -225,7 +362,16 @@ struct aqualinkdata
|
|||
//unsigned short total_ordered_buttons;
|
||||
unsigned char last_packet_type;
|
||||
int swg_delayed_percent;
|
||||
bool simulate_panel;
|
||||
//bool simulate_panel; // NSF remove in future
|
||||
unsigned char simulator_packet[AQ_MAXPKTLEN+1];
|
||||
bool simulator_packet_updated;
|
||||
int simulator_packet_length;
|
||||
|
||||
//bool simulator_active; // should be redundant with other two
|
||||
unsigned char simulator_id;
|
||||
//simulator_type simulator_active;
|
||||
emulation_type simulator_active;
|
||||
|
||||
bool aqManagerActive;
|
||||
int open_websockets;
|
||||
struct programmingthread active_thread;
|
||||
|
@ -233,11 +379,22 @@ struct aqualinkdata
|
|||
unsigned char raw_status[AQ_PSTLEN];
|
||||
// Multiple threads update this value.
|
||||
volatile bool updated;
|
||||
char self[AQ_MSGLEN*2];
|
||||
|
||||
int num_sensors;
|
||||
external_sensor sensors[MAX_SENSORS];
|
||||
|
||||
#ifdef AQ_MANAGER
|
||||
volatile bool run_slogger;
|
||||
int slogger_packets;
|
||||
bool slogger_debug;
|
||||
char slogger_ids[20];
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef AQ_RS16
|
||||
int rs16_vbutton_start;
|
||||
int rs16_vbutton_end;
|
||||
#endif
|
||||
|
||||
#ifdef AQ_PDA
|
||||
int pool_heater_index;
|
||||
int spa_heater_index;
|
||||
|
@ -248,7 +405,12 @@ struct aqualinkdata
|
|||
struct timespec last_active_time;
|
||||
struct timespec start_active_time;
|
||||
#endif
|
||||
|
||||
// Overcome color light bug, by reconnecting allbutton panel.
|
||||
//bool reconnectAllButton;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,346 @@
|
|||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
//#define COLOR_LIGHTS_C_
|
||||
#include "color_lights.h"
|
||||
|
||||
|
||||
/*
|
||||
Jandy Colors
|
||||
Jandy LED Light
|
||||
Sam/SL
|
||||
Color Logic
|
||||
Intelibright
|
||||
Haywood Universal Color
|
||||
|
||||
*/
|
||||
bool isShowMode(const char *mode);
|
||||
|
||||
|
||||
/****** This list MUST be in order of clight_type enum *******/
|
||||
char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] =
|
||||
//char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] =
|
||||
{
|
||||
// AqualnkD Colors ignored as no names in control panel.
|
||||
{ "Off", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18" },
|
||||
{ // Jandy Color
|
||||
"Off",
|
||||
"Alpine White", // 0x41
|
||||
"Sky Blue",
|
||||
"Cobalt Blue",
|
||||
"Caribbean Blue",
|
||||
"Spring Green",
|
||||
"Emerald Green",
|
||||
"Emerald Rose",
|
||||
"Magenta",
|
||||
"Garnet Red",
|
||||
"Violet",
|
||||
"Color Splash"
|
||||
},
|
||||
{ // Jandy LED
|
||||
"Off",
|
||||
"Alpine White",
|
||||
"Sky Blue",
|
||||
"Cobalt Blue",
|
||||
"Caribbean Blue",
|
||||
"Spring Green",
|
||||
"Emerald Green",
|
||||
"Emerald Rose",
|
||||
"Magenta",
|
||||
"Violet",
|
||||
"Slow Splash",
|
||||
"Fast Splash",
|
||||
"USA",
|
||||
"Fat Tuesday",
|
||||
"Disco Tech"
|
||||
},
|
||||
{ // SAm/SAL
|
||||
"Off",
|
||||
"White",
|
||||
"Light Green",
|
||||
"Green",
|
||||
"Cyan",
|
||||
"Blue",
|
||||
"Lavender",
|
||||
"Magenta"
|
||||
},
|
||||
{ // Color Logic
|
||||
"Off",
|
||||
"Voodoo Lounge", // 0x41 (both home and sim)
|
||||
"Deep Blue Sea", // 0x42 (both gome and sim)
|
||||
"Afternoon Skies", // 0x44 home // 0x43 sim // 'Afternoon Sky' on allbutton, Skies on iaqtouch
|
||||
"Emerald", // 0x44
|
||||
"Sangria",
|
||||
"Cloud White", // 0x46
|
||||
"Twilight", // 0x4c (home panel) // 0x47
|
||||
"Tranquility", // 0x4d (home panel) // 0x48
|
||||
"Gemstone", // 0x4e (home panel) // 0x49 (simulator)
|
||||
"USA", // 0x4f (home panel) // 0x4a (simulator)
|
||||
"Mardi Gras", // 0x50 (home panel) // 0x4b (simulator)
|
||||
"Cool Cabaret" // 0x51 (home panel) // 0x4c
|
||||
},
|
||||
{ // IntelliBrite
|
||||
"Off",
|
||||
"SAm",
|
||||
"Party",
|
||||
"Romance",
|
||||
"Caribbean",
|
||||
"American",
|
||||
"Cal Sunset",
|
||||
"Royal",
|
||||
"Blue",
|
||||
"Green",
|
||||
"Red",
|
||||
"White",
|
||||
"Magenta"
|
||||
},
|
||||
{ // Haywood Universal Color
|
||||
"Off",
|
||||
"Voodoo Lounge", // 0x41 (both home and sim) // Looks like 28 + <value or index> = 0x41 = 1st index
|
||||
"Deep Blue Sea", // 0x42 (both gome and sim)
|
||||
"Royal Blue", // // 0x43 home // non
|
||||
"Afternoon Skies", // 0x44 home // 0x43 sim // 'Afternoon Sky' on allbutton, Skies on iaqtouch
|
||||
"Aqua Green", //
|
||||
"Emerald", // 0x44
|
||||
"Cloud White", // 0x46
|
||||
"Warm Red", //
|
||||
"Flamingo", //
|
||||
"Vivid Violet", //
|
||||
"Sangria", // 0x4b (home panel) // Non existant
|
||||
"Twilight", // 0x4c (home panel) // 0x47
|
||||
"Tranquility", // 0x4d (home panel) // 0x48
|
||||
"Gemstone", // 0x4e (home panel) // 0x49 (simulator)
|
||||
"USA", // 0x4f (home panel) // 0x4a (simulator)
|
||||
"Mardi Gras", // 0x50 (home panel) // 0x4b (simulator)
|
||||
"Cool Cabaret" // 0x51 (home panel) // 0x4c
|
||||
},
|
||||
{/*Spare 1*/},
|
||||
{/*Spare 2*/},
|
||||
{/*Spare 3*/},
|
||||
{ // Dimmer // From manual this is 0 for off, 128+<value%> so 153 = 25% = 0x99
|
||||
"Off",
|
||||
"25%", // 0x99 (simulator) = 153 dec
|
||||
"50%", // 0xb2 (simulator) = 178 dec same as (0x99 + 25)
|
||||
"75%", // 0xcb (simulator) = 203 dec
|
||||
"100%" // 0xe4 = 228 dec
|
||||
},
|
||||
{/* Dimmer with full range */}
|
||||
};
|
||||
|
||||
// DON'T FORGET TO CHANGE #define DIMMER_LIGHT_INDEX 10 in color_lights.h
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void deleteLightOption(int type, int index)
|
||||
{
|
||||
int arrlen = LIGHT_COLOR_OPTIONS;
|
||||
memmove(_color_light_options[type]+index, _color_light_options[type]+index+1, (--arrlen - index) * sizeof *_color_light_options[type]);
|
||||
}
|
||||
|
||||
void setColorLightsPanelVersion(uint8_t supported)
|
||||
{
|
||||
static bool set = false;
|
||||
if (set)
|
||||
return;
|
||||
|
||||
if ((supported & REP_SUP_CLIT4) == REP_SUP_CLIT4)
|
||||
return; // Full panel support, no need to delete anything
|
||||
|
||||
//deleteLightOption(4, 11); // Color Logic "Sangria"
|
||||
deleteLightOption(4, 9); // Color Logic "Vivid Violet",
|
||||
deleteLightOption(4, 8); // Color Logic "Flamingo"
|
||||
deleteLightOption(4, 7); // Color Logic "Warm Red",
|
||||
deleteLightOption(4, 4); // Color Logic "Aqua Green"
|
||||
deleteLightOption(4, 2); // Color Logic "Royal Blue"
|
||||
|
||||
set = true;
|
||||
}
|
||||
*/
|
||||
void clear_aqualinkd_light_modes()
|
||||
{
|
||||
//_color_light_options[0] = _aqualinkd_custom_colors;
|
||||
|
||||
for (int i=0; i < LIGHT_COLOR_OPTIONS; i++) {
|
||||
_color_light_options[0][i] = NULL;
|
||||
//_color_light_options[0][i] = i;
|
||||
//_color_light_options[0][i] = _aqualinkd_custom_colors[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool set_aqualinkd_light_mode_name(char *name, int index, bool isShow)
|
||||
{
|
||||
static bool reset = false;
|
||||
|
||||
// Reset all options only once.
|
||||
if (!reset) {
|
||||
reset = true;
|
||||
for (int i=1; i<LIGHT_COLOR_OPTIONS; i++) {
|
||||
_color_light_options[0][i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO NSF check isShow and add a custom one if needed
|
||||
_color_light_options[0][index] = name;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *get_aqualinkd_light_mode_name(int index, bool *isShow)
|
||||
{
|
||||
// if index 1 is "1" then none are set.
|
||||
if ( _color_light_options[0][1] == NULL || strcmp(_color_light_options[0][1], "1") == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*isShow = isShowMode(_color_light_options[0][index]);
|
||||
return _color_light_options[0][index];
|
||||
}
|
||||
|
||||
const char *get_currentlight_mode_name(clight_detail light, emulation_type protocol)
|
||||
{
|
||||
/*
|
||||
if (light.lightType == LC_PROGRAMABLE && light.button->led->state == OFF) {
|
||||
return "Off";
|
||||
}
|
||||
*/
|
||||
|
||||
// Programmable light that's on but no mode, just return blank
|
||||
if (light.lightType == LC_PROGRAMABLE && light.button->led->state == ON && light.currentValue == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (light.currentValue < 0 || light.currentValue > LIGHT_COLOR_OPTIONS ){
|
||||
return "";
|
||||
}
|
||||
|
||||
if (_color_light_options[light.lightType][light.currentValue] == NULL) {
|
||||
return "";
|
||||
}
|
||||
// Rename any modes depending on emulation type
|
||||
if (protocol == ALLBUTTON) {
|
||||
if (strcmp(_color_light_options[light.lightType][light.currentValue],"Afternoon Skies") == 0) {
|
||||
return "Afternoon Sky";
|
||||
}
|
||||
}
|
||||
|
||||
return _color_light_options[light.lightType][light.currentValue];
|
||||
}
|
||||
|
||||
// This should not be uses for getting current lightmode name since it doesn;t have full logic
|
||||
|
||||
const char *light_mode_name(clight_type type, int index, emulation_type protocol)
|
||||
{
|
||||
if (index < 0 || index > LIGHT_COLOR_OPTIONS ){
|
||||
return "";
|
||||
}
|
||||
|
||||
if (_color_light_options[type][index] == NULL) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Rename any modes depending on emulation type
|
||||
if (protocol == ALLBUTTON) {
|
||||
if (strcmp(_color_light_options[type][index],"Afternoon Skies") == 0) {
|
||||
return "Afternoon Sky";
|
||||
}
|
||||
}
|
||||
|
||||
return _color_light_options[type][index];
|
||||
}
|
||||
|
||||
|
||||
bool isShowMode(const char *mode)
|
||||
{
|
||||
if (mode == NULL)
|
||||
return false;
|
||||
|
||||
if (strcmp(mode, "Color Splash") == 0 ||
|
||||
strcmp(mode, "Slow Splash") == 0 ||
|
||||
strcmp(mode, "Fast Splash") == 0 ||
|
||||
strcmp(mode, "Fat Tuesday") == 0 ||
|
||||
strcmp(mode, "Disco Tech") == 0 ||
|
||||
strcmp(mode, "Voodoo Lounge") == 0 ||
|
||||
strcmp(mode, "Twilight") == 0 ||
|
||||
strcmp(mode, "Tranquility") == 0 ||
|
||||
strcmp(mode, "Gemstone") == 0 ||
|
||||
strcmp(mode, "USA") == 0 ||
|
||||
strcmp(mode, "Mardi Gras") == 0 ||
|
||||
strcmp(mode, "Cool Cabaret") == 0 ||
|
||||
strcmp(mode, "SAm") == 0 ||
|
||||
strcmp(mode, "Party") == 0 ||
|
||||
strcmp(mode, "Romance") == 0 ||
|
||||
strcmp(mode, "Caribbean") == 0 ||
|
||||
strcmp(mode, "American") == 0 ||
|
||||
strcmp(mode, "Cal Sunset") == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void set_currentlight_value(clight_detail *light, int index)
|
||||
{
|
||||
// Dimmer 2 has different values (range 1 to 100)
|
||||
if (light->lightType == LC_DIMMER2) {
|
||||
if (index < 0 || index > 100)
|
||||
light->currentValue = 0;
|
||||
else
|
||||
light->currentValue = index;
|
||||
} else {
|
||||
// We want to leave the last color, so if 0 don't do anything, but set to 0 if bad value
|
||||
if (index <= 0 || index > LIGHT_COLOR_OPTIONS) {
|
||||
light->currentValue = 0;
|
||||
} else if (index > 0 && index < LIGHT_COLOR_OPTIONS) {
|
||||
light->currentValue = index;
|
||||
//light->lastValue = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used for dynamic config JS
|
||||
int build_color_lights_js(struct aqualinkdata *aqdata, char* buffer, int size)
|
||||
{
|
||||
memset(&buffer[0], 0, size);
|
||||
int length = 0;
|
||||
int i, j;
|
||||
|
||||
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");
|
||||
i=1;
|
||||
} else {
|
||||
i=0;
|
||||
}
|
||||
|
||||
for (; i < NUMBER_LIGHT_COLOR_TYPES; i++) {
|
||||
length += sprintf(buffer+length, "_light_program[%d] = [ ", i);
|
||||
for (j=1; j < LIGHT_COLOR_OPTIONS; j++) { // Start a 1 since index 0 is blank
|
||||
if (_color_light_options[i][j] != NULL)
|
||||
length += sprintf(buffer+length, "\"%s%s\",", _color_light_options[i][j], (isShowMode(_color_light_options[i][j])?" - Show":"") );
|
||||
}
|
||||
buffer[--length] = '\0';
|
||||
length += sprintf(buffer+length, "];\n");
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int build_color_light_jsonarray(int index, char* buffer, int size)
|
||||
{
|
||||
memset(&buffer[0], 0, size);
|
||||
int i;
|
||||
int length=0;
|
||||
|
||||
for (i=0; i < LIGHT_COLOR_OPTIONS; i++) { // Start a 1 since index 0 is blank
|
||||
if (_color_light_options[index][i] != NULL) {
|
||||
length += sprintf(buffer+length, "\"%s\",", _color_light_options[index][i] );
|
||||
}
|
||||
}
|
||||
buffer[--length] = '\0';
|
||||
|
||||
return length;
|
||||
}
|
||||
|
|
@ -3,11 +3,18 @@
|
|||
#define COLOR_LIGHTS_H_
|
||||
|
||||
#include "aqualink.h"
|
||||
#include "aq_programmer.h"
|
||||
|
||||
#define LIGHT_COLOR_NAME 16
|
||||
#define LIGHT_COLOR_OPTIONS 17
|
||||
#define LIGHT_COLOR_OPTIONS 19
|
||||
//#define LIGHT_COLOR_TYPES LC_DIMMER+1
|
||||
|
||||
// The status returned from RS Serial Adapter has this added as a base.
|
||||
#define RSSD_COLOR_LIGHT_OFFSET 64
|
||||
#define RSSD_DIMMER_LIGHT_OFFSET 128
|
||||
|
||||
//#define DIMMER_LIGHT_TYPE_INDEX 10
|
||||
|
||||
/*
|
||||
// color light modes (Aqualink program, Jandy, Jandy LED, SAm/SAL, Color Logic, Intellibrite)
|
||||
typedef enum clight_type {
|
||||
|
@ -19,15 +26,31 @@ typedef enum clight_type {
|
|||
LC_INTELLIB
|
||||
} clight_type;
|
||||
*/
|
||||
const char *light_mode_name(clight_type type, int index);
|
||||
//const char *light_mode_name(clight_type type, int index);
|
||||
const char *get_currentlight_mode_name(clight_detail light, emulation_type protocol);
|
||||
const char *light_mode_name(clight_type type, int index, emulation_type protocol);
|
||||
int build_color_lights_js(struct aqualinkdata *aqdata, char* buffer, int size);
|
||||
int build_color_light_jsonarray(int index, char* buffer, int size);
|
||||
|
||||
void clear_aqualinkd_light_modes();
|
||||
void set_currentlight_value(clight_detail *light, int index);
|
||||
|
||||
bool set_aqualinkd_light_mode_name(char *name, int index, bool isShow);
|
||||
const char *get_aqualinkd_light_mode_name(int index, bool *isShow);
|
||||
|
||||
//char *_color_light_options_[LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS][LIGHT_COLOR_NAME];
|
||||
|
||||
#endif //COLOR_LIGHTS_H_
|
||||
/*
|
||||
|
||||
Rev T.2 has the below
|
||||
Jandy colors <- Same
|
||||
Jandy LED <- Same
|
||||
SAm/Sal <- Same
|
||||
IntelliBrite <- Same
|
||||
Hayw Univ Col <- Color Logic
|
||||
|
||||
*/
|
||||
/*
|
||||
Color Name Jandy Colors Jandy LED SAm/SAL Color Logic IntelliBrite dimmer
|
||||
---------------------------------------------------------------------------------------------------------
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,373 @@
|
|||
|
||||
#ifndef CONFIG_H_
|
||||
#define CONFIG_H_
|
||||
|
||||
#include "utils.h"
|
||||
#include "aq_serial.h"
|
||||
#include "aqualink.h"
|
||||
|
||||
//#define DEFAULT_LOG_LEVEL 10
|
||||
#define DEFAULT_LOG_LEVEL LOG_NOTICE
|
||||
//#define DEFAULT_WEBPORT "6580"
|
||||
//#define DEFAULT_WEBROOT "./"
|
||||
#define DEFAULT_WEBPORT "80"
|
||||
#define DEFAULT_WEBROOT "/var/www/aqualinkd/"
|
||||
#define DEFAULT_SERIALPORT "/dev/ttyUSB0"
|
||||
#define DEFAULT_DEVICE_ID "0x0a"
|
||||
#define DEFAULT_MQTT_DZ_IN NULL // "domoticz/in"
|
||||
#define DEFAULT_MQTT_DZ_OUT NULL // "domoticz/out"
|
||||
#define DEFAULT_HASS_DISCOVER "homeassistant"
|
||||
#define DEFAULT_MQTT_AQ_TP "aqualinkd"
|
||||
#define DEFAULT_MQTT_SERVER NULL
|
||||
#define DEFAULT_MQTT_USER NULL
|
||||
#define DEFAULT_MQTT_PASSWD NULL
|
||||
|
||||
//#define DEFAULT_SWG_ZERO_IGNORE_COUNT 0
|
||||
|
||||
#define MQTT_ID_LEN 18 // 20 seems to kill mosquitto 1.6
|
||||
|
||||
// For aqconfig.read_RS485_devmask
|
||||
#define READ_RS485_SWG (1 << 0) // 1 SWG
|
||||
#define READ_RS485_JAN_PUMP (1 << 1) // 2 Jandy Pump
|
||||
#define READ_RS485_PEN_PUMP (1 << 2) // 4 Pentair Pump
|
||||
#define READ_RS485_JAN_JXI (1 << 3) // Jandy JX & LXi heater
|
||||
#define READ_RS485_JAN_LX (1 << 4) // Jandy LX heater
|
||||
#define READ_RS485_JAN_CHEM (1 << 5) // Jandy Chemical Feeder
|
||||
#define READ_RS485_IAQUALNK (1 << 6) // Read iAqualink messages
|
||||
#define READ_RS485_HEATPUMP (1 << 7) // Read HeatPump messages
|
||||
|
||||
#define MAX_RSSD_LOG_FILTERS 4
|
||||
|
||||
struct aqconfig
|
||||
{
|
||||
char *config_file;
|
||||
char *serial_port;
|
||||
unsigned int log_level;
|
||||
char *socket_port;
|
||||
char *web_directory;
|
||||
unsigned char device_id;
|
||||
unsigned char rssa_device_id;
|
||||
int16_t paneltype_mask;
|
||||
unsigned char extended_device_id;
|
||||
unsigned char extended_device_id2;
|
||||
bool extended_device_id_programming;
|
||||
bool enable_iaqualink;
|
||||
//bool enable_RS_device_value_print;
|
||||
bool deamonize;
|
||||
#ifndef AQ_MANAGER // Need to uncomment and clean up referances in future.
|
||||
char *log_file;
|
||||
#endif
|
||||
char *mqtt_dz_sub_topic;
|
||||
char *mqtt_dz_pub_topic;
|
||||
char *mqtt_aq_topic;
|
||||
char *mqtt_hass_discover_topic;
|
||||
char *mqtt_server;
|
||||
char *mqtt_user;
|
||||
char *mqtt_passwd;
|
||||
bool mqtt_hass_discover_use_mac;
|
||||
char mqtt_ID[MQTT_ID_LEN+1];
|
||||
int dzidx_air_temp;
|
||||
int dzidx_pool_water_temp;
|
||||
int dzidx_spa_water_temp;
|
||||
int dzidx_swg_percent;
|
||||
int dzidx_swg_ppm;
|
||||
int dzidx_swg_status;
|
||||
float light_programming_mode;
|
||||
int light_programming_initial_on;
|
||||
int light_programming_initial_off;
|
||||
bool override_freeze_protect;
|
||||
#ifdef AQ_PDA
|
||||
bool pda_sleep_mode;
|
||||
#endif
|
||||
bool convert_mqtt_temp;
|
||||
bool convert_dz_temp;
|
||||
bool report_zero_spa_temp;
|
||||
bool report_zero_pool_temp;
|
||||
//bool read_all_devices;
|
||||
//bool read_pentair_packets;
|
||||
uint8_t read_RS485_devmask;
|
||||
bool use_panel_aux_labels; // Took this option out of config
|
||||
|
||||
uint8_t force_device_devmask;
|
||||
|
||||
//int swg_zero_ignore; // This can be removed since this was due to VSP that's been fixed.
|
||||
bool display_warnings_web;
|
||||
bool log_protocol_packets; // Read & Write as packets
|
||||
bool log_raw_bytes; // Read as bytes
|
||||
unsigned char RSSD_LOG_filter[MAX_RSSD_LOG_FILTERS];
|
||||
//bool log_raw_RS_bytes;
|
||||
|
||||
bool mqtt_timed_update;
|
||||
bool sync_panel_time;
|
||||
bool enable_scheduler;
|
||||
int8_t schedule_event_mask; // Was int16_t, but no need
|
||||
int sched_chk_pumpon_hour;
|
||||
int sched_chk_pumpoff_hour;
|
||||
char *sched_chk_booston_device;
|
||||
bool ftdi_low_latency;
|
||||
int frame_delay;
|
||||
bool device_pre_state;
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
int rs_poll_speed; // Need to remove
|
||||
bool thread_netservices; // Need to remove
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef CONFIG_C
|
||||
extern struct aqconfig _aqconfig_;
|
||||
#else
|
||||
struct aqconfig _aqconfig_;
|
||||
#endif
|
||||
|
||||
|
||||
#define READ_RSDEV_SWG ((_aqconfig_.read_RS485_devmask & READ_RS485_SWG) == READ_RS485_SWG)
|
||||
#define READ_RSDEV_ePUMP ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_PUMP) == READ_RS485_JAN_PUMP)
|
||||
#define READ_RSDEV_vsfPUMP ((_aqconfig_.read_RS485_devmask & READ_RS485_PEN_PUMP) == READ_RS485_PEN_PUMP)
|
||||
#define READ_RSDEV_JXI ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_JXI) == READ_RS485_JAN_JXI)
|
||||
#define READ_RSDEV_LX ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_LX) == READ_RS485_JAN_LX)
|
||||
#define READ_RSDEV_CHEM ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_CHEM) == READ_RS485_JAN_CHEM)
|
||||
#define READ_RSDEV_iAQLNK ((_aqconfig_.read_RS485_devmask & READ_RS485_IAQUALNK) == READ_RS485_IAQUALNK)
|
||||
#define READ_RSDEV_HPUMP ((_aqconfig_.read_RS485_devmask & READ_RS485_HEATPUMP) == READ_RS485_HEATPUMP)
|
||||
|
||||
#define isPDA_IAQT (_aqconfig_.device_id == 0x33)
|
||||
//#define isPDA ((_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA)
|
||||
|
||||
|
||||
#define FORCE_SWG_SP (1 << 0)
|
||||
#define FORCE_POOLSPA_SP (1 << 1)
|
||||
#define FORCE_FREEZEPROTECT_SP (1 << 2)
|
||||
#define FORCE_CHEM_FEEDER (1 << 3)
|
||||
#define FORCE_CHILLER (1 << 4)
|
||||
|
||||
#define ENABLE_SWG ((_aqconfig_.force_device_devmask & FORCE_SWG_SP) == FORCE_SWG_SP)
|
||||
#define ENABLE_HEATERS ((_aqconfig_.force_device_devmask & FORCE_POOLSPA_SP) == FORCE_POOLSPA_SP)
|
||||
#define ENABLE_FREEZEPROTECT ((_aqconfig_.force_device_devmask & FORCE_FREEZEPROTECT_SP) == FORCE_FREEZEPROTECT_SP)
|
||||
#define ENABLE_CHEM_FEEDER ((_aqconfig_.force_device_devmask & FORCE_CHEM_FEEDER) == FORCE_CHEM_FEEDER)
|
||||
#define ENABLE_CHILLER ((_aqconfig_.force_device_devmask & FORCE_CHILLER) == FORCE_CHILLER)
|
||||
|
||||
/*
|
||||
#ifndef CONFIG_C
|
||||
#ifdef AQUALINKD_C
|
||||
extern struct aqconfig _aqconfig_;
|
||||
#else
|
||||
extern const struct aqconfig _aqconfig_;
|
||||
#endif
|
||||
#endif
|
||||
*/
|
||||
|
||||
void init_parameters (struct aqconfig * parms);
|
||||
//bool parse_config (struct aqconfig * parms, char *cfgfile);
|
||||
//void readCfg (struct aqconfig *config_parameters, char *cfgFile);
|
||||
//void readCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqualink_data, char *cfgFile);
|
||||
void read_config(struct aqualinkdata *aqdata, char *cfgFile);
|
||||
void init_config();
|
||||
|
||||
bool writeCfg (struct aqualinkdata *aqdata);
|
||||
bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value);
|
||||
bool mac(char *buf, int len, bool useDelimiter);
|
||||
char *cleanalloc(char *str);
|
||||
char *ncleanalloc(char *str, int length);
|
||||
|
||||
const char *pumpType2String(pump_type ptype);
|
||||
|
||||
int save_config_js(const char* inBuf, int inSize, char* outBuf, int outSize, struct aqualinkdata *aqdata);
|
||||
void check_print_config (struct aqualinkdata *aqdata);
|
||||
|
||||
|
||||
typedef enum cfg_value_type{
|
||||
CFG_STRING,
|
||||
CFG_INT,
|
||||
CFG_FLOAT,
|
||||
CFG_HEX,
|
||||
CFG_BOOL,
|
||||
CFG_BITMASK,
|
||||
CFG_SPECIAL
|
||||
} cfg_value_type;
|
||||
|
||||
|
||||
#define CFG_PERSISTANT (1 << 0) // Don't free memory, things referance the pointer
|
||||
#define CFG_GRP_ADVANCED (1 << 1) // Show in group advanced
|
||||
#define CFG_READONLY (1 << 2) // Don't show in UI, but do write to CFG file. (Maybe display in UI but no edit)
|
||||
#define CFG_HIDE (1 << 3) // Don't show in any UI listing, don't write to CFG file.
|
||||
//#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_ (1 << 3)
|
||||
|
||||
// Text to show when CFG_PASSWD_MASK is set
|
||||
#define PASSWD_MASK_TEXT "********"
|
||||
|
||||
#define isMASKSET(mask, bit) ((mask & bit) == bit)
|
||||
|
||||
typedef struct cfgParam {
|
||||
void *value_ptr;
|
||||
void *default_value;
|
||||
cfg_value_type value_type;
|
||||
uint8_t config_mask;
|
||||
char *name;
|
||||
char *valid_values;
|
||||
uint8_t mask;
|
||||
//bool advanced;
|
||||
} cfgParam;
|
||||
|
||||
#ifndef CONFIG_C
|
||||
extern cfgParam _cfgParams[];
|
||||
extern int _numCfgParams;
|
||||
#else
|
||||
cfgParam _cfgParams[100];
|
||||
int _numCfgParams;
|
||||
#endif // CONFIG_C
|
||||
|
||||
|
||||
// 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_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_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
|
|
@ -4,7 +4,7 @@
|
|||
#include <string.h>
|
||||
#include "debug_timer.h"
|
||||
#include "utils.h"
|
||||
//#include "timespec_subtract.h"
|
||||
#include "timespec_subtract.h"
|
||||
|
||||
#define NUM_DEBUG_TIMERS 10
|
||||
|
||||
|
@ -68,52 +68,8 @@ void stop_aqd_timer(int timeid, int16_t from, char *message)
|
|||
clear_aqd_timer(timeid);
|
||||
}
|
||||
|
||||
/* Copyright (c) 1991, 1999 Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
|
||||
/* Based on https://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
|
||||
Subtract the struct timespec values X and Y,
|
||||
storing the result in RESULT.
|
||||
Return 1 if the difference is negative, otherwise 0. */
|
||||
|
||||
//#include <string.h>
|
||||
//#include "timespec_subtract.h"
|
||||
|
||||
int timespec_subtract (struct timespec *result, const struct timespec *x,
|
||||
const struct timespec *y)
|
||||
{
|
||||
struct timespec tmp;
|
||||
|
||||
memcpy (&tmp, y, sizeof(struct timespec));
|
||||
/* Perform the carry for the later subtraction by updating y. */
|
||||
if (x->tv_nsec < tmp.tv_nsec)
|
||||
{
|
||||
int nsec = (tmp.tv_nsec - x->tv_nsec) / 1000000000 + 1;
|
||||
tmp.tv_nsec -= 1000000000 * nsec;
|
||||
tmp.tv_sec += nsec;
|
||||
}
|
||||
if (x->tv_nsec - tmp.tv_nsec > 1000000000)
|
||||
{
|
||||
int nsec = (x->tv_nsec - tmp.tv_nsec) / 1000000000;
|
||||
tmp.tv_nsec += 1000000000 * nsec;
|
||||
tmp.tv_sec -= nsec;
|
||||
}
|
||||
|
||||
/* Compute the time remaining to wait.
|
||||
tv_nsec is certainly positive. */
|
||||
result->tv_sec = x->tv_sec - tmp.tv_sec;
|
||||
result->tv_nsec = x->tv_nsec - tmp.tv_nsec;
|
||||
|
||||
/* Return 1 if result is negative. */
|
||||
return x->tv_sec < tmp.tv_sec;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -2,11 +2,13 @@
|
|||
#ifndef DEBUG_TIMER_H_
|
||||
#define DEBUG_TIMER_H_
|
||||
|
||||
int timespec_subtract (struct timespec *result, const struct timespec *x, const struct timespec *y);
|
||||
|
||||
#ifdef AQ_TM_DEBUG
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
void init_aqd_timer();
|
||||
int timespec_subtract (struct timespec *result, const struct timespec *x, const struct timespec *y);
|
||||
//int timespec_subtract (struct timespec *result, const struct timespec *x, const struct timespec *y);
|
||||
void stop_aqd_timer(int timeid, int16_t from, char *message);
|
||||
void start_aqd_timer(int *timeid);
|
||||
void clear_aqd_timer(int timeid);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,45 @@
|
|||
#ifndef AQUAPURE_H_
|
||||
#define AQUAPURE_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "aqualink.h"
|
||||
|
||||
bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
|
||||
bool processPacketToSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata/*, int swg_zero_ignore*/);
|
||||
bool processPacketFromSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to);
|
||||
bool processPacketToJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to);
|
||||
void processMissingAckPacketFromSWG(unsigned char destination, struct aqualinkdata *aqdata, const unsigned char previous_packet_to);
|
||||
void processMissingAckPacketFromJandyPump(unsigned char destination, struct aqualinkdata *aqdata, const unsigned char previous_packet_to);
|
||||
|
||||
bool processPacketFromJandyJXiHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to );
|
||||
bool processPacketToJandyJXiHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
bool processPacketFromJandyLXHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to );
|
||||
bool processPacketToJandyLXHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
|
||||
bool processPacketFromJandyChemFeeder(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to );
|
||||
bool processPacketToJandyChemFeeder(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
|
||||
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);
|
||||
|
||||
void get_swg_status_mqtt(struct aqualinkdata *aqdata, char *message, int *status, int *dzalert);
|
||||
aqledstate get_swg_led_state(struct aqualinkdata *aqdata);
|
||||
|
||||
bool changeSWGpercent(struct aqualinkdata *aqdata, int percent);
|
||||
void setSWGpercent(struct aqualinkdata *aqdata, int percent);
|
||||
void setSWGoff(struct aqualinkdata *aqdata);
|
||||
void setSWGenabled(struct aqualinkdata *aqdata);
|
||||
bool setSWGboost(struct aqualinkdata *aqdata, bool on);
|
||||
void setSWGdeviceStatus(struct aqualinkdata *aqdata, emulation_type requester, unsigned char status);
|
||||
|
||||
void getJandyHeaterError(struct aqualinkdata *aqdata, char *message);
|
||||
void getJandyHeaterErrorMQTT(struct aqualinkdata *aqdata, char *message);
|
||||
|
||||
int getPumpStatus(int pumpIndex, struct aqualinkdata *aqdata);
|
||||
|
||||
void processHeatPumpDisplayMessage(char *msg, struct aqualinkdata *aqdata);
|
||||
|
||||
#endif // AQUAPURE_H_
|
|
@ -0,0 +1,240 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2017 Shaun Feakes - All rights reserved
|
||||
*
|
||||
* You may use redistribute and/or modify this code under the terms of
|
||||
* the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. For the terms of this license,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* https://github.com/sfeakes/aqualinkd
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aqualink.h"
|
||||
#include "aq_serial.h"
|
||||
#include "devices_pentair.h"
|
||||
#include "utils.h"
|
||||
#include "packetLogger.h"
|
||||
|
||||
bool processPentairPacket(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
bool changedAnything = false;
|
||||
int i;
|
||||
|
||||
// Only log if we are pentair debug move and not serial (otherwise it'll print twice)
|
||||
if (getLogLevel(DPEN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
|
||||
char buff[1024];
|
||||
beautifyPacket(buff, 1024, packet, packet_length, true);
|
||||
LOG(DPEN_LOG,LOG_DEBUG, "%s", buff);
|
||||
}
|
||||
|
||||
//ID's 96 to 111 = Pentair (or 0x60 to 0x6F)
|
||||
|
||||
// Need to find a better way to support pump index
|
||||
|
||||
//static int pumpIndex = 1;
|
||||
|
||||
// Status from pump
|
||||
if ( packet[PEN_PKT_CMD] == PEN_CMD_STATUS && packet[PEN_PKT_FROM] >= PENTAIR_DEC_PUMP_MIN && packet[PEN_PKT_FROM] <= PENTAIR_DEC_PUMP_MAX ){
|
||||
// We have Pentair Pump packet, let's see if it's configured.
|
||||
//printf("PUMP\n");
|
||||
|
||||
for (i = 0; i < MAX_PUMPS; i++) {
|
||||
if ( aqdata->pumps[i].prclType == PENTAIR && aqdata->pumps[i].pumpID == packet[PEN_PKT_FROM] ) {
|
||||
// We found the pump.
|
||||
LOG(DPEN_LOG, LOG_INFO, "Pentair Pump 0x%02hhx Status message = RPM %d | WATTS %d | GPM %d | Mode %d | DriveState %d | Status %d | PresureCurve %d\n",
|
||||
packet[PEN_PKT_FROM],
|
||||
(packet[PEN_HI_B_RPM] * 256) + packet[PEN_LO_B_RPM],
|
||||
(packet[PEN_HI_B_WAT] * 256) + packet[PEN_LO_B_WAT],
|
||||
packet[PEN_FLOW],
|
||||
packet[PEN_MODE],
|
||||
packet[PEN_DRIVE_STATE],
|
||||
(packet[PEN_HI_B_STATUS] * 256) + packet[PEN_LO_B_STATUS],
|
||||
packet[PEN_PPC]);
|
||||
|
||||
aqdata->pumps[i].rpm = (packet[PEN_HI_B_RPM] * 256) + packet[PEN_LO_B_RPM];
|
||||
aqdata->pumps[i].watts = (packet[PEN_HI_B_WAT] * 256) + packet[PEN_LO_B_WAT];
|
||||
aqdata->pumps[i].gpm = packet[PEN_FLOW];
|
||||
aqdata->pumps[i].mode = packet[PEN_MODE];
|
||||
//aqdata->pumps[i].driveState = packet[PEN_DRIVE_STATE];
|
||||
aqdata->pumps[i].status = (packet[PEN_HI_B_STATUS] * 256) + packet[PEN_LO_B_STATUS];
|
||||
aqdata->pumps[i].pressureCurve = packet[PEN_PPC];
|
||||
|
||||
changedAnything = true;
|
||||
break;
|
||||
}
|
||||
if (changedAnything != true) {
|
||||
LOG(DPEN_LOG, LOG_NOTICE, "Pentair Pump found at ID 0x%02hhx values RPM %d | WATTS %d | PGM %d | Mode %d | DriveState %d | Status %d | PresureCurve %d\n",
|
||||
packet[PEN_PKT_FROM],
|
||||
(packet[PEN_HI_B_RPM] * 256) + packet[PEN_LO_B_RPM],
|
||||
(packet[PEN_HI_B_WAT] * 256) + packet[PEN_LO_B_WAT],
|
||||
packet[PEN_FLOW],
|
||||
packet[PEN_MODE],
|
||||
packet[PEN_DRIVE_STATE],
|
||||
(packet[PEN_HI_B_STATUS] * 256) + packet[PEN_LO_B_STATUS],
|
||||
packet[PEN_PPC]);
|
||||
}
|
||||
}
|
||||
//
|
||||
}
|
||||
// Set RPM/GPM to pump
|
||||
else if (packet[PEN_PKT_CMD] == PEN_CMD_SPEED && packet[PEN_PKT_DEST] >= PENTAIR_DEC_PUMP_MIN && packet[PEN_PKT_DEST] <= PENTAIR_DEC_PUMP_MAX) {
|
||||
|
||||
//(msg.extractPayloadByte(2) & 32) >> 5 === 0 ? 'RPM' : 'GPM';
|
||||
|
||||
bool isRPM = (packet[11] & 32) >> 5 == 0?true:false;
|
||||
|
||||
if (isRPM) {
|
||||
LOG(DPEN_LOG, LOG_INFO,"Pentair Pump 0x%02hhx request to set RPM to %d\n",packet[PEN_PKT_DEST], (packet[11] * 256) + packet[12]);
|
||||
} else {
|
||||
LOG(DPEN_LOG, LOG_INFO,"Pentair Pump 0x%02hhx request to set GPM to %d\n",packet[PEN_PKT_DEST],packet[11]);
|
||||
}
|
||||
}
|
||||
// Set power to pump
|
||||
else if (packet[PEN_PKT_CMD] == PEN_CMD_POWER && packet[PEN_PKT_DEST] >= PENTAIR_DEC_PUMP_MIN && packet[PEN_PKT_DEST] <= PENTAIR_DEC_PUMP_MAX) {
|
||||
if (packet[9] == 0x0A) {
|
||||
LOG(DPEN_LOG, LOG_INFO,"Pentair Pump 0x%02hhx request set power ON\n",packet[PEN_PKT_DEST]);
|
||||
} else {
|
||||
LOG(DPEN_LOG, LOG_INFO,"Pentair Pump 0x%02hhx request set power OFF\n",packet[PEN_PKT_DEST]);
|
||||
}
|
||||
}
|
||||
|
||||
return changedAnything;
|
||||
}
|
||||
/*
|
||||
VSP Pump Status.
|
||||
|
||||
Are you sure it is a VS pump because the flow rate byte(7)(PEN_FLOW) is only valid for VSF and VF pumps?
|
||||
|
||||
Mode 0=local control, 1=remote control
|
||||
DriveState = no idea
|
||||
Pressure Curve = see manual
|
||||
Status = below
|
||||
(packet[PEN_HI_B_STATUS] * 256) + packet[PEN_LO_B_STATUS];
|
||||
|
||||
Guess at the status would be.
|
||||
0 ok ( ok for VSF, looks like off for VF / VS? )
|
||||
1 ok ( ok for VF / VS?, not sure on VSF )
|
||||
2 filter warning
|
||||
4 Overcurrent condition
|
||||
8 Priming
|
||||
16 System blocked
|
||||
32 General alarm
|
||||
64 Overtemp condition
|
||||
128 Power outage
|
||||
256 Overcurrent condition 2
|
||||
512 Overvoltage condition
|
||||
1024 Unspecified Error
|
||||
2048 Unspecified Error
|
||||
4096 Unspecified Error
|
||||
8192 Unspecified Error
|
||||
16384 Unspecified Error
|
||||
32768 Communication failure
|
||||
|
||||
|
||||
// Below was pulled from another project. 0 doesn;t seem to be accurate.
|
||||
// 0 is OK on VSF pump
|
||||
[0, { name: 'off', desc: 'Off' }], // When the pump is disconnected or has no power then we simply report off as the status. This is not the recommended wiring
|
||||
// for a VS/VF pump as is should be powered at all times. When it is, the status will always report a value > 0.
|
||||
[1, { name: 'ok', desc: 'Ok' }], // Status is always reported when the pump is not wired to a relay regardless of whether it is on or not
|
||||
// as is should be if this is a VS / VF pump. However if it is wired to a relay most often filter, the pump will report status
|
||||
// 0 if it is not running. Essentially this is no error but it is not a status either.
|
||||
[2, { name: 'filter', desc: 'Filter warning' }],
|
||||
[3, { name: 'overcurrent', desc: 'Overcurrent condition' }],
|
||||
[4, { name: 'priming', desc: 'Priming' }],
|
||||
[5, { name: 'blocked', desc: 'System blocked' }],
|
||||
[6, { name: 'general', desc: 'General alarm' }],
|
||||
[7, { name: 'overtemp', desc: 'Overtemp condition' }],
|
||||
[8, { name: 'power', dec: 'Power outage' }],
|
||||
[9, { name: 'overcurrent2', desc: 'Overcurrent condition 2' }],
|
||||
[10, { name: 'overvoltage', desc: 'Overvoltage condition' }],
|
||||
[11, { name: 'error11', desc: 'Unspecified Error 11' }],
|
||||
[12, { name: 'error12', desc: 'Unspecified Error 12' }],
|
||||
[13, { name: 'error13', desc: 'Unspecified Error 13' }],
|
||||
[14, { name: 'error14', desc: 'Unspecified Error 14' }],
|
||||
[15, { name: 'error15', desc: 'Unspecified Error 15' }],
|
||||
[16, { name: 'commfailure', desc: 'Communication failure' }]
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Removed as iAqualink has a sleep mode, Keeping code to use as stub for other devices.
|
||||
|
||||
*/
|
||||
#ifdef DO_NOT_COMPILE
|
||||
|
||||
bool processiAqualinkMsg(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
bool changedAnything = false;
|
||||
static char lastmessage[AQ_MSGLONGLEN];
|
||||
|
||||
//static char message[AQ_MSGLONGLEN + 1];
|
||||
static int pumpIndex = 1;
|
||||
|
||||
/*
|
||||
|
||||
Jandy ePumpTM DC,
|
||||
Jandy ePumpTM AC,
|
||||
IntelliFlo 1 VF,
|
||||
IntelliFlo VS
|
||||
|
||||
Pump type are like // Not sure how to read this accuratly.
|
||||
"Jandy ePUMP 1"
|
||||
"Intelliflo VS 1"
|
||||
|
||||
RPM message always comes after the above, so maybe saving last string
|
||||
then when see RPM go back to get pump number.
|
||||
|
||||
' RPM: 2950'
|
||||
' Watts: 1028'
|
||||
' GPM: 1028'
|
||||
*/
|
||||
|
||||
if (packet_buffer[9] == 'R' && packet_buffer[10] == 'P' && packet_buffer[11] == 'M' && packet_buffer[12] == ':') {
|
||||
|
||||
pumpIndex = atoi((char *) &lastmessage[14]);
|
||||
|
||||
if ( pumpIndex < aqdata->num_pumps && pumpIndex < 0) {
|
||||
pumpIndex = 1;
|
||||
logMessage(LOG_ERR, "Can't find pump index for messsage '%.*s' in string '%.*s' using %d\n",AQ_MSGLEN, packet_buffer+4, AQ_MSGLEN, lastmessage, pumpIndex);
|
||||
}
|
||||
|
||||
aqdata->pumps[pumpIndex-1].rpm = atoi((char *) &packet_buffer[13]);
|
||||
|
||||
logMessage(LOG_DEBUG, "Read message '%.*s' from iAqualink device\n",AQ_MSGLEN, packet_buffer+4);
|
||||
changedAnything = true;
|
||||
}
|
||||
else if (packet_buffer[9] == 'G' && packet_buffer[10] == 'P' && packet_buffer[11] == 'H' && packet_buffer[12] == ':') {
|
||||
aqdata->pumps[pumpIndex-1].gph = atoi((char *) &packet_buffer[13]);
|
||||
logMessage(LOG_DEBUG, "Read message '%.*s' from iAqualink device\n",AQ_MSGLEN, packet_buffer+4);
|
||||
changedAnything = true;
|
||||
}
|
||||
else if (packet_buffer[7] == 'W' && packet_buffer[8] == 'a' && packet_buffer[9] == 't' && packet_buffer[10] == 't' && packet_buffer[11] == 's' && packet_buffer[12] == ':') {
|
||||
//printf("Punp %d, Watts = %d\n", pumpIndex, atoi((char *) &packet_buffer[13]));
|
||||
aqdata->pumps[pumpIndex-1].watts = atoi((char *) &packet_buffer[13]);
|
||||
logMessage(LOG_DEBUG, "Read message '%.*s' from iAqualink device\n",AQ_MSGLEN, packet_buffer+4);
|
||||
changedAnything = true;
|
||||
}
|
||||
|
||||
//printf("Message : '");
|
||||
//fwrite(packet_buffer + 4, 1, packet_length-7, stdout);
|
||||
//printf("'\n");
|
||||
|
||||
strncpy(lastmessage, (char *)&packet_buffer[4], packet_length-7);
|
||||
|
||||
return changedAnything;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
*
|
||||
* Program to simulate devices to help debug messages.
|
||||
* Not in release code / binary for AqualinkD
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#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"
|
||||
|
||||
|
||||
unsigned char DEVICE_ID = 0x70;
|
||||
|
||||
bool _keepRunning = true;
|
||||
int _rs_fd;
|
||||
|
||||
void intHandler(int dummy)
|
||||
{
|
||||
_keepRunning = false;
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Stopping!\n");
|
||||
}
|
||||
|
||||
bool isAqualinkDStopping() {
|
||||
return !_keepRunning;
|
||||
}
|
||||
|
||||
void process_heatpump_packet(unsigned char *packet_buffer, const int packet_length);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int logLevel = LOG_INFO;
|
||||
|
||||
int packet_length;
|
||||
unsigned char packet_buffer[AQ_MAXPKTLEN];
|
||||
|
||||
int blankReads = 0;
|
||||
bool returnError = false;
|
||||
|
||||
if (argc < 2 || access(argv[1], F_OK) == -1)
|
||||
{
|
||||
fprintf(stderr, "ERROR, first param must be valid serial port, ie:-\n\t%s /dev/ttyUSB0\n\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
setLoggingPrms(logLevel, false, NULL);
|
||||
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Starting %s\n", basename(argv[0]));
|
||||
|
||||
// _rs_fd = init_serial_port(argv[1]);
|
||||
_rs_fd = init_blocking_serial_port(argv[1]);
|
||||
|
||||
if (_rs_fd < 0)
|
||||
{
|
||||
LOG(SLOG_LOG, LOG_ERR, "Unable to open port: %s\n", argv[1]);
|
||||
displayLastSystemError(argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
signal(SIGINT, intHandler);
|
||||
signal(SIGTERM, intHandler);
|
||||
|
||||
// Force all packets to be printed.
|
||||
addDebugLogMask(RSSD_LOG);
|
||||
_aqconfig_.RSSD_LOG_filter[0] = DEVICE_ID;
|
||||
|
||||
while (_keepRunning)
|
||||
{
|
||||
if (_rs_fd < 0)
|
||||
{
|
||||
LOG(SLOG_LOG, LOG_ERR, "ERROR, serial port disconnect\n");
|
||||
_keepRunning = false;
|
||||
}
|
||||
|
||||
packet_length = get_packet(_rs_fd, packet_buffer);
|
||||
|
||||
if (packet_length == AQSERR_READ)
|
||||
{
|
||||
// Unrecoverable read error. Force an attempt to reconnect.
|
||||
LOG(SLOG_LOG, LOG_ERR, "ERROR, on serial port! Please check %s\n", argv[1]);
|
||||
_keepRunning = false;
|
||||
returnError = true;
|
||||
}
|
||||
else if (packet_length == AQSERR_TIMEOUT)
|
||||
{
|
||||
// Unrecoverable read error. Force an attempt to reconnect.
|
||||
LOG(SLOG_LOG, LOG_ERR, "ERROR, Timeout on serial port, nothing read! Please check %s\n", argv[1]);
|
||||
_keepRunning = false;
|
||||
returnError = true;
|
||||
}
|
||||
else if (packet_length < 0)
|
||||
{
|
||||
// Error condition
|
||||
if (packet_length == AQSERR_CHKSUM)
|
||||
{
|
||||
LOG(SLOG_LOG, LOG_WARNING, "Checksum error\n");
|
||||
}
|
||||
else if (packet_length == AQSERR_2LARGE)
|
||||
{
|
||||
LOG(SLOG_LOG, LOG_WARNING, "Packet too large error\n");
|
||||
}
|
||||
else if (packet_length == AQSERR_2SMALL)
|
||||
{
|
||||
LOG(SLOG_LOG, LOG_WARNING, "Packet too small error\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(SLOG_LOG, LOG_WARNING, "Unknown error reading packet\n");
|
||||
}
|
||||
}
|
||||
else if (packet_length == 0)
|
||||
{
|
||||
if (++blankReads > 10)
|
||||
{
|
||||
LOG(SLOG_LOG, LOG_ERR, "ERROR, too many blank reads! Please check %s\n", argv[1]);
|
||||
_keepRunning = false;
|
||||
returnError = true;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
else if (packet_length > 0)
|
||||
{
|
||||
blankReads = 0;
|
||||
//debuglogPacket(SLOG_LOG, packet_buffer, packet_length, true, true);
|
||||
|
||||
if (packet_buffer[PKT_DEST] == DEVICE_ID)
|
||||
{
|
||||
process_heatpump_packet(packet_buffer, packet_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Stopping!\n");
|
||||
|
||||
close_serial_port(_rs_fd);
|
||||
|
||||
if (returnError)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reply to message
|
||||
*/
|
||||
|
||||
|
||||
void process_heatpump_packet(unsigned char *packet_buffer, const int packet_length)
|
||||
{
|
||||
//LOG(SLOG_LOG, LOG_NOTICE, "Replying to packet 0x%02hhx!\n",packet_buffer[PKT_DEST]);
|
||||
|
||||
// reply to off 0x10|0x02|0x00|0x0d|0x40|0x00|0x00|0x5f|0x10|0x03|
|
||||
static unsigned char hp_off[] = {0x00, 0x0d, 0x40, 0x00, 0x00};
|
||||
static unsigned char hp_heat[] = {0x00, 0x0d, 0x48, 0x00, 0x00};
|
||||
static unsigned char hp_cool[] = {0x00, 0x0d, 0x68, 0x00, 0x00};
|
||||
|
||||
|
||||
if (packet_buffer[PKT_CMD] == CMD_PROBE)
|
||||
{
|
||||
send_ack(_rs_fd, 0x00);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Replied to Probe packet to 0x%02hhx with ACK\n",packet_buffer[PKT_DEST]);
|
||||
}
|
||||
else if (packet_buffer[3] == 0x0c)
|
||||
{
|
||||
if (packet_buffer[4] == 0x00)
|
||||
{ // Off
|
||||
send_jandy_command(_rs_fd, hp_off, 5);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Replied to OFF 0x%02hhx packet to 0x%02hhx with ACK\n",packet_buffer[4],packet_buffer[PKT_DEST]);
|
||||
}
|
||||
else if (packet_buffer[4] == 0x09) // Heat
|
||||
{ // Enable
|
||||
send_jandy_command(_rs_fd, hp_heat, 5);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Replied to HEAT 0x%02hhx packet to 0x%02hhx with ACK\n",packet_buffer[4],packet_buffer[PKT_DEST]);
|
||||
}
|
||||
else if (packet_buffer[4] == 0x29) // Cool
|
||||
{ // Enable
|
||||
send_jandy_command(_rs_fd, hp_cool, 5);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "Replied to COOL 0x%02hhx packet to 0x%02hhx with ACK\n",packet_buffer[4],packet_buffer[PKT_DEST]);
|
||||
}
|
||||
else
|
||||
{ // Enable
|
||||
LOG(SLOG_LOG, LOG_ERR, "************* Unknown State Request 0x%02hhx *************",packet_buffer[4]);
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "NOT Replying to UNKNOWN 0x%02hhx packet to 0x%02hhx with ACK\n",packet_buffer[4],packet_buffer[PKT_DEST]);
|
||||
//send_jandy_command(_rs_fd, hp_unknown, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,337 @@
|
|||
|
||||
/*
|
||||
Nothing seems to change these, need real pump to test
|
||||
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
|
||||
|
||||
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
|
||||
|
||||
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
|
||||
0x10|0x02|0x7a|0x41|0xcd|0x10|0x03|
|
||||
|
||||
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
|
||||
0x10|0x02|0x7a|0x41|0xcd|0x10|0x03|
|
||||
|
||||
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
|
||||
0x10|0x02|0x7a|0x41|0xcd|0x10|0x03|
|
||||
|
||||
|
||||
----------------
|
||||
|
||||
Set & Sataus WATTS. Looks like send to ePump type 0x45, return type 0xf1|0x45
|
||||
|
||||
JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x1d|0x05|0x9d|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f| 69| 0| 5| 29| 5|0x9d|0x10|0x03|
|
||||
Jun-24-23 08:30:53 AM Debug: PDA: PDA Menu Line 4 = WATTS: 1309
|
||||
|
||||
Type 0x1f (command 0x45 or 69)
|
||||
Watts = 5 * (256) + 29 = 1309 or Byte 8 * 265 + Byte 7
|
||||
|
||||
----------------
|
||||
|
||||
Set & Sataus RPM. Looks like send to ePump type 0x44, return type 0xf1|0x44
|
||||
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0xe8|0x35|0x00|0x92|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f| 68| 0| 232| 53| 0|0x92|0x10|0x03|
|
||||
PDA Menu Line 3 = SET TO 3450 RPM
|
||||
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x50|0x2d|0x00|0xf2|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f| 68| 0| 80| 45| 0|0xf2|0x10|0x03|
|
||||
PDA: PDA Menu Line 3 = SET TO 2900 RPM
|
||||
|
||||
JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f| 68| 0| 96| 39| 0|0xfc|0x10|0x03|
|
||||
PDA: PDA Menu Line 3 = SET TO 2520 RPM
|
||||
|
||||
Type 0x1F and cmd 0x44 is RPM = 39 * (256) + 96 / 4 = 2520 or Byte 7 * 265 + Byte 6 / 4
|
||||
|
||||
Other commands on 0x1f are 67 & 68 (0x43 )
|
||||
|
||||
|
||||
|
||||
|
||||
Some form of ping for being alive
|
||||
Jun-23-23 17:41:00 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:41:00 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
|
||||
|
||||
|
||||
Jun-23-23 09:01:29 AM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 09:01:29 AM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x04|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 09:01:35 AM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x42' | HEX: 0x10|0x02|0x78|0x42|0xcc|0x10|0x03|
|
||||
Jun-23-23 09:01:35 AM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x42|0x00|0x55|0x10|0x03|
|
||||
Jun-23-23 17:40:57 PM Debug: PDA: PDA Menu Line 2 = JANDY ePUMP 1
|
||||
Jun-23-23 17:40:57 PM Debug: PDA: PDA Menu Line 3 = RPM: 2520
|
||||
Jun-23-23 17:40:57 PM Debug: PDA: PDA Menu Line 4 = WATTS: 856
|
||||
|
||||
Jun-23-23 17:41:00 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:41:00 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:41:00 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:41:00 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:41:06 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:41:06 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:41:06 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:41:06 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:41:06 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:41:06 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
|
||||
Jun-23-23 17:41:11 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:41:11 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:41:11 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:41:11 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:41:17 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:41:17 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x57|0x03|0xd5|0x10|0x03|
|
||||
Jun-23-23 17:41:17 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:41:17 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:41:17 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:41:17 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:41:17 PM Debug: PDA: PDA Menu Line 2 = JANDY ePUMP 1
|
||||
Jun-23-23 17:41:17 PM Debug: PDA: PDA Menu Line 3 = RPM: 2520
|
||||
Jun-23-23 17:41:17 PM Debug: PDA: PDA Menu Line 4 = WATTS: 855
|
||||
|
||||
Jun-23-23 17:41:22 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:41:22 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:41:22 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:41:22 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:41:28 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:41:28 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:41:28 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:41:28 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:41:28 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:41:28 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:41:33 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:41:33 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:41:33 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:41:33 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:41:38 PM Debug: PDA: PDA Menu Line 2 = JANDY ePUMP 1
|
||||
Jun-23-23 17:41:38 PM Debug: PDA: PDA Menu Line 3 = RPM: 2520
|
||||
Jun-23-23 17:41:38 PM Debug: PDA: PDA Menu Line 4 = WATTS: 856
|
||||
|
||||
Jun-23-23 17:41:39 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:41:39 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:41:39 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:41:39 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:41:39 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:41:39 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:41:44 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:41:44 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:41:44 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:41:44 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:41:49 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:41:49 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:41:50 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:41:50 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:41:50 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:41:50 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:41:55 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:41:55 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:41:55 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:41:55 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:41:59 PM Debug: PDA: PDA Menu Line 2 = JANDY ePUMP 1
|
||||
Jun-23-23 17:41:59 PM Debug: PDA: PDA Menu Line 3 = RPM: 2520
|
||||
Jun-23-23 17:41:59 PM Debug: PDA: PDA Menu Line 4 = WATTS: 856
|
||||
|
||||
Jun-23-23 17:42:01 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:42:01 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:42:01 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:42:01 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:42:01 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:42:01 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:42:06 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:42:06 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:42:06 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:42:06 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:42:12 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:42:12 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:42:12 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:42:12 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:42:12 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:42:12 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:42:17 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:42:17 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:42:17 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:42:17 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:42:20 PM Debug: PDA: PDA Menu Line 2 = JANDY ePUMP 1
|
||||
Jun-23-23 17:42:20 PM Debug: PDA: PDA Menu Line 3 = RPM: 2520
|
||||
Jun-23-23 17:42:20 PM Debug: PDA: PDA Menu Line 4 = WATTS: 856
|
||||
|
||||
Jun-23-23 17:42:23 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:42:23 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x57|0x03|0xd5|0x10|0x03|
|
||||
Jun-23-23 17:42:23 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:42:23 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:42:23 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:42:23 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:42:28 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:42:28 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:42:28 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:42:28 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:42:33 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:42:33 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:42:33 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:42:33 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:42:33 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:42:34 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:42:39 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:42:39 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:42:39 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:42:39 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:42:41 PM Debug: PDA: PDA Menu Line 2 = JANDY ePUMP 1
|
||||
Jun-23-23 17:42:41 PM Debug: PDA: PDA Menu Line 3 = RPM: 2520
|
||||
Jun-23-23 17:42:41 PM Debug: PDA: PDA Menu Line 4 = WATTS: 856
|
||||
|
||||
Jun-23-23 17:42:45 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:42:45 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x57|0x03|0xd5|0x10|0x03|
|
||||
Jun-23-23 17:42:45 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:42:45 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:42:45 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:42:45 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:42:49 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:42:49 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:42:49 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:42:49 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:42:56 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:42:56 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x57|0x03|0xd5|0x10|0x03|
|
||||
Jun-23-23 17:42:56 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:42:56 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:42:56 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:42:56 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:43:00 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:43:00 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:43:00 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:43:00 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:43:02 PM Debug: PDA: PDA Menu Line 2 = JANDY ePUMP 1
|
||||
Jun-23-23 17:43:02 PM Debug: PDA: PDA Menu Line 3 = RPM: 2520
|
||||
Jun-23-23 17:43:02 PM Debug: PDA: PDA Menu Line 4 = WATTS: 855
|
||||
|
||||
Jun-23-23 17:43:07 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:43:07 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:43:07 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:43:07 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:43:07 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:43:07 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:43:11 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:43:11 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:43:12 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:43:12 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:43:17 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:43:18 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:43:18 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:43:18 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:43:18 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:43:18 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:43:23 PM Debug: PDA: PDA Menu Line 2 = JANDY ePUMP 1
|
||||
Jun-23-23 17:43:23 PM Debug: PDA: PDA Menu Line 3 = RPM: 2520
|
||||
Jun-23-23 17:43:23 PM Debug: PDA: PDA Menu Line 4 = WATTS: 856
|
||||
|
||||
Jun-23-23 17:43:23 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:43:23 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:43:23 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:43:23 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:43:28 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:43:28 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:43:28 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:43:29 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:43:29 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:43:29 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:43:34 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:43:34 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:43:34 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:43:34 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:43:39 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:43:39 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:43:39 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:43:39 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:43:39 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:43:40 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:43:44 PM Debug: PDA: PDA Menu Line 2 = JANDY ePUMP 1
|
||||
Jun-23-23 17:43:44 PM Debug: PDA: PDA Menu Line 3 = RPM: 2520
|
||||
Jun-23-23 17:43:44 PM Debug: PDA: PDA Menu Line 4 = WATTS: 856
|
||||
|
||||
Jun-23-23 17:43:44 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:43:44 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:43:44 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:43:45 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:43:50 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:43:50 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:43:50 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:43:51 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:43:51 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:43:51 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:43:55 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:43:55 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:43:56 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:43:56 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:44:01 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:44:01 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:44:01 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:44:02 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:44:02 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:44:02 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:44:05 PM Debug: PDA: PDA Menu Line 2 = JANDY ePUMP 1
|
||||
Jun-23-23 17:44:05 PM Debug: PDA: PDA Menu Line 3 = RPM: 2520
|
||||
Jun-23-23 17:44:05 PM Debug: PDA: PDA Menu Line 4 = WATTS: 856
|
||||
|
||||
Jun-23-23 17:44:06 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:44:06 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:44:06 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:44:06 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:44:12 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:44:12 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:44:12 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:44:12 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:44:12 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:44:13 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:44:17 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:44:18 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:44:18 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:44:18 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:44:23 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:44:23 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:44:23 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:44:24 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:44:24 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:44:24 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:44:26 PM Debug: PDA: PDA Menu Line 2 = JANDY ePUMP 1
|
||||
Jun-23-23 17:44:26 PM Debug: PDA: PDA Menu Line 3 = RPM: 2520
|
||||
Jun-23-23 17:44:26 PM Debug: PDA: PDA Menu Line 4 = WATTS: 856
|
||||
|
||||
Jun-23-23 17:44:28 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:44:29 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:44:29 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:44:29 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:44:34 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:44:35 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:44:35 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:44:35 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:44:35 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:44:35 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:44:39 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:44:39 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:44:40 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:44:40 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:44:45 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:44:45 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:44:45 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:44:45 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:44:45 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:44:45 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:44:47 PM Debug: PDA: PDA Menu Line 2 = JANDY ePUMP 1
|
||||
Jun-23-23 17:44:47 PM Debug: PDA: PDA Menu Line 3 = RPM: 2520
|
||||
Jun-23-23 17:44:47 PM Debug: PDA: PDA Menu Line 4 = WATTS: 856
|
||||
|
||||
Jun-23-23 17:44:50 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:44:50 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:44:51 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:44:51 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
Jun-23-23 17:44:56 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Jun-23-23 17:44:57 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x58|0x03|0xd6|0x10|0x03|
|
||||
Jun-23-23 17:44:57 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x43' | HEX: 0x10|0x02|0x78|0x43|0xcd|0x10|0x03|
|
||||
Jun-23-23 17:44:57 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x43|0x0b|0x00|0x00|0x00|0x7f|0x10|0x03|
|
||||
Jun-23-23 17:44:57 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x46' | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Jun-23-23 17:44:57 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x20' | HEX: 0x10|0x02|0x00|0x20|0x46|0x00|0x00|0x03|0x30|0x30|0x32|0x30|0x00|0x00|0x3d|0x10|0x03|
|
||||
Jun-23-23 17:45:01 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
Jun-23-23 17:45:02 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
Jun-23-23 17:45:02 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
Jun-23-23 17:45:02 PM Debug: JandyDvce: From ePump: Read To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x41|0x00|0x54|0x10|0x03|
|
||||
*/
|
|
@ -0,0 +1,738 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
#include "aqualink.h"
|
||||
#include "net_services.h"
|
||||
#include "json_messages.h"
|
||||
#include "aq_mqtt.h"
|
||||
#include "rs_msg_utils.h"
|
||||
#include "config.h"
|
||||
#include "color_lights.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
// NSF Need to find a better way, this is not thread safe, so don;t want to expost it from net_services.h.
|
||||
void send_mqtt(struct mg_connection *nc, const char *toppic, const char *message);
|
||||
|
||||
#define HASS_DEVICE "\"identifiers\": " \
|
||||
"[\"" AQUALINKD_SHORT_NAME "\"]," \
|
||||
" \"sw_version\": \"" AQUALINKD_VERSION "\"," \
|
||||
" \"model\": \"" AQUALINKD_NAME "\"," \
|
||||
" \"name\": \"AqualinkD\"," \
|
||||
" \"manufacturer\": \"" AQUALINKD_SHORT_NAME "\"," \
|
||||
"%s" \
|
||||
" \"suggested_area\": \"pool\""
|
||||
|
||||
#define HASS_AVAILABILITY "\"payload_available\" : \"1\"," \
|
||||
"\"payload_not_available\" : \"0\"," \
|
||||
"\"topic\": \"%s/" MQTT_LWM_TOPIC "\""
|
||||
|
||||
|
||||
const char *HASSIO_CLIMATE_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"climate\","
|
||||
"\"unique_id\": \"aqualinkd_%s\","
|
||||
"\"name\": \"%s\","
|
||||
"\"modes\": [\"off\", \"heat\"],"
|
||||
"\"send_if_off\": true,"
|
||||
"\"initial\": 36,"
|
||||
"\"power_command_topic\": \"%s/%s/set\","
|
||||
"\"payload_on\": \"1\","
|
||||
"\"payload_off\": \"0\","
|
||||
"\"current_temperature_topic\": \"%s/%s\","
|
||||
"\"mode_command_topic\": \"%s/%s/set\","
|
||||
"\"mode_state_topic\": \"%s/%s/enabled\","
|
||||
"\"mode_state_template\": \"{%% set values = { '0':'off', '1':'heat'} %%}{{ values[value] if value in values.keys() else 'off' }}\","
|
||||
"\"temperature_command_topic\": \"%s/%s/setpoint/set\","
|
||||
"\"temperature_state_topic\": \"%s/%s/setpoint\","
|
||||
"\"action_template\": \"{%% set values = { '0':'off', '1':'heating'} %%}{{ values[value] if value in values.keys() else 'off' }}\","
|
||||
"\"action_topic\": \"%s/%s\","
|
||||
/*"\"temperature_state_template\": \"{{ value_json }}\","*/
|
||||
"\"min_temp\": %.2f,"
|
||||
"\"max_temp\": %.2f,"
|
||||
"\"temperature_unit\": \"%s\""
|
||||
//"%s"
|
||||
"}";
|
||||
|
||||
const char *HASSIO_FREEZE_PROTECT_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"climate\","
|
||||
"\"unique_id\": \"aqualinkd_%s\","
|
||||
"\"name\": \"Freeze Protect\","
|
||||
"\"modes\": [\"off\", \"auto\"],"
|
||||
"\"send_if_off\": true,"
|
||||
"\"initial\": 34,"
|
||||
"\"payload_on\": \"1\","
|
||||
"\"payload_off\": \"0\","
|
||||
"\"current_temperature_topic\": \"%s/%s\","
|
||||
"\"mode_state_topic\": \"%s/%s\","
|
||||
"\"mode_state_template\": \"{%% set values = { '0':'off', '1':'auto'} %%}{{ values[value] if value in values.keys() else 'off' }}\","
|
||||
"\"temperature_command_topic\": \"%s/%s/setpoint/set\","
|
||||
"\"temperature_state_topic\": \"%s/%s/setpoint\","
|
||||
"\"action_template\": \"{%% set values = { '0':'off', '1':'cooling'} %%}{{ values[value] if value in values.keys() else 'off' }}\","
|
||||
"\"action_topic\": \"%s/%s\","
|
||||
/*"\"temperature_state_template\": \"{{ value_json }}\""*/
|
||||
"\"min_temp\": %0.2f,"
|
||||
"\"max_temp\": %0.2f,"
|
||||
"\"temperature_unit\": \"%s\""
|
||||
//"%s"
|
||||
"}";
|
||||
|
||||
/*
|
||||
const char *HASSIO_CONVERT_CLIMATE_TOF = "\"temperature_state_template\": \"{{ (value | float(0) * 1.8 + 32 + 0.5) | int }}\","
|
||||
"\"current_temperature_template\": \"{{ (value | float(0) * 1.8 + 32 + 0.5 ) | int }}\","
|
||||
"\"temperature_command_template\": \"{{ ((value | float(0) -32 ) / 1.8 + 0.5) | int }}\"";
|
||||
|
||||
const char *HASSIO_NO_CONVERT_CLIMATE = "\"temperature_state_template\": \"{{ value_json }}\"";
|
||||
*/
|
||||
|
||||
const char *HASSIO_SWG_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"humidifier\","
|
||||
"\"device_class\": \"humidifier\","
|
||||
"\"unique_id\": \"aqualinkd_%s\","
|
||||
"\"name\": \"Salt Water Generator\","
|
||||
"\"state_topic\": \"%s/%s\","
|
||||
"\"state_template\": \"{%% set values = { '0':'off', '2':'on'} %%}{{ values[value] if value in values.keys() else 'off' }}\","
|
||||
"\"command_topic\": \"%s/%s/set\","
|
||||
"\"current_humidity_topic\": \"%s/%s\","
|
||||
"\"target_humidity_command_topic\": \"%s/%s/set\","
|
||||
"\"target_humidity_state_topic\": \"%s/%s\","
|
||||
"\"payload_on\": \"2\","
|
||||
"\"payload_off\": \"0\","
|
||||
"\"min_humidity\":0,"
|
||||
"\"max_humidity\":100,"
|
||||
"\"optimistic\": false"
|
||||
"}";
|
||||
|
||||
const char *HASSIO_CHILLER_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"climate\","
|
||||
"\"unique_id\": \"aqualinkd_%s\","
|
||||
"\"name\": \"Chiller\","
|
||||
"\"modes\": [\"off\", \"cool\"],"
|
||||
"\"send_if_off\": true,"
|
||||
"\"initial\": 34,"
|
||||
"\"power_command_topic\": \"%s/%s/set\"," // add
|
||||
"\"payload_on\": \"2\","
|
||||
"\"payload_off\": \"0\","
|
||||
"\"current_temperature_topic\": \"%s/%s\","
|
||||
"\"mode_command_topic\": \"%s/%s/set\"," // add
|
||||
"\"mode_state_topic\": \"%s/%s\","
|
||||
"\"mode_state_template\": \"{%% set values = { '0':'off', '2':'cool'} %%}{{ values[value] if value in values.keys() else 'off' }}\","
|
||||
"\"temperature_command_topic\": \"%s/%s/setpoint/set\","
|
||||
"\"temperature_state_topic\": \"%s/%s/setpoint\","
|
||||
"\"action_template\": \"{%% set values = { '0':'off', '2':'cooling'} %%}{{ values[value] if value in values.keys() else 'off' }}\","
|
||||
"\"action_topic\": \"%s/%s\","
|
||||
/*"\"temperature_state_template\": \"{{ value_json }}\""*/
|
||||
"\"min_temp\": %0.2f,"
|
||||
"\"max_temp\": %0.2f,"
|
||||
"\"temperature_unit\": \"%s\""
|
||||
//"%s"
|
||||
"}";
|
||||
|
||||
// Use Fan for VSP
|
||||
// Need to change the max / min. These do NOT lomit the slider in hassio, only the MQTT limits.
|
||||
// So the 0-100% should be 600-3450 RPM and 15-130 GPM (ie 1% would = 600 & 0%=off)
|
||||
// (value-600) / (3450-600) * 100
|
||||
// (value) / 100 * (3450-600) + 600
|
||||
|
||||
const char *HASSIO_VSP_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"fan\","
|
||||
"\"unique_id\": \"aqualinkd_%s_%s\"," // filter_pump, RPM|GPM
|
||||
"\"name\": \"%s Speed\"," // filter_pump
|
||||
"\"state_topic\": \"%s/%s\"," // aqualinkd,filter_pump
|
||||
"\"command_topic\": \"%s/%s/set\"," // aqualinkd,filter_pump
|
||||
"\"json_attributes_topic\": \"%s/%s/delay\"," // aqualinkd,filter_pump
|
||||
"\"json_attributes_template\": \"{{ {'delay': value|int} | tojson }}\","
|
||||
"\"payload_on\": \"1\","
|
||||
"\"payload_off\": \"0\","
|
||||
"\"percentage_command_topic\": \"%s/%s/%s/set\"," // aqualinkd,filter_pump , RPM|GPM
|
||||
"\"percentage_state_topic\": \"%s/%s/%s\"," // aqualinkd,filter_pump , RPM|GPM
|
||||
//"\"percentage_value_template\": \"{%% if value | float(0) > %d %%} {{ (((value | float(0) - %d) / %d) * 100) | int }}{%% else %%} 1{%% endif %%}\"," // min,min,(max-min)
|
||||
//"\"percentage_command_template\": \"{{ ((value | float(0) / 100) * %d) + %d | int }}\"," // (3450-130), 600
|
||||
"\"speed_range_max\": 100,"
|
||||
"\"speed_range_min\": 1" // 18|12 600rpm|15gpm
|
||||
"}";
|
||||
|
||||
|
||||
const char *HASSIO_DIMMER_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"light\","
|
||||
"\"unique_id\": \"aqualinkd_%s\"," // Aux_5
|
||||
"\"name\": \"%s\"," // Dimmer_name
|
||||
"\"state_topic\": \"%s/%s\"," // aqualinkd,Aux_5
|
||||
"\"command_topic\": \"%s/%s/set\"," // aqualinkd,Aux_5
|
||||
"\"json_attributes_topic\": \"%s/%s/delay\"," // aqualinkd,Aux_5
|
||||
"\"json_attributes_template\": \"{{ {'delay': value|int} | tojson }}\","
|
||||
"\"payload_on\": \"1\","
|
||||
"\"payload_off\": \"0\","
|
||||
"\"brightness_command_topic\": \"%s/%s%s/set\"," // aqualinkd,Aux_5,/brightness
|
||||
"\"brightness_state_topic\": \"%s/%s%s\"," // aqualinkd/Aux_5,/brightness
|
||||
"\"brightness_scale\": 100"
|
||||
"}";
|
||||
|
||||
const char *HASSIO_SELECTOR_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"select\","
|
||||
"\"unique_id\": \"aqualinkd_%s_selector\"," // Aux_5
|
||||
"\"name\": \"%s program\"," // light name
|
||||
"\"state_topic\": \"%s/%s/program/name\"," // aqualinkd,Aux_5
|
||||
"\"state_template\": \"{{ this.attributes.options(value) }}\","
|
||||
"\"command_topic\": \"%s/%s/program/set\"," // aqualinkd,Aux_5
|
||||
"\"options\": [ %s ]," // "Off", "Voodoo Lounge", "Deep Blue Sea"
|
||||
"\"command_template\": \"{{ this.attributes.options.index(value) }}\","
|
||||
"\"icon\": \"%s\""
|
||||
"}";
|
||||
|
||||
// Need to add timer attributes to the switches, once figure out how to use in homeassistant
|
||||
// ie aqualinkd/Filter_Pump/timer/duration
|
||||
|
||||
const char *HASSIO_SWITCH_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"switch\","
|
||||
"\"unique_id\": \"aqualinkd_%s\","
|
||||
"\"name\": \"%s\","
|
||||
"\"state_topic\": \"%s/%s\","
|
||||
"\"command_topic\": \"%s/%s/set\","
|
||||
"\"json_attributes_topic\": \"%s/%s/delay\","
|
||||
"\"json_attributes_topic\": \"%s/%s/delay\","
|
||||
"\"json_attributes_template\": \"{{ {'delay': value|int} | tojson }}\","
|
||||
"\"payload_on\": \"1\","
|
||||
"\"payload_off\": \"0\","
|
||||
"\"icon\": \"%s\""
|
||||
"}";
|
||||
|
||||
const char *HASSIO_TEMP_SENSOR_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"sensor\","
|
||||
"\"state_class\": \"measurement\","
|
||||
"\"unique_id\": \"aqualinkd_%s_temp\","
|
||||
"\"name\": \"%s Temp\","
|
||||
"\"state_topic\": \"%s/%s\","
|
||||
"\"value_template\": \"{{ value_json }}\","
|
||||
"\"unit_of_measurement\": \"%s\","
|
||||
"\"device_class\": \"temperature\","
|
||||
"\"icon\": \"%s\""
|
||||
"}";
|
||||
|
||||
const char *HASSIO_SENSOR_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"sensor\","
|
||||
"\"state_class\": \"measurement\","
|
||||
"\"unique_id\": \"aqualinkd_%s\","
|
||||
"\"name\": \"%s\","
|
||||
"\"state_topic\": \"%s/%s\","
|
||||
"\"value_template\": \"{{ value_json }}\","
|
||||
"\"unit_of_measurement\": \"%s\","
|
||||
"\"icon\": \"%s\""
|
||||
"}";
|
||||
|
||||
const char *HASSIO_SERVICE_MODE_ENUM_SENSOR_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"sensor\","
|
||||
"\"unique_id\": \"aqualinkd_%s\","
|
||||
"\"name\": \"%s\","
|
||||
"\"state_topic\": \"%s/%s\","
|
||||
"\"device_class\": \"enum\","
|
||||
"\"options\": [\"auto\",\"service\",\"timeout\"],"
|
||||
"\"value_template\": \"{%% set values = { '0':'auto', '1':'service', '2':'timeout'} %%}{{ values[value] if value in values.keys() }}\","
|
||||
"\"icon\": \"%s\""
|
||||
"}";
|
||||
|
||||
const char *HASSIO_ONOFF_SENSOR_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"sensor\","
|
||||
"\"unique_id\": \"aqualinkd_%s\","
|
||||
"\"name\": \"%s\","
|
||||
"\"state_topic\": \"%s/%s\","
|
||||
"\"payload_on\": \"1\","
|
||||
"\"payload_off\": \"0\","
|
||||
"\"value_template\": \"{%% set values = { '0':'off', '1':'on'} %%}{{ values[value] if value in values.keys() else 'off' }}\","
|
||||
"\"icon\": \"%s\""
|
||||
"}";
|
||||
|
||||
const char *HASSIO_PUMP_SENSOR_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"sensor\","
|
||||
"\"state_class\": \"measurement\","
|
||||
"\"unique_id\": \"aqualinkd_%s%d_%s\","
|
||||
"\"name\": \"%s %s %s\","
|
||||
"\"state_topic\": \"%s/%s%s\","
|
||||
"\"value_template\": \"{{ value_json }}\","
|
||||
"\"unit_of_measurement\": \"%s\","
|
||||
"\"icon\": \"mdi:pump\""
|
||||
"}";
|
||||
|
||||
const char *HASSIO_BATTERY_SENSOR_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"binary_sensor\","
|
||||
"\"unique_id\": \"aqualinkd_%s\","
|
||||
"\"name\": \"%s\","
|
||||
"\"state_topic\": \"%s/%s\","
|
||||
"\"payload_on\": \"0\","
|
||||
"\"payload_off\": \"1\","
|
||||
"\"device_class\": \"battery\""
|
||||
"}";
|
||||
|
||||
// Same as above but no UOM
|
||||
const char *HASSIO_PUMP_SENSOR_DISCOVER2 = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"sensor\","
|
||||
"\"state_class\": \"measurement\","
|
||||
"\"unique_id\": \"aqualinkd_%s%d_%s\","
|
||||
"\"name\": \"%s %s %s\","
|
||||
"\"state_topic\": \"%s/%s%s\","
|
||||
"\"value_template\": \"{{ value_json }}\","
|
||||
"\"icon\": \"mdi:pump\""
|
||||
"}";
|
||||
|
||||
const char *HASS_PUMP_MODE_TEMPLATE = "\"{% set values = { '0':'local control', '1':'remote controled'} %}{{ values[value] if value in values.keys() else 'unknown' }}\"";
|
||||
|
||||
const char *HASS_PUMP_STATUS_TEMPLATE = "\"{% set values = { "
|
||||
"'-4':'Error',"
|
||||
"'-3':'Offline',"
|
||||
"'-2':'Priming',"
|
||||
"'-1':'Off',"
|
||||
"'0':'On',"
|
||||
"'1':'Ok', "
|
||||
"'2':'filter warning', "
|
||||
"'4':'Overcurrent condition', "
|
||||
"'8':'Priming', "
|
||||
"'16':'System blocked', "
|
||||
"'32':'General alarm', "
|
||||
"'64':'Overtemp condition', "
|
||||
"'128':'Power outage',"
|
||||
"'256':'Overcurrent condition 2',"
|
||||
"'512':'Overvoltage condition'} %}"
|
||||
"{{ values[value] if value in values.keys() else 'Unspecified Error' }}\"";
|
||||
|
||||
const char *HASSIO_PUMP_TEXT_SENSOR_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"sensor\","
|
||||
"\"unique_id\": \"aqualinkd_%s%d_%s\","
|
||||
"\"name\": \"%s %s %s\","
|
||||
"\"state_topic\": \"%s/%s%s\","
|
||||
"\"value_template\": %s,"
|
||||
"\"icon\": \"mdi:pump\""
|
||||
"}";
|
||||
/*
|
||||
Below doesn;t work (int and string values). Maybe try text sensor and add RPM/GPM to number
|
||||
Or add seperate text sensor. (this would be better options, that way you can see priming AND rpm)
|
||||
"value_template": "{% set values = { '-1':'priming', '-2':'offline', '-3':'error'} %}{{ values[value] if value in values.keys() else value }}",
|
||||
*/
|
||||
const char *HASSIO_TEXT_SENSOR_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"sensor\","
|
||||
"\"unique_id\": \"aqualinkd_%s\","
|
||||
"\"name\": \"%s\","
|
||||
"\"state_topic\": \"%s/%s\","
|
||||
"\"icon\": \"mdi:card-text\""
|
||||
"}";
|
||||
|
||||
const char *HASSIO_SWG_TEXT_SENSOR_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"sensor\","
|
||||
"\"unique_id\": \"%s\","
|
||||
"\"name\": \"%s\","
|
||||
"\"state_topic\": \"%s/%s\","
|
||||
"\"payload_on\": \"0\","
|
||||
"\"payload_off\": \"255\","
|
||||
"\"value_template\": \"{%% set values = { '0':'Generating',"
|
||||
"'1':'No flow', "
|
||||
"'2':'low salt', "
|
||||
"'4':'high salt', "
|
||||
"'8':'clean cell', "
|
||||
"'9':'turning off', "
|
||||
"'16':'high current', "
|
||||
"'32':'low volts', "
|
||||
"'64':'low temp', "
|
||||
"'128':'Check PCB',"
|
||||
"'253':'General Fault',"
|
||||
"'254':'Unknown',"
|
||||
"'255':'off'} %%}"
|
||||
"{{ values[value] if value in values.keys() else 'off' }}\","
|
||||
"\"icon\": \"mdi:card-text\""
|
||||
"}";
|
||||
|
||||
void publish_mqtt_hassio_discover(struct aqualinkdata *aqdata, struct mg_connection *nc)
|
||||
{
|
||||
if (_aqconfig_.mqtt_hass_discover_topic == NULL)
|
||||
return;
|
||||
|
||||
int i;
|
||||
char msg[JSON_STATUS_SIZE];
|
||||
char topic[250];
|
||||
char idbuf[128];
|
||||
char connections[128];
|
||||
|
||||
if (_aqconfig_.mqtt_hass_discover_use_mac) {
|
||||
char macaddress[20];
|
||||
mac(macaddress, 20, true);
|
||||
sprintf(connections, "\"connections\": [[\"mac\", \"%s\"]],", macaddress);
|
||||
} else {
|
||||
connections[0] = '\0';
|
||||
}
|
||||
|
||||
LOG(NET_LOG,LOG_INFO, "MQTT: Publishing discover messages to '%s'\n", _aqconfig_.mqtt_hass_discover_topic);
|
||||
|
||||
for (i=0; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
if (strcmp("NONE",aqdata->aqbuttons[i].label) != 0 ) {
|
||||
// Heaters
|
||||
if ( (strcmp(BTN_POOL_HTR,aqdata->aqbuttons[i].name) == 0 && (ENABLE_HEATERS || aqdata->pool_htr_set_point != TEMP_UNKNOWN)) ||
|
||||
(strcmp(BTN_SPA_HTR,aqdata->aqbuttons[i].name)==0 && (ENABLE_HEATERS || aqdata->spa_htr_set_point != TEMP_UNKNOWN)) ) {
|
||||
sprintf(msg,HASSIO_CLIMATE_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
aqdata->aqbuttons[i].name,
|
||||
aqdata->aqbuttons[i].label,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,(strcmp(BTN_POOL_HTR,aqdata->aqbuttons[i].name) == 0)?POOL_TEMP_TOPIC:SPA_TEMP_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
//(_aqconfig_.convert_mqtt_temp?HASSIO_CONVERT_CLIMATE_TOF:HASSIO_NO_CONVERT_CLIMATE));
|
||||
//(_aqconfig_.convert_mqtt_temp?degFtoC(36):36.00),
|
||||
//(_aqconfig_.convert_mqtt_temp?degFtoC(104):104.00),
|
||||
(_aqconfig_.convert_mqtt_temp?(float)HEATER_MIN_C:(float)HEATER_MIN_F),
|
||||
(_aqconfig_.convert_mqtt_temp?(float)HEATER_MAX_C:(float)HEATER_MAX_F),
|
||||
(_aqconfig_.convert_mqtt_temp?"C":"F"));
|
||||
sprintf(topic, "%s/climate/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->aqbuttons[i].name);
|
||||
send_mqtt(nc, topic, msg);
|
||||
} else if ( isPLIGHT(aqdata->aqbuttons[i].special_mask) && ((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType == LC_DIMMER2 ) {
|
||||
// Dimmer
|
||||
sprintf(msg,HASSIO_DIMMER_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
aqdata->aqbuttons[i].name,
|
||||
aqdata->aqbuttons[i].label,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,LIGHT_DIMMER_VALUE_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,LIGHT_DIMMER_VALUE_TOPIC);
|
||||
sprintf(topic, "%s/light/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->aqbuttons[i].name);
|
||||
send_mqtt(nc, topic, msg);
|
||||
} else if ( isPLIGHT(aqdata->aqbuttons[i].special_mask) ) {
|
||||
// Color Lights & Dimmer as selector switch
|
||||
// Build the
|
||||
|
||||
char buf[512];
|
||||
build_color_light_jsonarray(((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType, buf, 512 );
|
||||
sprintf(msg,HASSIO_SELECTOR_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
aqdata->aqbuttons[i].name,
|
||||
aqdata->aqbuttons[i].label,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
buf,
|
||||
"mdi:lightbulb");
|
||||
sprintf(topic, "%s/select/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->aqbuttons[i].name);
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
// Duplicate normal switch as we want a duplicate
|
||||
sprintf(msg, HASSIO_SWITCH_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
aqdata->aqbuttons[i].name,
|
||||
aqdata->aqbuttons[i].label,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
"mdi:lightbulb");
|
||||
sprintf(topic, "%s/switch/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->aqbuttons[i].name);
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
} else {
|
||||
// Switches
|
||||
//sprintf(msg,"{\"type\": \"switch\",\"unique_id\": \"%s\",\"name\": \"%s\",\"state_topic\": \"aqualinkd/%s\",\"command_topic\": \"aqualinkd/%s/set\",\"json_attributes_topic\": \"aqualinkd/%s/delay\",\"json_attributes_topic\": \"aqualinkd/%s/delay\",\"json_attributes_template\": \"{{ {'delay': value|int} | tojson }}\",\"payload_on\": \"1\",\"payload_off\": \"0\",\"qos\": 1,\"retain\": false}" ,
|
||||
sprintf(msg, HASSIO_SWITCH_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
aqdata->aqbuttons[i].name,
|
||||
aqdata->aqbuttons[i].label,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,
|
||||
"mdi:toggle-switch-variant");
|
||||
sprintf(topic, "%s/switch/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->aqbuttons[i].name);
|
||||
send_mqtt(nc, topic, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Freezeprotect
|
||||
if ( ENABLE_FREEZEPROTECT || (aqdata->frz_protect_set_point != TEMP_UNKNOWN && aqdata->air_temp != TEMP_UNKNOWN) ) {
|
||||
sprintf(msg, HASSIO_FREEZE_PROTECT_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
FREEZE_PROTECT,
|
||||
_aqconfig_.mqtt_aq_topic,AIR_TEMP_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,FREEZE_PROTECT_ENABELED,
|
||||
_aqconfig_.mqtt_aq_topic,FREEZE_PROTECT,
|
||||
_aqconfig_.mqtt_aq_topic,FREEZE_PROTECT,
|
||||
_aqconfig_.mqtt_aq_topic,FREEZE_PROTECT,
|
||||
//(_aqconfig_.convert_mqtt_temp?HASSIO_CONVERT_CLIMATE_TOF:HASSIO_NO_CONVERT_CLIMATE));
|
||||
//(_aqconfig_.convert_mqtt_temp?degFtoC(34):34.00),
|
||||
//(_aqconfig_.convert_mqtt_temp?degFtoC(42):42.00),
|
||||
(_aqconfig_.convert_mqtt_temp?(float)FREEZE_PT_MIN_C:(float)FREEZE_PT_MIN_F),
|
||||
(_aqconfig_.convert_mqtt_temp?(float)FREEZE_PT_MAX_C:(float)FREEZE_PT_MAX_F),
|
||||
(_aqconfig_.convert_mqtt_temp?"C":"F"));
|
||||
sprintf(topic, "%s/climate/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, FREEZE_PROTECT);
|
||||
send_mqtt(nc, topic, msg);
|
||||
}
|
||||
|
||||
//if (ENABLE_CHILLER || (aqdata->chiller_set_point != TEMP_UNKNOWN && aqdata->chiller_state != LED_S_UNKNOWN) ) {
|
||||
if ( (ENABLE_CHILLER || aqdata->chiller_set_point != TEMP_UNKNOWN ) && (aqdata->chiller_button != NULL) ) {
|
||||
// USe freeze protect for the moment.
|
||||
sprintf(msg, HASSIO_CHILLER_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
CHILLER,
|
||||
_aqconfig_.mqtt_aq_topic,CHILLER,
|
||||
_aqconfig_.mqtt_aq_topic,POOL_TEMP_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,CHILLER,
|
||||
_aqconfig_.mqtt_aq_topic,CHILLER_ENABELED,
|
||||
_aqconfig_.mqtt_aq_topic,CHILLER,
|
||||
_aqconfig_.mqtt_aq_topic,CHILLER,
|
||||
_aqconfig_.mqtt_aq_topic,CHILLER,
|
||||
//(_aqconfig_.convert_mqtt_temp?HASSIO_CONVERT_CLIMATE_TOF:HASSIO_NO_CONVERT_CLIMATE));
|
||||
//(_aqconfig_.convert_mqtt_temp?degFtoC(34):34.00),
|
||||
//(_aqconfig_.convert_mqtt_temp?degFtoC(104):104.00),
|
||||
(_aqconfig_.convert_mqtt_temp?(float)CHILLER_MIN_C:(float)CHILLER_MIN_F),
|
||||
(_aqconfig_.convert_mqtt_temp?(float)CHILLER_MAX_C:(float)CHILLER_MAX_F),
|
||||
(_aqconfig_.convert_mqtt_temp?"C":"F"));
|
||||
sprintf(topic, "%s/climate/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, CHILLER);
|
||||
send_mqtt(nc, topic, msg);
|
||||
}
|
||||
|
||||
// SWG
|
||||
if ( ENABLE_SWG || aqdata->swg_percent != TEMP_UNKNOWN ) {
|
||||
|
||||
sprintf(msg, HASSIO_SWG_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
SWG_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,SWG_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,SWG_PERCENT_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,SWG_PERCENT_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,SWG_PERCENT_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,SWG_PERCENT_TOPIC
|
||||
);
|
||||
sprintf(topic, "%s/humidifier/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, SWG_TOPIC);
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
rsm_char_replace(idbuf, SWG_BOOST_TOPIC, "/", "_");
|
||||
sprintf(msg, HASSIO_SWITCH_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
idbuf,
|
||||
"SWG Boost",
|
||||
_aqconfig_.mqtt_aq_topic,SWG_BOOST_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,SWG_BOOST_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,SWG_BOOST_TOPIC,
|
||||
_aqconfig_.mqtt_aq_topic,SWG_BOOST_TOPIC,
|
||||
"mdi:toggle-switch-variant");
|
||||
sprintf(topic, "%s/switch/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, idbuf);
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
rsm_char_replace(idbuf, SWG_PERCENT_TOPIC, "/", "_");
|
||||
sprintf(msg, HASSIO_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,idbuf,"SWG Percent",_aqconfig_.mqtt_aq_topic,SWG_PERCENT_TOPIC, "%", "mdi:water-outline");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, idbuf);
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
rsm_char_replace(idbuf, SWG_PPM_TOPIC, "/", "_");
|
||||
sprintf(msg, HASSIO_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,idbuf,"SWG PPM",_aqconfig_.mqtt_aq_topic,SWG_PPM_TOPIC, "ppm", "mdi:water-outline");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, idbuf);
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
rsm_char_replace(idbuf, SWG_EXTENDED_TOPIC, "/", "_");
|
||||
sprintf(msg, HASSIO_SWG_TEXT_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,idbuf,"SWG Msg",_aqconfig_.mqtt_aq_topic,SWG_EXTENDED_TOPIC);
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, idbuf);
|
||||
send_mqtt(nc, topic, msg);
|
||||
}
|
||||
|
||||
// Temperatures
|
||||
sprintf(msg, HASSIO_TEMP_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,"Pool","Pool",_aqconfig_.mqtt_aq_topic,POOL_TEMP_TOPIC,(_aqconfig_.convert_mqtt_temp?"°C":"°F"),"mdi:water-thermometer");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, "Pool");
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
sprintf(msg, HASSIO_TEMP_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,"Spa","Spa",_aqconfig_.mqtt_aq_topic,SPA_TEMP_TOPIC,(_aqconfig_.convert_mqtt_temp?"°C":"°F"),"mdi:water-thermometer");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, "Spa");
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
sprintf(msg, HASSIO_TEMP_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,"Air","Air",_aqconfig_.mqtt_aq_topic,AIR_TEMP_TOPIC,(_aqconfig_.convert_mqtt_temp?"°C":"°F"),"mdi:thermometer");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, "Air");
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
// VSP Pumps
|
||||
for (i=0; i < aqdata->num_pumps; i++) {
|
||||
char units[] = "Speed";
|
||||
// Create a FAN for pump against the button it' assigned to
|
||||
// In the future maybe change this to the pump# or change the sensors to button???
|
||||
sprintf(msg, HASSIO_VSP_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
aqdata->pumps[i].button->name,units,
|
||||
aqdata->pumps[i].button->label,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name,units,
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name,units);
|
||||
|
||||
sprintf(topic, "%s/fan/aqualinkd/aqualinkd_%s_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->pumps[i].button->name, units);
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
// Create sensors for each pump, against it's pump number
|
||||
int pn=i+1;
|
||||
|
||||
if (aqdata->pumps[i].pumpType==VFPUMP || aqdata->pumps[i].pumpType==VSPUMP) {
|
||||
// We have GPM info
|
||||
sprintf(msg, HASSIO_PUMP_SENSOR_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
"Pump",pn,"GPM",
|
||||
aqdata->pumps[i].button->label,(rsm_strncasestr(aqdata->pumps[i].button->label,"pump",strlen(aqdata->pumps[i].button->label))!=NULL)?"":"Pump","GPM",
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name ,PUMP_GPM_TOPIC,
|
||||
"GPM");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s%d_%s/config", _aqconfig_.mqtt_hass_discover_topic, "Pump",pn,"GPM");
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
if (READ_RSDEV_vsfPUMP ) {
|
||||
// All Pentair hame some other info we gather.
|
||||
sprintf(msg, HASSIO_PUMP_SENSOR_DISCOVER2,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
"Pump",pn,"PPC",
|
||||
aqdata->pumps[i].button->label,(rsm_strncasestr(aqdata->pumps[i].button->label,"pump",strlen(aqdata->pumps[i].button->label))!=NULL)?"":"Pump","Presure Curve",
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name ,PUMP_PPC_TOPIC);
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s%d_%s/config", _aqconfig_.mqtt_hass_discover_topic, "Pump",pn,"PPC");
|
||||
send_mqtt(nc, topic, msg);
|
||||
/*
|
||||
sprintf(msg, HASSIO_PUMP_SENSOR_DISCOVER2,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
"Pump",pn,"Mode",
|
||||
aqdata->pumps[i].button->label,(rsm_strncasestr(aqdata->pumps[i].button->label,"pump",strlen(aqdata->pumps[i].button->label))!=NULL)?"":"Pump","Mode",
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name ,PUMP_MODE_TOPIC);
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s%d_%s/config", _aqconfig_.mqtt_hass_discover_topic, "Pump",pn,"Mode");
|
||||
send_mqtt(nc, topic, msg);
|
||||
*/
|
||||
sprintf(msg, HASSIO_PUMP_TEXT_SENSOR_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
"Pump",pn,"Mode",
|
||||
aqdata->pumps[i].button->label,(rsm_strncasestr(aqdata->pumps[i].button->label,"pump",strlen(aqdata->pumps[i].button->label))!=NULL)?"":"Pump","Mode",
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name ,PUMP_MODE_TOPIC,
|
||||
HASS_PUMP_MODE_TEMPLATE);
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s%d_%s/config", _aqconfig_.mqtt_hass_discover_topic, "Pump",pn,"Mode");
|
||||
send_mqtt(nc, topic, msg);
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(msg, HASSIO_PUMP_TEXT_SENSOR_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
"Pump",pn,"Status",
|
||||
aqdata->pumps[i].button->label,(rsm_strncasestr(aqdata->pumps[i].button->label,"pump",strlen(aqdata->pumps[i].button->label))!=NULL)?"":"Pump","Status",
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name ,PUMP_STATUS_TOPIC,
|
||||
HASS_PUMP_STATUS_TEMPLATE);
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s%d_%s/config", _aqconfig_.mqtt_hass_discover_topic, "Pump",pn,"Status");
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
// All pumps have the below.
|
||||
sprintf(msg, HASSIO_PUMP_SENSOR_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
"Pump",pn,"RPM",
|
||||
aqdata->pumps[i].button->label,(rsm_strncasestr(aqdata->pumps[i].button->label,"pump",strlen(aqdata->pumps[i].button->label))!=NULL)?"":"Pump","RPM",
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name ,PUMP_RPM_TOPIC,
|
||||
"RPM");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s%d_%s/config", _aqconfig_.mqtt_hass_discover_topic, "Pump",pn,"RPM");
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
sprintf(msg, HASSIO_PUMP_SENSOR_DISCOVER,
|
||||
connections,
|
||||
_aqconfig_.mqtt_aq_topic,
|
||||
"Pump",pn,"Watts",
|
||||
aqdata->pumps[i].button->label,(rsm_strncasestr(aqdata->pumps[i].button->label,"pump",strlen(aqdata->pumps[i].button->label))!=NULL)?"":"Pump","Watts",
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name ,PUMP_WATTS_TOPIC,
|
||||
"Watts");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s%d_%s/config", _aqconfig_.mqtt_hass_discover_topic, "Pump",pn,"Watts");
|
||||
send_mqtt(nc, topic, msg);
|
||||
}
|
||||
|
||||
// Chem feeder (ph/orp)
|
||||
if (ENABLE_CHEM_FEEDER || aqdata->ph != TEMP_UNKNOWN) {
|
||||
rsm_char_replace(idbuf, CHEM_PH_TOPIC, "/", "_");
|
||||
sprintf(msg, HASSIO_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,idbuf,"Water Chemistry pH",_aqconfig_.mqtt_aq_topic,CHEM_PH_TOPIC, "pH", "mdi:water-outline");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, idbuf);
|
||||
send_mqtt(nc, topic, msg);
|
||||
}
|
||||
|
||||
if (ENABLE_CHEM_FEEDER || aqdata->orp != TEMP_UNKNOWN) {
|
||||
rsm_char_replace(idbuf, CHEM_ORP_TOPIC, "/", "_");
|
||||
sprintf(msg, HASSIO_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,idbuf,"Water Chemistry ORP",_aqconfig_.mqtt_aq_topic,CHEM_ORP_TOPIC, "orp", "mdi:water-outline");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, idbuf);
|
||||
send_mqtt(nc, topic, msg);
|
||||
}
|
||||
|
||||
// Misc stuff
|
||||
sprintf(msg, HASSIO_SERVICE_MODE_ENUM_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,SERVICE_MODE_TOPIC,"Service Mode",_aqconfig_.mqtt_aq_topic,SERVICE_MODE_TOPIC, "mdi:account-wrench");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, SERVICE_MODE_TOPIC);
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
/* // Leave below if we decide to go back to a text box
|
||||
sprintf(msg, HASSIO_TEXT_DISCOVER,DISPLAY_MSG_TOPIC,"Display Messages",_aqconfig_.mqtt_aq_topic,DISPLAY_MSG_TOPIC);
|
||||
sprintf(topic, "%s/text/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, DISPLAY_MSG_TOPIC);
|
||||
*/
|
||||
// It actually works better posting this to sensor and not text.
|
||||
sprintf(msg, HASSIO_TEXT_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,DISPLAY_MSG_TOPIC,"Display Msg",_aqconfig_.mqtt_aq_topic,DISPLAY_MSG_TOPIC);
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, DISPLAY_MSG_TOPIC);
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
sprintf(msg, HASSIO_BATTERY_SENSOR_DISCOVER,connections,_aqconfig_.mqtt_aq_topic,BATTERY_STATE,BATTERY_STATE,_aqconfig_.mqtt_aq_topic,BATTERY_STATE);
|
||||
sprintf(topic, "%s/binary_sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic,BATTERY_STATE);
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
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);
|
||||
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(topic, "%s/sensor/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, idbuf);
|
||||
send_mqtt(nc, topic, msg);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef HASSIO_H_
|
||||
#define HASSIO_H_
|
||||
|
||||
|
||||
|
||||
void publish_mqtt_hassio_discover(struct aqualinkdata *aqdata, struct mg_connection *nc);
|
||||
|
||||
#endif // HASSIO_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -5,7 +5,7 @@
|
|||
#define IAQT_MSGLEN 21
|
||||
|
||||
struct iaqt_page_button {
|
||||
char *name[IAQT_MSGLEN];
|
||||
char name[IAQT_MSGLEN];
|
||||
unsigned char type; // 0x01 box, 0x08 icon wirlpool, 0x0b icon heater, 0x01 icon (main page), 0x07 light
|
||||
unsigned char state;
|
||||
unsigned char keycode;
|
||||
|
@ -15,8 +15,9 @@ struct iaqt_page_button {
|
|||
bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data);
|
||||
unsigned char iaqtThreadKickType();
|
||||
unsigned char iaqtCurrentPage();
|
||||
unsigned char iaqtCurrentPageLoading();
|
||||
bool wasiaqtThreadKickTypePage();
|
||||
struct iaqt_page_button *iaqtFindButtonByLabel(char *label);
|
||||
struct iaqt_page_button *iaqtFindButtonByLabel(const char *label);
|
||||
struct iaqt_page_button *iaqtFindButtonByIndex(int index);
|
||||
const char *iaqtGetMessageLine(int index);
|
||||
const char *iaqtGetTableInfoLine(int index);
|
||||
|
@ -1697,4 +1698,4 @@ Jandy To 0x60 of type Probe | HEX: 0x10|0x02|0x60|0x00|0x72|0x10|0x03|
|
|||
Jandy To 0x31 of type Unknown | HEX: 0x10|0x02|0x31|0x30|0x73|0x10|0x03|
|
||||
Jandy From 0x31 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
|
||||
*/
|
||||
*/
|
|
@ -32,6 +32,7 @@
|
|||
#include "config.h"
|
||||
#include "devices_jandy.h"
|
||||
#include "packetLogger.h"
|
||||
#include "color_lights.h"
|
||||
|
||||
// System Page is obfiously fixed and not dynamic loaded, so set buttons to stop confustion.
|
||||
|
||||
|
@ -45,8 +46,6 @@
|
|||
#define KEY_IAQTCH_LOCKOUT_PASSWD KEY_IAQTCH_KEY08
|
||||
#define KEY_IAQTCH_SET_ACQUAPURE KEY_IAQTCH_KEY09
|
||||
|
||||
|
||||
|
||||
bool _cansend = false;
|
||||
|
||||
unsigned char _iaqt_pgm_command = NUL;
|
||||
|
@ -98,6 +97,12 @@ void waitfor_iaqt_queue2empty()
|
|||
delay(PROGRAMMING_POLL_DELAY_TIME);
|
||||
}
|
||||
|
||||
// Initial startup can take some time, _cansend should be false during this time.
|
||||
// If we start programming before we receive the first status page, nothing works, this forces that wait
|
||||
while(_cansend == false) {
|
||||
delay(PROGRAMMING_POLL_DELAY_TIME * 2);
|
||||
}
|
||||
|
||||
if (_iaqt_pgm_command != NUL) {
|
||||
// Wait for longer interval
|
||||
while ( (_iaqt_pgm_command != NUL) && ( i++ < PROGRAMMING_POLL_COUNTER * 2 ) ) {
|
||||
|
@ -125,7 +130,7 @@ void send_aqt_cmd(unsigned char cmd)
|
|||
*
|
||||
*/
|
||||
|
||||
unsigned char _iaqt_control_cmd[AQ_MAXPKTLEN];
|
||||
unsigned char _iaqt_control_cmd[AQ_MAXPKTLEN_SEND];
|
||||
int _iaqt_control_cmd_len;
|
||||
|
||||
|
||||
|
@ -135,9 +140,9 @@ int ref_iaqt_control_cmd(unsigned char **cmd)
|
|||
*cmd = _iaqt_control_cmd;
|
||||
|
||||
if ( getLogLevel(IAQT_LOG) >= LOG_DEBUG ) {
|
||||
char buff[1000];
|
||||
char buff[1024];
|
||||
//sprintf("Sending control command:")
|
||||
beautifyPacket(buff, _iaqt_control_cmd, _iaqt_control_cmd_len, false);
|
||||
beautifyPacket(buff, 1024, _iaqt_control_cmd, _iaqt_control_cmd_len, false);
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Sending commandsed : %s\n", buff);
|
||||
}
|
||||
|
||||
|
@ -146,7 +151,7 @@ int ref_iaqt_control_cmd(unsigned char **cmd)
|
|||
|
||||
void rem_iaqt_control_cmd(unsigned char *cmd)
|
||||
{
|
||||
memset(_iaqt_control_cmd, 0, AQ_MAXPKTLEN * sizeof(unsigned char));
|
||||
memset(_iaqt_control_cmd, 0, AQ_MAXPKTLEN_SEND * sizeof(unsigned char));
|
||||
_iaqt_control_cmd_len = 0;
|
||||
}
|
||||
|
||||
|
@ -167,9 +172,64 @@ bool waitfor_iaqt_ctrl_queue2empty()
|
|||
}
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
unsigned const char _waitfor_iaqt_nextPage(struct aqualinkdata *aq_data, int numMessageReceived) {
|
||||
|
||||
waitfor_iaqt_queue2empty();
|
||||
|
||||
int i=0;
|
||||
|
||||
pthread_mutex_lock(&aq_data->active_thread.thread_mutex);
|
||||
|
||||
while( ++i <= numMessageReceived)
|
||||
{
|
||||
//LOG(IAQT_LOG,LOG_DEBUG, "waitfor_iaqt_nextPage (%d of %d)\n",i,numMessageReceived);
|
||||
pthread_cond_wait(&aq_data->active_thread.thread_cond, &aq_data->active_thread.thread_mutex);
|
||||
if(wasiaqtThreadKickTypePage()) break;
|
||||
}
|
||||
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "waitfor_iaqt_nextPage finished in (%d of %d)\n",i,numMessageReceived);
|
||||
|
||||
pthread_mutex_unlock(&aq_data->active_thread.thread_mutex);
|
||||
|
||||
if(wasiaqtThreadKickTypePage())
|
||||
return iaqtCurrentPage();
|
||||
else
|
||||
return NUL;
|
||||
|
||||
}
|
||||
|
||||
unsigned const char shortwaitfor_iaqt_nextPage(struct aqualinkdata *aq_data) {
|
||||
return _waitfor_iaqt_nextPage(aq_data, 3);
|
||||
}
|
||||
*/
|
||||
unsigned const char waitfor_iaqt_messages(struct aqualinkdata *aq_data, int numMessageReceived) {
|
||||
//return _waitfor_iaqt_nextPage(aq_data, 30);
|
||||
|
||||
waitfor_iaqt_queue2empty();
|
||||
|
||||
int i=0;
|
||||
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "waitfor_iaqt_messages (%d of %d)\n",i,numMessageReceived);
|
||||
|
||||
pthread_mutex_lock(&aq_data->active_thread.thread_mutex);
|
||||
|
||||
while( ++i <= numMessageReceived)
|
||||
{
|
||||
//LOG(IAQT_LOG,LOG_DEBUG, "waitfor_iaqt_nextPage (%d of %d)\n",i,numMessageReceived);
|
||||
pthread_cond_wait(&aq_data->active_thread.thread_cond, &aq_data->active_thread.thread_mutex);
|
||||
|
||||
}
|
||||
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "waitfor_iaqt_messages finished in (%d of %d)\n",i,numMessageReceived);
|
||||
|
||||
pthread_mutex_unlock(&aq_data->active_thread.thread_mutex);
|
||||
|
||||
return iaqtLastMsg();
|
||||
}
|
||||
|
||||
unsigned const char waitfor_iaqt_nextPage(struct aqualinkdata *aq_data) {
|
||||
//return _waitfor_iaqt_nextPage(aq_data, 30);
|
||||
|
||||
waitfor_iaqt_queue2empty();
|
||||
|
||||
|
@ -193,9 +253,10 @@ unsigned const char waitfor_iaqt_nextPage(struct aqualinkdata *aq_data) {
|
|||
return iaqtCurrentPage();
|
||||
else
|
||||
return NUL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned const char waitfor_iaqt_nextMessage(struct aqualinkdata *aq_data, const unsigned char msg_type) {
|
||||
|
||||
waitfor_iaqt_queue2empty();
|
||||
|
@ -222,7 +283,7 @@ typedef enum {icct_setrpm, icct_settime, icct_setdate} iaqtControlCmdYype;
|
|||
|
||||
// Type is always 0 at the moment, haven't found any
|
||||
void queue_iaqt_control_command(iaqtControlCmdYype type, int num) {
|
||||
//unsigned char packets[AQ_MAXPKTLEN];
|
||||
//unsigned char packets[AQ_MAXPKTLEN_SEND];
|
||||
//int cnt;
|
||||
|
||||
if (waitfor_iaqt_ctrl_queue2empty() == false)
|
||||
|
@ -309,15 +370,28 @@ bool goto_iaqt_page(const unsigned char pageID, struct aqualinkdata *aq_data) {
|
|||
|
||||
if (pageID == IAQ_PAGE_DEVICES) {
|
||||
send_aqt_cmd(KEY_IAQTCH_HOMEP_KEY08);
|
||||
if (waitfor_iaqt_nextPage(aq_data) != IAQ_PAGE_DEVICES) {
|
||||
unsigned char page = waitfor_iaqt_nextPage(aq_data);
|
||||
if (page != IAQ_PAGE_DEVICES && page != IAQ_PAGE_DEVICES_REV_Yg) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find Device page\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
LOG(IAQT_LOG, LOG_DEBUG, "IAQ Touch got to Device page\n");
|
||||
return true;
|
||||
} else if (pageID == IAQ_PAGE_ONETOUCH) {
|
||||
send_aqt_cmd(KEY_IAQTCH_ONETOUCH);
|
||||
if (iaqtCurrentPage() != IAQ_PAGE_ONETOUCH) {
|
||||
unsigned char page = waitfor_iaqt_nextPage(aq_data);
|
||||
if (page != IAQ_PAGE_ONETOUCH ) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find OneTouch page\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
LOG(IAQT_LOG, LOG_DEBUG, "IAQ Touch got to OneTouch page\n");
|
||||
return true;
|
||||
} else if (pageID == IAQ_PAGE_MENU || pageID == IAQ_PAGE_SET_TEMP || pageID == IAQ_PAGE_SET_TIME || pageID == IAQ_PAGE_SET_SWG ||
|
||||
pageID == IAQ_PAGE_SYSTEM_SETUP || pageID == IAQ_PAGE_FREEZE_PROTECT || pageID == IAQ_PAGE_LABEL_AUX || pageID == IAQ_PAGE_VSP_SETUP) {
|
||||
pageID == IAQ_PAGE_SYSTEM_SETUP || pageID == IAQ_PAGE_FREEZE_PROTECT || pageID == IAQ_PAGE_LABEL_AUX ||
|
||||
pageID == IAQ_PAGE_VSP_SETUP) {
|
||||
// All other pages require us to go to Menu page
|
||||
send_aqt_cmd(KEY_IAQTCH_MENU);
|
||||
if (waitfor_iaqt_nextPage(aq_data) != IAQ_PAGE_MENU) {
|
||||
|
@ -388,8 +462,14 @@ bool goto_iaqt_page(const unsigned char pageID, struct aqualinkdata *aq_data) {
|
|||
|
||||
button = iaqtFindButtonByLabel(menuText);
|
||||
if (button == NULL) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find '%s' button on page setup\n", menuText);
|
||||
return false;
|
||||
//send_aqt_cmd(KEY_IAQTCH_NEXT_PAGE);
|
||||
// Try Next Page
|
||||
//unsigned char page = waitfor_iaqt_nextPage(aq_data);
|
||||
//LOG(IAQT_LOG, LOG_ERR, "PAGE RETURN IS 0x%02hhx\n",page);
|
||||
//if (waitfor_iaqt_nextPage(aq_data) != pageID) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find '%s' button on page setup\n", menuText);
|
||||
return false;
|
||||
//}
|
||||
}
|
||||
// send_aqt_cmd(KEY_IAQTCH_KEY01);
|
||||
send_aqt_cmd(button->keycode);
|
||||
|
@ -406,6 +486,250 @@ bool goto_iaqt_page(const unsigned char pageID, struct aqualinkdata *aq_data) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void *set_aqualink_iaqtouch_device_on_off( void *ptr )
|
||||
{
|
||||
struct programmingThreadCtrl *threadCtrl;
|
||||
threadCtrl = (struct programmingThreadCtrl *) ptr;
|
||||
struct aqualinkdata *aq_data = threadCtrl->aq_data;
|
||||
char *buf = (char*)threadCtrl->thread_args;
|
||||
//char device_name[15];
|
||||
struct iaqt_page_button *button;
|
||||
|
||||
unsigned int device = atoi(&buf[0]);
|
||||
unsigned int state = atoi(&buf[5]);
|
||||
|
||||
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_IAQTOUCH_DEVICE_ON_OFF);
|
||||
|
||||
if (device > aq_data->total_buttons) {
|
||||
LOG(IAQT_LOG,LOG_ERR, "(PDA mode) Device On/Off :- bad device number '%d'\n",device);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
LOG(IAQT_LOG,LOG_INFO, "PDA Device On/Off, device '%s', state %d\n",aq_data->aqbuttons[device].label,state);
|
||||
|
||||
// See if it's on the current page
|
||||
button = iaqtFindButtonByLabel(aq_data->aqbuttons[device].label);
|
||||
|
||||
if (button == NULL && isVBUTTON_ALTLABEL(aq_data->aqbuttons[device].special_mask) ) { // Try alt button name
|
||||
button = iaqtFindButtonByLabel(((vbutton_detail *)aq_data->aqbuttons[device].special_mask_ptr)->altlabel);
|
||||
}
|
||||
|
||||
if (button == NULL) {
|
||||
// No luck, go to the device page
|
||||
if ( goto_iaqt_page(IAQ_PAGE_DEVICES, aq_data) == false )
|
||||
goto f_end;
|
||||
|
||||
button = iaqtFindButtonByLabel(aq_data->aqbuttons[device].label);
|
||||
|
||||
if (button == NULL && isVBUTTON_ALTLABEL(aq_data->aqbuttons[device].special_mask) ) { // Try alt button name
|
||||
button = iaqtFindButtonByLabel(((vbutton_detail *)aq_data->aqbuttons[device].special_mask_ptr)->altlabel);
|
||||
}
|
||||
|
||||
// If not found see if page has next
|
||||
if (button == NULL && iaqtFindButtonByIndex(16)->type == 0x03 ) {
|
||||
iaqt_queue_cmd(KEY_IAQTCH_NEXT_PAGE);
|
||||
waitfor_iaqt_nextPage(aq_data);
|
||||
// This will fail, since not looking at device page 2 buttons
|
||||
button = iaqtFindButtonByLabel(aq_data->aqbuttons[device].label);
|
||||
}
|
||||
}
|
||||
|
||||
if (button == NULL) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find '%s' button on device list\n", aq_data->aqbuttons[device].label);
|
||||
goto f_end;
|
||||
}
|
||||
|
||||
send_aqt_cmd(button->keycode);
|
||||
//LOG(IAQT_LOG, LOG_ERR, "******* CURRENT MENU '0x%02hhx' *****\n",iaqtCurrentPage());
|
||||
// NSF NEED TO CHECK FOR POPUP MESSAGE, AND KILL IT.
|
||||
//page IAQ_PAGE_SET_TEMP hit button 0
|
||||
//page IAQ_PAGE_COLOR_LIGHT hit button ???????
|
||||
// Heater popup can be cleared with a home button and still turn on.
|
||||
// Color light can be cleared with a home button, but won;t turn on.
|
||||
|
||||
waitfor_iaqt_queue2empty();
|
||||
//waitfor_iaqt_messages(aq_data,1);
|
||||
|
||||
// OR maybe use waitfor_iaqt_messages(aq_data,1)
|
||||
|
||||
// Turn spa on when pump off, ned to remove message "spa will turn on after safty delay", home doesn't clear.
|
||||
send_aqt_cmd(KEY_IAQTCH_HOME);
|
||||
|
||||
// Turn spa off need to read message if heater is on AND hit ok......
|
||||
|
||||
f_end:
|
||||
goto_iaqt_page(IAQ_PAGE_HOME, aq_data);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
||||
// just stop compiler error, ptr is not valid as it's just been freed
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
// Not complete, and not needed with
|
||||
void *set_aqualink_iaqtouch_onetouch_on_off( void *ptr )
|
||||
{
|
||||
struct programmingThreadCtrl *threadCtrl;
|
||||
threadCtrl = (struct programmingThreadCtrl *) ptr;
|
||||
struct aqualinkdata *aq_data = threadCtrl->aq_data;
|
||||
char *buf = (char*)threadCtrl->thread_args;
|
||||
//char device_name[15];
|
||||
struct iaqt_page_button *button;
|
||||
|
||||
unsigned int device = atoi(&buf[0]);
|
||||
unsigned int state = atoi(&buf[5]);
|
||||
|
||||
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_IAQTOUCH_ONETOUCH_ON_OFF);
|
||||
|
||||
LOG(IAQT_LOG,LOG_INFO, "OneTouch Device On/Off, device '%s', state %d\n",aq_data->aqbuttons[device].label,state);
|
||||
|
||||
if ( goto_iaqt_page(IAQ_PAGE_ONETOUCH, aq_data) == false )
|
||||
goto f_end;
|
||||
|
||||
// See if it's on the current page
|
||||
button = iaqtFindButtonByLabel(aq_data->aqbuttons[device].label);
|
||||
|
||||
|
||||
f_end:
|
||||
goto_iaqt_page(IAQ_PAGE_HOME, aq_data);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void *set_aqualink_iaqtouch_light_colormode( void *ptr )
|
||||
{
|
||||
struct programmingThreadCtrl *threadCtrl;
|
||||
threadCtrl = (struct programmingThreadCtrl *) ptr;
|
||||
struct aqualinkdata *aq_data = threadCtrl->aq_data;
|
||||
char *buf = (char*)threadCtrl->thread_args;
|
||||
//char device_name[15];
|
||||
struct iaqt_page_button *button;
|
||||
const char *mode_name;
|
||||
int val = atoi(&buf[0]);
|
||||
int btn = atoi(&buf[5]);
|
||||
int typ = atoi(&buf[10]);
|
||||
bool use_current_mode = false;
|
||||
bool turn_off = false;
|
||||
|
||||
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE);
|
||||
|
||||
//char *buf = (char*)threadCtrl->thread_args;
|
||||
|
||||
|
||||
if (btn < 0 || btn >= aq_data->total_buttons ) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "Can't program light mode on button %d\n", btn);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
aqkey *key = &aq_data->aqbuttons[btn];
|
||||
//unsigned char code = key->code;
|
||||
|
||||
// We also need to cater for light being ON AND changing the color mode. we have extra OK to hit.
|
||||
if (val == 0) {
|
||||
use_current_mode = true;
|
||||
LOG(IAQT_LOG, LOG_INFO, "Light Programming #: %d, button: %s, color light type: %d, using current mode\n", val, key->label, typ);
|
||||
// NOT SURE WHAT TO DO HERE..... No color mode and iaatouch doesn;t support last color in PDA mode.
|
||||
} else if (val == -1) {
|
||||
turn_off = true;
|
||||
LOG(IAQT_LOG, LOG_INFO, "Light Programming #: %d, button: %s, color light type: %d, Turning off\n", val, key->label, typ);
|
||||
} else {
|
||||
mode_name = light_mode_name(typ, val-1, IAQTOUCH);
|
||||
use_current_mode = false;
|
||||
if (mode_name == NULL) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "Light Programming #: %d, button: %s, color light type: %d, couldn't find mode name '%s'\n", val, key->label, typ, mode_name);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
return ptr;
|
||||
} else {
|
||||
LOG(IAQT_LOG, LOG_INFO, "Light Programming #: %d, button: %s, color light type: %d, name '%s'\n", val, key->label, typ, mode_name);
|
||||
}
|
||||
}
|
||||
|
||||
// See if it's on the current page
|
||||
button = iaqtFindButtonByLabel(key->label);
|
||||
|
||||
if (button == NULL) {
|
||||
// No luck, go to the device page
|
||||
if ( goto_iaqt_page(IAQ_PAGE_DEVICES, aq_data) == false )
|
||||
goto f_end;
|
||||
|
||||
button = iaqtFindButtonByLabel(key->label);
|
||||
|
||||
// If not found see if page has next
|
||||
if (button == NULL && iaqtFindButtonByIndex(16)->type == 0x03 ) {
|
||||
iaqt_queue_cmd(KEY_IAQTCH_NEXT_PAGE);
|
||||
waitfor_iaqt_nextPage(aq_data);
|
||||
// This will fail, since not looking at device page 2 buttons
|
||||
button = iaqtFindButtonByLabel(key->label);
|
||||
}
|
||||
}
|
||||
|
||||
if (button == NULL) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find '%s' button on device list\n", key->label);
|
||||
goto f_end;
|
||||
}
|
||||
// WE have a iaqualink button, press it.
|
||||
send_aqt_cmd(button->keycode);
|
||||
|
||||
// See if we want to use the last color, or turn it off
|
||||
if (use_current_mode || turn_off) {
|
||||
// After pressing the button, Just need to wait for 5 seconds and it will :-
|
||||
// a) if off turn on and default to last color.
|
||||
// b) if on, turn off. (pain that we need to wait 5 seconds.)
|
||||
waitfor_iaqt_queue2empty();
|
||||
waitfor_iaqt_nextPage(aq_data);
|
||||
if (use_current_mode) {
|
||||
// Their is no message for this, so give one.
|
||||
sprintf(aq_data->last_display_message, "Light will turn on in 5 seconds");
|
||||
aq_data->is_display_message_programming = true;
|
||||
aq_data->updated = true;
|
||||
}
|
||||
// Wait for next page maybe?
|
||||
// Below needs a timeout.
|
||||
while (waitfor_iaqt_nextPage(aq_data) == IAQ_PAGE_COLOR_LIGHT);
|
||||
goto f_end;
|
||||
}
|
||||
|
||||
// BELOW WE NEED TO CATER FOR OK POPUP IF LIGHT IS ALREADY ON
|
||||
if (button->state == 0x01) { // Light is on, need to select the BUTTON
|
||||
waitfor_iaqt_queue2empty();
|
||||
// We Should wait for popup message, before sending code
|
||||
send_aqt_cmd(KEY_IAQTCH_OK);
|
||||
}
|
||||
|
||||
if (waitfor_iaqt_nextPage(aq_data) != IAQ_PAGE_COLOR_LIGHT) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not color light page\n");
|
||||
goto f_end;
|
||||
}
|
||||
|
||||
button = iaqtFindButtonByLabel(mode_name);
|
||||
|
||||
if (button == NULL) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did find color '%s' in color light page\n",mode_name);
|
||||
goto f_end;
|
||||
}
|
||||
|
||||
//LOG(IAQT_LOG, LOG_ERR, "IAQ Touch WAIYING FOR 1 MESSAGES\n");
|
||||
//waitfor_iaqt_messages(aq_data, 1);
|
||||
|
||||
// Finally found the color. select it
|
||||
send_aqt_cmd(button->keycode);
|
||||
waitfor_iaqt_nextPage(aq_data);
|
||||
|
||||
f_end:
|
||||
goto_iaqt_page(IAQ_PAGE_HOME, aq_data);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
||||
// just stop compiler error, ptr is not valid as it's just been freed
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void *set_aqualink_iaqtouch_pump_rpm( void *ptr )
|
||||
{
|
||||
struct programmingThreadCtrl *threadCtrl;
|
||||
|
@ -415,6 +739,7 @@ void *set_aqualink_iaqtouch_pump_rpm( void *ptr )
|
|||
char VSPstr[20];
|
||||
int structIndex;
|
||||
struct iaqt_page_button *button;
|
||||
char *pumpName = NULL;
|
||||
|
||||
//printf("**** program string '%s'\n",buf);
|
||||
|
||||
|
@ -423,6 +748,7 @@ void *set_aqualink_iaqtouch_pump_rpm( void *ptr )
|
|||
//int pumpRPM = atoi(&buf[2]);
|
||||
for (structIndex=0; structIndex < aq_data->num_pumps; structIndex++) {
|
||||
if (aq_data->pumps[structIndex].pumpIndex == pumpIndex) {
|
||||
pumpName = aq_data->pumps[structIndex].pumpName;
|
||||
if (aq_data->pumps[structIndex].pumpType == PT_UNKNOWN) {
|
||||
LOG(IAQT_LOG,LOG_ERR, "Can't set Pump RPM/GPM until type is known\n");
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
@ -436,8 +762,8 @@ void *set_aqualink_iaqtouch_pump_rpm( void *ptr )
|
|||
//int pumpRPM = atoi(&buf[2]);
|
||||
//int pumpIndex = 1;
|
||||
|
||||
// Just force to pump 1 for testing
|
||||
sprintf(VSPstr, "VSP%1d Spd ADJ",pumpIndex);
|
||||
|
||||
|
||||
// NSF Should probably check pumpRPM is not -1 here
|
||||
|
||||
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_IAQTOUCH_PUMP_RPM);
|
||||
|
@ -447,10 +773,17 @@ void *set_aqualink_iaqtouch_pump_rpm( void *ptr )
|
|||
if ( goto_iaqt_page(IAQ_PAGE_DEVICES, aq_data) == false )
|
||||
goto f_end;
|
||||
|
||||
sprintf(VSPstr, "VSP%1d Spd ADJ",pumpIndex);
|
||||
button = iaqtFindButtonByLabel(VSPstr);
|
||||
if (button == NULL && pumpName[0] != '\0') {
|
||||
// Try by name
|
||||
sprintf(VSPstr, "%s ADJ",pumpName);
|
||||
button = iaqtFindButtonByLabel(VSPstr);
|
||||
}
|
||||
|
||||
if (button == NULL) {
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find '%s' button on page setup\n", VSPstr);
|
||||
goto f_end;
|
||||
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not Pump by index 'VSP%1d Spd ADJ' or by name '%s' button on page setup\n", pumpIndex, VSPstr);
|
||||
goto f_end;
|
||||
}
|
||||
|
||||
send_aqt_cmd(button->keycode);
|
||||
|
@ -486,7 +819,9 @@ void *set_aqualink_iaqtouch_pump_rpm( void *ptr )
|
|||
//send_aqt_cmd(0x80);
|
||||
|
||||
// Go to status page on startup to read devices
|
||||
goto_iaqt_page(IAQ_PAGE_STATUS, aq_data);
|
||||
// This is too soon
|
||||
//goto_iaqt_page(IAQ_PAGE_STATUS, aq_data);
|
||||
//waitfor_iaqt_nextPage(aq_data);
|
||||
|
||||
f_end:
|
||||
goto_iaqt_page(IAQ_PAGE_HOME, aq_data);
|
||||
|
@ -563,6 +898,7 @@ void *get_aqualink_iaqtouch_freezeprotect( void *ptr )
|
|||
int frz = rsm_atoi(iaqtGetMessageLine(0));
|
||||
if (frz >= 0) {
|
||||
aq_data->frz_protect_set_point = frz;
|
||||
aq_data->frz_protect_state = ON;
|
||||
LOG(IAQT_LOG,LOG_NOTICE, "IAQ Touch Freeze Protection setpoint %d\n",frz);
|
||||
}
|
||||
|
||||
|
@ -587,6 +923,10 @@ void *get_aqualink_iaqtouch_setpoints( void *ptr )
|
|||
|
||||
waitForSingleThreadOrTerminate(threadCtrl, AQ_GET_IAQTOUCH_SETPOINTS);
|
||||
|
||||
// Get product info.
|
||||
send_aqt_cmd(KEY_IAQTCH_HELP);
|
||||
waitfor_iaqt_nextPage(aq_data);
|
||||
|
||||
if ( goto_iaqt_page(IAQ_PAGE_SET_TEMP, aq_data) == false )
|
||||
goto f_end;
|
||||
|
||||
|
@ -604,7 +944,7 @@ void *get_aqualink_iaqtouch_setpoints( void *ptr )
|
|||
if (isSINGLE_DEV_PANEL != true)
|
||||
{
|
||||
changePanelToMode_Only();
|
||||
LOG(AQRS_LOG,LOG_ERR, "AqualinkD set to 'Combo Pool & Spa' but detected 'Only Pool OR Spa' panel, please change config\n");
|
||||
LOG(IAQT_LOG,LOG_ERR, "AqualinkD set to 'Combo Pool & Spa' but detected 'Only Pool OR Spa' panel, please change config\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -621,11 +961,17 @@ void *get_aqualink_iaqtouch_setpoints( void *ptr )
|
|||
if (isSINGLE_DEV_PANEL != true)
|
||||
{
|
||||
changePanelToMode_Only();
|
||||
LOG(AQRS_LOG,LOG_ERR, "AqualinkD set to 'Combo Pool & Spa' but detected 'Only Pool OR Spa' panel, please change config\n");
|
||||
LOG(IAQT_LOG,LOG_ERR, "AqualinkD set to 'Combo Pool & Spa' but detected 'Only Pool OR Spa' panel, please change config\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button = iaqtFindButtonByLabel("Chiller");
|
||||
if (button != NULL) {
|
||||
aq_data->chiller_set_point = rsm_atoi((char *)&button->name + 8);
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "IAQ Touch got to Chiller setpoint %d\n",aq_data->chiller_set_point);
|
||||
}
|
||||
|
||||
if ( goto_iaqt_page(IAQ_PAGE_FREEZE_PROTECT, aq_data) == false )
|
||||
goto f_end;
|
||||
|
||||
|
@ -636,6 +982,52 @@ void *get_aqualink_iaqtouch_setpoints( void *ptr )
|
|||
LOG(IAQT_LOG,LOG_NOTICE, "IAQ Touch Freeze Protection setpoint %d\n",frz);
|
||||
}
|
||||
|
||||
// Get the temperature units if we are in iaq touch PDA mode
|
||||
if (isPDA_PANEL) {
|
||||
// If we are here, hit back then next button to get button with degrees on it.
|
||||
// Only if in PDA mode
|
||||
send_aqt_cmd(KEY_IAQTCH_BACK); // Clear the feeze protect menu and go back to system setup
|
||||
|
||||
if ( waitfor_iaqt_nextPage(aq_data) != IAQ_PAGE_SYSTEM_SETUP )
|
||||
{
|
||||
LOG(IAQT_LOG,LOG_ERR, "Couldn't get back to setup page, Temperature units unknown, default to DegF\n");
|
||||
aq_data->temp_units = FAHRENHEIT;
|
||||
goto f_end;
|
||||
}
|
||||
|
||||
send_aqt_cmd(KEY_IAQTCH_NEXT_PAGE_ALTERNATE); // Go to page 2
|
||||
|
||||
if ( waitfor_iaqt_nextPage(aq_data) != IAQ_PAGE_SYSTEM_SETUP2 )
|
||||
{
|
||||
LOG(IAQT_LOG,LOG_ERR, "Couldn't get back to setup page, Temperature units unknown, default to DegF\n");
|
||||
aq_data->temp_units = FAHRENHEIT;
|
||||
goto f_end;
|
||||
}
|
||||
|
||||
button = iaqtFindButtonByLabel("Degrees");
|
||||
|
||||
if (button != NULL) {
|
||||
LOG(IAQT_LOG,LOG_NOTICE, "Temperature units are '%s'\n",button->name);
|
||||
if (button->name[8] == 'C') {
|
||||
LOG(IAQT_LOG,LOG_NOTICE, "Temperature unit message is '%s' set to degC\n",button->name);
|
||||
aq_data->temp_units = CELSIUS;
|
||||
} else {
|
||||
LOG(IAQT_LOG,LOG_NOTICE, "Temperature unit message is '%s' set to degF\n",button->name);
|
||||
aq_data->temp_units = FAHRENHEIT;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
printf("************** DEG IS '%c'\n", (uintptr_t)button->name[8]);
|
||||
if ( (uintptr_t)button->name[8] == 'C') { // NSF THIS DOES NOT WORK, LEAVE COMPILER WARNING TO COME BACK AND FIX
|
||||
aq_data->temp_units = CELSIUS;
|
||||
} else {
|
||||
aq_data->temp_units = FAHRENHEIT;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
// Need to run over table messages and check ens with X for on off.
|
||||
|
||||
// Go to status page on startup to read devices
|
||||
|
@ -811,8 +1203,7 @@ void *set_aqualink_iaqtouch_swg_boost( void *ptr )
|
|||
}
|
||||
|
||||
|
||||
|
||||
bool set_aqualink_iaqtouch_heater_setpoint( struct aqualinkdata *aq_data, bool pool, int val)
|
||||
bool set_aqualink_iaqtouch_heater_setpoint( struct aqualinkdata *aq_data, SP_TYPE type, int val)
|
||||
{
|
||||
struct iaqt_page_button *button;
|
||||
char *name;
|
||||
|
@ -821,17 +1212,21 @@ bool set_aqualink_iaqtouch_heater_setpoint( struct aqualinkdata *aq_data, bool p
|
|||
return false;
|
||||
|
||||
if (isCOMBO_PANEL) {
|
||||
if (pool)
|
||||
if (type == SP_POOL)
|
||||
name = "Pool Heat";
|
||||
else
|
||||
name = "Spa Heat";
|
||||
} else {
|
||||
if (pool)
|
||||
if (type == SP_POOL)
|
||||
name = "Temp1";
|
||||
else
|
||||
name = "Temp2";
|
||||
}
|
||||
|
||||
if (type == SP_CHILLER) {
|
||||
name = "Chiller";
|
||||
}
|
||||
|
||||
button = iaqtFindButtonByLabel(name);
|
||||
|
||||
if (button == NULL) {
|
||||
|
@ -851,12 +1246,18 @@ bool set_aqualink_iaqtouch_heater_setpoint( struct aqualinkdata *aq_data, bool p
|
|||
button = iaqtFindButtonByLabel(name);
|
||||
|
||||
if (button != NULL) {
|
||||
if (pool)
|
||||
int value = 0;
|
||||
if (type == SP_POOL) {
|
||||
aq_data->pool_htr_set_point = rsm_atoi((char *)&button->name + strlen(name));
|
||||
else
|
||||
value = aq_data->pool_htr_set_point;
|
||||
} else if (type == SP_SPA) {
|
||||
aq_data->spa_htr_set_point = rsm_atoi((char *)&button->name + strlen(name));
|
||||
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "IAQ Touch set %s heater setpoint to %d\n",name,pool?aq_data->pool_htr_set_point:aq_data->spa_htr_set_point);
|
||||
value = aq_data->spa_htr_set_point;
|
||||
} else if (type == SP_CHILLER) {
|
||||
aq_data->chiller_set_point = rsm_atoi((char *)&button->name + strlen(name));
|
||||
value = aq_data->chiller_set_point;
|
||||
}
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "IAQ Touch set %s heater setpoint to %d\n",name,value);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -871,9 +1272,9 @@ void *set_aqualink_iaqtouch_spa_heater_temp( void *ptr )
|
|||
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_IAQTOUCH_SPA_HEATER_TEMP);
|
||||
|
||||
int val = atoi((char*)threadCtrl->thread_args);
|
||||
val = setpoint_check(SPA_HTR_SETOINT, val, aq_data);
|
||||
val = setpoint_check(SPA_HTR_SETPOINT, val, aq_data);
|
||||
|
||||
set_aqualink_iaqtouch_heater_setpoint(aq_data, false, val);
|
||||
set_aqualink_iaqtouch_heater_setpoint(aq_data, SP_SPA, val);
|
||||
|
||||
goto_iaqt_page(IAQ_PAGE_HOME, aq_data);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
@ -890,9 +1291,28 @@ void *set_aqualink_iaqtouch_pool_heater_temp( void *ptr )
|
|||
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_IAQTOUCH_POOL_HEATER_TEMP);
|
||||
|
||||
int val = atoi((char*)threadCtrl->thread_args);
|
||||
val = setpoint_check(POOL_HTR_SETOINT, val, aq_data);
|
||||
val = setpoint_check(POOL_HTR_SETPOINT, val, aq_data);
|
||||
|
||||
set_aqualink_iaqtouch_heater_setpoint(aq_data, true, val);
|
||||
set_aqualink_iaqtouch_heater_setpoint(aq_data, SP_POOL, val);
|
||||
|
||||
goto_iaqt_page(IAQ_PAGE_HOME, aq_data);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *set_aqualink_iaqtouch_chiller_temp( void *ptr )
|
||||
{
|
||||
struct programmingThreadCtrl *threadCtrl;
|
||||
threadCtrl = (struct programmingThreadCtrl *) ptr;
|
||||
struct aqualinkdata *aq_data = threadCtrl->aq_data;
|
||||
|
||||
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_IAQTOUCH_POOL_HEATER_TEMP);
|
||||
|
||||
int val = atoi((char*)threadCtrl->thread_args);
|
||||
//val = setpoint_check(POOL_HTR_SETPOINT, val, aq_data);
|
||||
|
||||
set_aqualink_iaqtouch_heater_setpoint(aq_data, SP_CHILLER, val);
|
||||
|
||||
goto_iaqt_page(IAQ_PAGE_HOME, aq_data);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
@ -1108,4 +1528,4 @@ void *set_aqualink_iaqtouch_time( void *ptr )
|
|||
// Debug: iAQ Touch: To 0x33 of type iAq pMes | HEX: 0x10|0x02|0x33|0x25|0x02|0x41|0x4d|0x00|0xfa|0x10|0x03|
|
||||
|
||||
//LOG(IAQT_LOG,LOG_DEBUG "Setting time to %d/%d/%d %d:%d\n", result->tm_mon + 1, result->tm_mday, result->tm_year + 1900, result->tm_hour + 1, result->tm_min);
|
||||
*/
|
||||
*/
|
|
@ -3,6 +3,8 @@
|
|||
#ifndef IAQ_TOUCH_PROGRAMMER_H_
|
||||
#define IAQ_TOUCH_PROGRAMMER_H_
|
||||
|
||||
|
||||
|
||||
unsigned char pop_iaqt_cmd(unsigned char receive_type);
|
||||
|
||||
void set_iaq_cansend(bool cansend);
|
||||
|
@ -17,8 +19,12 @@ void *set_aqualink_iaqtouch_swg_percent( void *ptr );
|
|||
void *set_aqualink_iaqtouch_swg_boost( void *ptr );
|
||||
void *set_aqualink_iaqtouch_spa_heater_temp( void *ptr );
|
||||
void *set_aqualink_iaqtouch_pool_heater_temp( void *ptr );
|
||||
void *set_aqualink_iaqtouch_chiller_temp( void *ptr );
|
||||
void *set_aqualink_iaqtouch_time( void *ptr );
|
||||
void *set_aqualink_iaqtouch_pump_vs_program( void *ptr );
|
||||
void *set_aqualink_iaqtouch_light_colormode( void *ptr );
|
||||
void *set_aqualink_iaqtouch_device_on_off( void *ptr ); // For PDA only
|
||||
void *set_aqualink_iaqtouch_onetouch_on_off( void *ptr );
|
||||
|
||||
int ref_iaqt_control_cmd(unsigned char **cmd);
|
||||
void rem_iaqt_control_cmd(unsigned char *cmd);
|
|
@ -0,0 +1,718 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Shaun Feakes - All rights reserved
|
||||
*
|
||||
* You may use redistribute and/or modify this code under the terms of
|
||||
* the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. For the terms of this license,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* https://github.com/sfeakes/aqualinkd
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "aq_serial.h"
|
||||
#include "aqualink.h"
|
||||
#include "iaqualink.h"
|
||||
#include "packetLogger.h"
|
||||
#include "aq_serial.h"
|
||||
#include "serialadapter.h"
|
||||
#include "rs_msg_utils.h"
|
||||
|
||||
#define IAQUA_QLEN 20
|
||||
|
||||
typedef struct iaqulnkcmd
|
||||
{
|
||||
unsigned char command[20];
|
||||
int length;
|
||||
} iaqualink_cmd;
|
||||
|
||||
iaqualink_cmd _iqaua_queue[IAQUA_QLEN];
|
||||
unsigned char _std_cmd[2];
|
||||
int _iaqua_q_length = 0;
|
||||
bool _aqua_last_cmdfrom_queue = false;
|
||||
|
||||
|
||||
unsigned char _cmd_readyCommand[] = {0x3f, 0x20};
|
||||
unsigned char _fullcmd[] = {0x00, 0x24, 0x73, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
|
||||
bool push_iaqualink_cmd(unsigned char *cmd, int length) {
|
||||
if (_iaqua_q_length >= IAQUA_QLEN ) {
|
||||
LOG(IAQL_LOG,LOG_ERR, "Queue overflow, last command ignored!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(_iqaua_queue[_iaqua_q_length].command, cmd, length);
|
||||
_iqaua_queue[_iaqua_q_length].length = length;
|
||||
_iaqua_q_length++;
|
||||
|
||||
LOG(IAQL_LOG, LOG_INFO, "Queue cmd, size %d, queu length=%d\n",length, _iaqua_q_length);
|
||||
|
||||
//LOG(IAQL_LOG,LOG_DEBUG, "Added to message queue, position %d 0x%02hhx|0x%02hhx|0x%02hhx|0x%02hhx\n",_rssa_q_length-1,_rssa_queue[_rssa_q_length-1][0],_rssa_queue[_rssa_q_length-1][1],_rssa_queue[_rssa_q_length-1][2],_rssa_queue[_rssa_q_length-1][3]);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//unsigned char *get_iaqualink_cmd(unsigned char source_message_type, unsigned char *dest_message, int *len) {
|
||||
int get_iaqualink_cmd(unsigned char source_message_type, unsigned char **dest_message) {
|
||||
|
||||
//LOG(IAQL_LOG, LOG_INFO, "Caculating cmd\n");
|
||||
|
||||
_aqua_last_cmdfrom_queue = false;
|
||||
|
||||
_std_cmd[0] = source_message_type;
|
||||
_std_cmd[1] = 0x00;
|
||||
*dest_message = _std_cmd;
|
||||
int len = 2;
|
||||
|
||||
if (source_message_type == 0x73 && _iaqua_q_length > 0)
|
||||
{ // Send big/long message
|
||||
if ( _iqaua_queue[0].length >= 19 ) {
|
||||
*dest_message = _iqaua_queue[0].command;
|
||||
len = _iqaua_queue[0].length;
|
||||
_aqua_last_cmdfrom_queue = true;
|
||||
} else {
|
||||
LOG(IAQL_LOG,LOG_WARNING,"Next command in queue is not full command, ignoring\n");
|
||||
}
|
||||
}
|
||||
else if (source_message_type == 0x53 && _iaqua_q_length > 0)
|
||||
{ // Send small command
|
||||
if ( _iqaua_queue[0].length <= 2 ) {
|
||||
*dest_message = _iqaua_queue[0].command;
|
||||
len = _iqaua_queue[0].length;
|
||||
_aqua_last_cmdfrom_queue = true;
|
||||
} else {
|
||||
LOG(IAQL_LOG,LOG_WARNING,"Next command in queue is too large, ignoring\n");
|
||||
LOG(IAQL_LOG,LOG_ERR,"Re sending get prepare frame\n");
|
||||
*dest_message = _cmd_readyCommand;
|
||||
}
|
||||
}
|
||||
|
||||
//LOG(IAQL_LOG, LOG_INFO, "Return cmd size %d\n",len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void remove_iaqualink_cmd() {
|
||||
if (_iaqua_q_length > 0 && _aqua_last_cmdfrom_queue == true) {
|
||||
LOG(IAQL_LOG,LOG_DEBUG, "Remove from message queue, length %d\n",_iaqua_q_length-1);
|
||||
memmove(&_iqaua_queue[0], &_iqaua_queue[1], (sizeof(iaqualink_cmd)) * _iaqua_q_length);
|
||||
_iaqua_q_length--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned char iAqalnkDevID(aqkey *button) {
|
||||
|
||||
// For the 3 actual vbuttons that exist, we have already set their codes so just return it with no conversion
|
||||
if ( ((button->special_mask & VIRTUAL_BUTTON) == VIRTUAL_BUTTON) && button->rssd_code != NUL ) {
|
||||
return button->rssd_code;
|
||||
}
|
||||
|
||||
switch (button->rssd_code) {
|
||||
case RS_SA_PUMP:
|
||||
return IAQ_PUMP;
|
||||
break;
|
||||
case RS_SA_SPA:
|
||||
return IAQ_SPA;
|
||||
break;
|
||||
case RS_SA_POOLHT:
|
||||
return IAQ_POOL_HTR;
|
||||
break;
|
||||
case RS_SA_SPAHT:
|
||||
return IAQ_SPA_HTR;
|
||||
break;
|
||||
case RS_SA_AUX1:
|
||||
return IAQ_AUX1;
|
||||
break;
|
||||
case RS_SA_AUX2:
|
||||
return IAQ_AUX2;
|
||||
break;
|
||||
case RS_SA_AUX3:
|
||||
return IAQ_AUX3;
|
||||
break;
|
||||
case RS_SA_AUX4:
|
||||
return IAQ_AUX4;
|
||||
break;
|
||||
case RS_SA_AUX5:
|
||||
return IAQ_AUX5;
|
||||
break;
|
||||
case RS_SA_AUX6:
|
||||
return IAQ_AUX6;
|
||||
break;
|
||||
case RS_SA_AUX7:
|
||||
return IAQ_AUX7;
|
||||
break;
|
||||
case RS_SA_AUX8:
|
||||
return IAQ_AUXB1;
|
||||
break;
|
||||
case RS_SA_AUX9:
|
||||
return IAQ_AUXB2;
|
||||
break;
|
||||
case RS_SA_AUX10:
|
||||
return IAQ_AUXB3;
|
||||
break;
|
||||
case RS_SA_AUX11:
|
||||
return IAQ_AUXB4;
|
||||
break;
|
||||
case RS_SA_AUX12:
|
||||
return IAQ_AUXB5;
|
||||
break;
|
||||
case RS_SA_AUX13:
|
||||
return IAQ_AUXB6;
|
||||
break;
|
||||
case RS_SA_AUX14:
|
||||
return IAQ_AUXB7;
|
||||
break;
|
||||
case RS_SA_AUX15:
|
||||
return IAQ_AUXB8;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void lastchecksum(unsigned char *packet, int length)
|
||||
{
|
||||
if (getLogLevel(IAQL_LOG) >= LOG_DEBUG)
|
||||
{
|
||||
static unsigned char last70checksum = 0x00;
|
||||
static unsigned char last71checksum = 0x00;
|
||||
static unsigned char last72checksum = 0x00;
|
||||
|
||||
switch (packet[PKT_CMD])
|
||||
{
|
||||
case 0x70:
|
||||
if (last70checksum != packet[length - 3] && last70checksum != 0x00)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "*****************************************\n");
|
||||
LOG(IAQL_LOG, LOG_INFO, "******* CHECKSUM CHANGED for 0x70 *******\n");
|
||||
LOG(IAQL_LOG, LOG_INFO, "*****************************************\n");
|
||||
}
|
||||
last70checksum = packet[length - 3];
|
||||
break;
|
||||
case 0x71:
|
||||
if (last71checksum != packet[length - 3] && last71checksum != 0x00)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "*****************************************\n");
|
||||
LOG(IAQL_LOG, LOG_INFO, "******* CHECKSUM CHANGED for 0x71 *******\n");
|
||||
LOG(IAQL_LOG, LOG_INFO, "*****************************************\n");
|
||||
}
|
||||
last71checksum = packet[length - 3];
|
||||
break;
|
||||
case 0x72:
|
||||
if (last72checksum != packet[length - 3] && last72checksum != 0x00)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "*****************************************\n");
|
||||
LOG(IAQL_LOG, LOG_INFO, "******* CHECKSUM CHANGED for 0x72 *******\n");
|
||||
LOG(IAQL_LOG, LOG_INFO, "*****************************************\n");
|
||||
}
|
||||
last72checksum = packet[length - 3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
All taken from panel Yg, but only heater setpoints seem to work.
|
||||
Only setpoints seem to work,
|
||||
|
||||
Can't get to work on T2 panel
|
||||
RPM to 2750
|
||||
Bit 6 = 0x5e
|
||||
Bit 10 * 256 + Bit 11
|
||||
Bit 7 or 9 probably pump index.
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x0a|0xbe|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xd5|0x10|0x03|
|
||||
|
||||
RPM to 2995
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x0b|0xb3|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xcb|0x10|0x03|
|
||||
|
||||
|
||||
Can't get to work on T2 panel
|
||||
SWG 50%
|
||||
Byte 6 = 0x19
|
||||
Byte 7 = 50%
|
||||
Byte 9 & 10 ????
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x32|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x0e|0x10|0x03|
|
||||
|
||||
SWG 51%
|
||||
Byte 7 = 51%
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x33|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x0f|0x10|0x03|
|
||||
|
||||
Works on T2
|
||||
Spa Setpoint 102
|
||||
Byte 6 = 0x06
|
||||
Byte 8 = 0x66=102
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x06|0x00|0x66|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x16|0x10|0x03|
|
||||
|
||||
Works on T2
|
||||
Pool Setpoint 72
|
||||
Byte 6 = 0x05
|
||||
Byte 8 = 0x48=72
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x05|0x00|0x48|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xf7|0x10|0x03|
|
||||
|
||||
*/
|
||||
|
||||
|
||||
void set_iaqualink_aux_state(aqkey *button, bool isON) {
|
||||
|
||||
_fullcmd[4] = iAqalnkDevID(button);
|
||||
|
||||
if (_fullcmd[4] != 0xFF) {
|
||||
push_iaqualink_cmd(_cmd_readyCommand, 2);
|
||||
push_iaqualink_cmd(_fullcmd, 19);
|
||||
} else {
|
||||
LOG(IAQL_LOG, LOG_ERR, "Couldn't find iaqualink keycode for button %s\n",button->label);
|
||||
}
|
||||
|
||||
// reset
|
||||
_fullcmd[4] = 0x00;
|
||||
}
|
||||
|
||||
|
||||
// AQ_SET_IAQTOUCH_CHILLER_TEMP
|
||||
// AQ_SET_IAQLINK_CHILLER_TEMP //
|
||||
|
||||
//void set_iaqualink_heater_setpoint(int value, bool isPool) {
|
||||
void set_iaqualink_heater_setpoint(int value, SP_TYPE type) {
|
||||
|
||||
if (type == SP_POOL) {
|
||||
_fullcmd[4] = 0x05;
|
||||
_fullcmd[6] = value;
|
||||
} else if (type == SP_SPA) {
|
||||
_fullcmd[4] = 0x06;
|
||||
_fullcmd[6] = value;
|
||||
} else if (type == SP_CHILLER) {
|
||||
// Note This doesn;t work on T2, but does on Yg. Turned off in aq_programmer
|
||||
_fullcmd[4] = 0x1f;
|
||||
_fullcmd[6] = 0x4b;
|
||||
_fullcmd[8] = 0x63;
|
||||
_fullcmd[10] = value;
|
||||
} else {
|
||||
LOG(IAQL_LOG, LOG_ERR, "Didn't understand setpoint type %d\n",type);
|
||||
return;
|
||||
}
|
||||
// byte[4] = 0x1f, byte[6]=0x4b, byte[8]=0x53, byte[10]=value // for Chiller
|
||||
|
||||
// Should check value is valid here.
|
||||
//_fullcmd[6] = value;
|
||||
|
||||
push_iaqualink_cmd(_cmd_readyCommand, 2);
|
||||
push_iaqualink_cmd(_fullcmd, 19);
|
||||
|
||||
// reset
|
||||
_fullcmd[4] = 0x00;
|
||||
_fullcmd[6] = 0x00;
|
||||
_fullcmd[8] = 0x00;
|
||||
_fullcmd[10] = 0x00;
|
||||
}
|
||||
|
||||
void iAqSetButtonState(struct aqualinkdata *aq_data, int index, const unsigned char byte)
|
||||
{
|
||||
if ( aq_data->aqbuttons[index].led->state != OFF && byte == 0x00) {
|
||||
aq_data->aqbuttons[index].led->state = OFF;
|
||||
LOG(IAQL_LOG, LOG_INFO, "Set %s off\n",aq_data->aqbuttons[index].label);
|
||||
} else if ( aq_data->aqbuttons[index].led->state != ON && byte == 0x01) {
|
||||
aq_data->aqbuttons[index].led->state = ON;
|
||||
LOG(IAQL_LOG, LOG_INFO, "Set %s on\n",aq_data->aqbuttons[index].label);
|
||||
} else if ( aq_data->aqbuttons[index].led->state != ENABLE && byte == 0x03) {
|
||||
aq_data->aqbuttons[index].led->state = ENABLE;
|
||||
LOG(IAQL_LOG, LOG_INFO, "Set %s enabled\n",aq_data->aqbuttons[index].label);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Status packets are requested on iAqualink ID 0xA? but received on AqualinkTouch ID 0x3?
|
||||
They are also sent when iAqualink is connected and a device changes.
|
||||
So good to catch in PDA mode when a physical iAqualink device is connected to PDA panel.
|
||||
packet has cmd of 0x70, 0x71, 0x72
|
||||
*/
|
||||
bool process_iAqualinkStatusPacket(unsigned char *packet, int length, struct aqualinkdata *aq_data)
|
||||
{
|
||||
if (packet[PKT_CMD] == CMD_IAQ_MAIN_STATUS)
|
||||
{
|
||||
logPacket(IAQL_LOG, LOG_INFO, packet, length, true);
|
||||
int startIndex = 4 + 1;
|
||||
int numberBytes = packet[4];
|
||||
int offsetIndex = startIndex + numberBytes;
|
||||
//bool foundSpaSP = false;
|
||||
//bool foundWaterTemp = false;
|
||||
//bool foundAirTemp = false;
|
||||
|
||||
for (int i = 0; i <= numberBytes; i++)
|
||||
{
|
||||
int byteType = packet[5 + i];
|
||||
int byte = packet[offsetIndex + i];
|
||||
char *label;
|
||||
|
||||
// Some panels have blanks for the last 3 buys, the first of which is "water temp" (not sure on others 0x20, 0x21)
|
||||
// So if we saw 0x1d break loop if not force next as water temp.
|
||||
/*
|
||||
if (foundWaterTemp && i == numberBytes)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (i == numberBytes)
|
||||
{
|
||||
byteType = 0x1d;
|
||||
}*/
|
||||
|
||||
// Seems to be in order rather than type
|
||||
label = " ";
|
||||
|
||||
if (byte != 0xff)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
// 0x00
|
||||
label = "Filter Pump ";
|
||||
if (byteType != 0x00)
|
||||
label = "Filter Pump *";
|
||||
break;
|
||||
case 1:
|
||||
// 0x01
|
||||
label = "Pool Heater ";
|
||||
if (byteType != 0x01)
|
||||
label = "Pool Heater *";
|
||||
break;
|
||||
case 2:
|
||||
// 0x02
|
||||
label = "Spa ";
|
||||
if (byteType != 0x02)
|
||||
label = "Spa *";
|
||||
break;
|
||||
case 3:
|
||||
// 0x03
|
||||
label = "Spa Heater ";
|
||||
if (byteType != 0x03)
|
||||
label = "Spa Heater *";
|
||||
break;
|
||||
case 5:
|
||||
// 0x06 good
|
||||
label = "Pool Heater SP ";
|
||||
if (byteType != 0x06)
|
||||
label = "Pool Heater SP *";
|
||||
break;
|
||||
case 7:
|
||||
// 0x08 good
|
||||
// 0x09 (when spa is on???)
|
||||
// 0x0e (good not sure)
|
||||
label = "Spa Heater SP ";
|
||||
if (byteType != 0x08)
|
||||
label = "Spa Heater SP *";
|
||||
break;
|
||||
case 9:
|
||||
// 0x0f good
|
||||
label = "Air Temp ";
|
||||
if (byteType != 0x0f)
|
||||
label = "Air Temp *";
|
||||
break;
|
||||
case 11:
|
||||
// 0x1d good
|
||||
// 0x1c (good) ?? maybe spa
|
||||
// 0x1f bad
|
||||
label = "Water Temp ";
|
||||
if (byteType != 0x1d)
|
||||
label = "Water Temp *";
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (byteType == 0) {
|
||||
label = "Filter Pump ";
|
||||
if (isPDA_PANEL) { iAqSetButtonState(aq_data, 0, byte); }
|
||||
} else if (byteType == 1) {
|
||||
label = "Pool Heater "; // 0x00 off 0x01=on&heating, 0x03=enabled
|
||||
if (isPDA_PANEL) { iAqSetButtonState(aq_data, aq_data->pool_heater_index , byte); }
|
||||
} else if (byteType == 2) {
|
||||
label = "Spa ";
|
||||
} else if (byteType == 3) {
|
||||
label = "Spa Heater "; // 0x01=on&heating, 0x03=ena
|
||||
if (isPDA_PANEL) { iAqSetButtonState(aq_data, aq_data->spa_heater_index , byte); }
|
||||
} else if (byteType == 6) {
|
||||
label = "Pool Htr setpoint";
|
||||
} else if (byteType == 8 || byteType == 9) {// 8 usually, also get 9 & 14 (different spa/heater modes not sorted out yet. 14 sometimes blank as well)
|
||||
label = "Spa Htr setpoint ";
|
||||
foundSpaSP=true;
|
||||
} else if ( (byteType == 12) && foundSpaSP==false && byte != 0) { // Sometimes 14
|
||||
label = "Spa Htr setpoint ";
|
||||
} else if ( (byteType == 14 || byteType == 15 || byteType == 26) && byte != 0 && byte != 255 && foundAirTemp == false ) {// 0x0f
|
||||
label = "Air Temp "; // we also see this as 14 (RS16) ONLY
|
||||
foundAirTemp = true;
|
||||
} else if ( (byteType == 27 || byteType == 28 || byteType == 29) && byte != 0 && byte != 255 && foundWaterTemp == false) {
|
||||
// Last 3 bytes don't have type on some panels
|
||||
label = "Water Temp ";
|
||||
foundWaterTemp = true;
|
||||
}
|
||||
else
|
||||
label = " ";
|
||||
*/
|
||||
LOG(IAQL_LOG, LOG_INFO, "%-17s = %3d | index=%d type=(%0.2d 0x%02hhx) value=0x%02hhx offset=%d\n", label, byte, i, byteType, byteType, byte, (offsetIndex + i));
|
||||
}
|
||||
LOG(IAQL_LOG, LOG_INFO, "Status from other protocols Pump %s, Spa %s, SWG %d, PumpRPM %d, PoolSP=%d, SpaSP=%d, WaterTemp=%d, AirTemp=%d\n",
|
||||
aq_data->aqbuttons[0].led->state == OFF ? "Off" : "On ",
|
||||
aq_data->aqbuttons[1].led->state == OFF ? "Off" : "On ",
|
||||
aq_data->swg_percent,
|
||||
aq_data->pumps[0].rpm,
|
||||
aq_data->pool_htr_set_point,
|
||||
aq_data->spa_htr_set_point,
|
||||
(aq_data->aqbuttons[1].led->state == OFF ? aq_data->pool_temp : aq_data->spa_temp),
|
||||
aq_data->air_temp);
|
||||
}
|
||||
else if (packet[PKT_CMD] == CMD_IAQ_1TOUCH_STATUS)
|
||||
{
|
||||
logPacket(IAQL_LOG, LOG_INFO, packet, length, true);
|
||||
int numLabels = packet[4];
|
||||
int start = numLabels + 4 + 1;
|
||||
|
||||
if (numLabels == 1)
|
||||
{
|
||||
// This just seem to list a ton of pump (names)
|
||||
LOG(IAQL_LOG, LOG_INFO, "**** !!! haven't decoded above packet yet !!! *****\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numLabels; i++)
|
||||
{
|
||||
int status = packet[start];
|
||||
int length = packet[start + 1];
|
||||
int byteType = packet[5 + i];
|
||||
LOG(IAQL_LOG, LOG_INFO, "%-15.*s = %s | index %d type=(%0.2d 0x%02hhx) status=0x%02hhx start=%d length=%d\n", length, &packet[start + 2], (status == 0x00 ? "Off" : "On "), i, byteType, byteType, status, start, length);
|
||||
// Check against virtual onetouch buttons.
|
||||
for (int bi=aq_data->virtual_button_start ; bi < aq_data->total_buttons ; bi++) {
|
||||
if (rsm_strcmp((char *)&packet[start + 2], aq_data->aqbuttons[bi].label) == 0) {
|
||||
//LOG(IAQL_LOG, LOG_INFO, "Status for %s is %s\n",aq_data->aqbuttons[bi].label,(status == 0x00 ? "Off" : "On "));
|
||||
// == means doesn;t match, RS 1=on 0=off / LED enum 1=off 0=on
|
||||
if (aq_data->aqbuttons[bi].led->state == status) {
|
||||
LOG(IAQL_LOG, LOG_INFO, "Updated Status for %s is %s\n",aq_data->aqbuttons[bi].label,(status == 0x00 ? "Off" : "On "));
|
||||
aq_data->aqbuttons[bi].led->state = (status == 0x00 ? OFF:ON);
|
||||
aq_data->updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
start = start + packet[start + 1] + 2;
|
||||
}
|
||||
}
|
||||
else if (packet[PKT_CMD] == CMD_IAQ_AUX_STATUS)
|
||||
{
|
||||
logPacket(IAQL_LOG, LOG_INFO, packet, length, true);
|
||||
// Look at notes in iaqualink.c for how this packet is made up
|
||||
// Since this is so similar to above CMD_IAQ_1TOUCH_STATUS, we should look at using same logic for both.
|
||||
int start = packet[4];
|
||||
start = start + 5;
|
||||
for (int i = start; i < length - 3; i = i)
|
||||
{
|
||||
int status = i;
|
||||
int labelstart = status + 5;
|
||||
int labellen = packet[status + 4];
|
||||
if (labelstart + labellen < length)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "%-15.*s = %s | bit1=0x%02hhx bit2=0x%02hhx bit3=0x%02hhx bit4=0x%02hhx\n", labellen, &packet[labelstart], (packet[status] == 0x00 ? "Off" : "On "), packet[status], packet[status + 1], packet[status + 2], packet[status + 3]);
|
||||
}
|
||||
if (isPDA_PANEL) {
|
||||
for (int bi=2 ; bi < aq_data->total_buttons ; bi++) {
|
||||
if (rsm_strcmp((char *)&packet[labelstart], aq_data->aqbuttons[bi].label) == 0) {
|
||||
if (aq_data->aqbuttons[bi].led->state == packet[status]) {
|
||||
LOG(IAQL_LOG, LOG_INFO, "Updated Status for %s is %s\n",aq_data->aqbuttons[bi].label,(packet[status] == 0x00 ? "Off" : "On "));
|
||||
aq_data->aqbuttons[bi].led->state = (packet[status] == 0x00 ? OFF:ON);
|
||||
aq_data->updated = true;
|
||||
}
|
||||
//LOG(IAQL_LOG, LOG_INFO, "Match %s to %.*s state(aqd=%d pnl=%d)\n",aq_data->aqbuttons[bi].label, labellen, (char *)&packet[labelstart], aq_data->aqbuttons[bi].led->state, packet[status]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = labelstart + labellen;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool process_iaqualink_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data)
|
||||
{
|
||||
|
||||
lastchecksum(packet, length);
|
||||
|
||||
unsigned char cmd_getMainstatus[] = {0x3f, 0x08};
|
||||
unsigned char cmd_getTouchstatus[] = {0x3f, 0x10};
|
||||
unsigned char cmd_getAuxstatus[] = {0x3f, 0x18};
|
||||
//unsigned char cmd_readyCommand[] = {0x3f, 0x20};
|
||||
//unsigned char fullcmd[] = {0x00, 0x24, 0x73, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
// byte 4 is ID. 0x00 pump, 0x02 spa etc
|
||||
|
||||
|
||||
if (packet[PKT_DEST] == _aqconfig_.extended_device_id2)
|
||||
{
|
||||
static int cnt = 0;
|
||||
//static unsigned char ID = 0;
|
||||
//static cur_swg = 0;
|
||||
//static unsigned char sendid = 0x00;
|
||||
|
||||
if (packet[PKT_CMD] == 0x53)
|
||||
{
|
||||
cnt++;
|
||||
if (cnt == 20) { // 20 is probably too low, should increase. (only RS16 and below)
|
||||
cnt=0;
|
||||
/*
|
||||
sendid=sendid==0x18?0x60:0x18;
|
||||
_fullcmd[4] = sendid;
|
||||
push_iaqualink_cmd(_cmd_readyCommand, 2);
|
||||
push_iaqualink_cmd(_fullcmd, 19);
|
||||
_fullcmd[4] = 0x00;
|
||||
*/
|
||||
push_iaqualink_cmd(cmd_getMainstatus, 2);
|
||||
push_iaqualink_cmd(cmd_getTouchstatus, 2);
|
||||
push_iaqualink_cmd(cmd_getAuxstatus, 2);
|
||||
/*
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
LOG(IAQL_LOG, LOG_INFO,"********** Send %d 0x%02hhx ************\n",ID,ID);
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
|
||||
_fullcmd[4] = ID++;
|
||||
push_iaqualink_cmd(_cmd_readyCommand, 2);
|
||||
push_iaqualink_cmd(_fullcmd, 19);
|
||||
|
||||
push_iaqualink_cmd(cmd_getMainstatus, 2);
|
||||
push_iaqualink_cmd(cmd_getTouchstatus, 2);
|
||||
push_iaqualink_cmd(cmd_getAuxstatus, 2);
|
||||
|
||||
push_iaqualink_cmd(_cmd_readyCommand, 2);
|
||||
push_iaqualink_cmd(_fullcmd, 19);
|
||||
*/
|
||||
|
||||
//fullcmd[4] = ID;
|
||||
//fullcmd[4] = ID;
|
||||
//fullcmd[5] = 0x32;
|
||||
|
||||
//fullcmd[7] = ID;
|
||||
//fullcmd[8] = 0x01;
|
||||
|
||||
|
||||
//set_iaqualink_heater_setpoint(50, true);
|
||||
|
||||
//push_iaqualink_cmd(cmd_getMainstatus, 2);
|
||||
//push_iaqualink_cmd(cmd_getTouchstatus, 2);
|
||||
//push_iaqualink_cmd(cmd_getAuxstatus, 2);
|
||||
/*
|
||||
if (aq_data->swg_percent != cur_swg && cur_swg != 0) {
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
LOG(IAQL_LOG, LOG_INFO,"********** SWG Changed to %d ************\n",aq_data->swg_percent);
|
||||
LOG(IAQL_LOG, LOG_INFO,"*****************************************\n");
|
||||
exit(0);
|
||||
}
|
||||
cur_swg = aq_data->swg_percent;
|
||||
LOG(IAQL_LOG, LOG_INFO,"******* QUEUE SWG Comand of %d | 0x%02hhx *************\n",ID,ID);
|
||||
ID++;*/
|
||||
|
||||
}
|
||||
}
|
||||
// Packets sent to iAqualink protocol
|
||||
// debuglogPacket(IAQL_LOG, packet, length, true, true);
|
||||
}
|
||||
else if (packet[PKT_DEST] == _aqconfig_.extended_device_id || (isPDA_PANEL && packet[PKT_DEST] == _aqconfig_.device_id) )
|
||||
{
|
||||
process_iAqualinkStatusPacket(packet, length, aq_data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DONOTCOMPILE
|
||||
|
||||
// This is onle here temporarly until we figure out the protocol.
|
||||
void send_iaqualink_ack(int rs_fd, unsigned char *packet_buffer)
|
||||
{
|
||||
/*
|
||||
Probe | HEX: 0x10|0x02|0xa3|0x00|0xb5|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
Unknown '0x61' | HEX: 0x10|0x02|0xa3|0x61|0x00|0x00|0x00|0x04|0x00|0x27|0x41|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x61|0x00|0x74|0x10|0x03|
|
||||
Unknown '0x50' | HEX: 0x10|0x02|0xa3|0x50|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x00|0x25|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x50|0x00|0x63|0x10|0x03|
|
||||
Unknown '0x51' | HEX: 0x10|0x02|0xa3|0x51|0x00|0x06|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x51|0x00|0x64|0x10|0x03|
|
||||
Unknown '0x59' | HEX: 0x10|0x02|0xa3|0x59|0x00|0x0e|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x59|0x00|0x6c|0x10|0x03|
|
||||
Unknown '0x52' | HEX: 0x10|0x02|0xa3|0x52|0x00|0x07|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x52|0x00|0x65|0x10|0x03|
|
||||
Unknown '0x53' | HEX: 0x10|0x02|0xa3|0x53|0x08|0x10|0x03|
|
||||
Ack | HEX: 0x10|0x02|0x00|0x01|0x3f|0x00|0x52|0x10|0x03|
|
||||
Use byte 3 as return ack, except for 0x53=0x3f
|
||||
*/
|
||||
if (packet_buffer[PKT_CMD] == CMD_PROBE)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "Got probe on '0x%02hhx' 2nd iAqualink Protocol\n", packet_buffer[PKT_DEST]);
|
||||
send_extended_ack(rs_fd, packet_buffer[PKT_CMD], 0x00);
|
||||
}
|
||||
else if (packet_buffer[PKT_CMD] == 0x53)
|
||||
{
|
||||
static int cnt = 0;
|
||||
cnt++;
|
||||
if (cnt == 10)
|
||||
{
|
||||
//cnt = 5;
|
||||
LOG(IAQL_LOG, LOG_INFO, "Sent accept next packet Comand\n");
|
||||
send_extended_ack(rs_fd, 0x3f, 0x20);
|
||||
}
|
||||
if (cnt == 20)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "Sending get status\n");
|
||||
send_extended_ack(rs_fd, 0x3f, 0x08);
|
||||
}
|
||||
else if (cnt == 22)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "Sending get other status\n");
|
||||
send_extended_ack(rs_fd, 0x3f, 0x10);
|
||||
}
|
||||
else if (cnt == 24)
|
||||
{
|
||||
LOG(IAQL_LOG, LOG_INFO, "Sending get aux button status\n");
|
||||
send_extended_ack(rs_fd, 0x3f, 0x18);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use 0x3f
|
||||
if (cnt > 24)
|
||||
{
|
||||
cnt = 0;
|
||||
}
|
||||
send_extended_ack(rs_fd, 0x3f, 0x00);
|
||||
}
|
||||
// send_jandy_command(rs_fd, get_rssa_cmd(packet_buffer[PKT_CMD]), 4);
|
||||
}
|
||||
else if (packet_buffer[PKT_CMD] == 0x73)
|
||||
{
|
||||
static int id = 10;
|
||||
// unsigned char pb1[] = {PCOL_JANDY,0x10,0x02,0x00,0x24,0x73,0x01,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0x10,0x03,0x00};
|
||||
// unsigned char pb2[] = {PCOL_JANDY,0x10,0x02,0x00,0x24,0x73,0x01,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcb,0x10,0x03,0x00};
|
||||
// 0x21 turns on filter_pump and aux 1
|
||||
//unsigned char pb3[] = {0x00, 0x24, 0x73, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
unsigned char swg[] = {0x00, 0x24, 0x73, 0x01, 0x19, 0x32, 0x00, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
//unsigned char swg[] = {0x00, 0x24, 0x73, 0x01, 0x19, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
unsigned char rpm[] = {0x00,0x24,0x73,0x01,0x5e,0x04,0x00,0x01,0x0a,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd5,0x10,0x03};
|
||||
//pb3[4] = id++;
|
||||
//swg[5] = ++id;
|
||||
|
||||
LOG(IAQL_LOG, LOG_INFO, "*** Sending SWG dec=%d hex=0x%02hhx\n", swg[5], swg[5]);
|
||||
// send_packet(rs_fd, pb2, 25);
|
||||
send_jandy_command(rs_fd, swg, 19);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use packet_buffer[PKT_CMD]
|
||||
send_extended_ack(rs_fd, packet_buffer[PKT_CMD], 0x00);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,419 @@
|
|||
|
||||
#ifndef AQ_IAQUALINK_H_
|
||||
#define AQ_IAQUALINK_H_
|
||||
|
||||
//void send_iaqualink_ack(int rs_fd, unsigned char *packet_buffer);
|
||||
|
||||
int get_iaqualink_cmd(unsigned char source_message_type, unsigned char **dest_message);
|
||||
void remove_iaqualink_cmd();
|
||||
|
||||
bool process_iaqualink_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data);
|
||||
bool process_iAqualinkStatusPacket(unsigned char *packet, int length, struct aqualinkdata *aq_data);
|
||||
|
||||
void set_iaqualink_aux_state(aqkey *button, bool isON);
|
||||
void set_iaqualink_heater_setpoint(int value, SP_TYPE type);
|
||||
|
||||
// Send the below commands to turn on/off (toggle)
|
||||
// This is the button in pButton. (byte 6 in below)
|
||||
// iAq pButton | HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x21|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xcb|0x10|0x03|
|
||||
|
||||
#define IAQ_PUMP 0x00
|
||||
#define IAQ_POOL_HTR 0x01
|
||||
#define IAQ_SPA 0x02
|
||||
#define IAQ_SPA_HTR 0x03
|
||||
//....... some missing ....
|
||||
//#define IAQ_ALL_OFF 0x10
|
||||
//#define IAQ_SPA_MODE 0x11
|
||||
//#define IAQ_CLEAN_MODE 0x12
|
||||
#define IAQ_ONETOUCH_1 0x10
|
||||
#define IAQ_ONETOUCH_2 0x11
|
||||
#define IAQ_ONETOUCH_3 0x12
|
||||
#define IAQ_ONETOUCH_4 0x13 // Im gessing
|
||||
#define IAQ_ONETOUCH_5 0x14 // Im gessing
|
||||
#define IAQ_ONETOUCH_6 0x15 // Im gessing
|
||||
|
||||
#define IAQ_ALL_OFF IAQ_ONETOUCH_1 // Using default name
|
||||
#define IAQ_SPA_MODE IAQ_ONETOUCH_2 // Using default name
|
||||
#define IAQ_CLEAN_MODE IAQ_ONETOUCH_3 // Using default name
|
||||
|
||||
#define IAD_SWG 0x19
|
||||
//....... some missing ....
|
||||
#define IAQ_AUX1 0x21 //0x25 RS16 & 12 // AUX5
|
||||
#define IAQ_AUX2 0x22 //0x26 RS16
|
||||
#define IAQ_AUX3 0x23 //0x27 RS16
|
||||
#define IAQ_AUX4 0x24 //0x28 RS16
|
||||
#define IAQ_AUX5 0x25 //0x29 RS16
|
||||
#define IAQ_AUX6 0x26 //0x2a RS16
|
||||
#define IAQ_AUX7 0x27 //0x2b RS16
|
||||
#define IAQ_AUXB1 0x28 //0x2c RS16
|
||||
#define IAQ_AUXB2 0x29 //0x2d RS16
|
||||
#define IAQ_AUXB3 0x2a //0x2e RS16
|
||||
#define IAQ_AUXB4 0x2b //0x2f RS16
|
||||
#define IAQ_AUXB5 0x2c //0x30 RS16
|
||||
#define IAQ_AUXB6 0x2d //0x31 RS16
|
||||
#define IAQ_AUXB7 0x2e //0x32 RS16
|
||||
#define IAQ_AUXB8 0x2f //0x33 RS16
|
||||
/*
|
||||
#define IAQ_AUX1 0x25 //0x25 RS16 & 12 // AUX5
|
||||
#define IAQ_AUX2 0x26 //0x26 RS16
|
||||
#define IAQ_AUX3 0x27 //0x27 RS16
|
||||
#define IAQ_AUX4 0x28 //0x28 RS16
|
||||
#define IAQ_AUX5 0x29 //0x29 RS16
|
||||
#define IAQ_AUX6 0x2a //0x2a RS16
|
||||
#define IAQ_AUX7 0x2b //0x2b RS16
|
||||
#define IAQ_AUXB1 0x2c //0x2c RS16
|
||||
#define IAQ_AUXB2 0x2d //0x2d RS16
|
||||
#define IAQ_AUXB3 0x2e //0x2e RS16
|
||||
#define IAQ_AUXB4 0x2f //0x2f RS16
|
||||
#define IAQ_AUXB5 0x30 //0x30 RS16
|
||||
#define IAQ_AUXB6 0x31 //0x31 RS16
|
||||
#define IAQ_AUXB7 0x32 //0x32 RS16
|
||||
#define IAQ_AUXB8 0x33 //0x33 RS16
|
||||
*/
|
||||
//... Looks like there are C & D buttons
|
||||
/* I got this when sending dec=53 hex=0x35 as the button, all of a sudden got extra buttons in the aux status message send to AqualinkTouch protocol
|
||||
Not sure on ordering BUT dec=57 hex=0x39 = button D2 / dec=58 hex=0x3a = D3
|
||||
Notice: iAQ Touch: Label Aux C1 = On
|
||||
Notice: iAQ Touch: Label Aux C2 = Off
|
||||
Notice: iAQ Touch: Label Aux C3 = Off
|
||||
Notice: iAQ Touch: Label Aux C4 = Off
|
||||
Notice: iAQ Touch: Label Aux C5 = Off
|
||||
Notice: iAQ Touch: Label Aux C6 = On
|
||||
Notice: iAQ Touch: Label Aux C7 = On
|
||||
Notice: iAQ Touch: Label Aux C8 = On
|
||||
Notice: iAQ Touch: Label Aux D1 = On
|
||||
Notice: iAQ Touch: Label Aux D2 = On
|
||||
Notice: iAQ Touch: Label Aux D3 = On
|
||||
Notice: iAQ Touch: Label Aux D4 = On
|
||||
Notice: iAQ Touch: Label Aux D5 = On
|
||||
Notice: iAQ Touch: Label Aux D6 = On
|
||||
Notice: iAQ Touch: Label Aux D7 = On
|
||||
Notice: iAQ Touch: Label Aux D8 = On
|
||||
*/
|
||||
#define IAQ_AUXD2 0x39
|
||||
#define IAQ_AUXD3 0x3a // 58 in dec
|
||||
#define IAQ_AUXD4 // 59 in dec
|
||||
#define IAQ_AUXD5 // 60 in dec
|
||||
#define IAQ_AUXD6 // 61 in dec
|
||||
#define IAQ_AUXD7 // 62 in dec
|
||||
#define IAQ_AUXD8 // 63 in dec (but this is VAUX1)
|
||||
//... Need to add Vitrual buttons...
|
||||
#define IAQ_VAUX1 0x3f
|
||||
|
||||
#define IAQ_PUMP_RPM 0x5e
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Read Jandy packet To 0xa3 of type Unknown '0x53' | HEX: 0x10|0x02|0xa3|0x53|0x08|0x10|0x03|
|
||||
Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x3f|0x00|0x52|0x10|0x03|
|
||||
|
||||
|
||||
Below get's sent to AqualinkTouch with iAqualink is enabled.
|
||||
End of message is board cpu and panel type.
|
||||
Read Jandy packet To 0x33 of type Unknown '0x70' | HEX: 0x10|0x02|0x33|0x70|0x0d|0x00|0x01|0x02|0x03|0x05|0x06|0x07|0x0e|0x0f|0x1a|0x1d|0x20|0x21|0x00|0x00|0x00|0x00|0x00|0x48|0x00|0x66|0x00|0x50|0x00|0x00|0x00|0xff|0x42|0x30|0x33|0x31|0x36|0x38|0x32|0x33|0x20|0x52|0x53|0x2d|0x34|0x20|0x43|0x6f|0x6d|0x62|0x6f|0x00|0x00|0x4b|0x10|0x03|
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
----
|
||||
Retrieve poll 0x53
|
||||
Reply ack w/ command 0x01|0x3f|0x20. (0x20 command)
|
||||
Retrieve 0x73 command Same ID iAqualink
|
||||
Reply iAQ pButton ( turn something on / set something)
|
||||
|
||||
Retrieve poll 0x53
|
||||
Reply ack w/ command 0x01|0x3f|0x08. (0x08 command)
|
||||
Retrieve 0x70 command on AqualinkTouch ID
|
||||
Reply iAQ pButton (status / last part of frame is board cpu)
|
||||
-- Byte 4 = offset.
|
||||
-- Byte 21 look like spa heat 0x00=off, 0x03=enabled
|
||||
-- offest+ 8 spa setpoint
|
||||
-- offset+ 10 air temp
|
||||
-- offest+ 13 pool temp
|
||||
-- offset+ 14 SWG% ?????
|
||||
-- Byte 27 looks like air temp
|
||||
-- Byte 28 air temp????
|
||||
-- Byte 30 pool temp
|
||||
-- Byte 34 looks like SWG%
|
||||
-- after byte 0xff is board
|
||||
|
||||
Retrieve poll 0x53
|
||||
Reply ack w/ command 0x01|0x3f|0x10. (0x10 command)
|
||||
Retrieve 0x71 command on AqualinkTouch ID
|
||||
Reply iAQ pButton (not sure)
|
||||
Byte 4 & 5 seems to indicate a different sub type
|
||||
0x71|0x01|0x19 = status about pool / spa / speed 1,2,3,4 / pool & spa heat
|
||||
0x71|0x01|0x1a = no idea
|
||||
0x71|0x01|0x17 = Pump numbers (doesn't seem to have any status, just pump names)
|
||||
|
||||
0x71|0x06|0x01 = Touch like spa mode / all off
|
||||
0x71|0x07|0x01 = Same as above. but more trailing packets.
|
||||
|
||||
Retrieve poll 0x53
|
||||
Reply ack w/ command 0x3f 0x18. (0x18 is command)
|
||||
Retrieve 0x72 command on AqualinkTouch ID
|
||||
Get a massive packet Aux status
|
||||
|
||||
----
|
||||
|
||||
Retrieve poll 0x53
|
||||
Reply ack w/ command 0x01|0x3f|0x20. (0x20 command)
|
||||
Retrieve 0x72 command
|
||||
Reply iAQ pButton (turn something on / set something). Below are examples.
|
||||
|
||||
RPM to 2750
|
||||
Bit 10 * 256 + Bit 11
|
||||
Bit 6 & 7 probably pump index.
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x0a|0xbe|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xd5|0x10|0x03|
|
||||
|
||||
RPM to 2995
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x0b|0xb3|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xcb|0x10|0x03|
|
||||
|
||||
SWG 50%
|
||||
Byte 7 = 50%
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x32|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x0e|0x10|0x03|
|
||||
|
||||
SWG 51%
|
||||
Byte 7 = 51%
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x33|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x0f|0x10|0x03|
|
||||
|
||||
---------
|
||||
|
||||
Send command 0x18 to 0xa1 returns below to 0x31. Looks like status of aux devices.
|
||||
Retrieve poll 0x53
|
||||
Reply ack w/ command 0x3f 0x18. (0x18 is command)
|
||||
Get a massive packet back, of aux status
|
||||
|
||||
Filter pump does not effect the below.
|
||||
Heater on/off does not effect below.
|
||||
HEater setpoints does not effect.
|
||||
Only Aux on/off seem to effect the status.
|
||||
|
||||
4th bit tells you where to start,
|
||||
after start 4 bits are status
|
||||
last bit of status tell you chars in label.
|
||||
after label repeat start 4 bits.
|
||||
|
||||
For Aux1 10th bit 0=off 1=on 11 to 14 15 to 19=name
|
||||
Aux2 19th
|
||||
Aux3 28
|
||||
Aux4 37
|
||||
|
||||
In Below Aux 3 color light / Aux 4 dimmer / Aux 5 color light (different type to aux3)
|
||||
|
||||
Aux 1 off / Aux 3 on
|
||||
HEX: 0x10|0x02|0x31|0x72|0x05|0x01|0x02|0x03|0x04|0x05|0x00|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x31|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x32|0x01|0x07|0x02|0x03|0x04|0x41|0x75|0x78|0x33|0x00|0x01|0x01|0x00|0x04|0x41|0x75|0x78|0x34|0x00|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x35|0xd5|0x10|0x03|
|
||||
Dec | 16| 2| 49| 114| 5| 1| 2| 3| 4| 5| 0| 1| 0| 0| 4| 65| 117| 120| 49| 1| 1| 0| 0| 4| 65| 117| 120| 50| 1| 7| 2| 3| 4| 65| 117| 120| 51| 0| 1| 1| 0| 4| 65| 117| 120| 52| 0| 1| 0| 0| 4| 65| 117| 120| 53| 213| 16| 3
|
||||
Ascii | | | 1| r| | | | | | | | | | | | A| u| x| 1| | | | | | A| u| x| 2| | | | | | A| u| x| 3| | | | | | A| u| x| 4| | | | | | A| u| x| 5| | |
|
||||
|
||||
Aux 1 on / Aux 3 on
|
||||
| HEX: 0x10|0x02|0x31|0x72|0x05|0x01|0x02|0x03|0x04|0x05|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x31|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x32|0x01|0x07|0x02|0x03|0x04|0x41|0x75|0x78|0x33|0x00|0x01|0x01|0x00|0x04|0x41|0x75|0x78|0x34|0x00|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x35|0xd6|0x10|0x03|
|
||||
Dec | 16| 2| 49| 114| 5| 1| 2| 3| 4| 5| 1| 1| 0| 0| 4| 65| 117| 120| 49| 1| 1| 0| 0| 4| 65| 117| 120| 50| 1| 7| 2| 3| 4| 65| 117| 120| 51| 0| 1| 1| 0| 4| 65| 117| 120| 52| 0| 1| 0| 0| 4| 65| 117| 120| 53| 214| 16| 3
|
||||
Ascii | | | 1| r| | | | | | | | | | | | A| u| x| 1| | | | | | A| u| x| 2| | | | | | A| u| x| 3| | | | | | A| u| x| 4| | | | | | A| u| x| 5| | |
|
||||
|
||||
Aux 1 off Aux3 to different light color
|
||||
Hex |0x10|0x02|0x31|0x72|0x05|0x01|0x02|0x03|0x04|0x05|0x00|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x31|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x32|0x00|0x07|0x02|0x03|0x04|0x41|0x75|0x78|0x33|0x00|0x01|0x01|0x00|0x04|0x41|0x75|0x78|0x34|0x00|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x35|0xd4|0x10|0x03|
|
||||
Dec | 16| 2| 49| 114| 5| 1| 2| 3| 4| 5| 0| 1| 0| 0| 4| 65| 117| 120| 49| 1| 1| 0| 0| 4| 65| 117| 120| 50| 0| 7| 2| 3| 4| 65| 117| 120| 51| 0| 1| 1| 0| 4| 65| 117| 120| 52| 0| 1| 0| 0| 4| 65| 117| 120| 53| 212| 16| 3
|
||||
Ascii | | | 1| r| | | | | | | | | | | | A| u| x| 1| | | | | | A| u| x| 2| | | | | | A| u| x| 3| | | | | | A| u| x| 4| | | | | | A| u| x| 5| | |
|
||||
|
||||
|
||||
|
||||
RS16 panel.
|
||||
HEX: 0x10|0x02|0x31|0x72|0x0f|0x01|0x02|0x03|0x04|0x05|0x06|0x07|0x08|0x09|0x0a|0x0b|0x0c|0x0d|0x0e|0x0f|0x00|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x31|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x32|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x33|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x34|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x35|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x36|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x37|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x31|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x32|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x33|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x34|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x35|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x36|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x37|0x01|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x38|0x77|0x10|0x03|
|
||||
Dec | 16| 2| 49| 114| 15| 1| 2| 3| 4| 5| 6| 7| 8| 9| 10| 11| 12| 13| 14| 15| 0| 1| 0| 0| 4| 65| 117| 120| 49| 1| 1| 0| 0| 4| 65| 117| 120| 50| 1| 1| 0| 0| 4| 65| 117| 120| 51| 1| 1| 0| 0| 4| 65| 117| 120| 52| 1| 1| 0| 0| 4| 65| 117| 120| 53| 1| 1| 0| 0| 4| 65| 117| 120| 54| 1| 1| 0| 0| 4| 65| 117| 120| 55| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 49| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 50| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 51| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 52| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 53| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 54| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 55| 1| 1| 0| 0| 6| 65| 117| 120| 32| 66| 56| 119| 16| 3
|
||||
Ascii | | | 1| r| | | | | | | | | | | | | | | | | | | | | | A| u| x| 1| | | | | | A| u| x| 2| | | | | | A| u| x| 3| | | | | | A| u| x| 4| | | | | | A| u| x| 5| | | | | | A| u| x| 6| | | | | | A| u| x| 7| | | | | | A| u| x| | B| 1| | | | | | A| u| x| | B| 2| | | | | | A| u| x| | B| 3| | | | | | A| u| x| | B| 4| | | | | | A| u| x| | B| 5| | | | | | A| u| x| | B| 6| | | | | | A| u| x| | B| 7| | | | | | A| u| x| | B| 8| w| |
|
||||
|
||||
Hex |0x10|0x02|0x31|0x72|
|
||||
|
||||
*/
|
||||
|
||||
/* Startup sequences
|
||||
|
||||
RS16 combo
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Probe | HEX: 0x10|0x02|0xa1|0x00|0xb3|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x61' | HEX: 0x10|0x02|0xa1|0x61|0x00|0x00|0x00|0x01|0x00|0x1d|0x32|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x61|0x00|0x74|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x50' | HEX: 0x10|0x02|0xa1|0x50|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x00|0x23|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x50|0x00|0x63|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x51' | HEX: 0x10|0x02|0xa1|0x51|0x31|0x42|0x41|0x36|0x32|0x38|0x32|0x35|0x42|0x37|0x43|0x36|0x39|0x41|0x34|0x43|0x00|0xa2|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x51|0x00|0x64|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x59' | HEX: 0x10|0x02|0xa1|0x59|0x00|0x0c|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x59|0x00|0x6c|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x52' | HEX: 0x10|0x02|0xa1|0x52|0x00|0x05|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x52|0x00|0x65|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type iAqalnk Poll | HEX: 0x10|0x02|0xa1|0x53|0x06|0x10|0x03|
|
||||
|
||||
RS8 Combo rev T.2
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Probe | HEX: 0x10|0x02|0xa1|0x00|0xb3|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x61' | HEX: 0x10|0x02|0xa1|0x61|0x00|0x00|0x00|0x01|0x00|0x1d|0x32|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x61|0x00|0x74|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x50' | HEX: 0x10|0x02|0xa1|0x50|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x00|0x23|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x50|0x00|0x63|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x51' | HEX: 0x10|0x02|0xa1|0x51|0x31|0x42|0x41|0x36|0x32|0x38|0x32|0x35|0x42|0x37|0x43|0x36|0x39|0x41|0x34|0x43|0x00|0xa2|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x51|0x00|0x64|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x59' | HEX: 0x10|0x02|0xa1|0x59|0x00|0x0c|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x59|0x00|0x6c|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x52' | HEX: 0x10|0x02|0xa1|0x52|0x00|0x05|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x52|0x00|0x65|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type iAqalnk Poll | HEX: 0x10|0x02|0xa1|0x53|0x06|0x10|0x03|
|
||||
|
||||
RS4 rev Yg
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Probe | HEX: 0x10|0x02|0xa3|0x00|0xb5|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Unknown '0x61' | HEX: 0x10|0x02|0xa3|0x61|0x00|0x00|0x00|0x04|0x00|0x27|0x41|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x61|0x00|0x74|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Unknown '0x50' | HEX: 0x10|0x02|0xa3|0x50|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x00|0x25|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x50|0x00|0x63|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Unknown '0x51' | HEX: 0x10|0x02|0xa3|0x51|0x00|0x06|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x51|0x00|0x64|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Unknown '0x59' | HEX: 0x10|0x02|0xa3|0x59|0x00|0x0e|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x59|0x00|0x6c|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Unknown '0x52' | HEX: 0x10|0x02|0xa3|0x52|0x00|0x07|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x52|0x00|0x65|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0xa3 of type Unknown '0x53' | HEX: 0x10|0x02|0xa3|0x53|0x08|0x10|0x03|
|
||||
Notice: Serial Log:Read Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x3f|0x00|0x52|0x10|0x03|
|
||||
|
||||
RS6 rev T2 RS8 (home)
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Probe | HEX: 0x10|0x02|0xa1|0x00|0xb3|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x61' | HEX: 0x10|0x02|0xa1|0x61|0x00|0x00|0x00|0x01|0x00|0x1d|0x32|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x61|0x00|0x74|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x50' | HEX: 0x10|0x02|0xa1|0x50|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x20|0x00|0x23|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x50|0x00|0x63|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x51' | HEX: 0x10|0x02|0xa1|0x51|0x31|0x42|0x41|0x36|0x32|0x38|0x32|0x35|0x42|0x37|0x43|0x36|0x39|0x41|0x34|0x43|0x00|0xa2|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x51|0x00|0x64|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x59' | HEX: 0x10|0x02|0xa1|0x59|0x01|0x0d|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x59|0x00|0x6c|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type Unknown '0x52' | HEX: 0x10|0x02|0xa1|0x52|0x03|0x08|0x10|0x03|
|
||||
Debug: RS Serial: Write Jandy packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x52|0x00|0x65|0x10|0x03|
|
||||
Debug: RS Serial: Read Jandy packet To 0xa1 of type iAqalnk Poll | HEX: 0x10|0x02|0xa1|0x53|0x06|0x10|0x03|
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
0x10|0x02|0x31|0x72|0x0f|0x01|0x02|0x03|0x04|0x05|0x06|0x07|0x08|0x09|0x0a|0x0b|0x0c|0x0d|0x0e|0x0f|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x31|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x32|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x33|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x34|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x35|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x36|0x01|0x01|0x00|0x00|0x04|0x41|0x75|0x78|0x37|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x31|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x32|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x33|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x34|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x35|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x36|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x37|0x00|0x01|0x00|0x00|0x06|0x41|0x75|0x78|0x20|0x42|0x38|0x70|0x10|0x03|
|
||||
|
||||
|
||||
Only panel (RS8)
|
||||
Air index 3 type 15 (pump off)
|
||||
Air index 3 type 14 (pump off)
|
||||
Air index 3 type 8 (pump on)
|
||||
Water index 5 type 15 (pump on)
|
||||
Temp2 ndex 8 type 20
|
||||
always 1 | index=4 type=(15 0x0f)
|
||||
|
||||
Comb0
|
||||
Spa setpoint index 8 type 14
|
||||
Air index 8 type 26
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Pump RPM
|
||||
|
||||
All taken from panel Yg, but only heater setpoints seem to work.
|
||||
Only setpoints seem to work,
|
||||
|
||||
RPM to 2750
|
||||
Bit 6 = 0x5e
|
||||
Bit 10 * 256 + Bit 11
|
||||
Bit 7 or 9 probably pump index.
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x0a|0xbe|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xd5|0x10|0x03|
|
||||
|
||||
RPM to 2995
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x0b|0xb3|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xcb|0x10|0x03|
|
||||
|
||||
|
||||
Below is setting RPM to 2505
|
||||
|
||||
packet To 0xa3 of type iAqalnk Poll | HEX: 0x10|0x02|0xa3|0x53|0x08|0x10|0x03|
|
||||
packet To 0x00 of type Ack w/ Command | HEX: 0x10|0x02|0x00|0x01|0x3f|0x20|0x72|0x10|0x03|
|
||||
packet To 0x33 of type iAq Poll | HEX: 0x10|0x02|0x33|0x30|0x75|0x10|0x03|
|
||||
packet To 0xa3 of type Unknown '0x73' | HEX: 0x10|0x02|0xa3|0x73|0x28|0x10|0x03|
|
||||
packet To 0x00 of type iAqualnk sendCmd | HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x5e|0x04|0x00|0x01|0x09|0xc9|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xdf|0x10|0x03|
|
||||
packet To 0x33 of type iAq Poll | HEX: 0x10|0x02|0x33|0x30|0x75|0x10|0x03|
|
||||
packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
packet To 0x33 of type iAq 1Tch status | HEX: 0x10|0x02|0x33|0x71|0x07|0x01|0x02|0x03|0x04|0x05|0x0f|0x12|0x00|0x07|0x41|0x6c|0x6c|0x20|0x4f|0x46|0x46|0x00|0x08|0x53|0x70|0x61|0x20|0x4d|0x6f|0x64|0x65|0x00|0x0a|0x43|0x6c|0x65|0x61|0x6e|0x20|0x4d|0x6f|0x64|0x65|0x00|0x08|0x42|0x75|0x62|0x62|0x6c|0x65|0x72|0x73|0x00|0x0a|0x57|0x61|0x74|0x65|0x72|0x66|0x61|0x6c|0x6c|0x31|0x04|0x09|0xc9|0x0d|0x7a|0x06|0xa4|0x0a|0xbe|0x08|0xca|0x08|0xca|0x0a|0xbe|0x0a|0xbe|0x05|0xdc|0x04|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x6a|0x10|0x03|
|
||||
All OFF = Off | index 0 type=(01 0x01) status=0x00 start=12 length=7
|
||||
Spa Mode = Off | index 1 type=(02 0x02) status=0x00 start=21 length=8
|
||||
Clean Mode = Off | index 2 type=(03 0x03) status=0x00 start=31 length=10
|
||||
Bubblers = Off | index 3 type=(04 0x04) status=0x00 start=43 length=8
|
||||
Waterfall1 = Off | index 4 type=(05 0x05) status=0x00 start=53 length=10
|
||||
*** RPM is in the next bytes from iAq 1Tch status. But can't tell how to pull them since SWG is also here as well. ****
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
SWG
|
||||
|
||||
SWG 50%
|
||||
Byte 6 = 0x19
|
||||
Byte 7 = 50%
|
||||
Byte 9 & 10 ????
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x32|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x0e|0x10|0x03|
|
||||
|
||||
SWG 51%
|
||||
Byte 7 = 51%
|
||||
HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x33|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x0f|0x10|0x03|
|
||||
|
||||
|
||||
Below is set SWG to 35
|
||||
|
||||
packet To 0xa3 of type iAqalnk Poll | HEX: 0x10|0x02|0xa3|0x53|0x08|0x10|0x03|
|
||||
packet To 0x00 of type Ack w/ Command | HEX: 0x10|0x02|0x00|0x01|0x3f|0x20|0x72|0x10|0x03|
|
||||
packet To 0x33 of type iAq Poll | HEX: 0x10|0x02|0x33|0x30|0x75|0x10|0x03|
|
||||
packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
packet To 0xa3 of type Unknown '0x73' | HEX: 0x10|0x02|0xa3|0x73|0x28|0x10|0x03|
|
||||
packet To 0x00 of type iAqualnk sendCmd | HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x19|0x23|0x00|0x18|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xff|0x10|0x03|
|
||||
packet To 0x33 of type iAq Poll | HEX: 0x10|0x02|0x33|0x30|0x75|0x10|0x03|
|
||||
packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
packet To 0x33 of type iAq 1Tch status | HEX: 0x10|0x02|0x33|0x71|0x07|0x01|0x02|0x03|0x04|0x05|0x12|0x20|0x00|0x07|0x41|0x6c|0x6c|0x20|0x4f|0x46|0x46|0x00|0x08|0x53|0x70|0x61|0x20|0x4d|0x6f|0x64|0x65|0x00|0x0a|0x43|0x6c|0x65|0x61|0x6e|0x20|0x4d|0x6f|0x64|0x65|0x00|0x08|0x42|0x75|0x62|0x62|0x6c|0x65|0x72|0x73|0x00|0x0a|0x57|0x61|0x74|0x65|0x72|0x66|0x61|0x6c|0x6c|0x31|0x04|0x01|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x23|0x00|0x00|0x18|0x00|0x00|0x01|0x00|0xd3|0x10|0x03|
|
||||
All OFF = Off | index 0 type=(01 0x01) status=0x00 start=12 length=7
|
||||
Spa Mode = Off | index 1 type=(02 0x02) status=0x00 start=21 length=8
|
||||
Clean Mode = Off | index 2 type=(03 0x03) status=0x00 start=31 length=10
|
||||
Bubblers = Off | index 3 type=(04 0x04) status=0x00 start=43 length=8
|
||||
Waterfall1 = Off | index 4 type=(05 0x05) status=0x00 start=53 length=10
|
||||
*** SWG is in the next bytes from iAq 1Tch status. But can't tell how to pull them since RPM is also here as well. ****
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
This works on rev Yg, but doesn't seem to T.2
|
||||
|
||||
Set Heat Pump Chiller Setpoint.
|
||||
Set to 94 (0x5e in type iAqualnk sendCmd)
|
||||
|
||||
Byte 12 in iAqualink sendCmd (sets set point)
|
||||
Byte 6 from end iAq Main status (looks like return)
|
||||
|
||||
Set to 94 (0x5e in type iAqualink sentCmd)
|
||||
packet To 0x33 of type iAq Poll | HEX: 0x10|0x02|0x33|0x30|0x75|0x10|0x03|
|
||||
packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
packet To 0xa3 of type Unknown '0x73' | HEX: 0x10|0x02|0xa3|0x73|0x28|0x10|0x03|
|
||||
packet To 0x00 of type iAqualnk sendCmd | HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x1f|0x00|0x4b|0x00|0x63|0x00|0x5e|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xd5|0x10|0x03|
|
||||
packet To 0x33 of type iAq Main status | HEX: 0x10|0x02|0x33|0x70|0x11|0x00|0x01|0x02|0x03|0x05|0x06|0x07|0x08|0x0e|0x0f|0x1a|0x1d|0x1f|0x20|0x21|0x24|0x25|0x01|0x00|0x00|0x00|0x00|0x4b|0x00|0x63|0x00|0x59|0x00|0x4f|0x00|0x00|0x00|0x37|0x18|0x42|0x30|0x33|0x31|0x36|0x38|0x32|0x33|0x20|0x52|0x53|0x2d|0x34|0x20|0x43|0x6f|0x6d|0x62|0x6f|0x00|0x00|0x00|0x5e|0x00|0x37|0xfd|0x10|0x03|
|
||||
|
||||
|
||||
Set to 92 (0x5c in type iAqualink sentCmd)
|
||||
packet To 0x33 of type iAq Poll | HEX: 0x10|0x02|0x33|0x30|0x75|0x10|0x03|
|
||||
packet To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
packet To 0xa3 of type Unknown '0x73' | HEX: 0x10|0x02|0xa3|0x73|0x28|0x10|0x03|
|
||||
packet To 0x00 of type iAqualnk sendCmd | HEX: 0x10|0x02|0x00|0x24|0x73|0x01|0x1f|0x00|0x4b|0x00|0x63|0x00|0x5c|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xd3|0x10|0x03|
|
||||
packet To 0x33 of type iAq Main status | HEX: 0x10|0x02|0x33|0x70|0x11|0x00|0x01|0x02|0x03|0x05|0x06|0x07|0x08|0x0e|0x0f|0x1a|0x1d|0x1f|0x20|0x21|0x24|0x25|0x01|0x00|0x00|0x00|0x00|0x4b|0x00|0x63|0x00|0x59|0x00|0x4f|0x00|0x00|0x00|0x37|0x18|0x42|0x30|0x33|0x31|0x36|0x38|0x32|0x33|0x20|0x52|0x53|0x2d|0x34|0x20|0x43|0x6f|0x6d|0x62|0x6f|0x00|0x00|0x00|0x5c|0x00|0x37|0xfb|0x10|0x03|
|
||||
|
||||
|
||||
|
||||
*/
|
|
@ -32,6 +32,9 @@
|
|||
#include "version.h"
|
||||
#include "aq_timer.h"
|
||||
#include "aq_programmer.h"
|
||||
#include "rs_msg_utils.h"
|
||||
#include "color_lights.h"
|
||||
#include "iaqualink.h"
|
||||
|
||||
//#define test_message "{\"type\": \"status\",\"version\": \"8157 REV MMM\",\"date\": \"09/01/16 THU\",\"time\": \"1:16 PM\",\"temp_units\": \"F\",\"air_temp\": \"96\",\"pool_temp\": \"86\",\"spa_temp\": \" \",\"battery\": \"ok\",\"pool_htr_set_pnt\": \"85\",\"spa_htr_set_pnt\": \"99\",\"freeze_protection\": \"off\",\"frz_protect_set_pnt\": \"0\",\"leds\": {\"pump\": \"on\",\"spa\": \"off\",\"aux1\": \"off\",\"aux2\": \"off\",\"aux3\": \"off\",\"aux4\": \"off\",\"aux5\": \"off\",\"aux6\": \"off\",\"aux7\": \"off\",\"pool_heater\": \"off\",\"spa_heater\": \"off\",\"solar_heater\": \"off\"}}"
|
||||
//#define test_labels "{\"type\": \"aux_labels\",\"aux1_label\": \"Cleaner\",\"aux2_label\": \"Waterfall\",\"aux3_label\": \"Spa Blower\",\"aux4_label\": \"Pool Light\",\"aux5_label\": \"Spa Light\",\"aux6_label\": \"Unassigned\",\"aux7_label\": \"Unassigned\"}"
|
||||
|
@ -43,27 +46,43 @@
|
|||
//SPA WILL TURN OFF AFTER COOL DOWN CYCLE
|
||||
|
||||
|
||||
bool printableChar(char ch)
|
||||
{
|
||||
if ( (ch < 32 || ch > 126) ||
|
||||
ch == 123 || // {
|
||||
ch == 125 || // }
|
||||
ch == 34 || // "
|
||||
ch == 92 // backslash
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
int json_chars(char *dest, const char *src, int dest_len, int src_len)
|
||||
{
|
||||
int i;
|
||||
int end = dest_len < src_len ? dest_len:src_len;
|
||||
for(i=0; i < end; i++) {
|
||||
/*
|
||||
if ( (src[i] < 32 || src[i] > 126) ||
|
||||
src[i] == 123 || // {
|
||||
src[i] == 125 || // }
|
||||
src[i] == 34 || // "
|
||||
src[i] == 92 // backslash
|
||||
) // only printable chars
|
||||
src[i] == 92 // backslash
|
||||
) // only printable chars*/
|
||||
if (! printableChar(src[i]))
|
||||
dest[i] = ' ';
|
||||
else
|
||||
dest[i] = src[i];
|
||||
}
|
||||
|
||||
i--;
|
||||
/* // Don't delete trailing whitespace
|
||||
while (dest[i] == ' ')
|
||||
i--;
|
||||
*/
|
||||
|
||||
if (dest[i] != '\0') {
|
||||
if (i < (dest_len-1))
|
||||
|
@ -71,13 +90,13 @@ int json_chars(char *dest, const char *src, int dest_len, int src_len)
|
|||
|
||||
dest[i] = '\0';
|
||||
}
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int build_logmsg_JSON(char *dest, const char *src, int dest_len, int src_len)
|
||||
int build_logmsg_JSON(char *dest, int loglevel, const char *src, int dest_len, int src_len)
|
||||
{
|
||||
int length = sprintf(dest, "{\"logmsg\":\"");
|
||||
int length = sprintf(dest, "{\"logmsg\":\"%-7s",elevel2text(loglevel));
|
||||
length += json_chars(dest+length, src, (dest_len-20), src_len);
|
||||
length += sprintf(dest+length, "\"}");
|
||||
dest[length] = '\0';
|
||||
|
@ -89,36 +108,58 @@ int build_logmsg_JSON(char *dest, const char *src, int dest_len, int src_len)
|
|||
|
||||
const char* _getStatus(struct aqualinkdata *aqdata, const char *blankmsg)
|
||||
{
|
||||
/*
|
||||
if (aqdata->active_thread.thread_id != 0 && !aqdata->simulate_panel) {
|
||||
//return JSON_PROGRAMMING;
|
||||
return programtypeDisplayName(aqdata->active_thread.ptype);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
printf("**** Programming=%s, length=%ld, empty=%s, Message=%s \n",
|
||||
aqdata->active_thread.thread_id==0?"no":"yes",
|
||||
strlen(aqdata->last_display_message),
|
||||
rsm_isempy(aqdata->last_display_message,strlen(aqdata->last_display_message))==true?"yes":"no",
|
||||
aqdata->last_display_message);
|
||||
*/
|
||||
|
||||
// If only one bit set (conected) then ignore all these if's
|
||||
if (aqdata->status_mask != CONNECTED) {
|
||||
if ((aqdata->status_mask & ERROR_SERIAL) == ERROR_SERIAL)
|
||||
return "ERROR No Serial connection";
|
||||
else if ((aqdata->status_mask & ERROR_NO_DEVICE_ID) == ERROR_NO_DEVICE_ID)
|
||||
return "ERROR No device ID";
|
||||
else if ((aqdata->status_mask & CHECKING_CONFIG) == CHECKING_CONFIG)
|
||||
return "Checking Config";
|
||||
else if ((aqdata->status_mask & AUTOCONFIGURE_ID) == AUTOCONFIGURE_ID)
|
||||
return "Searching for free device ID's, Please wait!";
|
||||
else if ((aqdata->status_mask & AUTOCONFIGURE_PANEL) == AUTOCONFIGURE_PANEL)
|
||||
return "Getting Panel Information";
|
||||
else if ((aqdata->status_mask & CONNECTING) == CONNECTING)
|
||||
return "Connecting (waiting for control panel)";
|
||||
else if ((aqdata->status_mask & NOT_CONNECTED) == NOT_CONNECTED)
|
||||
return "Not Connected to panel";
|
||||
}
|
||||
|
||||
if (aqdata->active_thread.thread_id != 0) {
|
||||
if (!aqdata->is_display_message_programming || rsm_isempy(aqdata->last_display_message,strlen(aqdata->last_display_message))){
|
||||
return programtypeDisplayName(aqdata->active_thread.ptype);
|
||||
}
|
||||
}
|
||||
|
||||
//if (aqdata->last_message != NULL && stristr(aqdata->last_message, "SERVICE") != NULL ) {
|
||||
|
||||
//if (aqdata->last_message != NULL && stristr(aqdata->last_message, "SERVICE") != NULL ) {
|
||||
if (aqdata->service_mode_state == ON) {
|
||||
return JSON_SERVICE;
|
||||
} else if (aqdata->service_mode_state == FLASH) {
|
||||
return JSON_TIMEOUT;
|
||||
}
|
||||
|
||||
// NSF should probably use json_chars here.
|
||||
if (aqdata->last_display_message[0] != '\0') {
|
||||
int i;
|
||||
for(i=0; i < strlen(aqdata->last_display_message); i++ ) {
|
||||
if (aqdata->last_display_message[i] <= 31 || aqdata->last_display_message[i] >= 127) {
|
||||
if (! printableChar(aqdata->last_display_message[i])) {
|
||||
aqdata->last_display_message[i] = ' ';
|
||||
} else {
|
||||
switch (aqdata->last_display_message[i]) {
|
||||
case '"':
|
||||
case '/':
|
||||
case '\n':
|
||||
case '\t':
|
||||
case '\f':
|
||||
case '\r':
|
||||
case '\b':
|
||||
aqdata->last_display_message[i] = ' ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf("JSON Sending '%s'\n",aqdata->last_display_message);
|
||||
|
@ -168,7 +209,7 @@ int build_mqtt_status_message_JSON(char* buffer, int size, int idx, int nvalue,
|
|||
return strlen(buffer);
|
||||
}
|
||||
|
||||
int build_aqualink_error_status_JSON(char* buffer, int size, char *msg)
|
||||
int build_aqualink_error_status_JSON(char* buffer, int size, const char *msg)
|
||||
{
|
||||
//return snprintf(buffer, size, "{\"type\": \"error\",\"status\":\"%s\"}", msg);
|
||||
return snprintf(buffer, size, "{\"type\": \"status\",\"status\":\"%s\",\"version\":\"xx\",\"time\":\"xx\",\"air_temp\":\"0\",\"pool_temp\":\"0\",\"spa_temp\":\"0\",\"pool_htr_set_pnt\":\"0\",\"spa_htr_set_pnt\":\"0\",\"frz_protect_set_pnt\":\"0\",\"temp_units\":\"f\",\"battery\":\"ok\",\"leds\":{\"Filter_Pump\": \"off\",\"Spa_Mode\": \"off\",\"Aux_1\": \"off\",\"Aux_2\": \"off\",\"Aux_3\": \"off\",\"Aux_4\": \"off\",\"Aux_5\": \"off\",\"Aux_6\": \"off\",\"Aux_7\": \"off\",\"Pool_Heater\": \"off\",\"Spa_Heater\": \"off\",\"Solar_Heater\": \"off\"}}", msg);
|
||||
|
@ -227,32 +268,54 @@ char *get_aux_information(aqkey *button, struct aqualinkdata *aqdata, char *buff
|
|||
int length = 0;
|
||||
buffer[0] = '\0';
|
||||
|
||||
if ((button->special_mask & VS_PUMP) == VS_PUMP)
|
||||
//if ((button->special_mask & VS_PUMP) == VS_PUMP)
|
||||
if (isVS_PUMP(button->special_mask))
|
||||
{
|
||||
//printf("Button %s is VSP\n", button->name);
|
||||
for (i=0; i < aqdata->num_pumps; i++) {
|
||||
if (button == aqdata->pumps[i].button) {
|
||||
length += sprintf(buffer, ",\"type_ext\":\"switch_vsp\",\"Pump_RPM\":\"%d\",\"Pump_GPM\":\"%d\",\"Pump_Watts\":\"%d\",\"Pump_Type\":\"%s\"",
|
||||
aqdata->pumps[i].rpm,aqdata->pumps[i].gpm,aqdata->pumps[i].watts,
|
||||
(aqdata->pumps[i].pumpType==VFPUMP?"vfPump":(aqdata->pumps[i].pumpType==VSPUMP?"vsPump":"ePump")));
|
||||
length += sprintf(buffer, ",\"type_ext\":\"switch_vsp\",\"Pump_RPM\":\"%d\",\"Pump_GPM\":\"%d\",\"Pump_Watts\":\"%d\",\"Pump_Type\":\"%s\",\"Pump_Status\":\"%d\",\"Pump_Speed\":\"%d\"",
|
||||
aqdata->pumps[i].rpm,
|
||||
aqdata->pumps[i].gpm,
|
||||
aqdata->pumps[i].watts,
|
||||
(aqdata->pumps[i].pumpType==VFPUMP?"vfPump":(aqdata->pumps[i].pumpType==VSPUMP?"vsPump":"ePump")),
|
||||
getPumpStatus(i, aqdata),
|
||||
getPumpSpeedAsPercent(&aqdata->pumps[i]));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((button->special_mask & PROGRAM_LIGHT) == PROGRAM_LIGHT)
|
||||
//else if ((button->special_mask & PROGRAM_LIGHT) == PROGRAM_LIGHT)
|
||||
else if (isPLIGHT(button->special_mask))
|
||||
{
|
||||
//printf("Button %s is ProgramableLight\n", button->name);
|
||||
for (i=0; i < aqdata->num_lights; i++) {
|
||||
if (button == aqdata->lights[i].button) {
|
||||
length += sprintf(buffer, ",\"type_ext\": \"switch_program\", \"Light_Type\":\"%d\"", aqdata->lights[i].lightType);
|
||||
if (aqdata->lights[i].lightType == LC_DIMMER2) {
|
||||
length += sprintf(buffer, ",\"type_ext\": \"light_dimmer\", \"Light_Type\":\"%d\", \"Light_Program\":\"%d\", \"Program_Name\":\"%d%%\" ",
|
||||
aqdata->lights[i].lightType,
|
||||
aqdata->lights[i].currentValue,
|
||||
aqdata->lights[i].currentValue);
|
||||
} else {
|
||||
length += sprintf(buffer, ",\"type_ext\": \"switch_program\", \"Light_Type\":\"%d\", \"Light_Program\":\"%d\", \"Program_Name\":\"%s\" ",
|
||||
aqdata->lights[i].lightType,
|
||||
aqdata->lights[i].currentValue,
|
||||
get_currentlight_mode_name(aqdata->lights[i], ALLBUTTON));
|
||||
//light_mode_name(aqdata->lights[i].lightType, aqdata->lights[i].currentValue, ALLBUTTON));
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isVBUTTON_ALTLABEL(button->special_mask))
|
||||
{
|
||||
length += sprintf(buffer, ",\"alt_label\":\"%s\", \"in_alt_mode\": \"%s\" ",((vbutton_detail *)button->special_mask_ptr)->altlabel, ((vbutton_detail *)button->special_mask_ptr)->in_alt_mode?JSON_ON:JSON_OFF );
|
||||
//return buffer;
|
||||
}
|
||||
|
||||
//printf("Button %s is Switch\n", button->name);
|
||||
length += sprintf(buffer, ",\"type_ext\": \"switch_timer\", \"timer_active\":\"%s\"", (((button->special_mask & TIMER_ACTIVE) == TIMER_ACTIVE)?JSON_ON:JSON_OFF) );
|
||||
length += sprintf(buffer+length, ",\"type_ext\": \"switch_timer\", \"timer_active\":\"%s\"", (((button->special_mask & TIMER_ACTIVE) == TIMER_ACTIVE)?JSON_ON:JSON_OFF) );
|
||||
if ((button->special_mask & TIMER_ACTIVE) == TIMER_ACTIVE) {
|
||||
length += sprintf(buffer+length,",\"timer_duration\":\"%d\"", get_timer_left(button));
|
||||
}
|
||||
|
@ -268,9 +331,10 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
int i;
|
||||
|
||||
// IF temp units are F assume homekit is using F
|
||||
bool homekit_f = (homekit && aqdata->temp_units==FAHRENHEIT);
|
||||
bool homekit_f = (homekit && ( aqdata->temp_units==FAHRENHEIT || aqdata->temp_units == UNKNOWN) );
|
||||
|
||||
length += sprintf(buffer+length, "{\"type\": \"devices\"");
|
||||
length += sprintf(buffer+length, ",\"aqualinkd_version\":\"%s\"",AQUALINKD_VERSION);//"09/01/16 THU",
|
||||
length += sprintf(buffer+length, ",\"date\":\"%s\"",aqdata->date );//"09/01/16 THU",
|
||||
length += sprintf(buffer+length, ",\"time\":\"%s\"",aqdata->time );//"1:16 PM",
|
||||
if ( aqdata->temp_units == FAHRENHEIT )
|
||||
|
@ -284,7 +348,7 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
|
||||
for (i=0; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
if ( strcmp(BTN_POOL_HTR,aqdata->aqbuttons[i].name) == 0 && (_aqconfig_.force_ps_setpoints || aqdata->pool_htr_set_point != TEMP_UNKNOWN)) {
|
||||
if ( strcmp(BTN_POOL_HTR,aqdata->aqbuttons[i].name) == 0 && (ENABLE_HEATERS || aqdata->pool_htr_set_point != TEMP_UNKNOWN)) {
|
||||
length += sprintf(buffer+length, "{\"type\": \"setpoint_thermo\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\", \"int_status\": \"%d\", \"timer_active\":\"%s\" },",
|
||||
aqdata->aqbuttons[i].name,
|
||||
aqdata->aqbuttons[i].label,
|
||||
|
@ -297,7 +361,7 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
LED2int(aqdata->aqbuttons[i].led->state),
|
||||
((aqdata->aqbuttons[i].special_mask & TIMER_ACTIVE) == TIMER_ACTIVE?JSON_ON:JSON_OFF) );
|
||||
|
||||
} else if ( strcmp(BTN_SPA_HTR,aqdata->aqbuttons[i].name)==0 && (_aqconfig_.force_ps_setpoints || aqdata->spa_htr_set_point != TEMP_UNKNOWN)) {
|
||||
} else if ( strcmp(BTN_SPA_HTR,aqdata->aqbuttons[i].name)==0 && (ENABLE_HEATERS || aqdata->spa_htr_set_point != TEMP_UNKNOWN)) {
|
||||
length += sprintf(buffer+length, "{\"type\": \"setpoint_thermo\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\", \"int_status\": \"%d\", \"timer_active\":\"%s\" },",
|
||||
aqdata->aqbuttons[i].name,
|
||||
aqdata->aqbuttons[i].label,
|
||||
|
@ -311,6 +375,10 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
((aqdata->aqbuttons[i].special_mask & TIMER_ACTIVE) == TIMER_ACTIVE?JSON_ON:JSON_OFF));
|
||||
|
||||
} else {
|
||||
if (!homekit && ENABLE_CHILLER && isVBUTTON_CHILLER(aqdata->aqbuttons[i].special_mask) ) {
|
||||
// We will add this VButton as a thermostat
|
||||
continue;
|
||||
}
|
||||
get_aux_information(&aqdata->aqbuttons[i], aqdata, aux_info);
|
||||
//length += sprintf(buffer+length, "{\"type\": \"switch\", \"type_ext\": \"switch_vsp\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"int_status\": \"%d\" %s},",
|
||||
length += sprintf(buffer+length, "{\"type\": \"switch\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"int_status\": \"%d\" %s},",
|
||||
|
@ -351,13 +419,11 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
}*/
|
||||
}
|
||||
|
||||
if ( aqdata->frz_protect_set_point != TEMP_UNKNOWN && aqdata->air_temp != TEMP_UNKNOWN) {
|
||||
if ( ENABLE_FREEZEPROTECT || (aqdata->frz_protect_set_point != TEMP_UNKNOWN && aqdata->air_temp != TEMP_UNKNOWN) ) {
|
||||
length += sprintf(buffer+length, "{\"type\": \"setpoint_freeze\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\", \"int_status\": \"%d\" },",
|
||||
FREEZE_PROTECT,
|
||||
"Freeze Protection",
|
||||
//JSON_OFF,
|
||||
aqdata->frz_protect_state==ON?JSON_ON:JSON_OFF,
|
||||
//JSON_ENABLED,
|
||||
aqdata->frz_protect_state==ON?LED2text(ON):LED2text(ENABLE),
|
||||
((homekit)?2:0),
|
||||
((homekit_f)?degFtoC(aqdata->frz_protect_set_point):aqdata->frz_protect_set_point),
|
||||
|
@ -366,6 +432,21 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
aqdata->frz_protect_state==ON?1:0);
|
||||
}
|
||||
|
||||
if ( (ENABLE_CHILLER || (aqdata->chiller_set_point != TEMP_UNKNOWN && getWaterTemp(aqdata) != TEMP_UNKNOWN)) && (aqdata->chiller_button != NULL) ) {
|
||||
length += sprintf(buffer+length, "{\"type\": \"setpoint_chiller\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\", \"int_status\": \"%d\" },",
|
||||
CHILLER,
|
||||
"Heat Pump Chiller",
|
||||
aqdata->chiller_button->led->state==ON?JSON_ON:JSON_OFF,
|
||||
//((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode?JSON_ON:JSON_OFF,
|
||||
aqdata->chiller_button->led->state==ON?LED2text(ON):LED2text(ENABLE),
|
||||
//((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode?(aqdata->chiller_button->led->state==ON?LED2text(ON):LED2text(ENABLE)):JSON_OFF,
|
||||
((homekit)?2:0),
|
||||
((homekit_f)?degFtoC(aqdata->chiller_set_point):aqdata->chiller_set_point),
|
||||
((homekit)?2:0),
|
||||
((homekit_f)?degFtoC(getWaterTemp(aqdata)):getWaterTemp(aqdata)),
|
||||
aqdata->chiller_button->led->state==ON?1:0);
|
||||
}
|
||||
|
||||
if (aqdata->swg_led_state != LED_S_UNKNOWN) {
|
||||
if ( aqdata->swg_percent != TEMP_UNKNOWN ) {
|
||||
length += sprintf(buffer+length, "{\"type\": \"setpoint_swg\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\", \"int_status\": \"%d\" },",
|
||||
|
@ -390,6 +471,7 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
((homekit_f)?2:0),
|
||||
((homekit_f)?degFtoC(aqdata->swg_percent):aqdata->swg_percent));
|
||||
//if (!homekit) { // For the moment keep boost off homekit
|
||||
|
||||
length += sprintf(buffer+length, "{\"type\": \"switch\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"int_status\": \"%d\"},",
|
||||
SWG_BOOST_TOPIC,
|
||||
"SWG Boost",
|
||||
|
@ -450,7 +532,7 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
"on",
|
||||
((homekit)?2:0),
|
||||
((homekit_f)?degFtoC(aqdata->pool_temp):aqdata->pool_temp));
|
||||
length += sprintf(buffer+length, "{\"type\": \"temperature\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"value\": \"%.*f\" }",
|
||||
length += sprintf(buffer+length, "{\"type\": \"temperature\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"value\": \"%.*f\" },",
|
||||
SPA_TEMP_TOPIC,
|
||||
/*SPA_TEMPERATURE,*/
|
||||
"Spa Water Temperature",
|
||||
|
@ -458,11 +540,26 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
((homekit)?2:0),
|
||||
((homekit_f)?degFtoC(aqdata->spa_temp):aqdata->spa_temp));
|
||||
|
||||
for (i=0; i < aqdata->num_sensors; i++)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
/*
|
||||
length += sprintf(buffer+length, "], \"aux_device_detail\": [");
|
||||
for (i=0; i < MAX_PUMPS; i++) {
|
||||
}
|
||||
*/
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
|
||||
length += sprintf(buffer+length, "]}");
|
||||
|
||||
LOG(NET_LOG,LOG_DEBUG, "JSON: %s used %d of %d\n", homekit?"homebridge":"web", length, size);
|
||||
|
@ -474,9 +571,20 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
//return length;
|
||||
}
|
||||
|
||||
int logmaskjsonobject(int16_t flag, char* buffer)
|
||||
int logmaskjsonobject(logmask_t flag, char* buffer)
|
||||
{
|
||||
int length = sprintf(buffer, "{\"name\":\"%s\",\"id\":\"%d\",\"set\":\"%s\"},", logmask2name(flag), flag,(isDebugLogMaskSet(flag)?JSON_ON:JSON_OFF));
|
||||
|
||||
if (flag == RSSD_LOG) {
|
||||
//length = sprintf(buffer, "{\"name\":\"%s\",\"id\":\"%d\",\"set\":\"%s\",\"filter\":\"0x%02hhx\"},", logmask2name(flag), flag,(isDebugLogMaskSet(flag)?JSON_ON:JSON_OFF), _aqconfig_.RSSD_LOG_filter[0]);
|
||||
length = sprintf(buffer, "{\"name\":\"%s\",\"id\":\"%d\",\"set\":\"%s\",\"filters\":[", logmask2name(flag), flag,(isDebugLogMaskSet(flag)?JSON_ON:JSON_OFF));
|
||||
for (int i=0; i < MAX_RSSD_LOG_FILTERS; i++) {
|
||||
length += sprintf(buffer+length, "\"0x%02hhx\",", _aqconfig_.RSSD_LOG_filter[i]);
|
||||
}
|
||||
//"]},"
|
||||
length += sprintf(buffer+length-1, "]},");
|
||||
length--;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
int logleveljsonobject(int level, char* buffer)
|
||||
|
@ -484,6 +592,7 @@ int logleveljsonobject(int level, char* buffer)
|
|||
int length = sprintf(buffer, "{\"name\":\"%s\",\"id\":\"%d\",\"set\":\"%s\"},", loglevel2name(level), level,(getSystemLogLevel()==level?JSON_ON:JSON_OFF));
|
||||
return length;
|
||||
}
|
||||
|
||||
int build_aqualink_aqmanager_JSON(struct aqualinkdata *aqdata, char* buffer, int size)
|
||||
{
|
||||
memset(&buffer[0], 0, size);
|
||||
|
@ -491,28 +600,44 @@ int build_aqualink_aqmanager_JSON(struct aqualinkdata *aqdata, char* buffer, int
|
|||
|
||||
length += sprintf(buffer+length, "{\"type\": \"aqmanager\"");
|
||||
length += sprintf(buffer+length, ",\"deamonized\": \"%s\"", (_aqconfig_.deamonize?JSON_ON:JSON_OFF) );
|
||||
|
||||
if ( isMASK_SET(aqdata->status_mask,AUTOCONFIGURE_ID ) ||
|
||||
isMASK_SET(aqdata->status_mask,AUTOCONFIGURE_PANEL ) /*||
|
||||
isMASK_SET(aqdata->status_mask,CONNECTING )*/ )
|
||||
{
|
||||
length += sprintf(buffer+length, ",\"config_editor\": \"no\"");
|
||||
} else {
|
||||
length += sprintf(buffer+length, ",\"config_editor\": \"yes\"");
|
||||
}
|
||||
|
||||
length += sprintf(buffer+length, ",\"aqualinkd_version\":\"%s\"",AQUALINKD_VERSION);
|
||||
|
||||
|
||||
/*
|
||||
length += sprintf(buffer+length, ",\"panel_type\":\"%s\"",getPanelString());
|
||||
length += sprintf(buffer+length, ",\"version\":\"%s\"",aqdata->version );//8157 REV MMM",
|
||||
length += sprintf(buffer+length, ",\"aqualinkd_version\":\"%s\"", AQUALINKD_VERSION ); //1.0b,
|
||||
*/
|
||||
//length += sprintf(buffer+length, ",\"logging2file\": \"%s\"",islogFileReady()?JSON_ON:JSON_OFF);
|
||||
length += sprintf(buffer+length, ",\"logfileready\": \"%s\"",islogFileReady()?JSON_ON:JSON_OFF);
|
||||
length += sprintf(buffer+length, ",\"logfilename\": \"%s\"",_aqconfig_.log_file);
|
||||
//length += sprintf(buffer+length, ",\"logfileready\": \"%s\"",islogFileReady()?JSON_ON:JSON_OFF);
|
||||
//length += sprintf(buffer+length, ",\"logfilename\": \"%s\"",_aqconfig_.log_file);
|
||||
length += sprintf(buffer+length, ",\"debugmasks\":[");
|
||||
length += logmaskjsonobject(AQUA_LOG, buffer+length);
|
||||
length += logmaskjsonobject(NET_LOG, buffer+length);
|
||||
length += logmaskjsonobject(AQRS_LOG, buffer+length);
|
||||
length += logmaskjsonobject(ALLB_LOG, buffer+length);
|
||||
length += logmaskjsonobject(ONET_LOG, buffer+length);
|
||||
length += logmaskjsonobject(IAQT_LOG, buffer+length);
|
||||
length += logmaskjsonobject(PDA_LOG, buffer+length);
|
||||
length += logmaskjsonobject(RSSA_LOG, buffer+length);
|
||||
length += logmaskjsonobject(DJAN_LOG, buffer+length);
|
||||
length += logmaskjsonobject(DPEN_LOG, buffer+length);
|
||||
length += logmaskjsonobject(RSSD_LOG, buffer+length);
|
||||
length += logmaskjsonobject(PROG_LOG, buffer+length);
|
||||
length += logmaskjsonobject(DBGT_LOG, buffer+length);
|
||||
length += logmaskjsonobject(TIMR_LOG, buffer+length);
|
||||
length += logmaskjsonobject(SCHD_LOG, buffer+length);
|
||||
length += logmaskjsonobject(RSTM_LOG, buffer+length);
|
||||
length += logmaskjsonobject(SIM_LOG, buffer+length);
|
||||
|
||||
length += logmaskjsonobject(RSSD_LOG, buffer+length); // Make sure the last one.
|
||||
// DBGT_LOG is a compile time only, so don;t include
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
length += sprintf(buffer+length, "]");
|
||||
|
@ -532,6 +657,7 @@ int build_aqualink_aqmanager_JSON(struct aqualinkdata *aqdata, char* buffer, int
|
|||
|
||||
return length;
|
||||
}
|
||||
|
||||
int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int size)
|
||||
{
|
||||
//strncpy(buffer, test_message, strlen(test_message)+1);
|
||||
|
@ -545,7 +671,8 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
|
|||
length += sprintf(buffer+length, "{\"type\": \"status\"");
|
||||
length += sprintf(buffer+length, ",\"status\":\"%s\"",getStatus(aqdata) );
|
||||
length += sprintf(buffer+length, ",\"panel_message\":\"%s\"",aqdata->last_message );
|
||||
length += sprintf(buffer+length, ",\"panel_type\":\"%s\"",getPanelString());
|
||||
length += sprintf(buffer+length, ",\"panel_type_full\":\"%s\"",getPanelString());
|
||||
length += sprintf(buffer+length, ",\"panel_type\":\"%s\"",getShortPanelString());
|
||||
//length += sprintf(buffer+length, ",\"message\":\"%s\"",aqdata->message );
|
||||
length += sprintf(buffer+length, ",\"version\":\"%s\"",aqdata->version );//8157 REV MMM",
|
||||
length += sprintf(buffer+length, ",\"aqualinkd_version\":\"%s\"", AQUALINKD_VERSION ); //1.0b,
|
||||
|
@ -559,6 +686,11 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
|
|||
length += sprintf(buffer+length, ",\"spa_htr_set_pnt\":\"%d\"",aqdata->spa_htr_set_point );//"99",
|
||||
//length += sprintf(buffer+length, ",\"freeze_protection":\"%s\"",aqdata->frz_protect_set_point );//"off",
|
||||
length += sprintf(buffer+length, ",\"frz_protect_set_pnt\":\"%d\"",aqdata->frz_protect_set_point );//"0",
|
||||
if ( (ENABLE_CHILLER || aqdata->chiller_set_point != TEMP_UNKNOWN) && aqdata->chiller_button != NULL) {
|
||||
length += sprintf(buffer+length, ",\"chiller_set_pnt\":\"%d\"",aqdata->chiller_set_point );//"0",
|
||||
if (isVBUTTON_CHILLER(aqdata->chiller_button->special_mask))
|
||||
length += sprintf(buffer+length, ",\"chiller_mode\":\"%s\"",((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode?"cool":"heat");
|
||||
}
|
||||
|
||||
if ( aqdata->air_temp == TEMP_UNKNOWN )
|
||||
length += sprintf(buffer+length, ",\"air_temp\":\" \"");
|
||||
|
@ -604,7 +736,7 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
|
|||
if ( aqdata->orp != TEMP_UNKNOWN )
|
||||
length += sprintf(buffer+length, ",\"chem_orp\":\"%d\"",aqdata->orp );
|
||||
|
||||
if ( READ_RSDEV_SWG )
|
||||
//if ( READ_RSDEV_SWG )
|
||||
length += sprintf(buffer+length, ",\"swg_fullstatus\": \"%d\"", aqdata->ar_swg_device_status);
|
||||
|
||||
length += sprintf(buffer+length, ",\"leds\":{" );
|
||||
|
@ -624,10 +756,14 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
|
|||
length += sprintf(buffer+length, ", \"%s\": \"%s\"", SWG_BOOST_TOPIC, aqdata->boost?JSON_ON:JSON_OFF);
|
||||
}
|
||||
//NSF Need to come back and read what the display states when Freeze protection is on
|
||||
if ( aqdata->frz_protect_set_point != TEMP_UNKNOWN ) {
|
||||
length += sprintf(buffer+length, ", \"%s\": \"%s\"", FREEZE_PROTECT, aqdata->frz_protect_state==ON?JSON_ON:JSON_ENABLED);
|
||||
if ( aqdata->frz_protect_set_point != TEMP_UNKNOWN || ENABLE_FREEZEPROTECT ) {
|
||||
//length += sprintf(buffer+length, ", \"%s\": \"%s\"", FREEZE_PROTECT, aqdata->frz_protect_state==ON?JSON_ON:JSON_ENABLED);
|
||||
length += sprintf(buffer+length, ", \"%s\": \"%s\"", FREEZE_PROTECT, LED2text(aqdata->frz_protect_state) );
|
||||
}
|
||||
// Add Chiller if exists
|
||||
if (aqdata->chiller_button != NULL) {
|
||||
length += sprintf(buffer+length, ", \"%s\": \"%s\"", CHILLER, LED2text(aqdata->chiller_button->led->state) );
|
||||
}
|
||||
|
||||
//length += sprintf(buffer+length, "}, \"extra\":{" );
|
||||
length += sprintf(buffer+length, "},");
|
||||
|
||||
|
@ -642,10 +778,12 @@ printf("Pump GPM %d\n",aqdata->pumps[i].gpm);
|
|||
printf("Pump GPM %d\n",aqdata->pumps[i].watts);
|
||||
printf("Pump Type %d\n",aqdata->pumps[i].pumpType);
|
||||
*/
|
||||
if (aqdata->pumps[i].pumpType != PT_UNKNOWN && (aqdata->pumps[i].rpm != TEMP_UNKNOWN || aqdata->pumps[i].gpm != TEMP_UNKNOWN || aqdata->pumps[i].watts != TEMP_UNKNOWN)) {
|
||||
length += sprintf(buffer+length, "\"Pump_%d\":{\"name\":\"%s\",\"id\":\"%s\",\"RPM\":\"%d\",\"GPM\":\"%d\",\"Watts\":\"%d\",\"Pump_Type\":\"%s\"},",
|
||||
//if (aqdata->pumps[i].pumpType != PT_UNKNOWN && (aqdata->pumps[i].rpm != TEMP_UNKNOWN || aqdata->pumps[i].gpm != TEMP_UNKNOWN || aqdata->pumps[i].watts != TEMP_UNKNOWN)) {
|
||||
if (aqdata->pumps[i].pumpType != PT_UNKNOWN ) {
|
||||
length += sprintf(buffer+length, "\"Pump_%d\":{\"name\":\"%s\",\"id\":\"%s\",\"RPM\":\"%d\",\"GPM\":\"%d\",\"Watts\":\"%d\",\"Pump_Type\":\"%s\",\"Status\":\"%d\"},",
|
||||
i+1,aqdata->pumps[i].button->label,aqdata->pumps[i].button->name,aqdata->pumps[i].rpm,aqdata->pumps[i].gpm,aqdata->pumps[i].watts,
|
||||
(aqdata->pumps[i].pumpType==VFPUMP?"vfPump":(aqdata->pumps[i].pumpType==VSPUMP?"vsPump":"ePump")));
|
||||
(aqdata->pumps[i].pumpType==VFPUMP?"vfPump":(aqdata->pumps[i].pumpType==VSPUMP?"vsPump":"ePump")),
|
||||
getPumpStatus(i, aqdata));
|
||||
}
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
|
@ -674,8 +812,45 @@ printf("Pump Type %d\n",aqdata->pumps[i].pumpType);
|
|||
length--;
|
||||
length += sprintf(buffer+length, "}");
|
||||
|
||||
length += sprintf(buffer+length, ",\"light_program_names\":{" );
|
||||
for (i=0; i < aqdata->num_lights; i++)
|
||||
{
|
||||
if (aqdata->lights[i].lightType == LC_DIMMER2) {
|
||||
length += sprintf(buffer+length, "\"%s\": \"%d%%\",", aqdata->lights[i].button->name, aqdata->lights[i].currentValue );
|
||||
} else {
|
||||
//length += sprintf(buffer+length, "\"%s\": \"%s\",", aqdata->lights[i].button->name, light_mode_name(aqdata->lights[i].lightType, aqdata->lights[i].currentValue, RSSADAPTER) );
|
||||
length += sprintf(buffer+length, "\"%s\": \"%s\",", aqdata->lights[i].button->name, get_currentlight_mode_name(aqdata->lights[i], RSSADAPTER) );
|
||||
}
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
length += sprintf(buffer+length, "}");
|
||||
|
||||
|
||||
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 (buffer[length-1] == ',')
|
||||
length--;
|
||||
length += sprintf(buffer+length, "}");
|
||||
|
||||
|
||||
length += sprintf(buffer+length, ",\"sensors\":{" );
|
||||
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 );
|
||||
}
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
length += sprintf(buffer+length, "}");
|
||||
|
||||
|
||||
length += sprintf(buffer+length, "}" );
|
||||
|
||||
|
@ -705,6 +880,83 @@ int build_aux_labels_JSON(struct aqualinkdata *aqdata, char* buffer, int size)
|
|||
|
||||
//return strlen(buffer);
|
||||
}
|
||||
/*
|
||||
const char* emulationtype2name(emulation_type type) {
|
||||
switch (type) {
|
||||
case ALLBUTTON:
|
||||
return "allbutton";
|
||||
break;
|
||||
case RSSADAPTER:
|
||||
return "allbutton";
|
||||
break;
|
||||
case ONETOUCH:
|
||||
return "onetouch";
|
||||
break;
|
||||
case IAQTOUCH:
|
||||
return "iaqualinktouch";
|
||||
break;
|
||||
case AQUAPDA:
|
||||
return "aquapda";
|
||||
break;
|
||||
case JANDY_DEVICE:
|
||||
return "jandydevice";
|
||||
break;
|
||||
case SIMULATOR:
|
||||
return "allbutton";
|
||||
break;
|
||||
default:
|
||||
return "none";
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
int build_aqualink_simulator_packet_JSON(struct aqualinkdata *aqdata, char* buffer, int size)
|
||||
{
|
||||
memset(&buffer[0], 0, size);
|
||||
int length = 0;
|
||||
int i;
|
||||
|
||||
length += sprintf(buffer+length, "{\"type\": \"simpacket\"");
|
||||
|
||||
if (aqdata->simulator_packet[PKT_DEST] >= 0x40 && aqdata->simulator_packet[PKT_DEST] <= 0x43) {
|
||||
length += sprintf(buffer+length, ",\"simtype\": \"onetouch\"");
|
||||
} else if (aqdata->simulator_packet[PKT_DEST] >= 0x08 && aqdata->simulator_packet[PKT_DEST] <= 0x0a) {
|
||||
length += sprintf(buffer+length, ",\"simtype\": \"allbutton\"");
|
||||
} else if (aqdata->simulator_packet[PKT_DEST] >= 0x30 && aqdata->simulator_packet[PKT_DEST] <= 0x33) {
|
||||
length += sprintf(buffer+length, ",\"simtype\": \"iaqtouch\"");
|
||||
} else if (aqdata->simulator_packet[PKT_DEST] >= 0x60 && aqdata->simulator_packet[PKT_DEST] <= 0x63) {
|
||||
length += sprintf(buffer+length, ",\"simtype\": \"aquapda\"");
|
||||
} else {
|
||||
length += sprintf(buffer+length, ",\"simtype\": \"unknown\"");
|
||||
}
|
||||
//if (aqdata->simulator_packet[i][])
|
||||
//length += sprintf(buffer+length, ",\"simtype\": \"onetouch\"");
|
||||
|
||||
length += sprintf(buffer+length, ",\"raw\": [");
|
||||
for (i=0; i < aqdata->simulator_packet_length; i++)
|
||||
{
|
||||
length += sprintf(buffer+length, "\"0x%02hhx\",", aqdata->simulator_packet[i]);
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
length += sprintf(buffer+length, "]");
|
||||
|
||||
length += sprintf(buffer+length, ",\"dec\": [");
|
||||
for (i=0; i < aqdata->simulator_packet_length; i++)
|
||||
{
|
||||
length += sprintf(buffer+length, "%d,", aqdata->simulator_packet[i]);
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
|
||||
length += sprintf(buffer+length, "]");
|
||||
|
||||
length += sprintf(buffer+length, "}");
|
||||
|
||||
//printf("Buffer=%d, used=%d, OUT='%s'\n",size,length,buffer);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// WS Received '{"parameter":"SPA_HTR","value":99}'
|
||||
// WS Received '{"command":"KEY_HTR_POOL"}'
|
||||
|
@ -890,4 +1142,372 @@ bool parseJSONmqttrequest(const char *str, size_t len, int *idx, int *nvalue, ch
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
int json_cfg_element_OLD(char* buffer, int size, const char *name, const void *value, cfg_value_type type, char *valid_val) {
|
||||
int result = 0;
|
||||
|
||||
char valid_values[256];
|
||||
|
||||
if (valid_val != NULL) {
|
||||
sprintf(valid_values,",\"valid values\":%s",valid_val);
|
||||
}
|
||||
|
||||
switch(type){
|
||||
case CFG_INT:
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%d\", \"type\":\"int\" %s}", name, *(int *)value, (valid_val==NULL?"":valid_values) );
|
||||
break;
|
||||
case CFG_STRING:
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%s\", \"type\":\"string\" %s}", name, (char *)value, (valid_val==NULL?"":valid_values) );
|
||||
break;
|
||||
case CFG_BOOL:
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%s\", \"type\":\"bool\" %s}", name, bool2text(*(bool *)value), (valid_val==NULL?"":valid_values));
|
||||
break;
|
||||
case CFG_HEX:
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"0x%02hhx\", \"type\":\"hex\" %s}", name, *(unsigned char *)value, (valid_val==NULL?"":valid_values) );
|
||||
break;
|
||||
}
|
||||
|
||||
if (result <= 0 || result >= size) {
|
||||
LOG(NET_LOG,LOG_ERR, "Buffer full in build_aqualink_config_JSON(), result truncated!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
//#ifdef CONFIG_EDITOR
|
||||
|
||||
int json_cfg_element(char* buffer, int size, const char *name, const void *value, cfg_value_type type, uint8_t mask, char *valid_val, uint8_t config_mask) {
|
||||
int result = 0;
|
||||
|
||||
char valid_values[256];
|
||||
char adv[128];
|
||||
int adv_size=0;
|
||||
|
||||
// We shouldn't get CFG_HIDE here. Since we can't exit with 0, simply add a space
|
||||
if (isMASKSET(config_mask, CFG_HIDE)) {
|
||||
return snprintf(buffer, size, " ");
|
||||
}
|
||||
|
||||
if (valid_val != NULL) {
|
||||
sprintf(valid_values,",\"valid values\":%s",valid_val);
|
||||
}
|
||||
|
||||
adv_size = sprintf(adv,",\"advanced\": \"%s\"", isMASKSET(config_mask, CFG_GRP_ADVANCED)?"yes":"no");
|
||||
|
||||
if (isMASKSET(config_mask, CFG_READONLY))
|
||||
adv_size += sprintf(adv+adv_size,",\"readonly\": \"yes\"");
|
||||
|
||||
if (isMASKSET(config_mask, CFG_FORCE_RESTART))
|
||||
adv_size += sprintf(adv+adv_size,",\"force_restart\": \"yes\"");
|
||||
|
||||
|
||||
switch(type){
|
||||
case CFG_INT:
|
||||
if (*(int *)value == AQ_UNKNOWN) {
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"\", \"type\":\"int\" %s %s}", name, (valid_val==NULL?"":valid_values),adv );
|
||||
} else {
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%d\", \"type\":\"int\" %s %s}", name, *(int *)value, (valid_val==NULL?"":valid_values),adv );
|
||||
}
|
||||
break;
|
||||
case CFG_STRING:
|
||||
if (*(char **)value == NULL) {
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"\", \"type\":\"string\" %s %s}", name, (valid_val==NULL?"":valid_values),adv );
|
||||
} else {
|
||||
if (isMASK_SET(config_mask, CFG_PASSWD_MASK)) {
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%s\", \"type\":\"string\", \"passwd_mask\":\"yes\" %s}", name, PASSWD_MASK_TEXT,adv);
|
||||
} else {
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%s\", \"type\":\"string\" %s %s}", name, *(char **)value, (valid_val==NULL?"":valid_values),adv );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CFG_BOOL:
|
||||
//result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%s\", \"type\":\"bool\" %s}", name, bool2text(*(bool *)value), (valid_val==NULL?"":valid_values));
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%s\", \"type\":\"bool\", \"valid values\": %s %s}", name, bool2text(*(bool *)value), CFG_V_BOOL, adv);
|
||||
break;
|
||||
case CFG_HEX:
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"0x%02hhx\", \"type\":\"hex\" %s %s}", name, *(unsigned char *)value, (valid_val==NULL?"":valid_values), adv );
|
||||
break;
|
||||
case CFG_FLOAT:
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%f\", \"type\":\"float\" %s %s}", name, *(float *)value, (valid_val==NULL?"":valid_values), adv );
|
||||
break;
|
||||
case CFG_BITMASK:
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%s\", \"type\":\"bool\", \"valid values\": %s %s}", name, (*(uint8_t *)value & mask) == mask? bool2text(true):bool2text(false) ,CFG_V_BOOL, adv );
|
||||
break;
|
||||
case CFG_SPECIAL:
|
||||
if (strncasecmp(name, CFG_N_log_level, strlen(CFG_N_log_level)) == 0) {
|
||||
//fprintf(fp, "%s=%s\n", _cfgParams[i].name, loglevel2cgn_name(_aqconfig_.log_level));
|
||||
//result = json_cfg_element(buffer+length, size-length, CFG_N_log_level, &stringptr, CFG_STRING, "[\"DEBUG\", \"INFO\", \"NOTICE\", \"WARNING\", \"ERROR\"]"));
|
||||
//stringptr = loglevel2cgn_name(_aqconfig_.log_level);
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%s\", \"type\":\"string\" %s %s}",name,loglevel2cgn_name(*(int *)value), ",\"valid values\":[\"DEBUG\", \"INFO\", \"NOTICE\", \"WARNING\", \"ERROR\"]", adv);
|
||||
} else if (strncasecmp(name, CFG_N_panel_type, strlen(CFG_N_panel_type)) == 0) {
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%s\", \"type\":\"string\" %s}",name,getShortPanelString(), adv);
|
||||
} else {
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"Something went wrong\", \"type\":\"string\"}",name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (result <= 0 || result >= size) {
|
||||
LOG(NET_LOG,LOG_ERR, "Buffer full, result truncated! size left=%d needed=%d @ element %s\n",size,result,name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
const char *pumpType2String(pump_type ptype) {
|
||||
switch (ptype) {
|
||||
case EPUMP:
|
||||
return "JANDY ePUMP";
|
||||
break;
|
||||
case VSPUMP:
|
||||
return "Pentair VF";
|
||||
break;
|
||||
case VFPUMP:
|
||||
return "Pentair VS";
|
||||
break;
|
||||
case PT_UNKNOWN:
|
||||
default:
|
||||
return "unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
int build_aqualink_config_JSON(char* buffer, int size, struct aqualinkdata *aq_data)
|
||||
{
|
||||
memset(&buffer[0], 0, size);
|
||||
int length = 0;
|
||||
int result;
|
||||
int i;
|
||||
char buf[256];
|
||||
char buf1[256];
|
||||
const char *stringptr;
|
||||
int delectCharAt = 0;
|
||||
|
||||
if ((result = snprintf(buffer+length, size-length, "{\"type\": \"config\"")) < 0 || result >= size-length) {
|
||||
length += snprintf(buffer+length, size-length, "}");
|
||||
return length;
|
||||
} else {
|
||||
length += result;
|
||||
}
|
||||
/*
|
||||
if ((result = snprintf(buffer+length, size-length, ",\"status\": \"!!!! NOT FULLY IMPLIMENTED YET !!!!\"")) < 0 || result >= size-length) {
|
||||
length += snprintf(buffer+length, size-length, "}");
|
||||
return length;
|
||||
} else {
|
||||
length += result;
|
||||
}
|
||||
*/
|
||||
if ((result = snprintf(buffer+length, size-length, ",\"max_pumps\": \"%d\",\"max_lights\": \"%d\",\"max_sensors\": \"%d\",\"max_light_programs\": \"%d\",\"max_vbuttons\": \"%d\"",
|
||||
MAX_PUMPS,MAX_LIGHTS,MAX_SENSORS,LIGHT_COLOR_OPTIONS-1, (TOTAL_BUTTONS - aq_data->virtual_button_start) )) < 0 || result >= size-length) {
|
||||
length += snprintf(buffer+length, size-length, "}");
|
||||
return length;
|
||||
} else {
|
||||
length += result;
|
||||
}
|
||||
|
||||
|
||||
//#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;
|
||||
}
|
||||
|
||||
if ((result = json_cfg_element(buffer+length, size-length, _cfgParams[i].name, _cfgParams[i].value_ptr, _cfgParams[i].value_type, _cfgParams[i].mask, _cfgParams[i].valid_values, _cfgParams[i].config_mask)) <= 0) {
|
||||
LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length);
|
||||
return length;
|
||||
} else {
|
||||
length += result;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1; i <= aq_data->num_sensors; i++)
|
||||
{
|
||||
length += sprintf(buffer+length, ",\"sensor_%.2d\":{ \"advanced\":\"yes\",",i );
|
||||
// The next json_cfg_element() call will add a , at the beginning, so save the next char index so we can delete it later.
|
||||
delectCharAt = length;
|
||||
|
||||
//fprintf(fp,"\nsensor_%.2d_path=%s\n",i+1,aqdata->sensors->path);
|
||||
//fprintf(fp,"sensor_%.2d_label=%s\n",i+1,aqdata->sensors->label);
|
||||
//fprintf(fp,"sensor_%.2d_factor=%f\n",i+1,aqdata->sensors->factor);
|
||||
sprintf(buf,"sensor_%.2d_path", i);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &aq_data->sensors[i-1].path, CFG_STRING, 0, NULL, CFG_GRP_ADVANCED)) <= 0)
|
||||
return length;
|
||||
else
|
||||
length += result;
|
||||
|
||||
sprintf(buf,"sensor_%.2d_label", i);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &aq_data->sensors[i-1].label, CFG_STRING, 0, NULL, CFG_GRP_ADVANCED)) <= 0)
|
||||
return length;
|
||||
else
|
||||
length += result;
|
||||
|
||||
sprintf(buf,"sensor_%.2d_factor", i);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &aq_data->sensors[i-1].factor, CFG_FLOAT, 0, NULL, CFG_GRP_ADVANCED)) <= 0)
|
||||
return length;
|
||||
else
|
||||
length += result;
|
||||
|
||||
length += sprintf(buffer+length, "}" );
|
||||
if (delectCharAt != 0) {
|
||||
buffer[delectCharAt] = ' ';
|
||||
delectCharAt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// add custom light modes/colors
|
||||
bool isShow;
|
||||
const char *lname;
|
||||
const char *bufptr = buf1;
|
||||
for (i=1; i < LIGHT_COLOR_OPTIONS; i++) {
|
||||
if ((lname = get_aqualinkd_light_mode_name(i, &isShow)) != NULL) {
|
||||
//fprintf(fp,"light_program_%.2d=%s%s\n",i,lname,isShow?" - show":"");
|
||||
sprintf(buf,"light_program_%.2d", i);
|
||||
sprintf(buf1,"%s%s",lname,isShow?" - show":"");
|
||||
//printf("%s %s\n",buf,buf1);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &bufptr, CFG_STRING, 0, NULL, CFG_GRP_ADVANCED)) <= 0)
|
||||
return length;
|
||||
else
|
||||
length += result;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// All buttons
|
||||
|
||||
for (i = 0; i < aq_data->total_buttons; i++)
|
||||
{
|
||||
char prefix[30];
|
||||
if (isVBUTTON(aq_data->aqbuttons[i].special_mask)) {
|
||||
sprintf(prefix,"virtual_button_%.2d",(i+1)-aq_data->virtual_button_start);
|
||||
} else {
|
||||
sprintf(prefix,"button_%.2d",i+1);
|
||||
}
|
||||
|
||||
//length += sprintf(buffer+length, ",\"%s\":{",prefix );
|
||||
length += sprintf(buffer+length, ",\"%s\":{ \"default\":\"%s\", ",prefix, aq_data->aqbuttons[i].name );
|
||||
// The next json_cfg_element() call will add a , at the beginning, so save the next char index so we can delete it later.
|
||||
delectCharAt = length;
|
||||
|
||||
sprintf(buf,"%s_label", prefix);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &aq_data->aqbuttons[i].label, CFG_STRING, 0, NULL, 0)) <= 0) {
|
||||
LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length);
|
||||
return length;
|
||||
} else
|
||||
length += result;
|
||||
|
||||
if (isVS_PUMP(aq_data->aqbuttons[i].special_mask))
|
||||
{
|
||||
if (((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->pumpIndex > 0) {
|
||||
sprintf(buf,"%s_pumpIndex", prefix);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->pumpIndex, CFG_INT, 0, NULL, 0)) <= 0) {
|
||||
LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length);
|
||||
return length;
|
||||
} else
|
||||
length += result;
|
||||
}
|
||||
|
||||
if (((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->pumpID != NUL) {
|
||||
sprintf(buf,"%s_pumpID", prefix);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->pumpID, CFG_HEX, 0, NULL, 0)) <= 0) {
|
||||
LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length);
|
||||
return length;
|
||||
} else
|
||||
length += result;
|
||||
}
|
||||
|
||||
if (((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->pumpName[0] != '\0') {
|
||||
sprintf(buf,"%s_pumpName", prefix);
|
||||
stringptr = ((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->pumpName;
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &stringptr, CFG_STRING, 0, NULL, 0)) <= 0) {
|
||||
LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length);
|
||||
return length;
|
||||
} else
|
||||
length += result;
|
||||
}
|
||||
|
||||
if (((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->pumpType != PT_UNKNOWN) {
|
||||
sprintf(buf,"%s_pumpType", prefix);
|
||||
stringptr = pumpType2String(((pump_detail *)aq_data->aqbuttons[i].special_mask_ptr)->pumpType);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &stringptr, CFG_STRING, 0, "[\"\", \"JANDY ePUMP\",\"Pentair VS\",\"Pentair VF\"]", 0) ) <= 0) {
|
||||
LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length);
|
||||
return length;
|
||||
} else
|
||||
length += result;
|
||||
}
|
||||
} else if (isPLIGHT(aq_data->aqbuttons[i].special_mask)) {
|
||||
if (((clight_detail *)aq_data->aqbuttons[i].special_mask_ptr)->lightType > 0) {
|
||||
sprintf(buf,"%s_lightMode", prefix);
|
||||
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);
|
||||
return length;
|
||||
} else
|
||||
length += result;
|
||||
}
|
||||
} else if ( (isVBUTTON(aq_data->aqbuttons[i].special_mask) && aq_data->aqbuttons[i].rssd_code >= IAQ_ONETOUCH_1 && aq_data->aqbuttons[i].rssd_code <= IAQ_ONETOUCH_6 ) ) {
|
||||
sprintf(buf,"%s_onetouchID", prefix);
|
||||
int oID = (aq_data->aqbuttons[i].rssd_code - 15);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &oID, CFG_INT, 0, "[\"\", \"1\",\"2\",\"3\",\"4\",\"5\",\"6\"]", 0)) <= 0) {
|
||||
LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length);
|
||||
return length;
|
||||
} else
|
||||
length += result;
|
||||
} else if ( isVBUTTON_ALTLABEL(aq_data->aqbuttons[i].special_mask)) {
|
||||
sprintf(buf,"%s_altlabel", prefix);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &((vbutton_detail *)aq_data->aqbuttons[i].special_mask_ptr)->altlabel, CFG_STRING, 0, NULL, 0)) <= 0) {
|
||||
LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length);
|
||||
return length;
|
||||
} else
|
||||
length += result;
|
||||
}
|
||||
|
||||
length += sprintf(buffer+length, "}" );
|
||||
if (delectCharAt != 0) {
|
||||
buffer[delectCharAt] = ' ';
|
||||
delectCharAt = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Need to add one last element, can be crap. Makes the HTML/JS easier in the loop
|
||||
if ((result = snprintf(buffer+length, size-length, ",\"version\": \"1.0\"")) < 0 || result >= size-length) {
|
||||
length += snprintf(buffer+length, size-length, "}");
|
||||
return length;
|
||||
} else {
|
||||
length += result;
|
||||
}
|
||||
|
||||
|
||||
if ((result = snprintf(buffer+length, size-length, "}")) < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
length += result;
|
||||
}
|
||||
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
//#endif
|
|
@ -7,8 +7,11 @@
|
|||
//#define JSON_BUFFER_SIZE 4000
|
||||
//#define JSON_STATUS_SIZE 1024
|
||||
#define JSON_LABEL_SIZE 600
|
||||
#define JSON_BUFFER_SIZE 5120
|
||||
//#define JSON_BUFFER_SIZE 8192
|
||||
//#define JSON_BUFFER_SIZE 10240
|
||||
#define JSON_BUFFER_SIZE 12288
|
||||
#define JSON_STATUS_SIZE 2048
|
||||
#define JSON_SIMULATOR_SIZE 2048
|
||||
|
||||
#define JSON_MQTT_MSG_SIZE 100
|
||||
|
||||
|
@ -48,15 +51,19 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
|
|||
int build_aux_labels_JSON(struct aqualinkdata *aqdata, char* buffer, int size);
|
||||
bool parseJSONwebrequest(char *buffer, struct JSONwebrequest *request);
|
||||
bool parseJSONrequest(char *buffer, struct JSONkvptr *request);
|
||||
int build_logmsg_JSON(char *dest, const char *src, int dest_len, int src_len);
|
||||
int build_logmsg_JSON(char *dest, int loglevel, const char *src, int dest_len, int src_len);
|
||||
int build_mqtt_status_JSON(char* buffer, int size, int idx, int nvalue, float setpoint/*char *svalue*/);
|
||||
bool parseJSONmqttrequest(const char *str, size_t len, int *idx, int *nvalue, char *svalue);
|
||||
int build_aqualink_error_status_JSON(char* buffer, int size, char *msg);
|
||||
int build_aqualink_error_status_JSON(char* buffer, int size, const char *msg);
|
||||
int build_mqtt_status_message_JSON(char* buffer, int size, int idx, int nvalue, char *svalue);
|
||||
int build_aqualink_aqmanager_JSON(struct aqualinkdata *aqdata, char* buffer, int size);
|
||||
//int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char* buffer, int size, bool homekit);
|
||||
//int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch1, int programable_switch2, char* buffer, int size, bool homekit);
|
||||
int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool homekit);
|
||||
int build_aqualink_simulator_packet_JSON(struct aqualinkdata *aqdata, char* buffer, int size);
|
||||
int build_aqualink_config_JSON(char* buffer, int size, struct aqualinkdata *aq_data);
|
||||
|
||||
char *LED2text(aqledstate state);
|
||||
|
||||
#endif /* JSON_MESSAGES_H_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -28,8 +28,16 @@ bool start_net_services(struct aqualinkdata *aqdata);
|
|||
void stop_net_services();
|
||||
time_t poll_net_services(int timeout_ms);
|
||||
void broadcast_aqualinkstate();
|
||||
void broadcast_aqualinkstate_error(char *msg);
|
||||
void broadcast_log(char *msg);
|
||||
void broadcast_aqualinkstate_error(const char *msg);
|
||||
void broadcast_simulator_message();
|
||||
|
||||
|
||||
|
||||
// NSF Need to find a better way, this is not thread safe, so don;t like exposting it.
|
||||
//void send_mqtt(struct mg_connection *nc, const char *toppic, const char *message);
|
||||
|
||||
// superseded with systemd/sd-journal
|
||||
//void broadcast_log(char *msg);
|
||||
//#endif
|
||||
|
||||
|
|
@ -40,30 +40,32 @@ static int _ot_hlightcharindexstart = -1;
|
|||
static int _ot_hlightcharindexstop = -1;
|
||||
static char _menu[ONETOUCH_LINES][AQ_MSGLEN+1];
|
||||
static struct ot_macro _macros[3];
|
||||
bool _panel_version_P2 = false; // Older panels REV 0.1 and 0.2
|
||||
|
||||
|
||||
void set_macro_status();
|
||||
void pump_update(struct aqualinkdata *aq_data, int updated);
|
||||
bool log_heater_setpoints(struct aqualinkdata *aq_data);
|
||||
|
||||
#ifdef AQ_RS16
|
||||
|
||||
void rs16led_update(struct aqualinkdata *aq_data, int updated);
|
||||
#endif
|
||||
|
||||
|
||||
void print_onetouch_menu()
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < ONETOUCH_LINES; i++) {
|
||||
//printf("PDA Line %d = %s\n",i,_menu[i]);
|
||||
LOG(ONET_LOG,LOG_INFO, "OneTouch Menu Line %d = %s\n",i,_menu[i]);
|
||||
LOG(ONET_LOG,LOG_INFO, "Menu Line %d = %s\n",i,_menu[i]);
|
||||
}
|
||||
|
||||
if (_ot_hlightcharindexstart > -1) {
|
||||
LOG(ONET_LOG,LOG_INFO, "OneTouch Menu highlighted line = %d, '%s' hligh-char(s) '%.*s'\n",
|
||||
LOG(ONET_LOG,LOG_INFO, "Menu highlighted line = %d, '%s' hligh-char(s) '%.*s'\n",
|
||||
_ot_hlightindex,_menu[_ot_hlightindex],
|
||||
(_ot_hlightcharindexstop - _ot_hlightcharindexstart + 1),
|
||||
&_menu[_ot_hlightindex][_ot_hlightcharindexstart]);
|
||||
} else if (_ot_hlightindex > -1) {
|
||||
LOG(ONET_LOG,LOG_INFO, "OneTouch Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
|
||||
LOG(ONET_LOG,LOG_INFO, "Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,7 +180,7 @@ bool process_onetouch_menu_packet(struct aqualinkdata *aq_data, unsigned char* p
|
|||
_ot_hlightcharindexstart = -1;
|
||||
_ot_hlightcharindexstart = -1;
|
||||
}
|
||||
LOG(ONET_LOG,LOG_DEBUG, "OneTouch Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
|
||||
LOG(ONET_LOG,LOG_DEBUG, "Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
|
||||
//if (getLogLevel() >= LOG_DEBUG){print_onetouch_menu();}
|
||||
break;
|
||||
case CMD_PDA_HIGHLIGHTCHARS:
|
||||
|
@ -193,7 +195,7 @@ bool process_onetouch_menu_packet(struct aqualinkdata *aq_data, unsigned char* p
|
|||
_ot_hlightcharindexstart = -1;
|
||||
_ot_hlightcharindexstart = -1;
|
||||
}
|
||||
LOG(ONET_LOG,LOG_DEBUG, "OneTouch Menu highlighted line = %d, '%s' chars '%.*s'\n",
|
||||
LOG(ONET_LOG,LOG_DEBUG, "Menu highlighted line = %d, '%s' chars '%.*s'\n",
|
||||
_ot_hlightindex,
|
||||
_menu[_ot_hlightindex],
|
||||
(_ot_hlightcharindexstop - _ot_hlightcharindexstart) + 1,
|
||||
|
@ -255,7 +257,7 @@ bool log_heater_setpoints(struct aqualinkdata *aq_data)
|
|||
if (isSINGLE_DEV_PANEL != true)
|
||||
{
|
||||
changePanelToMode_Only();
|
||||
LOG(AQRS_LOG,LOG_ERR, "AqualinkD set to 'Combo Pool & Spa' but detected 'Only Pool OR Spa' panel, please change config\n");
|
||||
LOG(ONET_LOG,LOG_ERR, "AqualinkD set to 'Combo Pool & Spa' but detected 'Only Pool OR Spa' panel, please change config\n");
|
||||
}
|
||||
}
|
||||
if (rsm_strcmp(_menu[3], "Temp2") == 0 )
|
||||
|
@ -271,12 +273,41 @@ bool log_heater_setpoints(struct aqualinkdata *aq_data)
|
|||
return rtn;
|
||||
}
|
||||
|
||||
/*
|
||||
One Touch: OneTouch Menu Line 0 =
|
||||
One Touch: OneTouch Menu Line 1 =
|
||||
One Touch: OneTouch Menu Line 2 =
|
||||
One Touch: OneTouch Menu Line 3 =
|
||||
One Touch: OneTouch Menu Line 4 = MODEL E0260801
|
||||
One Touch: OneTouch Menu Line 5 = RS-8 Combo
|
||||
One Touch: OneTouch Menu Line 6 =
|
||||
One Touch: OneTouch Menu Line 7 = REV. O.2
|
||||
One Touch: OneTouch Menu Line 8 =
|
||||
One Touch: OneTouch Menu Line 9 =
|
||||
One Touch: OneTouch Menu Line 10 =
|
||||
One Touch: OneTouch Menu Line 11 =
|
||||
*/
|
||||
bool log_panelversion(struct aqualinkdata *aq_data)
|
||||
{
|
||||
char *end;
|
||||
static bool revTest=false;
|
||||
|
||||
setPanelInformationFromPanelMsg(aq_data, _menu[4], PANEL_CPU, ONETOUCH);
|
||||
setPanelInformationFromPanelMsg(aq_data, _menu[5], PANEL_STRING, ONETOUCH);
|
||||
setPanelInformationFromPanelMsg(aq_data, _menu[7], PANEL_REV, ONETOUCH);
|
||||
|
||||
// It's already been set
|
||||
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);
|
||||
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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -290,6 +321,17 @@ bool log_panelversion(struct aqualinkdata *aq_data)
|
|||
end = aq_data->version + strlen(aq_data->version) - 1;
|
||||
while(end > aq_data->version && isspace(*end)) end--;
|
||||
|
||||
rsm_get_revision(aq_data->revision, _menu[7], AQ_MSGLEN);
|
||||
LOG(ONET_LOG,LOG_NOTICE, "Control Panel version %s\n", aq_data->version);
|
||||
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;
|
||||
}
|
||||
|
||||
// Probably should check the panel size here as well.
|
||||
// One Touch: OneTouch Menu Line 5 = RS-16 Combo
|
||||
// Write new null terminator
|
||||
*(end+1) = 0;
|
||||
|
||||
|
@ -313,119 +355,308 @@ bool log_freeze_setpoints(struct aqualinkdata *aq_data)
|
|||
return rtn;
|
||||
}
|
||||
|
||||
|
||||
bool log_qeuiptment_status(struct aqualinkdata *aq_data)
|
||||
/*
|
||||
bool get_pumpinfo_from_menu_OLD(struct aqualinkdata *aq_data, int menuLineIdx)
|
||||
{
|
||||
int rpm = 0;
|
||||
int watts = 0;
|
||||
int gpm = 0;
|
||||
panel_vsp_status panelStatus = PS_OK;
|
||||
int pump_index = rsm_atoi(&_menu[menuLineIdx][14]);
|
||||
if (pump_index <= 0)
|
||||
pump_index = rsm_atoi(&_menu[menuLineIdx][12]); // Pump inxed is in different position on line ` ePump AC 4`
|
||||
|
||||
// RPM displays differently depending on 3 or 4 digit rpm.
|
||||
if (rsm_strcmp(_menu[menuLineIdx + 1], "RPM:") == 0)
|
||||
{
|
||||
rpm = rsm_atoi(&_menu[menuLineIdx + 1][10]);
|
||||
if (rsm_strcmp(_menu[menuLineIdx + 2], "Watts:") == 0){
|
||||
watts = rsm_atoi(&_menu[menuLineIdx + 2][10]);
|
||||
}
|
||||
if (rsm_strcmp(_menu[menuLineIdx + 3], "GPM:") == 0){
|
||||
gpm = rsm_atoi(&_menu[menuLineIdx + 3][10]);
|
||||
}
|
||||
}
|
||||
else if (rsm_strcmp(_menu[menuLineIdx+1], "*** Priming ***") == 0){
|
||||
//rpm = PUMP_PRIMING; // NSF need to remove future
|
||||
panelStatus = PS_PRIMING;
|
||||
}
|
||||
else if (rsm_strcmp(_menu[menuLineIdx+1], "(Offline)") == 0){
|
||||
//rpm = PUMP_OFFLINE; // NSF need to remove future
|
||||
panelStatus = PS_OFFLINE;
|
||||
}
|
||||
else if (rsm_strcmp(_menu[menuLineIdx+1], "(Priming Error)") == 0){
|
||||
//rpm = PUMP_ERROR; // NSF need to remove future
|
||||
panelStatus = PS_ERROR;
|
||||
}
|
||||
|
||||
LOG(ONET_LOG, LOG_DEBUG, "Found Pump '%s', Index %d, RPM %d, Watts %d, GPM %d\n", _menu[menuLineIdx], pump_index, rpm, watts, gpm);
|
||||
|
||||
for (int i = 0; i < aq_data->num_pumps; i++)
|
||||
{
|
||||
if (aq_data->pumps[i].pumpIndex == pump_index)
|
||||
{
|
||||
// printf("**** FOUND PUMP %d at index %d *****\n",pump_index,i);
|
||||
// aq_data->pumps[i].updated = true;
|
||||
pump_update(aq_data, i);
|
||||
aq_data->pumps[i].rpm = rpm;
|
||||
aq_data->pumps[i].watts = watts;
|
||||
aq_data->pumps[i].gpm = gpm;
|
||||
aq_data->pumps[i].pStatus = panelStatus;
|
||||
// LOG(ONET_LOG,LOG_INFO, "Matched OneTouch Pump to Index %d, RPM %d, Watts %d, GPM %d\n",i,rpm,watts,gpm);
|
||||
LOG(ONET_LOG, LOG_INFO, "Matched Pump to '%s', Index %d, RPM %d, Watts %d, GPM %d\n", aq_data->pumps[i].button->name, i, rpm, watts, gpm);
|
||||
if (aq_data->pumps[i].pumpType == PT_UNKNOWN)
|
||||
{
|
||||
if (rsm_strcmp(_menu[2], "Intelliflo VS") == 0)
|
||||
aq_data->pumps[i].pumpType = VSPUMP;
|
||||
else if (rsm_strcmp(_menu[2], "Intelliflo VF") == 0)
|
||||
aq_data->pumps[i].pumpType = VFPUMP;
|
||||
else if (rsm_strcmp(_menu[2], "Jandy ePUMP") == 0 ||
|
||||
rsm_strcmp(_menu[2], "ePump AC") == 0)
|
||||
aq_data->pumps[i].pumpType = EPUMP;
|
||||
|
||||
LOG(ONET_LOG, LOG_INFO, "Pump index %d set PumpType to %d\n", i, aq_data->pumps[i].pumpType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
LOG(ONET_LOG, LOG_WARNING, "Did not find AqualinkD config for Pump '%s'\n",_menu[menuLineIdx]);
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
bool get_pumpinfo_from_menu(struct aqualinkdata *aq_data, int menuLineIdx, int pump_number)
|
||||
{
|
||||
int rpm = 0;
|
||||
int watts = 0;
|
||||
int gpm = 0;
|
||||
panel_vsp_status pStatus = PS_OK;
|
||||
char *cidx = NULL;
|
||||
|
||||
// valid controlpanel pump numbers are 1,2,3,4
|
||||
if (pump_number < 1 || pump_number > MAX_PUMPS) {
|
||||
LOG(ONET_LOG, LOG_WARNING, "Pump number %d for pump '%s' is invalid, ignoring!\n",pump_number,_menu[menuLineIdx]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( (cidx = rsm_charafterstr(_menu[menuLineIdx + 1], "RPM", AQ_MSGLEN)) != NULL ){
|
||||
rpm = rsm_atoi(cidx);
|
||||
// Assuming Watts is always next line and GPM (if available) line after
|
||||
if ( (cidx = rsm_charafterstr(_menu[menuLineIdx + 2], "Watts", AQ_MSGLEN)) != NULL ){
|
||||
watts = rsm_atoi(cidx);
|
||||
}
|
||||
if ( (cidx = rsm_charafterstr(_menu[menuLineIdx + 3], "GPM", AQ_MSGLEN)) != NULL ){
|
||||
gpm = rsm_atoi(cidx);
|
||||
}
|
||||
}
|
||||
else if (rsm_strcmp(_menu[menuLineIdx + 1], "*** Priming ***") == 0){
|
||||
pStatus = PS_PRIMING;
|
||||
}
|
||||
else if (rsm_strcmp(_menu[menuLineIdx + 1], "(Offline)") == 0){
|
||||
pStatus = PS_OFFLINE;
|
||||
}
|
||||
else if (rsm_strcmp(_menu[menuLineIdx + 1], "(Priming Error)") == 0){
|
||||
pStatus = PS_ERROR;
|
||||
}
|
||||
|
||||
if (rpm==0 && watts==0 && rpm==0) {
|
||||
// Didn't get any info, so return.
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(ONET_LOG, LOG_DEBUG, "Found Pump information '%s', RPM %d, Watts %d, GPM %d\n", _menu[menuLineIdx], rpm, watts, gpm);
|
||||
|
||||
for (int i=0; i < aq_data->num_pumps; i++) {
|
||||
if (aq_data->pumps[i].pumpIndex == pump_number) {
|
||||
LOG(ONET_LOG,LOG_INFO, "Pump label: %s Index: %d, Number: %d, RPM: %d, Watts: %d, GPM: %d\n",aq_data->pumps[i].button->name, i ,pump_number,rpm,watts,gpm);
|
||||
pump_update(aq_data, i);
|
||||
aq_data->pumps[i].rpm = rpm;
|
||||
aq_data->pumps[i].watts = watts;
|
||||
aq_data->pumps[i].gpm = gpm;
|
||||
aq_data->pumps[i].pStatus = pStatus;
|
||||
if (aq_data->pumps[i].pumpType == PT_UNKNOWN){
|
||||
if (rsm_strcmp(_menu[menuLineIdx],"Intelliflo VS") == 0)
|
||||
aq_data->pumps[i].pumpType = VSPUMP;
|
||||
else if (rsm_strcmp(_menu[menuLineIdx],"Intelliflo VF") == 0)
|
||||
aq_data->pumps[i].pumpType = VFPUMP;
|
||||
else if (rsm_strcmp(_menu[menuLineIdx],"Jandy ePUMP") == 0 ||
|
||||
rsm_strcmp(_menu[menuLineIdx],"ePump AC") == 0)
|
||||
aq_data->pumps[i].pumpType = EPUMP;
|
||||
|
||||
LOG(ONET_LOG, LOG_INFO, "Pump index %d set PumpType to %d\n", i, aq_data->pumps[i].pumpType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
LOG(ONET_LOG,LOG_WARNING, "Could not find config for Pump %s, Number %d, RPM %d, Watts %d, GPM %d\n",_menu[menuLineIdx],pump_number,rpm,watts,gpm);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Info: OneTouch Menu Line 1 =
|
||||
Info: OneTouch Menu Line 2 = Chemlink 1
|
||||
Info: OneTouch Menu Line 3 = ORP 750/PH 7.0
|
||||
*/
|
||||
bool get_chemlinkinfo_from_menu(struct aqualinkdata *aq_data, int menuLineIdx)
|
||||
{
|
||||
if (rsm_strcmp(_menu[menuLineIdx + 1], "ORP") == 0)
|
||||
{
|
||||
int orp = atoi(&_menu[menuLineIdx + 1][4]);
|
||||
char *indx = strchr(_menu[menuLineIdx + 1], '/');
|
||||
float ph = atof(indx + 3);
|
||||
LOG(ONET_LOG, LOG_INFO, "Cemlink ORP = %d PH = %f\n", orp, ph);
|
||||
if (aq_data->ph != ph || aq_data->orp != orp)
|
||||
{
|
||||
aq_data->ph = ph;
|
||||
aq_data->orp = orp;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
LOG(ONET_LOG, LOG_WARNING, "Did not understand Chemlink message '%s'\n",_menu[menuLineIdx + 1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Info: OneTouch Menu Line 2 = AQUAPURE 60%
|
||||
Info: OneTouch Menu Line 3 = Salt 7600 PPM */
|
||||
bool get_aquapureinfo_from_menu(struct aqualinkdata *aq_data, int menuLineIdx)
|
||||
{
|
||||
int i;
|
||||
bool rtn = false;
|
||||
|
||||
#ifdef READ_SWG_FROM_EXTENDED_ID
|
||||
|
||||
int swgp = atoi(&_menu[menuLineIdx][10]);
|
||||
if (aq_data->swg_percent != swgp)
|
||||
{
|
||||
changeSWGpercent(aq_data, swgp);
|
||||
rtn = true;
|
||||
}
|
||||
|
||||
if (rsm_strcmp(_menu[menuLineIdx+1], "Salt") == 0)
|
||||
{
|
||||
int ppm = atoi(&_menu[menuLineIdx+1][6]);
|
||||
if (aq_data->swg_ppm != ppm)
|
||||
{
|
||||
aq_data->swg_ppm = ppm;
|
||||
rtn = true;
|
||||
}
|
||||
LOG(ONET_LOG, LOG_INFO, "Aquapure SWG %d%, %d PPM\n", swgp, ppm);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
|
||||
bool get_RS16buttoninfo_from_menu(struct aqualinkdata *aq_data, int menuLineIdx)
|
||||
{
|
||||
for (int i = aq_data->rs16_vbutton_start; i <= aq_data->rs16_vbutton_end; i++)
|
||||
{
|
||||
if (rsm_strcmp(_menu[menuLineIdx], aq_data->aqbuttons[i].label) == 0)
|
||||
{
|
||||
// Matched must be on.
|
||||
LOG(ONET_LOG, LOG_INFO, "RS16 equiptment status '%s' matched '%s'\n", _menu[menuLineIdx], aq_data->aqbuttons[i].label);
|
||||
rs16led_update(aq_data, i);
|
||||
aq_data->aqbuttons[i].led->state = ON;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
For older Panel versions 0.1 and 0.2
|
||||
These display information all on one page, kind'a limped together like PDA
|
||||
OneTouch Menu Line 0 = EQUIPMENT STATUS
|
||||
OneTouch Menu Line 1 =
|
||||
OneTouch Menu Line 2 = AquaPure 35%
|
||||
OneTouch Menu Line 3 = SALT 3200 PPM
|
||||
OneTouch Menu Line 4 = FILTER PUMP
|
||||
OneTouch Menu Line 5 = Intelliflo VS 1
|
||||
OneTouch Menu Line 6 = RPM: 1750
|
||||
OneTouch Menu Line 7 = WATTS: 330
|
||||
OneTouch Menu Line 8 =
|
||||
OneTouch Menu Line 9 =
|
||||
OneTouch Menu Line 10 =
|
||||
OneTouch Menu Line 11 =
|
||||
*/
|
||||
bool log_qeuiptment_status_VP2(struct aqualinkdata *aq_data)
|
||||
{
|
||||
bool rtn = false;
|
||||
char *cidx = NULL;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < ONETOUCH_LINES; i++)
|
||||
{
|
||||
/*
|
||||
if (rsm_strcmp(_menu[i], "Intelliflo VS") == 0 ||
|
||||
rsm_strcmp(_menu[i], "Intelliflo VF") == 0 ||
|
||||
rsm_strcmp(_menu[i], "Jandy ePUMP") == 0 ||
|
||||
rsm_strcmp(_menu[i], "ePump AC") == 0)
|
||||
{
|
||||
rtn = get_pumpinfo_from_menu(aq_data, i);
|
||||
}*/
|
||||
if ( (cidx = rsm_charafterstr(_menu[i], "Intelliflo VS", AQ_MSGLEN)) != NULL ||
|
||||
(cidx = rsm_charafterstr(_menu[i], "Intelliflo VF", AQ_MSGLEN)) != NULL ||
|
||||
(cidx = rsm_charafterstr(_menu[i], "Jandy ePUMP", AQ_MSGLEN)) != NULL ||
|
||||
(cidx = rsm_charafterstr(_menu[i], "ePump AC", AQ_MSGLEN)) != NULL)
|
||||
{
|
||||
rtn = get_pumpinfo_from_menu(aq_data, i, rsm_atoi(cidx));
|
||||
} else if (rsm_strcmp(_menu[2],"AQUAPURE") == 0) {
|
||||
rtn = get_aquapureinfo_from_menu(aq_data, i);
|
||||
} else if (rsm_strcmp(_menu[i],"Chemlink") == 0) {
|
||||
rtn = get_chemlinkinfo_from_menu(aq_data, i);
|
||||
|
||||
} else if (PANEL_SIZE() >= 16 ) {
|
||||
// Loop over RS 16 buttons.
|
||||
get_RS16buttoninfo_from_menu(aq_data, i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
/*
|
||||
Newer panels have a page per device and specific lines with information
|
||||
*/
|
||||
bool log_qeuiptment_status(struct aqualinkdata *aq_data)
|
||||
{
|
||||
if (_panel_version_P2)
|
||||
return log_qeuiptment_status_VP2(aq_data);
|
||||
|
||||
bool rtn = false;
|
||||
char *cidx = NULL;
|
||||
/*
|
||||
if (rsm_strcmp(_menu[2],"Intelliflo VS") == 0 ||
|
||||
rsm_strcmp(_menu[2],"Intelliflo VF") == 0 ||
|
||||
rsm_strcmp(_menu[2],"Jandy ePUMP") == 0 ||
|
||||
rsm_strcmp(_menu[2],"ePump AC") == 0) {
|
||||
rtn = true;
|
||||
int rpm = 0;
|
||||
int watts = 0;
|
||||
int gpm = 0;
|
||||
int pump_index = rsm_atoi(&_menu[2][14]);
|
||||
if (pump_index <= 0)
|
||||
pump_index = rsm_atoi(&_menu[2][12]); // Pump inxed is in different position on line ` ePump AC 4`
|
||||
// RPM displays differently depending on 3 or 4 digit rpm.
|
||||
if (rsm_strcmp(_menu[3],"RPM:") == 0){
|
||||
rpm = rsm_atoi(&_menu[3][10]);
|
||||
if (rsm_strcmp(_menu[4],"Watts:") == 0) {
|
||||
watts = rsm_atoi(&_menu[4][10]);
|
||||
}
|
||||
if (rsm_strcmp(_menu[5],"GPM:") == 0) {
|
||||
gpm = rsm_atoi(&_menu[5][10]);
|
||||
}
|
||||
} else if (rsm_strcmp(_menu[3],"*** Priming ***") == 0){
|
||||
rpm = PUMP_PRIMING;
|
||||
} else if (rsm_strcmp(_menu[3],"(Offline)") == 0){
|
||||
rpm = PUMP_OFFLINE;
|
||||
} else if (rsm_strcmp(_menu[3],"(Priming Error)") == 0){
|
||||
rpm = PUMP_ERROR;
|
||||
}
|
||||
|
||||
LOG(ONET_LOG,LOG_INFO, "OneTouch Pump %s, Index %d, RPM %d, Watts %d, GPM %d\n",_menu[2],pump_index,rpm,watts,gpm);
|
||||
|
||||
for (i=0; i < aq_data->num_pumps; i++) {
|
||||
if (aq_data->pumps[i].pumpIndex == pump_index) {
|
||||
//printf("**** FOUND PUMP %d at index %d *****\n",pump_index,i);
|
||||
//aq_data->pumps[i].updated = true;
|
||||
pump_update(aq_data, i);
|
||||
aq_data->pumps[i].rpm = rpm;
|
||||
aq_data->pumps[i].watts = watts;
|
||||
aq_data->pumps[i].gpm = gpm;
|
||||
if (aq_data->pumps[i].pumpType == PT_UNKNOWN){
|
||||
if (rsm_strcmp(_menu[2],"Intelliflo VS") == 0)
|
||||
aq_data->pumps[i].pumpType = VSPUMP;
|
||||
else if (rsm_strcmp(_menu[2],"Intelliflo VF") == 0)
|
||||
aq_data->pumps[i].pumpType = VFPUMP;
|
||||
else if (rsm_strcmp(_menu[2],"Jandy ePUMP") == 0 ||
|
||||
rsm_strcmp(_menu[2],"ePump AC") == 0)
|
||||
aq_data->pumps[i].pumpType = EPUMP;
|
||||
}
|
||||
//printf ("Set Pump Type to %d\n",aq_data->pumps[i].pumpType);
|
||||
}
|
||||
}
|
||||
#ifdef READ_SWG_FROM_EXTENDED_ID
|
||||
rtn = get_pumpinfo_from_menu(aq_data, 2);
|
||||
} */
|
||||
if ( (cidx = rsm_charafterstr(_menu[2], "Intelliflo VS", AQ_MSGLEN)) != NULL ||
|
||||
(cidx = rsm_charafterstr(_menu[2], "Intelliflo VF", AQ_MSGLEN)) != NULL ||
|
||||
(cidx = rsm_charafterstr(_menu[2], "Jandy ePUMP", AQ_MSGLEN)) != NULL ||
|
||||
(cidx = rsm_charafterstr(_menu[2], "ePump AC", AQ_MSGLEN)) != NULL)
|
||||
{
|
||||
rtn = get_pumpinfo_from_menu(aq_data, 2, rsm_atoi(cidx));
|
||||
} else if (rsm_strcmp(_menu[2],"AQUAPURE") == 0) {
|
||||
/* Info: OneTouch Menu Line 0 = Equipment Status
|
||||
Info: OneTouch Menu Line 1 =
|
||||
Info: OneTouch Menu Line 2 = AQUAPURE 60%
|
||||
Info: OneTouch Menu Line 3 = Salt 7600 PPM */
|
||||
int swgp = atoi(&_menu[2][10]);
|
||||
if ( aq_data->swg_percent != swgp ) {
|
||||
//aq_data->swg_percent = swgp;
|
||||
if (changeSWGpercent(aq_data, swgp))
|
||||
LOG(ONET_LOG,LOG_INFO, "OneTouch SWG = %d\n",swgp);
|
||||
rtn = true;
|
||||
}
|
||||
|
||||
if (rsm_strcmp(_menu[3],"Salt") == 0) {
|
||||
int ppm = atoi(&_menu[3][6]);
|
||||
if ( aq_data->swg_ppm != ppm ) {
|
||||
aq_data->swg_ppm = ppm;
|
||||
rtn = true;
|
||||
}
|
||||
LOG(ONET_LOG,LOG_INFO, "OneTouch PPM = %d\n",ppm);
|
||||
}
|
||||
#endif
|
||||
rtn = get_aquapureinfo_from_menu(aq_data, 2);
|
||||
} else if (rsm_strcmp(_menu[2],"Chemlink") == 0) {
|
||||
/* Info: OneTouch Menu Line 0 = Equipment Status
|
||||
Info: OneTouch Menu Line 1 =
|
||||
Info: OneTouch Menu Line 2 = Chemlink 1
|
||||
Info: OneTouch Menu Line 3 = ORP 750/PH 7.0 */
|
||||
if (rsm_strcmp(_menu[3],"ORP") == 0) {
|
||||
int orp = atoi(&_menu[3][4]);
|
||||
char *indx = strchr(_menu[3], '/');
|
||||
float ph = atof(indx+3);
|
||||
if (aq_data->ph != ph || aq_data->orp != orp) {
|
||||
aq_data->ph = ph;
|
||||
aq_data->orp = orp;
|
||||
return true;
|
||||
}
|
||||
LOG(ONET_LOG,LOG_INFO, "OneTouch Cemlink ORP = %d PH = %f\n",orp,ph);
|
||||
}
|
||||
rtn = get_chemlinkinfo_from_menu(aq_data, 2);
|
||||
}
|
||||
|
||||
#ifdef AQ_RS16
|
||||
else if (PANEL_SIZE() >= 16 ) { // This fails on RS4, comeback and find out why. // Run over devices that have no status LED's on RS12&16 panels.
|
||||
//else if ( 16 <= (int)PANEL_SIZE ) {
|
||||
int j;
|
||||
int i;
|
||||
for (i=2; i <= ONETOUCH_LINES; i++) {
|
||||
for (j = aq_data->rs16_vbutton_start; j <= aq_data->rs16_vbutton_end; j++) {
|
||||
if ( rsm_strcmp(_menu[i], aq_data->aqbuttons[j].label) == 0 ) {
|
||||
//Matched must be on.
|
||||
LOG(ONET_LOG,LOG_DEBUG, "OneTouch equiptment status '%s' matched '%s'\n",_menu[i],aq_data->aqbuttons[j].label);
|
||||
rs16led_update(aq_data, j);
|
||||
aq_data->aqbuttons[j].led->state = ON;
|
||||
}
|
||||
}
|
||||
get_RS16buttoninfo_from_menu(aq_data, i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -456,7 +687,7 @@ ot_menu_type get_onetouch_menu_type()
|
|||
return OTM_BOOST;
|
||||
else if (rsm_strcmp(_menu[0],"Set AQUAPURE") == 0)
|
||||
return OTM_SET_AQUAPURE;
|
||||
else if (rsm_strcmp(_menu[7],"REV ") == 0) // NSF Need a better check.
|
||||
else if (rsm_strcmp(_menu[7],"REV") == 0) // NSF Need a better check.
|
||||
return OTM_VERSION;
|
||||
|
||||
return OTM_UNKNOWN;
|
||||
|
@ -473,6 +704,7 @@ void pump_update(struct aqualinkdata *aq_data, int updated) {
|
|||
aq_data->pumps[i].rpm = PUMP_OFF_RPM;
|
||||
aq_data->pumps[i].gpm = PUMP_OFF_GPM;
|
||||
aq_data->pumps[i].watts = PUMP_OFF_WAT;
|
||||
aq_data->pumps[i].pStatus = PS_OFF;
|
||||
}
|
||||
}
|
||||
updates = '\0';
|
||||
|
@ -481,7 +713,7 @@ void pump_update(struct aqualinkdata *aq_data, int updated) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef AQ_RS16
|
||||
|
||||
void rs16led_update(struct aqualinkdata *aq_data, int updated) {
|
||||
//LOG(ONET_LOG,LOG_INFO, "******* VLED check %d ******\n",updated);
|
||||
const int bitmask[4] = {1,2,4,8};
|
||||
|
@ -504,7 +736,7 @@ void rs16led_update(struct aqualinkdata *aq_data, int updated) {
|
|||
//LOG(ONET_LOG,LOG_INFO, "******* Updated VLED status %d ******\n",updated);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
bool new_menu(struct aqualinkdata *aq_data)
|
||||
|
@ -552,10 +784,10 @@ bool new_menu(struct aqualinkdata *aq_data)
|
|||
if (last_menu_type == OTM_EQUIPTMENT_STATUS && menu_type != OTM_EQUIPTMENT_STATUS && !in_ot_programming_mode(aq_data) ) {
|
||||
// End of equiptment status chain of menus, reset any pump that wasn't listed in menus as long as we are not in programming mode
|
||||
pump_update(aq_data, -1);
|
||||
#ifdef AQ_RS16
|
||||
|
||||
if (PANEL_SIZE() >= 16)
|
||||
rs16led_update(aq_data, -1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
last_menu_type = menu_type;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue