mirror of https://github.com/sfeakes/AqualinkD.git
parent
53c88deda2
commit
b0ead8dfe9
26
Makefile
26
Makefile
|
@ -139,13 +139,15 @@ 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 timespec_subtract.c
|
||||
#MG_SRC = mongoose.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
|
||||
|
||||
INCLUDES := -I$(SRC_DIR)
|
||||
|
||||
|
@ -161,11 +163,13 @@ SL_OBJ_DIR_AMD64 := $(OBJ_DIR_AMD64)/slog
|
|||
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))
|
||||
|
@ -194,6 +198,7 @@ SL_OBJ_FILES_AMD64 := $(patsubst $(SRC_DIR)/%.c,$(SL_OBJ_DIR_AMD64)/%.o,$(SL_SRC
|
|||
MAIN = ./release/aqualinkd
|
||||
SLOG = ./release/serial_logger
|
||||
DEBG = ./release/aqualinkd-debug
|
||||
DDEVICE = ./release/dummydevice
|
||||
|
||||
MAIN_ARM64 = ./release/aqualinkd-arm64
|
||||
MAIN_ARMHF = ./release/aqualinkd-armhf
|
||||
|
@ -256,6 +261,9 @@ 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)
|
||||
|
@ -307,6 +315,9 @@ $(DBG_OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(DBG_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 $@ $<
|
||||
|
||||
|
@ -357,6 +368,10 @@ $(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) $(call FixPath,$@)
|
||||
|
@ -364,6 +379,9 @@ $(OBJ_DIR):
|
|||
$(SL_OBJ_DIR):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(DD_OBJ_DIR):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
$(DBG_OBJ_DIR):
|
||||
$(MKDIR) $(call FixPath,$@)
|
||||
|
||||
|
@ -388,10 +406,10 @@ $(SL_OBJ_DIR_AMD64):
|
|||
# Clean rules
|
||||
|
||||
clean: clean-buildfiles
|
||||
$(RM) *.o *~ $(MAIN) $(MAIN_U) $(PLAY) $(PL_EXOBJ) $(DEBG)
|
||||
$(RM) $(wildcard *.o) $(wildcard *~) $(MAIN) $(MAIN_ARM64) $(MAIN_ARMHF) $(MAIN_AMD64) $(SLOG) $(SLOG_ARM64) $(SLOG_ARMHF) $(SLOG_AMD64) $(MAIN_U) $(PLAY) $(PL_EXOBJ) $(LOGR) $(PLAY) $(DEBG)
|
||||
$(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) $(OBJ_FILES_ARMHF) $(OBJ_FILES_ARM64) $(OBJ_FILES_AMD64) $(SL_OBJ_FILES_ARMHF) $(SL_OBJ_FILES_ARM64) $(SL_OBJ_FILES_AMD64)
|
||||
$(RM) $(wildcard *.o) $(wildcard *~) $(OBJ_FILES) $(DBG_OBJ_FILES) $(SL_OBJ_FILES) $(DD_OBJ_FILES) $(OBJ_FILES_ARMHF) $(OBJ_FILES_ARM64) $(OBJ_FILES_AMD64) $(SL_OBJ_FILES_ARMHF) $(SL_OBJ_FILES_ARM64) $(SL_OBJ_FILES_AMD64)
|
||||
|
||||
|
||||
|
|
|
@ -131,6 +131,10 @@ NEED TO FIX FOR THIS RELEASE.
|
|||
* Check SWG messages like "#1 TruClear", see log in this post https://github.com/sfeakes/AqualinkD/discussions/388
|
||||
|
||||
* Finish off heat pump / chiller. Probably use a thermostat for both with heat going to heater SP can cool to chiller SP
|
||||
|
||||
* Hide passwords (bitmask)
|
||||
* Startup config validity checks
|
||||
* remove "extended_programming", or hide it.
|
||||
-->
|
||||
|
||||
|
||||
|
@ -143,7 +147,7 @@ NEED TO FIX FOR THIS RELEASE.
|
|||
* 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 preliminary Heat Pump / Chiller support (MQTT & HA support only, no Homekit or web ui yet)
|
||||
* Added support for Heat Pump / Chiller support.
|
||||
|
||||
|
||||
# Updates in 2.5.0
|
||||
|
|
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,19 +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
|
||||
|
||||
|
||||
# Note on serial port below. If you want aqualinkd to start and run without connecting to a panel or port
|
||||
# use 0x00 for device_id and a dummy serial_port like /dev/tty0.
|
||||
|
||||
# The serial port the daemon access to read the Aqualink RS8
|
||||
serial_port=/dev/ttyUSB0
|
||||
|
||||
# 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.
|
||||
|
@ -63,6 +54,7 @@ panel_type = RS-8 Combo
|
|||
# Working RS ID's are 0x0a 0x0b 0x09 0x08 <- 0x08 is usually taken
|
||||
# If your panel is a PDA only model, then PDA device ID's are 0x60, 0x61, 0x62, 0x63.
|
||||
# (These are NOT recomended to use unless you absolutly have no other option)
|
||||
# Use 0xFF to let Aqualink auto configure all the ID's device_id, rssa_device_id, extended_device_id
|
||||
device_id=0xFF
|
||||
|
||||
|
||||
|
@ -80,21 +72,16 @@ device_id=0xFF
|
|||
# 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 relivent in PDA mode IF you have iAqualink2/3 device
|
||||
# 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
|
||||
|
@ -102,61 +89,18 @@ device_id=0xFF
|
|||
#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
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# When pool or spa is off, report 0deg for water temp. If set to no, last known value will be used.
|
||||
report_zero_pool_temp = yes
|
||||
report_zero_spa_temp = yes
|
||||
|
||||
# mqtt stuff
|
||||
#mqtt_address = localhost:1883
|
||||
#mqtt_user = someusername
|
||||
#mqtt_passwd = somepassword
|
||||
#mqtt_dz_pub_topic = domoticz/in
|
||||
#mqtt_dz_sub_topic = domoticz/out
|
||||
#mqtt_aq_topic = aqualinkd
|
||||
#mqtt_ha_discover_topic = homeassistant
|
||||
#mqtt_ha_discover_use_mac = no
|
||||
|
||||
# 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
|
||||
|
||||
# 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 = 0
|
||||
|
||||
# Get rid of the startup warning message about no low latency. BETTER option is to buy a better adapter.
|
||||
#ftdi_low_latency = no
|
||||
|
||||
# Enable AqualinkD scheduler.
|
||||
# A version of cron that supports cron.d must be installed for the scheduler to work.
|
||||
|
@ -168,11 +112,42 @@ enable_scheduler = yes
|
|||
# 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.
|
||||
#scheduler_check_pumpon_hour = 6
|
||||
#scheduler_check_pumpoff_hour = 23
|
||||
#scheduler_check_poweron = yes
|
||||
#scheduler_check_freezeprotectoff = yes
|
||||
#scheduler_check_boostoff = yes
|
||||
#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
|
||||
|
||||
# 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.
|
||||
|
@ -180,54 +155,44 @@ enable_scheduler = yes
|
|||
# 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
|
||||
|
||||
# AqualinkD can take sime time to find freeze protect (if panel supports it), This will force the freeze protect
|
||||
# to be listed as thermostat on startup.
|
||||
force_Frzprotect_setpoints = no
|
||||
|
||||
# AqualinkD can take sime time to find chemical feeder (if panel supports it), This will force the chemical feeder
|
||||
# to be listed on startup.
|
||||
force_chem_feeder = 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 :-
|
||||
|
@ -285,31 +250,29 @@ use_panel_aux_labels=no
|
|||
# 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
|
||||
#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_06_label=Pool Light
|
||||
#button_05_lightMode=0
|
||||
|
||||
button_07_label=Spa Light
|
||||
#button_05_lightMode=0
|
||||
|
||||
button_08_label=NONE
|
||||
|
||||
button_09_label=NONE
|
||||
|
||||
button_10_label=Pool Heater
|
||||
|
||||
button_11_label=Spa Heater
|
||||
|
||||
button_12_label=Solar Heater
|
||||
#button_08_label=NONE\
|
||||
#button_09_label=NONE
|
||||
#button_10_label=Pool Heater
|
||||
#button_11_label=Spa Heater
|
||||
#button_12_label=Solar Heater
|
||||
|
||||
# Virtual buttons.
|
||||
# To use these you must have extended_device_id set to AqualnkTouch protocol, ie 0x31, 0x31, 0x32, 0x33
|
||||
|
@ -339,3 +302,5 @@ button_12_label=Solar Heater
|
|||
#sensor_02_path = /sys/class/thermal/thermal_zone1/temp
|
||||
#sensor_02_label = GPU
|
||||
#sensor_02_factor = 0.001
|
||||
|
||||
|
||||
|
|
|
@ -129,11 +129,12 @@ else
|
|||
fi
|
||||
fi
|
||||
|
||||
# V2.3.9 has kind-a breaking change for config.js, so check existing and rename if needed
|
||||
# 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)
|
||||
if ! grep -q 'Aux_V1' $WEBLocation/$file || ! grep -q '"Spa"' $WEBLocation/$file; then
|
||||
# Version 2.6.0 added Chiller as well
|
||||
if ! grep -q 'Aux_V1' $WEBLocation/$file || ! grep -q '"Spa"' $WEBLocation/$file || ! grep -q '"Chiller"' $WEBLocation/$file; then
|
||||
dateext=`date +%Y%m%d_%H_%M_%S`
|
||||
echo "AqualinkD web config is old, making copy to $WEBLocation/config.js.$dateext"
|
||||
echo "Please make changes to new version $WEBLocation/config.js"
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -349,11 +349,20 @@ aqkey *addVirtualButton(struct aqualinkdata *aqdata, char *label, int vindex) {
|
|||
|
||||
int index = vindex;
|
||||
|
||||
|
||||
// vindex 0 means find first index.
|
||||
if (vindex == 0) {
|
||||
printf(" TOTAL=%d VSTART=%d\n",aqdata->total_buttons,aqdata->virtual_button_start);
|
||||
index = aqdata->total_buttons - aqdata->virtual_button_start + 1;
|
||||
//printf(" TOTAL=%d VSTART=%d\n",aqdata->total_buttons,aqdata->virtual_button_start);
|
||||
//index = aqdata->total_buttons - aqdata->virtual_button_start + 1;
|
||||
if (aqdata->virtual_button_start <= 0) {
|
||||
// Their are no vbuttons, so start at 1.
|
||||
index = 1;
|
||||
} else {
|
||||
index = aqdata->total_buttons - aqdata->virtual_button_start + 1;
|
||||
}
|
||||
printf("TOTAL=%d VSTART=%d INDEXNAME=%d\n",aqdata->total_buttons,aqdata->virtual_button_start,index);
|
||||
}
|
||||
|
||||
|
||||
if (aqdata->virtual_button_start <= 0) {
|
||||
aqdata->virtual_button_start = aqdata->total_buttons;
|
||||
|
@ -452,7 +461,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
int index = 0;
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[7-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_PUMP):BTN_PDA_PUMP;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_PUMP):cleanalloc(BTN_PDA_PUMP);
|
||||
aqdata->aqbuttons[index].name = BTN_PUMP;
|
||||
aqdata->aqbuttons[index].code = KEY_PUMP;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
|
@ -463,7 +472,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
if (combo) {
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[6-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_SPA):BTN_PDA_SPA;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_SPA):cleanalloc(BTN_PDA_SPA);
|
||||
aqdata->aqbuttons[index].name = BTN_SPA;
|
||||
aqdata->aqbuttons[index].code = KEY_SPA;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
|
@ -474,7 +483,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[5-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX1):BTN_PDA_AUX1;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX1):cleanalloc(BTN_PDA_AUX1);
|
||||
aqdata->aqbuttons[index].name = BTN_AUX1;
|
||||
aqdata->aqbuttons[index].code = KEY_AUX1;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
|
@ -484,7 +493,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[4-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX2):BTN_PDA_AUX2;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX2):cleanalloc(BTN_PDA_AUX2);
|
||||
aqdata->aqbuttons[index].name = BTN_AUX2;
|
||||
aqdata->aqbuttons[index].code = KEY_AUX2;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
|
@ -494,7 +503,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[3-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX3):BTN_PDA_AUX3;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX3):cleanalloc(BTN_PDA_AUX3);
|
||||
aqdata->aqbuttons[index].name = BTN_AUX3;
|
||||
aqdata->aqbuttons[index].code = KEY_AUX3;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
|
@ -506,7 +515,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
if (size >= 6) {
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[9-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX4):BTN_PDA_AUX4;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX4):cleanalloc(BTN_PDA_AUX4);
|
||||
aqdata->aqbuttons[index].name = BTN_AUX4;
|
||||
aqdata->aqbuttons[index].code = KEY_AUX4;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
|
@ -516,7 +525,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[8-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX5):BTN_PDA_AUX5;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX5):cleanalloc(BTN_PDA_AUX5);
|
||||
aqdata->aqbuttons[index].name = BTN_AUX5;
|
||||
aqdata->aqbuttons[index].code = KEY_AUX5;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
|
@ -528,7 +537,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
if (size >= 8) {
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[12-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX6):BTN_PDA_AUX6;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX6):cleanalloc(BTN_PDA_AUX6);
|
||||
aqdata->aqbuttons[index].name = BTN_AUX6;
|
||||
aqdata->aqbuttons[index].code = KEY_AUX6;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
|
@ -538,7 +547,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[1-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX7):BTN_PDA_AUX7;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX7):cleanalloc(BTN_PDA_AUX7);
|
||||
aqdata->aqbuttons[index].name = BTN_AUX7;
|
||||
aqdata->aqbuttons[index].code = KEY_AUX7;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
|
@ -668,7 +677,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[15-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(combo?BTN_POOL_HTR:BTN_TEMP1_HTR):BTN_PDA_POOL_HTR;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(combo?BTN_POOL_HTR:BTN_TEMP1_HTR):cleanalloc(BTN_PDA_POOL_HTR);
|
||||
aqdata->aqbuttons[index].name = BTN_POOL_HTR;
|
||||
aqdata->aqbuttons[index].code = KEY_POOL_HTR;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
|
@ -678,7 +687,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[17-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(combo?BTN_SPA_HTR:BTN_TEMP2_HTR):BTN_PDA_SPA_HTR;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(combo?BTN_SPA_HTR:BTN_TEMP2_HTR):cleanalloc(BTN_PDA_SPA_HTR);
|
||||
aqdata->aqbuttons[index].name = BTN_SPA_HTR;
|
||||
aqdata->aqbuttons[index].code = KEY_SPA_HTR;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
|
@ -688,7 +697,7 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
|
|||
|
||||
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[19-1];
|
||||
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_EXT_AUX):BTN_PDA_EXT_AUX;
|
||||
aqdata->aqbuttons[index].label = rs?name2label(BTN_EXT_AUX):cleanalloc(BTN_PDA_EXT_AUX);
|
||||
aqdata->aqbuttons[index].name = BTN_EXT_AUX;
|
||||
aqdata->aqbuttons[index].code = KEY_EXT_AUX;
|
||||
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
|
||||
|
|
|
@ -517,6 +517,12 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat
|
|||
else if ((isIAQT_ENABLED && isEXTP_ENABLED) || isPDA_IAQT) {
|
||||
// IAQ Touch programming modes that should overite standard ones.
|
||||
switch (r_type){
|
||||
case AQ_SET_CHILLER_TEMP:
|
||||
//if (isIAQL_ACTIVE)
|
||||
// type = AQ_SET_IAQLINK_CHILLER_TEMP; // This might work on rev Yg, but not on T2
|
||||
//else
|
||||
type = AQ_SET_IAQTOUCH_CHILLER_TEMP;
|
||||
break;
|
||||
case AQ_GET_POOL_SPA_HEATER_TEMPS:
|
||||
//case AQ_GET_FREEZE_PROTECT_TEMP:
|
||||
type = AQ_GET_IAQTOUCH_SETPOINTS;
|
||||
|
@ -528,10 +534,16 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat
|
|||
type = AQ_SET_IAQTOUCH_SWG_BOOST;
|
||||
break;
|
||||
case AQ_SET_POOL_HEATER_TEMP:
|
||||
type = AQ_SET_IAQTOUCH_POOL_HEATER_TEMP;
|
||||
if (isIAQL_ACTIVE)
|
||||
type = AQ_SET_IAQLINK_POOL_HEATER_TEMP;
|
||||
else
|
||||
type = AQ_SET_IAQTOUCH_POOL_HEATER_TEMP;
|
||||
break;
|
||||
case AQ_SET_SPA_HEATER_TEMP:
|
||||
type = AQ_SET_IAQTOUCH_SPA_HEATER_TEMP;
|
||||
if (isIAQL_ACTIVE)
|
||||
type = AQ_SET_IAQLINK_SPA_HEATER_TEMP;
|
||||
else
|
||||
type = AQ_SET_IAQTOUCH_SPA_HEATER_TEMP;
|
||||
break;
|
||||
case AQ_SET_TIME:
|
||||
type = AQ_SET_IAQTOUCH_SET_TIME;
|
||||
|
@ -654,11 +666,15 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat
|
|||
return; // No need to create this as thread.
|
||||
break;
|
||||
case AQ_SET_IAQLINK_POOL_HEATER_TEMP:
|
||||
set_iaqualink_heater_setpoint(atoi(args), true);
|
||||
set_iaqualink_heater_setpoint(atoi(args), SP_POOL);
|
||||
return; // No need to create this as thread.
|
||||
break;
|
||||
case AQ_SET_IAQLINK_SPA_HEATER_TEMP:
|
||||
set_iaqualink_heater_setpoint(atoi(args), false);
|
||||
set_iaqualink_heater_setpoint(atoi(args), SP_SPA);
|
||||
return; // No need to create this as thread.
|
||||
break;
|
||||
case AQ_SET_IAQLINK_CHILLER_TEMP:
|
||||
set_iaqualink_heater_setpoint(atoi(args), SP_CHILLER);
|
||||
return; // No need to create this as thread.
|
||||
break;
|
||||
default:
|
||||
|
@ -903,6 +919,9 @@ const char *ptypeName(program_type type)
|
|||
case AQ_SET_IAQLINK_SPA_HEATER_TEMP:
|
||||
return "Set iAqualink Pool Heater";
|
||||
break;
|
||||
case AQ_SET_IAQLINK_CHILLER_TEMP:
|
||||
return "Set iAqualink Chiller Heater";
|
||||
break;
|
||||
|
||||
#ifdef AQ_PDA
|
||||
case AQ_PDA_INIT:
|
||||
|
|
|
@ -62,6 +62,7 @@ typedef enum {
|
|||
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,
|
||||
|
@ -106,6 +107,7 @@ typedef enum {
|
|||
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,
|
||||
|
@ -118,7 +120,7 @@ typedef enum {
|
|||
|
||||
|
||||
|
||||
#define AQ_SET_CHILLER_TEMP AQ_SET_IAQTOUCH_CHILLER_TEMP
|
||||
//#define AQ_SET_CHILLER_TEMP AQ_SET_IAQTOUCH_CHILLER_TEMP
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "config.h"
|
||||
#include "packetLogger.h"
|
||||
#include "timespec_subtract.h"
|
||||
#include "aqualink.h"
|
||||
|
||||
/*
|
||||
Notes for serial usb speed
|
||||
|
@ -304,6 +305,13 @@ const char* get_jandy_packet_type(unsigned char* packet , int length)
|
|||
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;
|
||||
|
@ -544,13 +552,23 @@ 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
|
||||
|
@ -565,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);
|
||||
|
@ -655,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);
|
||||
|
@ -1137,13 +1162,17 @@ 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
|
||||
|
|
|
@ -422,6 +422,8 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
#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
|
||||
|
@ -575,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);
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
|
||||
void intHandler(int dummy);
|
||||
|
||||
bool isAqualinkDStopping();
|
||||
|
||||
#ifdef AQ_PDA
|
||||
bool checkAqualinkTime(); // Only need to externalise this for PDA
|
||||
#endif
|
||||
|
@ -182,6 +184,13 @@ typedef enum simulator_type {
|
|||
} 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
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "simulator.h"
|
||||
#include "debug_timer.h"
|
||||
#include "aq_scheduler.h"
|
||||
#include "json_messages.h"
|
||||
|
||||
#ifdef AQ_MANAGER
|
||||
#include "serial_logger.h"
|
||||
|
@ -94,6 +95,11 @@ bool _cmdln_nostartupcheck = false;
|
|||
void main_loop();
|
||||
int startup(char *self, char *cfgFile);
|
||||
|
||||
|
||||
bool isAqualinkDStopping() {
|
||||
return !_keepRunning;
|
||||
}
|
||||
|
||||
void intHandler(int sig_num)
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Stopping!\n");
|
||||
|
@ -483,11 +489,7 @@ int main(int argc, char *argv[])
|
|||
else if (strcmp(argv[i], "-rsrd") == 0)
|
||||
{
|
||||
_cmdln_lograwRS485 = true;
|
||||
}
|
||||
else if (strcmp(argv[i], "-nc") == 0)
|
||||
{
|
||||
_cmdln_nostartupcheck = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set this here, so it doesn;t get reset if the manager restarts the AqualinkD process.
|
||||
|
@ -505,6 +507,8 @@ int startup(char *self, char *cfgFile)
|
|||
|
||||
AddAQDstatusMask(CHECKING_CONFIG);
|
||||
AddAQDstatusMask(NOT_CONNECTED);
|
||||
_aqualink_data.updated = true;
|
||||
//_aqualink_data.chiller_button == NULL; // HATE having this here, but needs to be null before config.
|
||||
|
||||
sprintf(_aqualink_data.self, basename(self));
|
||||
clearDebugLogMask();
|
||||
|
@ -693,6 +697,8 @@ void caculate_ack_packet(int rs_fd, unsigned char *packet_buffer, emulation_type
|
|||
|
||||
}
|
||||
|
||||
#define MAX_AUTO_PACKETS 1200
|
||||
|
||||
bool auto_configure(unsigned char* packet) {
|
||||
// Loop over PROBE packets and store any we can use,
|
||||
// once we see the 2nd probe of any ID we fave stored, then the loop is complete,
|
||||
|
@ -709,6 +715,12 @@ bool auto_configure(unsigned char* packet) {
|
|||
static unsigned char lastID = 0x00;
|
||||
static bool seen_iAqualink2 = false;
|
||||
static int foundIDs = 0;
|
||||
static int packetsReceived=0;
|
||||
|
||||
if (++packetsReceived >= MAX_AUTO_PACKETS ) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Received %d packets, and didn't get a full probe cycle, stoping Auto Configure!\n",packetsReceived);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( packet[PKT_CMD] == CMD_PROBE ) {
|
||||
LOG(AQUA_LOG,LOG_INFO, "Got Probe on ID 0x%02hhx\n",packet[PKT_DEST]);
|
||||
|
@ -727,7 +739,9 @@ bool auto_configure(unsigned char* packet) {
|
|||
_aqconfig_.device_id = 0x00;
|
||||
_aqconfig_.rssa_device_id = 0x00;
|
||||
_aqconfig_.extended_device_id = 0x00;
|
||||
_aqconfig_.extended_device_id_programming = false;
|
||||
AddAQDstatusMask(AUTOCONFIGURE_ID);
|
||||
_aqualink_data.updated = true;
|
||||
//AddAQDstatusMask(AUTOCONFIGURE_PANEL); // Not implimented yet.
|
||||
}
|
||||
|
||||
|
@ -768,6 +782,7 @@ bool auto_configure(unsigned char* packet) {
|
|||
LOG(AQUA_LOG,LOG_NOTICE, "Finished Autoconfigure using device_id=0x%02hhx rssa_device_id=0x%02hhx extended_device_id=0x%02hhx (%s iAqualink2/3)\n",
|
||||
_aqconfig_.device_id,_aqconfig_.rssa_device_id,_aqconfig_.extended_device_id, _aqconfig_.enable_iaqualink?"Enable":"Disable");
|
||||
RemoveAQDstatusMask(AUTOCONFIGURE_ID);
|
||||
_aqualink_data.updated = true;
|
||||
return true; // we can exit finally.
|
||||
}
|
||||
|
||||
|
@ -833,6 +848,7 @@ void main_loop()
|
|||
|
||||
//_aqualink_data.panelstatus = STARTING;
|
||||
AddAQDstatusMask(CHECKING_CONFIG);
|
||||
_aqualink_data.updated = true;
|
||||
sprintf(_aqualink_data.last_display_message, "%s", "Connecting to Control Panel");
|
||||
_aqualink_data.is_display_message_programming = false;
|
||||
//_aqualink_data.simulate_panel = false;
|
||||
|
@ -863,6 +879,7 @@ void main_loop()
|
|||
_aqualink_data.simulator_active = SIM_NONE;
|
||||
_aqualink_data.boost_duration = 0;
|
||||
_aqualink_data.boost = false;
|
||||
|
||||
|
||||
pthread_mutex_init(&_aqualink_data.active_thread.thread_mutex, NULL);
|
||||
pthread_cond_init(&_aqualink_data.active_thread.thread_cond, NULL);
|
||||
|
@ -927,17 +944,25 @@ void main_loop()
|
|||
|
||||
rs_fd = init_serial_port(_aqconfig_.serial_port);
|
||||
|
||||
/*
|
||||
if (rs_fd == -1) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Error Aqualink setting serial port: %s\n", _aqconfig_.serial_port);
|
||||
//_aqualink_data.panelstatus = SERIAL_ERROR;
|
||||
AddAQDstatusMask(ERROR_SERIAL);
|
||||
_aqualink_data.updated = true;
|
||||
#ifndef AQ_CONTAINER
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
} else {
|
||||
//AddAQDstatusMask(CHECKING_CONFIG);
|
||||
}
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Listening to Aqualink RS8 on serial port: %s\n", _aqconfig_.serial_port);
|
||||
*/
|
||||
if (is_valid_port(rs_fd)) {
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Listening to Aqualink RS8 on serial port: %s\n", _aqconfig_.serial_port);
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Error Aqualink bad serial port: %s\n", _aqconfig_.serial_port);
|
||||
AddAQDstatusMask(ERROR_SERIAL);
|
||||
}
|
||||
|
||||
if (!serial_blockingmode())
|
||||
blank_read_reconnect = MAX_ZERO_READ_BEFORE_RECONNECT_NONBLOCKING;
|
||||
|
@ -957,6 +982,7 @@ void main_loop()
|
|||
// Set probes to true for any device we are not searching for.
|
||||
|
||||
RemoveAQDstatusMask(CHECKING_CONFIG);
|
||||
_aqualink_data.updated = true;
|
||||
|
||||
if (_aqconfig_.rssa_device_id == 0x00)
|
||||
got_probe_rssa = true;
|
||||
|
@ -969,27 +995,29 @@ void main_loop()
|
|||
}
|
||||
|
||||
if (_aqconfig_.device_id == 0xFF) {
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Waiting for Control Panel information\n\n");
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Waiting for Control Panel information");
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Unsing Auto configure, this will take some time, (make sure to undate aqualinkd configuration to speed up startup!)\n");
|
||||
auto_config_complete = false;
|
||||
//_aqualink_data.panelstatus = LOOKING_IDS;
|
||||
AddAQDstatusMask(AUTOCONFIGURE_ID);
|
||||
_aqualink_data.updated = true;
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Waiting for Control Panel probe\n");
|
||||
//_aqualink_data.panelstatus = CONECTING;
|
||||
AddAQDstatusMask(CONNECTING);
|
||||
_aqualink_data.updated = true;
|
||||
}
|
||||
i=0;
|
||||
|
||||
// Loop until we get the probe messages, that means we didn;t start too soon after last shutdown.
|
||||
while ( (got_probe == false || got_probe_rssa == false || got_probe_extended == false || auto_config_complete == false) && _keepRunning == true && _cmdln_nostartupcheck == false)
|
||||
while ( is_valid_port(rs_fd) && (got_probe == false || got_probe_rssa == false || got_probe_extended == false || auto_config_complete == false) && _keepRunning == true && _cmdln_nostartupcheck == false)
|
||||
{
|
||||
if (blank_read == blank_read_reconnect / 2) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Nothing read on '%s', are you sure that's right?\n",_aqconfig_.serial_port);
|
||||
#ifdef AQ_CONTAINER
|
||||
//#ifdef AQ_CONTAINER
|
||||
// Reset blank reads here, we want to ignore TTY errors in container to keep it running
|
||||
blank_read = 1;
|
||||
#endif
|
||||
//#endif
|
||||
if (_aqconfig_.device_id == 0x00) {
|
||||
blank_read = 1; // if device id=0x00 it's code for don't exit
|
||||
}
|
||||
|
@ -1013,6 +1041,7 @@ void main_loop()
|
|||
blank_read = 0;
|
||||
auto_config_complete = auto_configure(packet_buffer);
|
||||
AddAQDstatusMask(AUTOCONFIGURE_ID);
|
||||
_aqualink_data.updated = true;
|
||||
if (auto_config_complete) {
|
||||
//if (_aqconfig_.device_id != 0x00)
|
||||
got_probe = true;
|
||||
|
@ -1026,6 +1055,7 @@ void main_loop()
|
|||
if (packet_length > 0 && _aqconfig_.device_id == 0x00) {
|
||||
blank_read = 0;
|
||||
AddAQDstatusMask(AUTOCONFIGURE_ID);
|
||||
_aqualink_data.updated = true;
|
||||
_aqconfig_.device_id = find_unused_address(packet_buffer);
|
||||
continue;
|
||||
}
|
||||
|
@ -1104,15 +1134,16 @@ void main_loop()
|
|||
RemoveAQDstatusMask(AUTOCONFIGURE_ID);
|
||||
RemoveAQDstatusMask(NOT_CONNECTED);
|
||||
AddAQDstatusMask(CONNECTING);
|
||||
|
||||
_aqualink_data.updated = true;
|
||||
|
||||
//At this point we should have correct ID and seen probes on those ID's.
|
||||
// Setup the panel
|
||||
if (_aqconfig_.device_id == 0x00) {
|
||||
if (_aqconfig_.device_id <= 0x08 && _aqconfig_.device_id >= 0x0B && _aqconfig_.device_id != 0x60 && _aqconfig_.device_id != 0x33) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Aqualink daemon has no valid device_id, can't connect to control panel");
|
||||
//_aqualink_data.panelstatus = NO_IDS_ERROR;
|
||||
RemoveAQDstatusMask(CONNECTING); // Not sure if we should remove this
|
||||
AddAQDstatusMask(ERROR_NO_DEVICE_ID);
|
||||
_aqualink_data.updated = true;
|
||||
}
|
||||
|
||||
if (_aqconfig_.rssa_device_id >= 0x48 && _aqconfig_.rssa_device_id <= 0x49) {
|
||||
|
@ -1128,6 +1159,7 @@ void main_loop()
|
|||
// We can only get panel size info from extended ID
|
||||
if (_aqconfig_.extended_device_id != 0x00) {
|
||||
RemoveAQDstatusMask(AUTOCONFIGURE_PANEL);
|
||||
_aqualink_data.updated = true;
|
||||
}
|
||||
|
||||
if (_aqconfig_.extended_device_id_programming == true && (isONET_ENABLED || isIAQT_ENABLED) )
|
||||
|
@ -1164,14 +1196,17 @@ void main_loop()
|
|||
while ((rs_fd < 0 || blank_read >= blank_read_reconnect) && _keepRunning == true)
|
||||
{
|
||||
//printf("rs_fd =% d\n",rs_fd);
|
||||
if (rs_fd < 0)
|
||||
if (!is_valid_port(rs_fd))
|
||||
{
|
||||
sleep(1);
|
||||
LOG(AQUA_LOG,LOG_ERR, "Bad serial port '%s', are you sure that's right?\n",_aqconfig_.serial_port);
|
||||
sprintf(_aqualink_data.last_display_message, CONNECTION_ERROR);
|
||||
LOG(AQUA_LOG,LOG_ERR, "Aqualink daemon waiting to connect to master device...\n");
|
||||
//LOG(AQUA_LOG,LOG_ERR, "Serial port error, Aqualink daemon waiting to connect to master device...\n");
|
||||
_aqualink_data.updated = true;
|
||||
AddAQDstatusMask(ERROR_SERIAL);
|
||||
broadcast_aqualinkstate_error(CONNECTION_ERROR);
|
||||
//broadcast_aqualinkstate_error(CONNECTION_ERROR);
|
||||
broadcast_aqualinkstate_error(getAqualinkDStatusMessage(&_aqualink_data));
|
||||
sleep(10);
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
poll_net_services(1000);
|
||||
poll_net_services(3000);
|
||||
|
@ -1184,11 +1219,12 @@ void main_loop()
|
|||
LOG(AQUA_LOG,LOG_ERR, "Aqualink daemon looks like serial error, resetting.\n");
|
||||
_aqualink_data.updated = true;
|
||||
AddAQDstatusMask(ERROR_SERIAL);
|
||||
broadcast_aqualinkstate_error(CONNECTION_ERROR);
|
||||
//broadcast_aqualinkstate_error(CONNECTION_ERROR);
|
||||
broadcast_aqualinkstate_error(getAqualinkDStatusMessage(&_aqualink_data));
|
||||
close_serial_port(rs_fd);
|
||||
rs_fd = init_serial_port(_aqconfig_.serial_port);
|
||||
//rs_fd = init_serial_port(_aqconfig_.serial_port);
|
||||
}
|
||||
|
||||
rs_fd = init_serial_port(_aqconfig_.serial_port);
|
||||
blank_read = 0;
|
||||
}
|
||||
|
||||
|
@ -1243,6 +1279,7 @@ void main_loop()
|
|||
RemoveAQDstatusMask(ERROR_SERIAL);
|
||||
RemoveAQDstatusMask(CONNECTING);
|
||||
AddAQDstatusMask(CONNECTED);
|
||||
_aqualink_data.updated = true;
|
||||
DEBUG_TIMER_START(&_rs_packet_timer);
|
||||
|
||||
blank_read = 0;
|
||||
|
|
135
source/config.c
135
source/config.c
|
@ -175,6 +175,8 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_socket_port;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
//_cfgParams[_numCfgParams].config_mask |= CFG_READONLY; // Take out once below is working
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)_dcfg_web_port;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -183,6 +185,8 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_serial_port;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
//_cfgParams[_numCfgParams].config_mask |= CFG_READONLY; // Take out once below is working
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)_dcfg_serial_port;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -192,6 +196,15 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].valid_values = CFG_V_log_level;
|
||||
_cfgParams[_numCfgParams].default_value = (void *) &_dcfg_loglevel;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.web_directory;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_STRING;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_web_directory;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_READONLY;
|
||||
_cfgParams[_numCfgParams].default_value = NULL;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.paneltype_mask;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_SPECIAL;
|
||||
|
@ -217,6 +230,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].value_type = CFG_BOOL;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_extended_device_id_programming;
|
||||
_cfgParams[_numCfgParams].valid_values = CFG_V_BOOL;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_HIDE;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_true;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -232,14 +246,6 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].name = CFG_N_enable_iaqualink;
|
||||
_cfgParams[_numCfgParams].valid_values = CFG_V_BOOL;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_false;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.web_directory;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_STRING;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_web_directory;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].default_value = NULL;
|
||||
|
||||
#ifndef AQ_MANAGER
|
||||
_numCfgParams++;
|
||||
|
@ -267,6 +273,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_passwd;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_STRING;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_mqtt_passwd;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_PASSWD_MASK;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)NULL;
|
||||
|
||||
_numCfgParams++;
|
||||
|
@ -466,7 +473,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].value_type = CFG_BITMASK;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_force_swg;
|
||||
_cfgParams[_numCfgParams].mask = FORCE_SWG_SP;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_true;
|
||||
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_false;
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.force_device_devmask;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_BITMASK;
|
||||
|
@ -940,14 +947,21 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (isMASK_SET(_cfgParams[i].config_mask, CFG_PASSWD_MASK)) {
|
||||
if (strncmp(value, PASSWD_MASK_TEXT, strlen(PASSWD_MASK_TEXT)) == 0) {
|
||||
// Don't set password when it's the mask text
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (_cfgParams[i].value_type) {
|
||||
case CFG_STRING:
|
||||
if (_cfgParams[i].value_ptr != NULL && *(char **)_cfgParams[i].value_ptr != _cfgParams[i].default_value) {
|
||||
LOG(AQUA_LOG,LOG_DEBUG,"FREE Memory for config %s %s\n",_cfgParams[i].name, *(char **)_cfgParams[i].value_ptr);
|
||||
free(*(char **)_cfgParams[i].value_ptr);
|
||||
*(char **)_cfgParams[i].value_ptr = NULL;
|
||||
}
|
||||
*(char **)_cfgParams[i].value_ptr = cleanalloc(value);
|
||||
if (_cfgParams[i].value_ptr != NULL && *(char **)_cfgParams[i].value_ptr != _cfgParams[i].default_value) {
|
||||
LOG(AQUA_LOG,LOG_DEBUG,"FREE Memory for config %s %s\n",_cfgParams[i].name, *(char **)_cfgParams[i].value_ptr);
|
||||
free(*(char **)_cfgParams[i].value_ptr);
|
||||
*(char **)_cfgParams[i].value_ptr = NULL;
|
||||
}
|
||||
*(char **)_cfgParams[i].value_ptr = cleanalloc(value);
|
||||
break;
|
||||
case CFG_INT:
|
||||
*(int *)_cfgParams[i].value_ptr = strtoul(cleanwhitespace(value), NULL, 10);
|
||||
|
@ -1546,40 +1560,62 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
|
||||
// Check chiller
|
||||
if (ENABLE_CHILLER) {
|
||||
for (i = 0; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
if (isVBUTTON_ALTLABEL(aqdata->aqbuttons[i].special_mask) && (rsm_strmatch(((vbutton_detail *)aqdata->aqbuttons[i].special_mask_ptr)->altlabel, "Chiller") == 0) ){
|
||||
aqdata->chiller_button = &aqdata->aqbuttons[i];
|
||||
} else if (isVBUTTON(aqdata->aqbuttons[i].special_mask) && rsm_strmatch(aqdata->aqbuttons[i].label, "Heat Pump") == 0 ) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, `%s` is enabled, but Virtual Button Heat Pump does not have alt_name Chiller! Creating.",CFG_N_force_chiller);
|
||||
setVirtualButtonAltLabel(&aqdata->aqbuttons[i], "Chiller");
|
||||
aqdata->chiller_button = &aqdata->aqbuttons[i];
|
||||
aqdata->chiller_button->special_mask |= VIRTUAL_BUTTON_CHILLER;
|
||||
if (_aqconfig_.extended_device_id >= 0x30 && _aqconfig_.extended_device_id <= 0x33) {
|
||||
for (i = 0; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
if (isVBUTTON_ALTLABEL(aqdata->aqbuttons[i].special_mask) && (rsm_strmatch(((vbutton_detail *)aqdata->aqbuttons[i].special_mask_ptr)->altlabel, "Chiller") == 0) ){
|
||||
aqdata->chiller_button = &aqdata->aqbuttons[i];
|
||||
//aqdata->chiller_button->special_mask |= VIRTUAL_BUTTON_CHILLER;
|
||||
setMASK(aqdata->chiller_button->special_mask, VIRTUAL_BUTTON_CHILLER);
|
||||
} else if (isVBUTTON(aqdata->aqbuttons[i].special_mask) && rsm_strmatch(aqdata->aqbuttons[i].label, "Heat Pump") == 0 ) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, `%s` is enabled, but Virtual Button Heat Pump does not have alt_name Chiller! Creating.",CFG_N_force_chiller);
|
||||
setVirtualButtonAltLabel(&aqdata->aqbuttons[i], cleanalloc("Chiller")); // Need to malloc this so it can be freed
|
||||
aqdata->chiller_button = &aqdata->aqbuttons[i];
|
||||
//aqdata->chiller_button->special_mask |= VIRTUAL_BUTTON_CHILLER;
|
||||
setMASK(aqdata->chiller_button->special_mask, VIRTUAL_BUTTON_CHILLER);
|
||||
}
|
||||
}
|
||||
if (aqdata->chiller_button == NULL) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, `%s` is enabled, but no Virtual Button set for Heat Pump / Chiller! Creating vbutton.",CFG_N_force_chiller);
|
||||
aqkey *button = getVirtualButton(aqdata, 0);
|
||||
setVirtualButtonLabel(button, cleanalloc("Heat Pump"));// Need to malloc this so it can be freed
|
||||
setVirtualButtonAltLabel(button, cleanalloc("Chiller"));// Need to malloc this so it can be freed
|
||||
aqdata->chiller_button = button;
|
||||
//aqdata->chiller_button->special_mask |= VIRTUAL_BUTTON_CHILLER;
|
||||
setMASK(aqdata->chiller_button->special_mask, VIRTUAL_BUTTON_CHILLER);
|
||||
}
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, `%s` can only be enabled, if using an iAqualink Touch ID for `%s`, Turning off\n",CFG_N_force_chiller, CFG_N_extended_device_id );
|
||||
removeMASK(_aqconfig_.force_device_devmask,FORCE_CHILLER);
|
||||
aqdata->chiller_button = NULL;
|
||||
}
|
||||
if (aqdata->chiller_button == NULL) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, `%s` is enabled, but no Virtual Button set for Heat Pump / Chiller! Creating vbutton.",CFG_N_force_chiller);
|
||||
aqkey *button = getVirtualButton(aqdata, 0);
|
||||
setVirtualButtonLabel(button, "Heat Pump");
|
||||
setVirtualButtonAltLabel(button, "Chiller");
|
||||
aqdata->chiller_button = button;
|
||||
aqdata->chiller_button->special_mask |= VIRTUAL_BUTTON_CHILLER;
|
||||
}
|
||||
} else {
|
||||
aqdata->chiller_button = NULL;
|
||||
}
|
||||
|
||||
|
||||
// Turn off extended programming if we don't have device
|
||||
if ( _aqconfig_.extended_device_id == 0x00 )
|
||||
{
|
||||
_aqconfig_.extended_device_id_programming = false;
|
||||
}
|
||||
/*
|
||||
_cfgParams[_numCfgParams].mask = READ_RS485_IAQUALNK;
|
||||
if ( bitmask READ_RS485_IAQUALNK && _aqconfig_.enable_iaqualink ) error and use (_aqconfig_.enable_iaqualink, disable bitmask
|
||||
if (_aqconfig_.enable_iaqualink)
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'read_RS485_iAqualink' is not valid when 'enable_iaqualink=yes', ignoring read_RS485_iAqualink!\n");
|
||||
else
|
||||
_aqconfig_.read_RS485_devmask |= READ_RS485_IAQUALNK;
|
||||
} else {
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_IAQUALNK;
|
||||
}
|
||||
if ( bitmask READ_RS485_IAQUALNK && _aqconfig_.enable_iaqualink ) error and use (_aqconfig_.enable_iaqualink, disable bitmask
|
||||
*/
|
||||
|
||||
if (_aqconfig_.enable_iaqualink==true && (_aqconfig_.extended_device_id < 0x30 || _aqconfig_.extended_device_id > 0x33) )
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'enable_iaqualink', is only valed with AqualinkTouch ID's, ignoring!\n");
|
||||
_aqconfig_.enable_iaqualink = true;
|
||||
}
|
||||
// Can't read iaqualink if we are also using iaqualink protocol.
|
||||
if (isMASK_SET(_aqconfig_.enable_iaqualink, READ_RS485_IAQUALNK) && _aqconfig_.enable_iaqualink == true )
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'read_RS485_iAqualink' is not valid when 'enable_iaqualink=yes', ignoring read_RS485_iAqualink!\n");
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_IAQUALNK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
PDA sleep and PDA ID.
|
||||
*/
|
||||
|
@ -1610,8 +1646,12 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
case CFG_STRING:
|
||||
if (*(char **)_cfgParams[i].value_ptr == NULL)
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "%-35s =\n", name);
|
||||
else
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "%-35s = %s\n",name, *(char **)_cfgParams[i].value_ptr);
|
||||
else {
|
||||
if (isMASK_SET(_cfgParams[i].config_mask ,CFG_PASSWD_MASK) )
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "%-35s = %s\n",name, PASSWD_MASK_TEXT);
|
||||
else
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "%-35s = %s\n",name, *(char **)_cfgParams[i].value_ptr);
|
||||
}
|
||||
break;
|
||||
case CFG_INT:
|
||||
if (*(int *)_cfgParams[i].value_ptr == TEMP_UNKNOWN)
|
||||
|
@ -1662,7 +1702,7 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
for (i = 0; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
//char ext[] = " VSP ID None | AL ID 0 ";
|
||||
char ext[40];
|
||||
char ext[60];
|
||||
ext[0] = '\0';
|
||||
for (j = 0; j < aqdata->num_pumps; j++) {
|
||||
if (aqdata->pumps[j].button == &aqdata->aqbuttons[i]) {
|
||||
|
@ -1782,6 +1822,7 @@ int save_config_js(const char* inBuf, int inSize, char* outBuf, int outSize, str
|
|||
} else if (isPLIGHT(aqdata->aqbuttons[i].special_mask)) {
|
||||
((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->button = NULL;
|
||||
}
|
||||
//printf("Freeing %d of %d - %s\n",i,aqdata->total_buttons,aqdata->aqbuttons[i].label);
|
||||
free ( aqdata->aqbuttons[i].label);
|
||||
aqdata->aqbuttons[i].special_mask = 0;
|
||||
aqdata->aqbuttons[i].special_mask_ptr = NULL;
|
||||
|
@ -1827,6 +1868,8 @@ int save_config_js(const char* inBuf, int inSize, char* outBuf, int outSize, str
|
|||
//cursor = inBuf+start+1;
|
||||
for (m = 0; m < maxMatches; m ++)
|
||||
{
|
||||
ignorePair = false;
|
||||
|
||||
if (0 != (rc = regexec(®exCompiled, cursor, maxGroups, groupArray, 0))) {
|
||||
//printf("Failed to match '%s' with '%s',returning %d.\n", cursor, pattern, rc);
|
||||
break;
|
||||
|
@ -1846,6 +1889,7 @@ int save_config_js(const char* inBuf, int inSize, char* outBuf, int outSize, str
|
|||
|
||||
if (!ignorePair) {
|
||||
setConfigValue(_aqdata ,key,value);
|
||||
//printf("Config pair %s %s\n",key,value);
|
||||
}
|
||||
|
||||
// Check if panel size has changed
|
||||
|
@ -1922,6 +1966,9 @@ bool writeCfg (struct aqualinkdata *aqdata)
|
|||
//char fp[100];
|
||||
|
||||
for ( i=0; i <= _numCfgParams; i++) {
|
||||
if (isMASK_SET(_cfgParams[i].config_mask, CFG_HIDE) ) {
|
||||
continue;
|
||||
}
|
||||
//printf("Writing %s\n",_cfgParams[i].name);
|
||||
// Group values by fist letter, if the same group together.
|
||||
if (lastName != NULL && lastName[0] != _cfgParams[i].name[0]) {
|
||||
|
|
|
@ -185,11 +185,17 @@ typedef enum cfg_value_type{
|
|||
|
||||
|
||||
#define CFG_PERSISTANT (1 << 0) // Don't free memory, things referance the pointer
|
||||
#define CFG_NO_EDIT (1 << 1) // Don't allow editing
|
||||
#define CFG_GRP_ADVANCED (1 << 2) // Show in group advanced
|
||||
#define CFG_HIDE (1 << 3) // Like passwords.
|
||||
#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 {
|
||||
|
@ -230,7 +236,7 @@ int _numCfgParams;
|
|||
#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\", \"0xFF\"]"
|
||||
#define CFG_V_rssa_device_id "[\"0x00\", \"0x48\"]"
|
||||
#define CFG_C_rssa_device_id 14
|
||||
|
||||
#define CFG_N_RSSD_LOG_filter "RSSD_LOG_filter"
|
||||
|
@ -239,7 +245,7 @@ int _numCfgParams;
|
|||
#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\", \"0xFF\"]"
|
||||
#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"
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "packetLogger.h"
|
||||
#include "iaqualink.h"
|
||||
|
||||
#include "json_messages.h"
|
||||
/*
|
||||
All button errors
|
||||
'Check AQUAPURE No Flow'
|
||||
|
@ -35,7 +36,13 @@
|
|||
|
||||
static int _swg_noreply_cnt = 0;
|
||||
|
||||
void updateHeatPumpLed(aqledstate state, struct aqualinkdata *aqdata);
|
||||
typedef enum heatpumpstate{
|
||||
HP_HEAT,
|
||||
HP_COOL,
|
||||
HP_UNKNOWN
|
||||
} heatpumpstate;
|
||||
|
||||
void updateHeatPumpLed(heatpumpstate state, aqledstate ledstate, struct aqualinkdata *aqdata, bool fromMessage);
|
||||
|
||||
bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
|
@ -585,7 +592,7 @@ bool processPacketToJandyPump(unsigned char *packet_buffer, int packet_length, s
|
|||
if (getLogLevel(DJAN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
|
||||
char msg[1024];
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "To ePump: %s\n", msg);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "To ePump: %s", msg);
|
||||
}
|
||||
|
||||
// If type 0x45 and 0x44 set to interested in next command.
|
||||
|
@ -618,7 +625,7 @@ bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length,
|
|||
char msg[1024];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "From ePump: %s\n", msg);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "From ePump: %s", msg);
|
||||
}
|
||||
|
||||
if (packet_buffer[3] == CMD_EPUMP_STATUS && packet_buffer[4] == CMD_EPUMP_RPM) {
|
||||
|
@ -683,7 +690,7 @@ bool processPacketToJandyJXiHeater(unsigned char *packet_buffer, int packet_leng
|
|||
char msg[1024];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "To JXi: %s\n", msg);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "To JXi: %s", msg);
|
||||
}
|
||||
|
||||
if (packet_buffer[3] != CMD_JXI_PING) {
|
||||
|
@ -816,7 +823,7 @@ bool processPacketFromJandyJXiHeater(unsigned char *packet_buffer, int packet_le
|
|||
char msg[1024];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "From JXi: %s\n", msg);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "From JXi: %s", msg);
|
||||
}
|
||||
|
||||
if (packet_buffer[3] != CMD_JXI_STATUS) {
|
||||
|
@ -873,7 +880,7 @@ bool processPacketToJandyLXHeater(unsigned char *packet_buffer, int packet_lengt
|
|||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "To LX: %s\n", msg);
|
||||
LOG(DJAN_LOG, LOG_INFO, "To LX: %s", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
||||
|
@ -902,7 +909,7 @@ bool processPacketFromJandyLXHeater(unsigned char *packet_buffer, int packet_len
|
|||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "From LX: %s\n", msg);
|
||||
LOG(DJAN_LOG, LOG_INFO, "From LX: %s", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
||||
|
@ -931,7 +938,7 @@ bool processPacketToJandyChemFeeder(unsigned char *packet_buffer, int packet_len
|
|||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "To Chem: %s\n", msg);
|
||||
LOG(DJAN_LOG, LOG_INFO, "To Chem: %s", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
||||
|
@ -947,7 +954,7 @@ bool processPacketFromJandyChemFeeder(unsigned char *packet_buffer, int packet_l
|
|||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "From Chem: %s\n", msg);
|
||||
LOG(DJAN_LOG, LOG_INFO, "From Chem: %s", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
||||
|
@ -970,36 +977,40 @@ bool processPacketToHeatPump(unsigned char *packet_buffer, int packet_length, st
|
|||
char msg[1024];
|
||||
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "To HPump: %s\n", msg);
|
||||
LOG(DJAN_LOG, LOG_INFO, "To HPump: %s", msg);
|
||||
/* Byted 3 and 4
|
||||
0x0c|0x01 = Heat Pump Enabled
|
||||
0x0c|0x29 = Chiller on
|
||||
0x0c|0x00 = Off
|
||||
0x0c|0x09 = inknown at present
|
||||
0x0c|0x0a = unknown at present
|
||||
*/
|
||||
/*
|
||||
0x0c|0x00 = Request off
|
||||
0x0c|0x09 = Request Heat
|
||||
0x0c|0x29 = Request Cool
|
||||
*/
|
||||
if (packet_buffer[3] == 0x0c ) {
|
||||
if (packet_buffer[4] == 0x00) {
|
||||
// Heat Pump is off
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx is Off - status 0x%02hhx\n",packet_buffer[2],packet_buffer[4] );
|
||||
updateHeatPumpLed(OFF, aqdata);
|
||||
} else if (packet_buffer[4] == 0x01) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx is Enabled - status 0x%02hhx\n",packet_buffer[2],packet_buffer[4] );
|
||||
// Think this is Heat Pump Only, Not Chiller. Not sure.
|
||||
// Looks like heat pump name simply changes to chiller depending on in the water temp is above or below the chiller set point
|
||||
// So I think "Enabled" is the same for both.
|
||||
// So going to set it to enabled.
|
||||
updateHeatPumpLed(ENABLE, aqdata);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx request to Off - status 0x%02hhx\n",packet_buffer[PKT_DEST],packet_buffer[4] );
|
||||
updateHeatPumpLed(false, OFF, aqdata, false);
|
||||
} else if (packet_buffer[4] == 0x09) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx request to Heat - status 0x%02hhx\n",packet_buffer[PKT_DEST],packet_buffer[4] );
|
||||
// Heat
|
||||
updateHeatPumpLed(false, ENABLE, aqdata, false);
|
||||
} else if (packet_buffer[4] == 0x29) {
|
||||
// not sure if this is also Heat on.
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx Chiller is On - status 0x%02hhx\n",packet_buffer[2],packet_buffer[4] );
|
||||
updateHeatPumpLed(ON, aqdata);
|
||||
// Cool
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx request to Cool - status 0x%02hhx\n",packet_buffer[PKT_DEST],packet_buffer[4] );
|
||||
updateHeatPumpLed(true, ENABLE, aqdata, false);
|
||||
} else {
|
||||
// Heat Pump is on or enabled (not sure what state), but set to something other than off
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Heat Pump 0x%02hhx is (unknown status) 0x%02hhx\n",packet_buffer[2], packet_buffer[4]);
|
||||
LOG(DJAN_LOG, LOG_INFO, "Heat Pump 0x%02hhx request to (unknown status) 0x%02hhx\n",packet_buffer[PKT_DEST], packet_buffer[4]);
|
||||
if (aqdata->chiller_button != NULL && aqdata->chiller_button->led->state == OFF)
|
||||
updateHeatPumpLed(ENABLE, aqdata); // Guess at enabled. ()
|
||||
updateHeatPumpLed(false, ENABLE, aqdata, false); // Guess at enabled. ()
|
||||
}
|
||||
} else {
|
||||
LOG(DJAN_LOG, LOG_INFO, "Heat Pump 0x%02hhx request unknown 0x%02hhx 0x%02hhx\n",packet_buffer[PKT_DEST], packet_buffer[3] , packet_buffer[4]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1015,8 +1026,27 @@ bool processPacketFromHeatPump(unsigned char *packet_buffer, int packet_length,
|
|||
|
||||
// Reply is some status 0x40,0x48,0x68
|
||||
*/
|
||||
// 0x40 = OFF
|
||||
// 0x48 = HEATING.
|
||||
// 0x68 = COOL.
|
||||
|
||||
if (packet_buffer[3] == 0x0d ) {
|
||||
if (packet_buffer[4] == 0x40) {
|
||||
updateHeatPumpLed(HP_HEAT, OFF, aqdata, false);
|
||||
} else if (packet_buffer[4] == 0x48) {
|
||||
updateHeatPumpLed(HP_HEAT, ON, aqdata, false);
|
||||
} else if (packet_buffer[4] == 0x68) {
|
||||
updateHeatPumpLed(HP_COOL, ON, aqdata, false);
|
||||
} else {
|
||||
//LOG(DJAN_LOG, LOG_INFO, "Heat Pump 0x%02hhx ");
|
||||
LOG(DJAN_LOG, LOG_INFO, "Heat Pump 0x%02hhx returned unknown state 0x%02hhx\n",packet_buffer[PKT_DEST], packet_buffer[4]);
|
||||
}
|
||||
} else {
|
||||
LOG(DJAN_LOG, LOG_INFO, "Heat Pump 0x%02hhx returned unknown information 0x%02hhx 0x%02hhx\n",packet_buffer[PKT_DEST], packet_buffer[3], packet_buffer[4]);
|
||||
}
|
||||
|
||||
beautifyPacket(msg, 1024, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "From HPump: %s\n", msg);
|
||||
LOG(DJAN_LOG, LOG_INFO, "From HPump: %s", msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1028,34 +1058,51 @@ void processHeatPumpDisplayMessage(char *msg, struct aqualinkdata *aqdata) {
|
|||
// ' Heat Pump ENA '
|
||||
// 'Heat Pump Enabled'
|
||||
// Or chiller.
|
||||
heatpumpstate hpstate = HP_HEAT;
|
||||
|
||||
// are we heat pump or chiller
|
||||
if (stristr(msg,"Chiller") != NULL) {
|
||||
// NSF Should check alt_mode is Chiller and not Heat Pump
|
||||
((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode = true;
|
||||
hpstate = HP_COOL;
|
||||
}
|
||||
if (stristr(msg," ENA") != NULL) {
|
||||
updateHeatPumpLed(ENABLE, aqdata);
|
||||
updateHeatPumpLed(hpstate, ENABLE, aqdata, true);
|
||||
} else if (stristr(msg," OFF") != NULL) {
|
||||
updateHeatPumpLed(OFF, aqdata);
|
||||
updateHeatPumpLed(hpstate, OFF, aqdata, true);
|
||||
} else if (stristr(msg," ON") != NULL) {
|
||||
updateHeatPumpLed(ON, aqdata);
|
||||
updateHeatPumpLed(hpstate, ON, aqdata, true);
|
||||
}
|
||||
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Set %s to %s from message '%s'",
|
||||
((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode?((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->altlabel:aqdata->chiller_button->label,
|
||||
aqdata->chiller_button->led->state==ENABLE?"Enabled":(aqdata->chiller_button->led->state==ON?"On":"Off"),
|
||||
msg);
|
||||
LED2text(aqdata->chiller_button->led->state), msg);
|
||||
}
|
||||
|
||||
void updateHeatPumpLed(aqledstate state, struct aqualinkdata *aqdata) {
|
||||
|
||||
//void updateHeatPumpLed(bool chiller, aqledstate state, struct aqualinkdata *aqdata) {
|
||||
void updateHeatPumpLed(heatpumpstate state, aqledstate ledstate, struct aqualinkdata *aqdata, bool fromMessage)
|
||||
{
|
||||
if (aqdata->chiller_button == NULL)
|
||||
return;
|
||||
|
||||
if (aqdata->chiller_button->led->state != state) {
|
||||
aqdata->chiller_button->led->state = ON;
|
||||
// If LED state is enable (that's a reqest), so only change if off.
|
||||
// if froma displayed message, that's from ON to ENA, so set that one.
|
||||
if ( !fromMessage && ledstate == ENABLE && aqdata->chiller_button->led->state == ON) {
|
||||
//printf("**** Request from %s Heat Pump %s, currently %s, ignore!\n",fromMessage?"Display":"RS485",LED2text(ledstate),LED2text(aqdata->chiller_button->led->state) );
|
||||
return;
|
||||
}
|
||||
|
||||
if (aqdata->chiller_button->led->state != ledstate) {
|
||||
//printf("**** Heat Pump Setting to %s, from %s!\n",LED2text(ledstate),LED2text(aqdata->chiller_button->led->state));
|
||||
aqdata->chiller_button->led->state = ledstate;
|
||||
aqdata->updated = true;
|
||||
if (state == HP_COOL) {
|
||||
((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode = true;
|
||||
} else if (state == HP_HEAT) {
|
||||
((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode = false;
|
||||
}
|
||||
} else {
|
||||
//printf("**** Heat Pump %s, already %s, ignore!\n",LED2text(ledstate),LED2text(aqdata->chiller_button->led->state));
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -595,7 +595,7 @@ void iaqt_pump_update(struct aqualinkdata *aq_data, int updated) {
|
|||
|
||||
|
||||
/* Some newer revisions support pump by name and not number.
|
||||
Seen this is rev Yg
|
||||
Seen this is rev Yg Looks like this ID came in T.2g (not T.2 though)
|
||||
|
||||
Info: iAQ Touch: Page: Status (diff ID) | 0x2a\
|
||||
Info: iAQ Touch: Status page 00| Filter Pump\
|
||||
|
|
|
@ -46,13 +46,6 @@
|
|||
#define KEY_IAQTCH_LOCKOUT_PASSWD KEY_IAQTCH_KEY08
|
||||
#define KEY_IAQTCH_SET_ACQUAPURE KEY_IAQTCH_KEY09
|
||||
|
||||
// Set Point types
|
||||
typedef enum SP_TYPE{
|
||||
SP_POOL,
|
||||
SP_SPA,
|
||||
SP_CHILLER
|
||||
} SP_TYPE;
|
||||
|
||||
bool _cansend = false;
|
||||
|
||||
unsigned char _iaqt_pgm_command = NUL;
|
||||
|
|
|
@ -278,17 +278,33 @@ void set_iaqualink_aux_state(aqkey *button, bool isON) {
|
|||
_fullcmd[4] = 0x00;
|
||||
}
|
||||
|
||||
void set_iaqualink_heater_setpoint(int value, bool isPool) {
|
||||
|
||||
|
||||
if (isPool) {
|
||||
// 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;
|
||||
} else {
|
||||
_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;
|
||||
//_fullcmd[6] = value;
|
||||
|
||||
push_iaqualink_cmd(_cmd_readyCommand, 2);
|
||||
push_iaqualink_cmd(_fullcmd, 19);
|
||||
|
@ -296,6 +312,8 @@ void set_iaqualink_heater_setpoint(int value, bool isPool) {
|
|||
// 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)
|
||||
|
@ -326,9 +344,9 @@ bool process_iAqualinkStatusPacket(unsigned char *packet, int length, struct aqu
|
|||
int startIndex = 4 + 1;
|
||||
int numberBytes = packet[4];
|
||||
int offsetIndex = startIndex + numberBytes;
|
||||
bool foundSpaSP = false;
|
||||
bool foundWaterTemp = false;
|
||||
bool foundAirTemp = false;
|
||||
//bool foundSpaSP = false;
|
||||
//bool foundWaterTemp = false;
|
||||
//bool foundAirTemp = false;
|
||||
|
||||
for (int i = 0; i <= numberBytes; i++)
|
||||
{
|
||||
|
@ -338,6 +356,7 @@ bool process_iAqualinkStatusPacket(unsigned char *packet, int length, struct aqu
|
|||
|
||||
// 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;
|
||||
|
@ -345,8 +364,70 @@ bool process_iAqualinkStatusPacket(unsigned char *packet, int length, struct aqu
|
|||
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); }
|
||||
|
@ -363,7 +444,7 @@ bool process_iAqualinkStatusPacket(unsigned char *packet, int length, struct aqu
|
|||
} else if (byteType == 8 || byteType == 9) {// 8 usually, also get 9 & 14 (different spa/heater modes not sorted out yet. 14 sometimes blank as well)
|
||||
label = "Spa Htr setpoint ";
|
||||
foundSpaSP=true;
|
||||
} else if ( (/*byteType == 14 ||*/ byteType == 12) && foundSpaSP==false && byte != 0) {
|
||||
} 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
|
||||
|
@ -375,7 +456,7 @@ bool process_iAqualinkStatusPacket(unsigned char *packet, int length, struct aqu
|
|||
}
|
||||
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",
|
||||
|
|
|
@ -11,7 +11,7 @@ bool process_iaqualink_packet(unsigned char *packet, int length, struct aqualink
|
|||
bool process_iAqualinkStatusPacket(unsigned char *packet, int length, struct aqualinkdata *aq_data);
|
||||
|
||||
void set_iaqualink_aux_state(aqkey *button, bool isON);
|
||||
void set_iaqualink_heater_setpoint(int value, bool isPool);
|
||||
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)
|
||||
|
@ -385,4 +385,35 @@ 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|
|
||||
|
||||
|
||||
|
||||
*/
|
|
@ -126,9 +126,9 @@ const char* _getStatus(struct aqualinkdata *aqdata, const char *blankmsg)
|
|||
// 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 SERIAL CONNECTION";
|
||||
return "ERROR No Serial connection";
|
||||
else if ((aqdata->status_mask & ERROR_NO_DEVICE_ID) == ERROR_NO_DEVICE_ID)
|
||||
return "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)
|
||||
|
@ -138,7 +138,7 @@ const char* _getStatus(struct aqualinkdata *aqdata, const char *blankmsg)
|
|||
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";
|
||||
return "Not Connected to panel";
|
||||
}
|
||||
|
||||
if (aqdata->active_thread.thread_id != 0) {
|
||||
|
@ -209,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);
|
||||
|
@ -375,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},",
|
||||
|
@ -431,11 +435,11 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
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,
|
||||
"Chiller",
|
||||
//aqdata->chiller_state==ON?JSON_ON:JSON_OFF,
|
||||
((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode?JSON_ON:JSON_OFF,
|
||||
//aqdata->chiller_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,
|
||||
"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),
|
||||
|
@ -664,8 +668,10 @@ 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) {
|
||||
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 )
|
||||
|
@ -736,7 +742,10 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
|
|||
//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, "},");
|
||||
|
||||
|
@ -800,6 +809,18 @@ printf("Pump Type %d\n",aqdata->pumps[i].pumpType);
|
|||
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++)
|
||||
{
|
||||
|
@ -1143,13 +1164,25 @@ int json_cfg_element(char* buffer, int size, const char *name, const void *value
|
|||
int result = 0;
|
||||
|
||||
char valid_values[256];
|
||||
char adv[20];
|
||||
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);
|
||||
}
|
||||
|
||||
sprintf(adv,",\"advanced\": \"%s\"", isMASKSET(config_mask, CFG_GRP_ADVANCED)?"yes":"no");
|
||||
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){
|
||||
|
@ -1164,7 +1197,11 @@ int json_cfg_element(char* buffer, int size, const char *name, const void *value
|
|||
if (*(char **)value == NULL) {
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"\", \"type\":\"string\" %s %s}", name, (valid_val==NULL?"":valid_values),adv );
|
||||
} else {
|
||||
result = snprintf(buffer, size, ",\"%s\" : {\"value\":\"%s\", \"type\":\"string\" %s %s}", name, *(char **)value, (valid_val==NULL?"":valid_values),adv );
|
||||
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:
|
||||
|
@ -1260,13 +1297,23 @@ int build_aqualink_config_JSON(char* buffer, int size, struct aqualinkdata *aq_d
|
|||
|
||||
//#ifdef CONFIG_DEV_TEST
|
||||
for (int i=0; i <= _numCfgParams; i++) {
|
||||
if (isMASK_SET(_cfgParams[i].config_mask, CFG_HIDE) ) {
|
||||
continue;
|
||||
}
|
||||
// We can't change web_directory or port while running, so don;t even chow those options.
|
||||
// mongoose holds a pointer to the string web_directoy, so can;t change that easily while running
|
||||
// web port = well derr we are using that currently
|
||||
/*
|
||||
if ( strncasecmp(_cfgParams[i].name, CFG_N_socket_port, strlen(CFG_N_socket_port)) == 0 ||
|
||||
strncasecmp(_cfgParams[i].name, CFG_N_web_directory, strlen(CFG_N_web_directory)) == 0 ) {
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
if (isMASK_SET(_cfgParams[i].config_mask, CFG_READONLY) ) {
|
||||
// NSF in the future we should allow these to pass, but set the UI as readonly.
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -1385,7 +1432,7 @@ int build_aqualink_config_JSON(char* buffer, int size, struct aqualinkdata *aq_d
|
|||
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) {
|
||||
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
|
||||
|
@ -1403,7 +1450,7 @@ int build_aqualink_config_JSON(char* buffer, int size, struct aqualinkdata *aq_d
|
|||
} 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) {
|
||||
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
|
||||
|
|
|
@ -54,7 +54,7 @@ bool parseJSONrequest(char *buffer, struct JSONkvptr *request);
|
|||
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);
|
||||
|
@ -63,6 +63,8 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
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_ */
|
||||
|
||||
/*
|
||||
|
|
|
@ -133,10 +133,11 @@ static void ws_send(struct mg_connection *nc, char *msg)
|
|||
//LOG(NET_LOG,LOG_DEBUG, "WS: Sent %d characters '%s'\n",size, msg);
|
||||
}
|
||||
|
||||
void _broadcast_aqualinkstate_error(struct mg_connection *nc, char *msg)
|
||||
void _broadcast_aqualinkstate_error(struct mg_connection *nc, const char *msg)
|
||||
{
|
||||
struct mg_connection *c;
|
||||
char data[JSON_STATUS_SIZE];
|
||||
|
||||
build_aqualink_error_status_JSON(data, JSON_STATUS_SIZE, msg);
|
||||
|
||||
for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
|
||||
|
@ -2288,7 +2289,7 @@ f_end:
|
|||
void broadcast_aqualinkstate() {
|
||||
_aqualink_data->updated = true;
|
||||
}
|
||||
void broadcast_aqualinkstate_error(char *msg) {
|
||||
void broadcast_aqualinkstate_error(const char *msg) {
|
||||
_broadcast_aqualinkstate_error(_mgr.active_connections, msg);
|
||||
}
|
||||
void broadcast_simulator_message() {
|
||||
|
|
|
@ -28,7 +28,7 @@ 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_aqualinkstate_error(const char *msg);
|
||||
void broadcast_simulator_message();
|
||||
|
||||
|
||||
|
|
|
@ -135,11 +135,12 @@ void _logPacket(logmask_t from, unsigned char *packet_buffer, int packet_length,
|
|||
lastPacketTo = packet_buffer[PKT_DEST];
|
||||
}
|
||||
|
||||
#ifndef DUMMY_DEVICE // Not interested if in dummy_device
|
||||
if (is_read)
|
||||
LOG(from,LOG_DEBUG_SERIAL, "Serial read %d bytes\n",packet_length);
|
||||
else
|
||||
LOG(from,LOG_DEBUG_SERIAL, "Serial write %d bytes\n",packet_length);
|
||||
|
||||
#endif
|
||||
//char buff[1000];
|
||||
char buff[LARGELOGBUFFER];
|
||||
|
||||
|
|
|
@ -33,15 +33,15 @@
|
|||
#include "rs_msg_utils.h"
|
||||
|
||||
#ifdef SERIAL_LOGGER
|
||||
// Make us look lie config.c when we load config.h
|
||||
// Make us look like config.c when we load config.h so we get globals.
|
||||
#define CONFIG_C
|
||||
#endif
|
||||
#include "config.h"
|
||||
|
||||
#define SLOG_MAX 80
|
||||
#define PACKET_MAX 800
|
||||
#define PACKET_MAX 1200
|
||||
|
||||
#define VERSION "serial_logger V2.8"
|
||||
#define VERSION "serial_logger V2.9"
|
||||
|
||||
/*
|
||||
typedef enum used {
|
||||
|
@ -103,6 +103,9 @@ void intHandler(int dummy) {
|
|||
if (_playback_file) // If we are reading file, loop is irevelent
|
||||
exit(0);
|
||||
}
|
||||
bool isAqualinkDStopping() {
|
||||
return !_keepRunning;
|
||||
}
|
||||
#else
|
||||
int serial_logger (int rs_fd, char *port_name, int logLevel, int slogger_packets, char *slogger_ids)
|
||||
{
|
||||
|
@ -531,7 +534,7 @@ int main(int argc, char *argv[]) {
|
|||
fprintf(stderr, "Optional parameters are :-\n");
|
||||
fprintf(stderr, "\t-n (Do not probe panel for type/rev info)\n");
|
||||
fprintf(stderr, "\t-d (debug / print messages)\n");
|
||||
fprintf(stderr, "\t-p <number> (# packets to log, default=%d)\n",PACKET_MAX);
|
||||
fprintf(stderr, "\t-p <number> (# packets to log, default=%d, use -1 for probe cycle <quickest> )\n",PACKET_MAX);
|
||||
fprintf(stderr, "\t-i <ID> (just log specific ID, can use multiple -i. will also force -d switc)\n");
|
||||
fprintf(stderr, "\t-pi <ID> (just log specific Pantair ID, can use multiple -pi. will also force -d switch)\n");
|
||||
fprintf(stderr, "\t-r (raw)\n");
|
||||
|
@ -550,7 +553,9 @@ int main(int argc, char *argv[]) {
|
|||
if (strcmp(argv[i], "-d") == 0) {
|
||||
logLevel = LOG_DEBUG;
|
||||
} else if (strcmp(argv[i], "-p") == 0 && i+1 < argc) {
|
||||
logPackets = atoi(argv[i+1]);
|
||||
char *endptr;
|
||||
//logPackets = atoi(argv[i+1]);
|
||||
logPackets = strtol(argv[i+1], &endptr, 10);
|
||||
} else if (strcmp(argv[i], "-i") == 0 && i+1 < argc) {
|
||||
unsigned int n;
|
||||
sscanf(argv[i+1], "0x%2x", &n);
|
||||
|
@ -651,6 +656,7 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
unsigned char packet_buffer[AQ_MAXPKTLEN];
|
||||
unsigned char last_packet_buffer[AQ_MAXPKTLEN];
|
||||
unsigned char lastID = 0x00;
|
||||
unsigned char firstProbe = 0x00;
|
||||
int i = 0;
|
||||
bool found;
|
||||
serial_id_log slog[SLOG_MAX];
|
||||
|
@ -676,6 +682,14 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
bool found_pent_vsp =false;
|
||||
bool found_iAqualnk =false;
|
||||
|
||||
bool probeCycle = false;
|
||||
int probeCycleCnt = 0;
|
||||
|
||||
if (logPackets <= 0) {
|
||||
logPackets = PACKET_MAX;
|
||||
probeCycle = true;
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &start_time);
|
||||
if (timePackets) {
|
||||
clock_gettime(CLOCK_REALTIME, &packet_start_time);
|
||||
|
@ -725,6 +739,25 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
delay(1);
|
||||
} else if (packet_length > 0) {
|
||||
blankReads = 0;
|
||||
|
||||
if (probeCycle) {
|
||||
if (packet_buffer[PKT_CMD] == CMD_PROBE &&
|
||||
packet_buffer[PKT_DEST] != 0x60 &&
|
||||
packet_buffer[PKT_DEST] != DEV_MASTER &&
|
||||
firstProbe == 0x00)
|
||||
{
|
||||
firstProbe = packet_buffer[PKT_DEST];
|
||||
printf("\nFirst Probe = 0x%02hhx\n",firstProbe);
|
||||
} else if ( firstProbe != 0x00 && packet_buffer[PKT_DEST] == firstProbe && packet_buffer[PKT_CMD] == CMD_PROBE ) {
|
||||
printf("\nGot probe again after %d packets\n",received_packets);
|
||||
if (++probeCycleCnt > 2) {
|
||||
_keepRunning = false;
|
||||
}
|
||||
} else if ( firstProbe != 0x00 && packet_buffer[PKT_DEST] == firstProbe && packet_buffer[PKT_CMD] != CMD_PROBE ) {
|
||||
// Something connected to the first probe we saw, can't exit quickley
|
||||
printf("\n Someone connected to probe 0x%02hhx\n",packet_buffer[PKT_DEST]);
|
||||
}
|
||||
}
|
||||
//LOG(SLOG_LOG, LOG_DEBUG_SERIAL, "Received Packet for ID 0x%02hhx of type %s\n", packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length));
|
||||
#ifdef SERIAL_LOGGER
|
||||
if (logLevel > LOG_NOTICE)
|
||||
|
@ -945,8 +978,10 @@ int _serial_logger(int rs_fd, char *port_name, int logPackets, int logLevel, boo
|
|||
LOG(SLOG_LOG, LOG_NOTICE, "read_RS485_LX = yes\n");
|
||||
if (found_chem)
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "read_RS485_Chem = yes\n");
|
||||
if (found_iAqualnk && _panelPDA)
|
||||
if (found_iAqualnk)
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "read_RS485_iAqualink = yes\n");
|
||||
else if (!found_iAqualnk && (extID >= JANDY_DEV_AQLNK_MIN && extID <= JANDY_DEV_AQLNK_MAX))
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "enable_iaqualink = yes\n");
|
||||
|
||||
LOG(SLOG_LOG, LOG_NOTICE, "-------------------------\n");
|
||||
|
||||
|
|
|
@ -398,7 +398,8 @@ char *cleanwhitespace(char *str)
|
|||
while(end > str && isspace(*end)) end--;
|
||||
|
||||
// Write new null terminator
|
||||
*(end+1) = 0;
|
||||
if (end != (str + strlen(str) - 1) )
|
||||
*(end+1) = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
#define AQUALINKD_SHORT_NAME "AqualinkD"
|
||||
|
||||
// Use Magor . Minor . Patch
|
||||
#define AQUALINKD_VERSION "2.6.0 (dev 0.3)"
|
||||
#define AQUALINKD_VERSION "2.6.0"
|
||||
|
|
|
@ -399,10 +399,10 @@
|
|||
|
||||
if (log_element_count >= LOGS2DISPLAY) {
|
||||
try {
|
||||
console.log("Removing " + logcontainer.lastElementChild.innerHTML);
|
||||
//console.log("Removing " + logcontainer.lastElementChild.innerHTML);
|
||||
logcontainer.lastElementChild.remove();
|
||||
} catch (e) {
|
||||
console.log("ERROR Removing log '" + logcontainer.lastElementChild.innerHTML + "'");
|
||||
//console.log("ERROR Removing log '" + logcontainer.lastElementChild.innerHTML + "'");
|
||||
log_element_count++;
|
||||
}
|
||||
} else {
|
||||
|
@ -546,15 +546,15 @@
|
|||
for (var obj in _config) {
|
||||
|
||||
if (_config[obj].value !== undefined) {
|
||||
//if (_config[obj].value) {
|
||||
if (_config[obj].value) {
|
||||
json_ordered.values[obj] = _config[obj].value;
|
||||
//}
|
||||
}
|
||||
} else if (obj.toString().startsWith("button_") || obj.toString().startsWith("virtual_button_") || obj.toString().startsWith("sensor_") ) {
|
||||
for (var obj1 in _config[obj]) {
|
||||
if (obj1.toString() != "advanced") {
|
||||
//if (_config[obj][obj1].value) {
|
||||
if (_config[obj][obj1].value) {
|
||||
json_ordered.values[obj1] = _config[obj][obj1].value;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -635,6 +635,10 @@
|
|||
input.addEventListener('change', cfgValueChanged);
|
||||
input.appendChild(option);
|
||||
}
|
||||
input.addEventListener('change', cfgValueChanged);
|
||||
if (data[obj].force_restart == "yes") {
|
||||
input.addEventListener('click', cfgAlertForceRestart);
|
||||
}
|
||||
cell2.appendChild(input);
|
||||
} else if (data[obj].type == "string") {
|
||||
const input = document.createElement("input");
|
||||
|
@ -644,6 +648,9 @@
|
|||
}
|
||||
input.setAttribute('key', obj.toString());
|
||||
input.addEventListener('change', cfgValueChanged);
|
||||
if (data[obj].force_restart == "yes") {
|
||||
input.addEventListener('click', cfgAlertForceRestart);
|
||||
}
|
||||
cell2.appendChild(input);
|
||||
} else if (data[obj].type == "int") {
|
||||
const input = document.createElement("input");
|
||||
|
@ -655,6 +662,9 @@
|
|||
input.step = 1;
|
||||
input.setAttribute('key', obj.toString());
|
||||
input.addEventListener('change', cfgValueChanged);
|
||||
if (data[obj].force_restart == "yes") {
|
||||
input.addEventListener('click', cfgAlertForceRestart);
|
||||
}
|
||||
cell2.appendChild(input);
|
||||
} else if (data[obj].type == "float") {
|
||||
const input = document.createElement("input");
|
||||
|
@ -664,6 +674,9 @@
|
|||
input.step = 0.01;
|
||||
input.setAttribute('key', obj.toString());
|
||||
input.addEventListener('change', cfgValueChanged);
|
||||
if (data[obj].force_restart == "yes") {
|
||||
input.addEventListener('click', cfgAlertForceRestart);
|
||||
}
|
||||
cell2.appendChild(input);
|
||||
} else if (data[obj].type == "hex") {
|
||||
const input = document.createElement("input");
|
||||
|
@ -672,6 +685,9 @@
|
|||
input.size = 4;
|
||||
input.setAttribute('key', obj.toString());
|
||||
input.addEventListener('change', cfgValueChanged);
|
||||
if (data[obj].force_restart == "yes") {
|
||||
input.addEventListener('click', cfgAlertForceRestart);
|
||||
}
|
||||
cell2.appendChild(input);
|
||||
} else {
|
||||
cell2.textContent = data[obj].value;
|
||||
|
@ -989,8 +1005,8 @@
|
|||
break;
|
||||
case "pumpType":
|
||||
js.type = "string";
|
||||
let validvalues = ["", "JANDY ePUMP", "Pentair VS", "Pentair VF"];
|
||||
js['valid values'] = validvalues;
|
||||
//let validvalues = ["BLANK", "JANDY ePUMP", "Pentair VS", "Pentair VF"];
|
||||
//js['valid values'] = validvalues;
|
||||
break;
|
||||
case "pumpName":
|
||||
case "altLabel":
|
||||
|
@ -1208,6 +1224,14 @@
|
|||
|
||||
}
|
||||
|
||||
function cfgAlertForceRestart(event) {
|
||||
console.log("Caught event");
|
||||
var key = event.srcElement.getAttribute('key');
|
||||
var value = event.srcElement.value;
|
||||
|
||||
alert("If you change "+key+" You will need to restart AqualinkD after saving config!");
|
||||
}
|
||||
|
||||
function cfgValueChanged(event) {
|
||||
var key = event.srcElement.getAttribute('key');
|
||||
var value = event.srcElement.value;
|
||||
|
@ -1217,14 +1241,15 @@
|
|||
try {
|
||||
_config[key].value = value;
|
||||
} catch (exception) {
|
||||
console.log("Error setting cfg");
|
||||
//console.error(exception);
|
||||
//console.log("Error setting cfg '"+key+"' to '"+value+"'");
|
||||
if (key.startsWith("button_") ) {
|
||||
_config[key.slice(0, 9)][key].value = value
|
||||
} else if (key.startsWith("virtual_button_") ) {
|
||||
_config[key.slice(0, 17)][key].value = value
|
||||
} else if (key.startsWith("sensor_") ) {
|
||||
_config[key.slice(0, 9)][key].value = value
|
||||
} else {
|
||||
console.log("Error setting cfg '"+key+"' to '"+value+"'");
|
||||
}
|
||||
}
|
||||
console.log(_config);
|
||||
|
@ -1548,17 +1573,22 @@
|
|||
send_command(cmd);
|
||||
}
|
||||
|
||||
function getLatestVersion() {
|
||||
function getLatestVersion(url="https://api.github.com/repos/AqualinkD/AqualinkD/releases/latest", tryagain=true) {
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.onreadystatechange = function () {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
var JS = JSON.parse(this.responseText);
|
||||
_latestVersionAvailable = JS.tag_name.replace(/[^\d.-]/g, '');
|
||||
document.getElementById("latestaqualinkdversion").innerHTML = _latestVersionAvailable;
|
||||
|
||||
document.getElementById("latestaqualinkdversion").innerHTML = _latestVersionAvailable;
|
||||
} else if (this.readyState == 4 && this.status == 404) {
|
||||
//console.log("URL ERROR "+this.readyState+" "+this.status);
|
||||
if (tryagain) {
|
||||
// Try sfeakes repo
|
||||
getLatestVersion("https://api.github.com/repos/sfeakes/AqualinkD/releases/latest", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
xmlhttp.open("GET", "https://api.github.com/repos/sfeakes/AqualinkD/releases/latest", true);
|
||||
xmlhttp.open("GET", url);
|
||||
xmlhttp.send();
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
"Aux_V13",
|
||||
"Aux_V14",
|
||||
"Aux_V15",
|
||||
"Chiller",
|
||||
];
|
||||
|
||||
// This get's picked up by dynamic_config.js and used as mode 0
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
var _confighelp = {};
|
||||
_confighelp["panel_type"]="Your RS panel type & size. ie 4, 6, 8, 12 or 16 relates to RS4, RS6, RS8, RS12 or RS16. Must be in format XX-N ???? (XX=RS or PD, N=Circuits, ????=Combo or Only or Dual)";
|
||||
_confighelp["device_id"]="The id of the AqualinkD to use. Valid RS ID's are 0x0a 0x0b 0x09 0x08. If your panel is a PDA only model then PDA device ID is 0x60. This HAS to be an ID that's not currently used by another device (like keypad), run serial_logger if unsure";
|
||||
_confighelp["panel_type"]="Your RS panel type & size. ie 4, 6, 8, 12 or 16 relates to RS4, RS6, RS8, RS12 or RS16. Must be in format XX-N ZZZZ (XX=RS or PD, N=Circuits, ZZZ=Combo or Only or Dual)";
|
||||
_confighelp["device_id"]="The id of the AqualinkD to use, use serial_logger to find ID's. If your panel is a PDA only model then PDA device ID is 0x60. set to device_id to 0xFF for to autoconfigure all this section";
|
||||
_confighelp["mqtt_address"]="MQTT address has to be set to ip:port enable MQTT"
|
||||
_confighelp["read_RS485_swg"]="Read device information directly from RS485 bus"
|
||||
_confighelp["force_swg"]="Force any devices to be active at startup. Must set these for Home Assistant integration"
|
||||
_confighelp["enable_scheduler"]="AqualinkD's internal scheduler"
|
||||
_confighelp["event_check_use_scheduler_times"]="Turn on filter pump from events that can cause it to turn off"
|
|
@ -1005,7 +1005,7 @@
|
|||
value = '--';
|
||||
} else {
|
||||
if ((type = document.getElementById(id).getAttribute('type')) != null) {
|
||||
if (type == 'temperature' || type == 'setpoint_thermo' || type == 'setpoint_freeze')
|
||||
if (type == 'temperature' || type == 'setpoint_thermo' || type == 'setpoint_freeze' || type == 'setpoint_chiller')
|
||||
ext = '°';
|
||||
else if (type == 'setpoint_swg')
|
||||
ext = '%';
|
||||
|
@ -1098,6 +1098,10 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
function capitalizeFirstLetter(str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
||||
function formatSatus(status) {
|
||||
var index;
|
||||
var aux;
|
||||
|
@ -1171,15 +1175,23 @@
|
|||
else
|
||||
text = 'Generating';
|
||||
}
|
||||
else if (type == 'setpoint_thermo')
|
||||
else if (type == 'setpoint_thermo') {
|
||||
//if (status == 'enabled')
|
||||
text = 'Heat to ' + tile.getAttribute('setpoint');
|
||||
//else
|
||||
// text = 'Heating to ' + tile.getAttribute('setpoint'); // too large for phone
|
||||
else if (type == 'setpoint_freeze')
|
||||
}
|
||||
else if (type == 'setpoint_chiller') {
|
||||
try{
|
||||
text = capitalizeFirstLetter(tile.getAttribute("mode"))+' to ' + tile.getAttribute('setpoint');
|
||||
} catch (except){}
|
||||
//text = 'Cool to ' + tile.getAttribute('setpoint');
|
||||
}
|
||||
else if (type == 'setpoint_freeze') {
|
||||
text = 'Turn on ' + tile.getAttribute('setpoint') + "°";
|
||||
//else
|
||||
// text = "On";
|
||||
}
|
||||
}
|
||||
//document.getElementById(id + '_status').innerHTML = "On";
|
||||
} else {
|
||||
|
@ -1217,6 +1229,17 @@
|
|||
tile_icon.classList.remove("disabled");
|
||||
tile_icon.classList.remove("cool");
|
||||
tile_icon.classList.add("heat");
|
||||
} else if (status == 'on' && type == 'setpoint_chiller') {
|
||||
tile_icon.classList.remove("enabled");
|
||||
tile_icon.classList.remove("disabled");
|
||||
console.log("mode="+tile_icon.parentElement.parentElement.getAttribute("mode"));
|
||||
if ( tile_icon.parentElement.parentElement.getAttribute("mode") == "heat" ) {
|
||||
tile_icon.classList.remove("cool");
|
||||
tile_icon.classList.add("heat");
|
||||
} else {
|
||||
tile_icon.classList.remove("heat");
|
||||
tile_icon.classList.add("cool");
|
||||
}
|
||||
} else if (status == 'on') {
|
||||
tile_icon.classList.remove("enabled");
|
||||
tile_icon.classList.remove("disabled");
|
||||
|
@ -1289,7 +1312,7 @@
|
|||
} else if (object.type == 'value' || object.type == 'temperature') {
|
||||
add_tile(object.id, object.name, object.state, 'value', object.type);
|
||||
setTileValue(object.id, object.value);
|
||||
} else if (object.type == 'setpoint_thermo' || object.type == 'setpoint_swg' || object.type == 'setpoint_freeze') {
|
||||
} else if (object.type == 'setpoint_thermo' || object.type == 'setpoint_swg' || object.type == 'setpoint_freeze' || object.type == 'setpoint_chiller') {
|
||||
add_tile(object.id, object.name, object.state, 'thermostat', object.type);
|
||||
document.getElementById(object.id).setAttribute('setpoint', object.spvalue);
|
||||
setTileValue(object.id, object.value);
|
||||
|
@ -1297,13 +1320,24 @@
|
|||
} else {
|
||||
//console.log("Unknown Device");
|
||||
}
|
||||
|
||||
// Set Alternate name
|
||||
|
||||
if (object.alt_label !== undefined) {
|
||||
//console.log("Set "+object.id+" label "+object.name+" alt_label "+object.alt_label);
|
||||
document.getElementById(object.id).setAttribute('alt_label', object.alt_label);
|
||||
document.getElementById(object.id).setAttribute('label', object.name);
|
||||
//document.getElementById(object.id).setAttribute('id', object.id + '_status_line2');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function showTileOptions(show, id, contex) {
|
||||
var active_option;
|
||||
if (show == true) {
|
||||
var wrapH = document.getElementById('wrapper').clientHeight + 'px';
|
||||
if (id != null && document.getElementById(id).getAttribute('type') == 'setpoint_thermo') {
|
||||
if (id != null && (document.getElementById(id).getAttribute('type') == 'setpoint_thermo' ||
|
||||
document.getElementById(id).getAttribute('type') == 'setpoint_chiller')) {
|
||||
active_option = document.getElementById('thermostat_options');
|
||||
document.getElementById('swg_options').style.display = 'none';
|
||||
document.getElementById('pswitch_options').style.display = 'none';
|
||||
|
@ -1512,7 +1546,7 @@
|
|||
slider.max = 5;
|
||||
slider.step = 1;
|
||||
}
|
||||
} else if (type == 'setpoint_thermo') {
|
||||
} else if (type == 'setpoint_thermo' || type == 'setpoint_chiller') {
|
||||
if (_temperature_units != 'c') { // Change to DegF
|
||||
//slider.min = 36;
|
||||
//slider.max = 104;
|
||||
|
@ -1874,6 +1908,7 @@
|
|||
switch (obj.type) {
|
||||
case "setpoint_thermo":
|
||||
case "setpoint_freeze":
|
||||
case "setpoint_chiller":
|
||||
return "temperature";
|
||||
break;
|
||||
case "setpoint_swg":
|
||||
|
@ -2056,6 +2091,7 @@
|
|||
}
|
||||
break
|
||||
case "setpoint_thermo":
|
||||
case "setpoint_chiller":
|
||||
html = html + '<option value="' + V_SETPOINT + '" ' + cs_isSelected("setpoint", val1, val2) + '>Temp</option>'
|
||||
break
|
||||
case "setpoint_swg":
|
||||
|
@ -2127,6 +2163,7 @@
|
|||
if (device == obj.id) {
|
||||
switch (obj.type) {
|
||||
case "setpoint_thermo":
|
||||
case "setpoint_chiller":
|
||||
case "setpoint_freeze":
|
||||
return "/setpoint";
|
||||
break;
|
||||
|
@ -2227,6 +2264,20 @@
|
|||
setThermostatTile("Pool_Heater", data.pool_temp, data.pool_htr_set_pnt);
|
||||
setThermostatTile("Spa_Heater", data.spa_temp, data.spa_htr_set_pnt);
|
||||
setThermostatTile("Freeze_Protect", data.air_temp, data.frz_protect_set_pnt);
|
||||
|
||||
if ( data.chiller_set_pnt !== undefined ) {
|
||||
// NSF Should use spa temp if in spa mode
|
||||
if (data.leds.Spa !== undefined && data.leds.Spa == "on")
|
||||
setThermostatTile("Chiller", data.spa_temp, data.chiller_set_pnt);
|
||||
else
|
||||
setThermostatTile("Chiller", data.pool_temp, data.chiller_set_pnt);
|
||||
}
|
||||
if ( data.chiller_mode !== undefined ) {
|
||||
try{
|
||||
let elmt = document.getElementById("Chiller");
|
||||
elmt.setAttribute("mode", data.chiller_mode);
|
||||
} catch (exception){}
|
||||
}
|
||||
|
||||
setTileValue("Temperature/Air", data.air_temp);
|
||||
setTileValue("Temperature/Pool", data.pool_temp);
|
||||
|
@ -2269,6 +2320,19 @@
|
|||
//console.log("TIMER "+obj.toString()+" duration "+data.timer_durations[obj]);
|
||||
}
|
||||
|
||||
for (var obj in data.alternate_modes) {
|
||||
//console.log(obj.toString() +" "+ data.alternate_modes[obj.toString()] );
|
||||
try {
|
||||
let element = document.getElementById(obj.toString());
|
||||
let label = document.getElementById(obj.toString()+'_name');
|
||||
if ( data.alternate_modes[obj.toString()] == "on") {
|
||||
label.textContent = element.getAttribute('label')+" "+element.getAttribute('alt_label');
|
||||
} else {
|
||||
label.textContent = element.getAttribute('label');
|
||||
}
|
||||
} catch (exception){}
|
||||
}
|
||||
|
||||
for (var obj in data.light_program_names) {
|
||||
if (data.light_program_names[obj] != "") {
|
||||
var light_mode_name = data.light_program_names[obj];
|
||||
|
@ -2295,7 +2359,7 @@
|
|||
}
|
||||
} catch (e) { /*console.log(e);*/ }
|
||||
|
||||
if (light_mode_name != "-999%" && light_mode_name != "Off")
|
||||
if (light_mode_name != "-999%" && light_mode_name != "Off" && light_mode_name != "off")
|
||||
setTileOnText(obj.toString(),light_mode_name);
|
||||
|
||||
try {
|
||||
|
|
Loading…
Reference in New Issue