mirror of https://github.com/sfeakes/AqualinkD.git
Update
parent
c3e0e319b4
commit
61a09820b6
7
Makefile
7
Makefile
|
@ -14,7 +14,7 @@ AQ_PDA = true
|
|||
AQ_ONETOUCH = true
|
||||
AQ_IAQTOUCH = true
|
||||
AQ_MANAGER =true
|
||||
AQ_RS_EXTRA_OPTS = false
|
||||
#AQ_RS_EXTRA_OPTS = false
|
||||
#AQ_CONTAINER = false // this is for compiling for containers
|
||||
#AQ_MEMCMP = true // Not implimented correctly yet.
|
||||
|
||||
|
@ -76,7 +76,7 @@ endif
|
|||
# Main source files
|
||||
SRCS = aqualinkd.c utils.c config.c aq_serial.c aq_panel.c aq_programmer.c net_services.c json_messages.c rs_msg_utils.c\
|
||||
devices_jandy.c packetLogger.c devices_pentair.c color_lights.c serialadapter.c aq_timer.c aq_scheduler.c web_config.c\
|
||||
serial_logger.c mongoose.c timespec_subtract.c
|
||||
serial_logger.c mongoose.c simulator.c timespec_subtract.c
|
||||
|
||||
|
||||
AQ_FLAGS =
|
||||
|
@ -131,6 +131,7 @@ 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
|
||||
|
||||
# Build durectories
|
||||
OBJ_DIR := ./build
|
||||
|
@ -141,7 +142,7 @@ SL_OBJ_DIR := $(OBJ_DIR)/slog
|
|||
OBJ_FILES := $(patsubst %.c,$(OBJ_DIR)/%.o,$(SRCS))
|
||||
DBG_OBJ_FILES := $(patsubst %.c,$(DBG_OBJ_DIR)/%.o,$(DBG_SRC))
|
||||
SL_OBJ_FILES := $(patsubst %.c,$(SL_OBJ_DIR)/%.o,$(SL_SRC))
|
||||
|
||||
#MG_OBJ_FILES := $(patsubst %.c,$(OBJ_DIR)/%.o,$(MG_SRC))
|
||||
|
||||
# define the executable file
|
||||
MAIN = ./release/aqualinkd
|
||||
|
|
|
@ -29,12 +29,14 @@
|
|||
#define LIGHT_MODE_BUFER PTHREAD_ARG
|
||||
|
||||
typedef enum emulation_type{
|
||||
SIM_NONE = -1,
|
||||
ALLBUTTON,
|
||||
RSSADAPTER,
|
||||
ONETOUCH,
|
||||
IAQTOUCH,
|
||||
AQUAPDA, // AQUAPALM and PDA are taken as specific type.
|
||||
JANDY_DEVICE // Very rarley used.
|
||||
JANDY_DEVICE, // Very rarley used.
|
||||
SIMULATOR
|
||||
} emulation_type;
|
||||
|
||||
typedef enum {
|
||||
|
|
48
aq_serial.c
48
aq_serial.c
|
@ -336,30 +336,15 @@ int _init_serial_port(const char* tty, bool blocking, bool readahead);
|
|||
int init_serial_port(const char* tty)
|
||||
{
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
if (_aqconfig_.rs_poll_speed < 0)
|
||||
return init_blocking_serial_port(_aqconfig_.serial_port);
|
||||
else if (_aqconfig_.readahead_b4_write)
|
||||
return init_readahead_serial_port(_aqconfig_.serial_port);
|
||||
else
|
||||
return init_serial_port(_aqconfig_.serial_port);
|
||||
#elif AQ_RS_EXTRA_OPTS
|
||||
if (_aqconfig_.readahead_b4_write)
|
||||
return init_readahead_serial_port(_aqconfig_.serial_port);
|
||||
else
|
||||
if (_aqconfig_.rs_poll_speed < 0) {
|
||||
return init_blocking_serial_port(_aqconfig_.serial_port);
|
||||
}
|
||||
#else
|
||||
return init_blocking_serial_port(_aqconfig_.serial_port);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
int init_readahead_serial_port(const char* tty)
|
||||
{
|
||||
return _init_serial_port(tty, false, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
int init_blocking_serial_port(const char* tty)
|
||||
{
|
||||
_blocking_fds = _init_serial_port(tty, true, false);
|
||||
|
@ -767,14 +752,6 @@ void send_packet(int fd, unsigned char *packet, int length)
|
|||
if (nwrite != length)
|
||||
LOG(RSSD_LOG, LOG_ERR, "write to serial port failed\n");
|
||||
} else {
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
if (_aqconfig_.readahead_b4_write) {
|
||||
if (cleanOutSerial(fd, false) != 0x00) {
|
||||
LOG(RSSD_LOG, LOG_ERR, "ERROR on RS485, AqualinkD was too slow in replying to message! (please check for performance issues)\n");
|
||||
cleanOutSerial(fd, true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
int nwrite, i;
|
||||
for (i = 0; i < length; i += nwrite) {
|
||||
nwrite = write(fd, packet + i, length - i);
|
||||
|
@ -1026,25 +1003,8 @@ int get_packet(int fd, unsigned char* packet)
|
|||
|
||||
// Clean out rest of buffer, make sure their is nothing else
|
||||
/* Doesn't work for shit due to probe message speed, need to come back and re-think
|
||||
if (_aqconfig_.readahead_b4_write) {
|
||||
if (endOfPacket == true) {
|
||||
do {
|
||||
bytesRead = read(fd, &byte, 1);
|
||||
//if (bytesRead==1) { LOG(RSSD_LOG,LOG_ERR, "Cleanout buffer read 0x%02hhx\n",byte); }
|
||||
if (bytesRead==1 && byte != 0x00) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "SERIOUS ERROR on RS485, AqualinkD caught packet collision on bus, ignoring!\n");
|
||||
LOG(RSSD_LOG,LOG_ERR, "Error Cleanout read 0x%02hhx\n",byte);
|
||||
// Run the buffer out
|
||||
do {
|
||||
bytesRead = read(fd, &byte, 1);
|
||||
if (bytesRead==1) { LOG(RSSD_LOG,LOG_ERR, "Error Cleanout read 0x%02hhx\n",byte); }
|
||||
} while (bytesRead==1);
|
||||
return 0;
|
||||
}
|
||||
} while (bytesRead==1);
|
||||
}
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
//LOG(RSSD_LOG,LOG_DEBUG, "Serial checksum, length %d got 0x%02hhx expected 0x%02hhx\n", index, packet[index-3], generate_checksum(packet, index));
|
||||
if (jandyPacketStarted) {
|
||||
if (check_jandy_checksum(packet, index) != true){
|
||||
|
|
|
@ -458,7 +458,7 @@ typedef enum {
|
|||
|
||||
int init_serial_port(const char* tty);
|
||||
int init_blocking_serial_port(const char* tty);
|
||||
int init_readahead_serial_port(const char* tty);
|
||||
//int init_readahead_serial_port(const char* tty);
|
||||
|
||||
void close_serial_port(int file_descriptor);
|
||||
void close_blocking_serial_port();
|
||||
|
|
21
aqualink.h
21
aqualink.h
|
@ -138,6 +138,16 @@ typedef enum pump_type {
|
|||
} pump_type;
|
||||
*/
|
||||
|
||||
/*
|
||||
typedef enum simulator_type {
|
||||
SIM_NONE,
|
||||
SIM_ALLB,
|
||||
SIM_ONET,
|
||||
SIM_PDA,
|
||||
SIM_IAQT
|
||||
} simulator_type;
|
||||
*/
|
||||
|
||||
#define PUMP_PRIMING -1
|
||||
#define PUMP_OFFLINE -2
|
||||
#define PUMP_ERROR -3
|
||||
|
@ -227,7 +237,16 @@ struct aqualinkdata
|
|||
//unsigned short total_ordered_buttons;
|
||||
unsigned char last_packet_type;
|
||||
int swg_delayed_percent;
|
||||
bool simulate_panel;
|
||||
//bool simulate_panel; // NSF remove in future
|
||||
unsigned char simulator_packet[AQ_MAXPKTLEN+1];
|
||||
bool simulator_packet_updated;
|
||||
int simulator_packet_length;
|
||||
|
||||
//bool simulator_active; // should be redundant with other two
|
||||
unsigned char simulator_id;
|
||||
//simulator_type simulator_active;
|
||||
emulation_type simulator_active;
|
||||
|
||||
bool aqManagerActive;
|
||||
int open_websockets;
|
||||
struct programmingthread active_thread;
|
||||
|
|
129
aqualinkd.c
129
aqualinkd.c
|
@ -50,6 +50,7 @@
|
|||
#include "version.h"
|
||||
#include "rs_msg_utils.h"
|
||||
#include "serialadapter.h"
|
||||
#include "simulator.h"
|
||||
#include "debug_timer.h"
|
||||
|
||||
#ifdef AQ_MANAGER
|
||||
|
@ -743,7 +744,8 @@ void _processMessage(char *message, bool reset)
|
|||
{
|
||||
LOG(AQRS_LOG,LOG_DEBUG_SERIAL, "Ignoring '%s'\n", msg);
|
||||
//_aqualink_data.display_message = msg;
|
||||
if (in_programming_mode(&_aqualink_data) == false && _aqualink_data.simulate_panel == false &&
|
||||
//if (in_programming_mode(&_aqualink_data) == false && _aqualink_data.simulate_panel == false &&
|
||||
if (in_programming_mode(&_aqualink_data) == false &&
|
||||
stristr(msg, "JANDY AquaLinkRS") == NULL &&
|
||||
//stristr(msg, "PUMP O") == NULL &&// Catch 'PUMP ON' and 'PUMP OFF' but not 'PUMP WILL TURN ON'
|
||||
strncasecmp(msg, "PUMP O", 6) != 0 &&// Catch 'PUMP ON' and 'PUMP OFF' but not 'PUMP WILL TURN ON'
|
||||
|
@ -1059,7 +1061,6 @@ int main(int argc, char *argv[])
|
|||
char defaultCfg[] = "./aqualinkd.conf";
|
||||
char *cfgFile;
|
||||
|
||||
|
||||
//printf ("TIMER = %d\n",TIMR_LOG);
|
||||
|
||||
#ifdef AQ_MEMCMP
|
||||
|
@ -1316,14 +1317,6 @@ int startup(char *self, char *cfgFile)
|
|||
if (READ_RSDEV_SWG && _aqconfig_.swg_zero_ignore != DEFAULT_SWG_ZERO_IGNORE_COUNT)
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Ignore SWG 0 msg count = %d\n", _aqconfig_.swg_zero_ignore);
|
||||
|
||||
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
if (_aqconfig_.readahead_b4_write == true)
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Serial Read Ahead Write = %s\n", bool2text(_aqconfig_.readahead_b4_write));
|
||||
if (_aqconfig_.prioritize_ack == true)
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Serial Prioritize Ack = %s\n", bool2text(_aqconfig_.prioritize_ack));
|
||||
#endif
|
||||
|
||||
if (_aqconfig_.ftdi_low_latency == true)
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Serial FTDI low latency = %s\n", bool2text(_aqconfig_.ftdi_low_latency));
|
||||
|
||||
|
@ -1342,13 +1335,6 @@ int startup(char *self, char *cfgFile)
|
|||
LOG(AQUA_LOG,LOG_NOTICE, "RS Poll Speed = %d\n", _aqconfig_.rs_poll_speed);
|
||||
#endif
|
||||
|
||||
#if defined AQ_RS_EXTRA_OPTS && defined AQ_NO_THREAD_NETSERVICE
|
||||
if (_aqconfig_.rs_poll_speed < 0 && _aqconfig_.readahead_b4_write) {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Serial Read Ahead Write is not valid when using Negative RS Poll Speed, turning Serial Read Ahead Write off\n");
|
||||
_aqconfig_.readahead_b4_write = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
//for (i = 0; i < TOTAL_BUTONS; i++)
|
||||
for (i = 0; i < _aqualink_data.total_buttons; i++)
|
||||
{
|
||||
|
@ -1451,6 +1437,18 @@ void caculate_ack_packet(int rs_fd, unsigned char *packet_buffer, emulation_type
|
|||
//DEBUG_TIMER_STOP(_rs_packet_timer,AQUA_LOG,"PDA Emulation type Processed packet in");
|
||||
break;
|
||||
#endif
|
||||
case SIMULATOR:
|
||||
if (_aqualink_data.simulator_active == ALLBUTTON) {
|
||||
send_extended_ack(rs_fd, (packet_buffer[PKT_CMD]==CMD_MSG_LONG?ACK_SCREEN_BUSY_SCROLL:ACK_NORMAL), pop_simulator_cmd(packet_buffer[PKT_CMD]));
|
||||
} else if (_aqualink_data.simulator_active == ONETOUCH) {
|
||||
send_extended_ack(rs_fd, ACK_ONETOUCH, pop_simulator_cmd(packet_buffer[PKT_CMD]));
|
||||
} else if (_aqualink_data.simulator_active == IAQTOUCH) {
|
||||
|
||||
} else {
|
||||
// SHOW SOME ERROR
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Can't caculate ACK, No idea what packet this source packet was for!\n");
|
||||
//DEBUG_TIMER_STOP(_rs_packet_timer,AQUA_LOG,"Unknown Emulation type Processed packet in");
|
||||
|
@ -1507,7 +1505,7 @@ void main_loop()
|
|||
int blank_read_reconnect = MAX_ZERO_READ_BEFORE_RECONNECT_BLOCKING; // Will get reset if non blocking
|
||||
|
||||
sprintf(_aqualink_data.last_display_message, "%s", "Connecting to Control Panel");
|
||||
_aqualink_data.simulate_panel = false;
|
||||
//_aqualink_data.simulate_panel = false;
|
||||
_aqualink_data.active_thread.thread_id = 0;
|
||||
_aqualink_data.air_temp = TEMP_UNKNOWN;
|
||||
_aqualink_data.pool_temp = TEMP_UNKNOWN;
|
||||
|
@ -1528,6 +1526,8 @@ void main_loop()
|
|||
_aqualink_data.open_websockets = 0;
|
||||
_aqualink_data.ph = TEMP_UNKNOWN;
|
||||
_aqualink_data.orp = TEMP_UNKNOWN;
|
||||
_aqualink_data.simulator_id = NUL;
|
||||
_aqualink_data.simulator_active = SIM_NONE;
|
||||
|
||||
pthread_mutex_init(&_aqualink_data.active_thread.thread_mutex, NULL);
|
||||
pthread_cond_init(&_aqualink_data.active_thread.thread_cond, NULL);
|
||||
|
@ -1636,11 +1636,6 @@ void main_loop()
|
|||
LOG(AQUA_LOG,LOG_NOTICE, "Waiting for Control Panel probe\n");
|
||||
i=0;
|
||||
|
||||
// Turn off read ahead while dealing with probes
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
bool read_ahead = _aqconfig_.readahead_b4_write;
|
||||
_aqconfig_.readahead_b4_write = false;
|
||||
#endif
|
||||
// Loop until we get the probe messages, that means we didn;t start too soon after last shutdown.
|
||||
while ( (got_probe == false || got_probe_rssa == false || got_probe_extended == false ) && _keepRunning == true)
|
||||
{
|
||||
|
@ -1755,11 +1750,6 @@ void main_loop()
|
|||
*
|
||||
*/
|
||||
|
||||
//int max_blank_read = 0;
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
_aqconfig_.readahead_b4_write = read_ahead;
|
||||
#endif
|
||||
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Starting communication with Control Panel\n");
|
||||
|
||||
// Not the best way to do this, but ok for moment
|
||||
|
@ -1825,7 +1815,6 @@ void main_loop()
|
|||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
if (_aqconfig_.rs_poll_speed < 0) {
|
||||
#else
|
||||
//if (!_aqconfig_.readahead_b4_write) {
|
||||
if (serial_blockingmode() && (packet_length == AQSERR_READ || packet_length == AQSERR_TIMEOUT) ) {
|
||||
#endif
|
||||
LOG(AQUA_LOG,LOG_ERR, "Nothing read on blocking serial port\n");
|
||||
|
@ -1849,21 +1838,40 @@ void main_loop()
|
|||
blank_read = 0;
|
||||
//changed = false;
|
||||
|
||||
if (_aqualink_data.simulator_active != SIM_NONE) {
|
||||
// Check if we have a valid connection
|
||||
if ( _aqualink_data.simulator_id != NUL && packet_buffer[PKT_DEST] == _aqualink_data.simulator_id) {
|
||||
// Action comand and Send to web
|
||||
processSimulatorPacket(packet_buffer, packet_length, &_aqualink_data);
|
||||
caculate_ack_packet(rs_fd, packet_buffer, SIMULATOR);
|
||||
DEBUG_TIMER_STOP(_rs_packet_timer,AQUA_LOG,"Simulator Emulation Processed packet in");
|
||||
}
|
||||
else if ( _aqualink_data.simulator_id == NUL && packet_buffer[PKT_CMD] == CMD_PROBE ) {
|
||||
// Check it's a probe we are after
|
||||
//if (_aqualink_data.simulator_active == ONETOUCH && packet_buffer[PKT_DEST] >= 0x40 && packet_buffer[PKT_DEST] <= 0x43 && packet_buffer[PKT_DEST] != _aqconfig_.extended_device_id) {
|
||||
if ( (_aqualink_data.simulator_active == ONETOUCH && packet_buffer[PKT_DEST] >= 0x40 && packet_buffer[PKT_DEST] <= 0x43) ||
|
||||
(_aqualink_data.simulator_active == ALLBUTTON && packet_buffer[PKT_DEST] >= 0x08 && packet_buffer[PKT_DEST] <= 0x0a)
|
||||
) {
|
||||
_aqualink_data.simulator_id = packet_buffer[PKT_DEST];
|
||||
// reply to probe
|
||||
LOG(SIM_LOG,LOG_NOTICE, "Got probe on '0x%02hhx', using for simulator ID\n",packet_buffer[PKT_DEST]);
|
||||
processSimulatorPacket(packet_buffer, packet_length, &_aqualink_data);
|
||||
caculate_ack_packet(rs_fd, packet_buffer, SIMULATOR);
|
||||
} else {
|
||||
LOG(SIM_LOG,LOG_INFO, "Got probe on '0x%02hhx' Still waiting for valid simulator probe\n",packet_buffer[PKT_DEST]);
|
||||
}
|
||||
DEBUG_TIMER_STOP(_rs_packet_timer,AQUA_LOG,"Simulator Emulation Processed packet in");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (packet_length > 0 && packet_buffer[PKT_DEST] == _aqconfig_.device_id && getProtocolType(packet_buffer) == JANDY)
|
||||
{
|
||||
if (getLogLevel(AQUA_LOG) >= LOG_DEBUG) {
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "RS received packet of type %s length %d\n", get_packet_type(packet_buffer, packet_length), packet_length);
|
||||
logPacketRead(packet_buffer, packet_length);
|
||||
}
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
// If we did not process the packet, above we need to record it for the caculate_ack_packet call.
|
||||
// Should find a better place to put this, but since prioritize_ack is expermental it's ok for now.
|
||||
// NSF We shouldn;t need to do the same for rssa / onetouch / iaqtouch and probably rssaadapter since they don;t queue commands & programming commands.
|
||||
if (_aqconfig_.prioritize_ack) {
|
||||
_aqualink_data.last_packet_type = packet_buffer[PKT_CMD];
|
||||
else
|
||||
#endif
|
||||
_aqualink_data.updated = process_packet(packet_buffer, packet_length);
|
||||
_aqualink_data.updated = process_packet(packet_buffer, packet_length);
|
||||
|
||||
#ifdef AQ_PDA
|
||||
if (isPDA_PANEL)
|
||||
|
@ -1872,57 +1880,24 @@ void main_loop()
|
|||
#endif
|
||||
caculate_ack_packet(rs_fd, packet_buffer, ALLBUTTON);
|
||||
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
if (_aqconfig_.prioritize_ack)
|
||||
_aqualink_data.updated = process_packet(packet_buffer, packet_length);
|
||||
#endif
|
||||
DEBUG_TIMER_STOP(_rs_packet_timer,AQUA_LOG,"AllButton Emulation Processed packet in");
|
||||
}
|
||||
else if (packet_length > 0 && isRSSA_ENABLED && packet_buffer[PKT_DEST] == _aqconfig_.rssa_device_id && getProtocolType(packet_buffer) == JANDY) {
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
if (_aqconfig_.prioritize_ack) {
|
||||
caculate_ack_packet(rs_fd, packet_buffer, RSSADAPTER);
|
||||
_aqualink_data.updated = process_rssadapter_packet(packet_buffer, packet_length, &_aqualink_data);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
_aqualink_data.updated = process_rssadapter_packet(packet_buffer, packet_length, &_aqualink_data);
|
||||
caculate_ack_packet(rs_fd, packet_buffer, RSSADAPTER);
|
||||
}
|
||||
_aqualink_data.updated = process_rssadapter_packet(packet_buffer, packet_length, &_aqualink_data);
|
||||
caculate_ack_packet(rs_fd, packet_buffer, RSSADAPTER);
|
||||
DEBUG_TIMER_STOP(_rs_packet_timer,AQUA_LOG,"SerialAdapter Emulation Processed packet in");
|
||||
}
|
||||
#ifdef AQ_ONETOUCH
|
||||
else if (packet_length > 0 && isONET_ENABLED && packet_buffer[PKT_DEST] == _aqconfig_.extended_device_id && getProtocolType(packet_buffer) == JANDY) {
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
if (_aqconfig_.prioritize_ack) {
|
||||
set_onetouch_lastmsg(packet_buffer[PKT_CMD]);
|
||||
caculate_ack_packet(rs_fd, packet_buffer, ONETOUCH);
|
||||
_aqualink_data.updated = process_onetouch_packet(packet_buffer, packet_length, &_aqualink_data);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
_aqualink_data.updated = process_onetouch_packet(packet_buffer, packet_length, &_aqualink_data);
|
||||
caculate_ack_packet(rs_fd, packet_buffer, ONETOUCH);
|
||||
}
|
||||
_aqualink_data.updated = process_onetouch_packet(packet_buffer, packet_length, &_aqualink_data);
|
||||
caculate_ack_packet(rs_fd, packet_buffer, ONETOUCH);
|
||||
DEBUG_TIMER_STOP(_rs_packet_timer,AQUA_LOG,"OneTouch Emulation Processed packet in");
|
||||
}
|
||||
#endif
|
||||
#ifdef AQ_IAQTOUCH
|
||||
else if (packet_length > 0 && isIAQT_ENABLED && packet_buffer[PKT_DEST] == _aqconfig_.extended_device_id && getProtocolType(packet_buffer) == JANDY) {
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
if (_aqconfig_.prioritize_ack) {
|
||||
set_iaqtouch_lastmsg(packet_buffer[PKT_CMD]);
|
||||
caculate_ack_packet(rs_fd, packet_buffer, IAQTOUCH);
|
||||
_aqualink_data.updated = process_iaqtouch_packet(packet_buffer, packet_length, &_aqualink_data);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
_aqualink_data.updated = process_iaqtouch_packet(packet_buffer, packet_length, &_aqualink_data);
|
||||
caculate_ack_packet(rs_fd, packet_buffer, IAQTOUCH);
|
||||
}
|
||||
_aqualink_data.updated = process_iaqtouch_packet(packet_buffer, packet_length, &_aqualink_data);
|
||||
caculate_ack_packet(rs_fd, packet_buffer, IAQTOUCH);
|
||||
DEBUG_TIMER_STOP(_rs_packet_timer,AQUA_LOG,"AquaTouch Emulation Processed packet in");
|
||||
}
|
||||
#endif
|
||||
|
|
15
config.c
15
config.c
|
@ -138,13 +138,6 @@ void init_parameters (struct aqconfig * parms)
|
|||
|
||||
parms->sync_panel_time = true;
|
||||
|
||||
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
// Default parameters for threading and USB blocking
|
||||
parms->readahead_b4_write = false;
|
||||
parms->prioritize_ack = false;
|
||||
#endif
|
||||
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
parms->rs_poll_speed = DEFAULT_POLL_SPEED;
|
||||
parms->thread_netservices = true;
|
||||
|
@ -589,14 +582,6 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
|
|||
} else if (strncasecmp (param, "display_warnings_in_web", 23) == 0) {
|
||||
_aqconfig_.display_warnings_web = text2bool(value);
|
||||
rtn=true;
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
} else if (strncasecmp (param, "serial_readahead_b4_write", 25) == 0) {
|
||||
_aqconfig_.readahead_b4_write = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "prioritize_ack", 14) == 0) {
|
||||
_aqconfig_.prioritize_ack = text2bool(value);
|
||||
rtn=true;
|
||||
#endif
|
||||
} else if (strncasecmp (param, "mqtt_timed_update", 17) == 0) {
|
||||
_aqconfig_.mqtt_timed_update = text2bool(value);
|
||||
rtn=true;
|
||||
|
|
2
config.h
2
config.h
|
@ -85,10 +85,12 @@ struct aqconfig
|
|||
bool log_raw_bytes; // Read as bytes
|
||||
unsigned char RSSD_LOG_filter;
|
||||
//bool log_raw_RS_bytes;
|
||||
/*
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
bool readahead_b4_write;
|
||||
bool prioritize_ack;
|
||||
#endif
|
||||
*/
|
||||
bool mqtt_timed_update;
|
||||
bool sync_panel_time;
|
||||
bool enable_scheduler;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "version.h"
|
||||
#include "aq_timer.h"
|
||||
#include "aq_programmer.h"
|
||||
#include "rs_msg_utils.h"
|
||||
|
||||
//#define test_message "{\"type\": \"status\",\"version\": \"8157 REV MMM\",\"date\": \"09/01/16 THU\",\"time\": \"1:16 PM\",\"temp_units\": \"F\",\"air_temp\": \"96\",\"pool_temp\": \"86\",\"spa_temp\": \" \",\"battery\": \"ok\",\"pool_htr_set_pnt\": \"85\",\"spa_htr_set_pnt\": \"99\",\"freeze_protection\": \"off\",\"frz_protect_set_pnt\": \"0\",\"leds\": {\"pump\": \"on\",\"spa\": \"off\",\"aux1\": \"off\",\"aux2\": \"off\",\"aux3\": \"off\",\"aux4\": \"off\",\"aux5\": \"off\",\"aux6\": \"off\",\"aux7\": \"off\",\"pool_heater\": \"off\",\"spa_heater\": \"off\",\"solar_heater\": \"off\"}}"
|
||||
//#define test_labels "{\"type\": \"aux_labels\",\"aux1_label\": \"Cleaner\",\"aux2_label\": \"Waterfall\",\"aux3_label\": \"Spa Blower\",\"aux4_label\": \"Pool Light\",\"aux5_label\": \"Spa Light\",\"aux6_label\": \"Unassigned\",\"aux7_label\": \"Unassigned\"}"
|
||||
|
@ -91,10 +92,12 @@ int build_logmsg_JSON(char *dest, int loglevel, const char *src, int dest_len, i
|
|||
|
||||
const char* _getStatus(struct aqualinkdata *aqdata, const char *blankmsg)
|
||||
{
|
||||
/*
|
||||
if (aqdata->active_thread.thread_id != 0 && !aqdata->simulate_panel) {
|
||||
//return JSON_PROGRAMMING;
|
||||
return programtypeDisplayName(aqdata->active_thread.ptype);
|
||||
}
|
||||
*/
|
||||
|
||||
//if (aqdata->last_message != NULL && stristr(aqdata->last_message, "SERVICE") != NULL ) {
|
||||
if (aqdata->service_mode_state == ON) {
|
||||
|
@ -516,6 +519,7 @@ int build_aqualink_aqmanager_JSON(struct aqualinkdata *aqdata, char* buffer, int
|
|||
length += logmaskjsonobject(PROG_LOG, buffer+length);
|
||||
length += logmaskjsonobject(DBGT_LOG, buffer+length);
|
||||
length += logmaskjsonobject(TIMR_LOG, buffer+length);
|
||||
length += logmaskjsonobject(SIM_LOG, buffer+length);
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
length += sprintf(buffer+length, "]");
|
||||
|
@ -710,6 +714,40 @@ int build_aux_labels_JSON(struct aqualinkdata *aqdata, char* buffer, int size)
|
|||
//return strlen(buffer);
|
||||
}
|
||||
|
||||
int build_aqualink_simulator_packet_JSON(struct aqualinkdata *aqdata, char* buffer, int size)
|
||||
{
|
||||
memset(&buffer[0], 0, size);
|
||||
int length = 0;
|
||||
int i;
|
||||
|
||||
length += sprintf(buffer+length, "{\"type\": \"simpacket\"");
|
||||
|
||||
length += sprintf(buffer+length, ",\"raw\": [");
|
||||
for (i=0; i < aqdata->simulator_packet_length; i++)
|
||||
{
|
||||
length += sprintf(buffer+length, "\"0x%02hhx\",", aqdata->simulator_packet[i]);
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
length += sprintf(buffer+length, "]");
|
||||
|
||||
length += sprintf(buffer+length, ",\"dec\": [");
|
||||
for (i=0; i < aqdata->simulator_packet_length; i++)
|
||||
{
|
||||
length += sprintf(buffer+length, "%d,", aqdata->simulator_packet[i]);
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
|
||||
length += sprintf(buffer+length, "]");
|
||||
|
||||
length += sprintf(buffer+length, "}");
|
||||
|
||||
//printf("Buffer=%d, used=%d, OUT='%s'\n",size,length,buffer);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// WS Received '{"parameter":"SPA_HTR","value":99}'
|
||||
// WS Received '{"command":"KEY_HTR_POOL"}'
|
||||
// WS Received '{"command":"GET_AUX_LABELS"}'
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#define JSON_LABEL_SIZE 600
|
||||
#define JSON_BUFFER_SIZE 5120
|
||||
#define JSON_STATUS_SIZE 2048
|
||||
#define JSON_SIMULATOR_SIZE 2048
|
||||
|
||||
#define JSON_MQTT_MSG_SIZE 100
|
||||
|
||||
|
@ -57,6 +58,7 @@ int build_aqualink_aqmanager_JSON(struct aqualinkdata *aqdata, char* buffer, int
|
|||
//int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char* buffer, int size, bool homekit);
|
||||
//int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch1, int programable_switch2, char* buffer, int size, bool homekit);
|
||||
int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool homekit);
|
||||
int build_aqualink_simulator_packet_JSON(struct aqualinkdata *aqdata, char* buffer, int size);
|
||||
|
||||
#endif /* JSON_MESSAGES_H_ */
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "aq_timer.h"
|
||||
#include "aq_scheduler.h"
|
||||
#include "rs_msg_utils.h"
|
||||
#include "simulator.h"
|
||||
#include "version.h"
|
||||
|
||||
#ifdef AQ_PDA
|
||||
|
@ -141,6 +142,24 @@ void _broadcast_aqualinkstate_error(struct mg_connection *nc, char *msg)
|
|||
// Maybe enhacment in future to sent error messages to MQTT
|
||||
}
|
||||
|
||||
|
||||
void _broadcast_simulator_message(struct mg_connection *nc) {
|
||||
struct mg_connection *c;
|
||||
char data[JSON_SIMULATOR_SIZE];
|
||||
|
||||
build_aqualink_simulator_packet_JSON(_aqualink_data, data, JSON_SIMULATOR_SIZE);
|
||||
|
||||
for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
|
||||
if (is_websocket(c) && is_websocket_simulator(c)) {
|
||||
ws_send(c, data);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(NET_LOG,LOG_DEBUG, "Sent to simulator '%s'\n",data);
|
||||
|
||||
_aqualink_data->simulator_packet_updated = false;
|
||||
}
|
||||
|
||||
#ifdef AQ_MANAGER
|
||||
|
||||
#define WS_LOG_LENGTH 200
|
||||
|
@ -421,7 +440,8 @@ void _broadcast_aqualinkstate(struct mg_connection *nc)
|
|||
#endif
|
||||
|
||||
for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
|
||||
if (is_websocket(c))
|
||||
//if (is_websocket(c) && !is_websocket_simulator(c)) // No need to broadcast status messages to simulator.
|
||||
if (is_websocket(c)) // All button simulator needs status messages
|
||||
ws_send(c, data);
|
||||
#ifndef MG_DISABLE_MQTT
|
||||
else if (is_mqtt(c))
|
||||
|
@ -965,11 +985,24 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
return uSetSchedules;
|
||||
} else if (strncmp(ri1, "schedules", 9) == 0) {
|
||||
return uSchedules;
|
||||
} else if (strncmp(ri1, "simulator", 9) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
} else if (strncmp(ri1, "simulator/onetouch", 18) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
LOG(NET_LOG,LOG_NOTICE, "Received request to start Onetouch Simulator!\n");
|
||||
_aqualink_data->simulator_active = ONETOUCH;
|
||||
return uSimulator;
|
||||
} else if (strncmp(ri1, "simulator/allbutton", 19) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
LOG(NET_LOG,LOG_NOTICE, "Received request to start AllButton Simulator!\n");
|
||||
_aqualink_data->simulator_active = ALLBUTTON;
|
||||
return uSimulator;
|
||||
/*
|
||||
} else if (strncmp(ri1, "simulator", 9) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
return uSimulator;*/
|
||||
} else if (strncmp(ri1, "simcmd", 10) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
simulator_send_cmd((unsigned char)value);
|
||||
return uActioned;
|
||||
/*
|
||||
} else if (strncmp(ri1, "rawcommand", 10) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
aq_send_cmd((unsigned char)value);
|
||||
return uActioned;
|
||||
return uActioned;*/
|
||||
#ifdef AQ_MANAGER
|
||||
} else if (strncmp(ri1, "aqmanager", 9) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
return uAQmanager;
|
||||
|
@ -1571,7 +1604,11 @@ void action_websocket_request(struct mg_connection *nc, struct websocket_message
|
|||
{
|
||||
LOG(NET_LOG,LOG_DEBUG, "Started Simulator Mode\n");
|
||||
set_websocket_simulator(nc);
|
||||
_aqualink_data->simulate_panel = true;
|
||||
//_aqualink_data->simulate_panel = true;
|
||||
// Clear simulator ID incase sim type changes
|
||||
_aqualink_data->simulator_id = NUL;
|
||||
LOG(NET_LOG,LOG_ERR, "Started Simulator Mode, code removed for dubug, put back in\n");
|
||||
|
||||
DEBUG_TIMER_START(&tid);
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
build_aqualink_status_JSON(_aqualink_data, message, JSON_BUFFER_SIZE);
|
||||
|
@ -1713,9 +1750,9 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
|||
if (is_websocket(nc)) {
|
||||
_aqualink_data->open_websockets--;
|
||||
LOG(NET_LOG,LOG_DEBUG, "-- Websocket left\n");
|
||||
// Need something below to detect is_websocket_simulator() and turn off aq_data.simulate_panel
|
||||
if (is_websocket_simulator(nc)) {
|
||||
_aqualink_data->simulate_panel = false;
|
||||
_aqualink_data->simulator_active = SIM_NONE;
|
||||
_aqualink_data->simulator_id = NUL;
|
||||
LOG(NET_LOG,LOG_DEBUG, "Stoped Simulator Mode\n");
|
||||
} else if (is_websocket_aqmanager(nc)) {
|
||||
_aqualink_data->aqManagerActive = false;
|
||||
|
@ -1930,9 +1967,9 @@ void *net_services_thread( void *ptr )
|
|||
while (_keepNetServicesRunning == true)
|
||||
{
|
||||
//poll_net_services(&_mgr, 10);
|
||||
// Shorten poll cycle when logging messages to WS
|
||||
//mg_mgr_poll(&_mgr, (_aqualink_data->aqManagerActive)?50:100);
|
||||
mg_mgr_poll(&_mgr, 100);
|
||||
// Shorten poll cycle when in simulator mode
|
||||
mg_mgr_poll(&_mgr, (_aqualink_data->simulator_active != SIM_NONE)?10:100);
|
||||
//mg_mgr_poll(&_mgr, 100);
|
||||
|
||||
if (aqdata->updated == true /*|| _broadcast == true*/) {
|
||||
//LOG(NET_LOG,LOG_DEBUG, "********** Broadcast ************\n");
|
||||
|
@ -1940,10 +1977,13 @@ void *net_services_thread( void *ptr )
|
|||
aqdata->updated = false;
|
||||
}
|
||||
#ifdef AQ_MANAGER
|
||||
if ( ! broadcast_systemd_logmessages(_aqualink_data->aqManagerActive)) {
|
||||
if ( ! broadcast_systemd_logmessages(aqdata->aqManagerActive)) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Couldn't open systemd journal log\n");
|
||||
}
|
||||
#endif
|
||||
if (aqdata->simulator_active != SIM_NONE && aqdata->simulator_packet_updated == true ) {
|
||||
_broadcast_simulator_message(_mgr.active_connections);
|
||||
}
|
||||
}
|
||||
|
||||
f_end:
|
||||
|
@ -1965,6 +2005,10 @@ void broadcast_aqualinkstate() {
|
|||
void broadcast_aqualinkstate_error(char *msg) {
|
||||
_broadcast_aqualinkstate_error(_mgr.active_connections, msg);
|
||||
}
|
||||
void broadcast_simulator_message() {
|
||||
_aqualink_data->simulator_packet_updated = true;
|
||||
}
|
||||
|
||||
|
||||
void stop_net_services() {
|
||||
_keepNetServicesRunning = false;
|
||||
|
@ -2016,6 +2060,11 @@ void broadcast_aqualinkstate_error(/*struct mg_connection *nc,*/ char *msg)
|
|||
}
|
||||
LOG(NET_LOG,LOG_NOTICE, "Broadcast error to network\n");
|
||||
}
|
||||
void broadcast_simulator_message() {
|
||||
if ( ! _aqconfig_.thread_netservices) {
|
||||
return _broadcast_simulator_message();
|
||||
}
|
||||
}
|
||||
time_t poll_net_services(/*struct mg_mgr *mgr,*/ int timeout_ms)
|
||||
{
|
||||
if (timeout_ms < 0)
|
||||
|
|
|
@ -29,6 +29,7 @@ void stop_net_services();
|
|||
time_t poll_net_services(int timeout_ms);
|
||||
void broadcast_aqualinkstate();
|
||||
void broadcast_aqualinkstate_error(char *msg);
|
||||
void broadcast_simulator_message();
|
||||
|
||||
// superseded with systemd/sd-journal
|
||||
//void broadcast_log(char *msg);
|
||||
|
|
Binary file not shown.
|
@ -132,8 +132,6 @@ report_zero_pool_temp = no
|
|||
#serial_debug_filter = 0x00
|
||||
|
||||
# Not documented. These are experimental. Will change how RS485 / Serial works, Only use if asked to for problem solving purposes.
|
||||
#serial_readahead_b4_write = yes
|
||||
#prioritize_ack = yes
|
||||
rs485_frame_delay = 4
|
||||
|
||||
# Get rid of the startup warning message about no low latency. BETTER option is to buy a better adapter.
|
||||
|
|
Binary file not shown.
|
@ -364,9 +364,6 @@ int main(int argc, char *argv[]) {
|
|||
bool errorMonitor = false;
|
||||
|
||||
// aq_serial.c uses the following
|
||||
#ifdef AQ_RS_EXTRA_OPTS
|
||||
_aqconfig_.readahead_b4_write = false;
|
||||
#endif
|
||||
_aqconfig_.log_protocol_packets = false;
|
||||
_aqconfig_.log_raw_bytes = false;
|
||||
_aqconfig_.ftdi_low_latency = true;
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aqualink.h"
|
||||
#include "net_services.h"
|
||||
#include "packetLogger.h"
|
||||
|
||||
#define MAX_STACK 20
|
||||
int _sim_stack_place = 0;
|
||||
unsigned char _commands[MAX_STACK];
|
||||
|
||||
bool push_simulator_cmd(unsigned char cmd);
|
||||
|
||||
int simulator_cmd_length()
|
||||
{
|
||||
return _sim_stack_place;
|
||||
}
|
||||
|
||||
// External command
|
||||
void simulator_send_cmd(unsigned char cmd)
|
||||
{
|
||||
push_simulator_cmd(cmd);
|
||||
}
|
||||
|
||||
bool push_simulator_cmd(unsigned char cmd)
|
||||
{
|
||||
if (_sim_stack_place < MAX_STACK) {
|
||||
_commands[_sim_stack_place] = cmd;
|
||||
_sim_stack_place++;
|
||||
} else {
|
||||
LOG(SIM_LOG, LOG_ERR, "Command queue overflow, too many unsent commands to RS control panel\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char pop_simulator_cmd(unsigned char receive_type)
|
||||
{
|
||||
unsigned char cmd = NUL;
|
||||
|
||||
if (_sim_stack_place > 0 && receive_type == CMD_STATUS ) {
|
||||
cmd = _commands[0];
|
||||
_sim_stack_place--;
|
||||
memmove(&_commands[0], &_commands[1], sizeof(unsigned char) * _sim_stack_place ) ;
|
||||
}
|
||||
|
||||
LOG(SIM_LOG,LOG_DEBUG, "Sending '0x%02hhx' to controller\n", cmd);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
bool processSimulatorPacket(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
// copy packed into buffer to be sent to web
|
||||
//memset(aqdata->simulator_packet, 0, sizeof aqdata->simulator_packet);
|
||||
memcpy(aqdata->simulator_packet, packet, packet_length);
|
||||
aqdata->simulator_packet_length = packet_length;
|
||||
|
||||
if ( getLogLevel(SIM_LOG) >= LOG_DEBUG ) {
|
||||
char buff[1000];
|
||||
//sprintf("Sending control command:")
|
||||
beautifyPacket(buff, packet, packet_length, false);
|
||||
LOG(SIM_LOG,LOG_DEBUG, "Received message : %s", buff);
|
||||
}
|
||||
|
||||
broadcast_simulator_message();
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef SIMULATOR_H_
|
||||
#define SIMULATOR_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool processSimulatorPacket(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
//unsigned char pop_simulator_cmd(struct aqualinkdata *aq_data);
|
||||
unsigned char pop_simulator_cmd(unsigned char receive_type);
|
||||
int simulator_cmd_length();
|
||||
//bool push_simulator_cmd(unsigned char cmd);
|
||||
void simulator_send_cmd(unsigned char cmd);
|
||||
|
||||
#endif // SIMULATOR_H_
|
3
utils.c
3
utils.c
|
@ -322,6 +322,9 @@ const char* logmask2name(int16_t from)
|
|||
case TIMR_LOG:
|
||||
return "Schd/Timer:";
|
||||
break;
|
||||
case SIM_LOG:
|
||||
return "Simulator: ";
|
||||
break;
|
||||
case AQUA_LOG:
|
||||
default:
|
||||
return "AqualinkD: ";
|
||||
|
|
1
utils.h
1
utils.h
|
@ -42,6 +42,7 @@
|
|||
#define PROG_LOG (1 << 10) // Programmer
|
||||
#define DBGT_LOG (1 << 11) // Debug Timer
|
||||
#define TIMR_LOG (1 << 12) // Timers
|
||||
#define SIM_LOG (1 << 13) // Simulator
|
||||
|
||||
// Set scheduler log to timer log
|
||||
#define SCHD_LOG TIMR_LOG
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
|
||||
#define AQUALINKD_NAME "Aqualink Daemon"
|
||||
#define AQUALINKD_VERSION "2.3.3"
|
||||
#define AQUALINKD_VERSION "2.3.4"
|
||||
|
|
|
@ -0,0 +1,668 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang='en'>
|
||||
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=windows-1252'>
|
||||
<title>AqualinkD Simulator</title>
|
||||
<meta name='viewport' content='width=device-width'>
|
||||
<meta name='apple-mobile-web-app-capable' content='yes'>
|
||||
<meta name='apple-mobile-web-app-status-bar-style' content='black'>
|
||||
<meta name='apple-mobile-web-app-status-bar-style' content='black'>
|
||||
<link href="aqualinkd.png" rel="apple-touch-icon">
|
||||
<link href="aqualinkd.png" rel="icon">
|
||||
<style>
|
||||
html {}
|
||||
|
||||
body {
|
||||
font-family: 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif;
|
||||
font-weight: 300;
|
||||
background-color: white;
|
||||
color: #000000;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
/*position: absolute;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;*/
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: rgb(221, 221, 221);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
#title {
|
||||
background-color: rgb(200, 200, 200);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
input[type=button],
|
||||
input[type=submit],
|
||||
input[type=reset] {
|
||||
background-color: rgb(165, 165, 165);
|
||||
border: none;
|
||||
color: rgb(0, 0, 0);
|
||||
padding: 2px 2px;
|
||||
text-decoration: none;
|
||||
margin: 0px 0px;
|
||||
min-width: 70px;
|
||||
border-radius: 70px;
|
||||
}
|
||||
|
||||
.led {
|
||||
border-radius: calc(var(--tile_icon-height) / 2);
|
||||
border-radius: 20px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
filter: alpha(opacity=100);
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.on {
|
||||
background-color: rgb(255, 0, 0);
|
||||
}
|
||||
|
||||
.off {
|
||||
background-color: rgb(116, 116, 116);
|
||||
}
|
||||
|
||||
.error {
|
||||
background-color: rgb(255, 0, 0) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type='text/javascript'>
|
||||
|
||||
var _panel_size = 6;
|
||||
var _panel_set = 0;
|
||||
|
||||
function send(source) {
|
||||
console.log("from" + source.id);
|
||||
|
||||
var cmd = {};
|
||||
cmd.uri = "simcmd"
|
||||
switch (source.id) {
|
||||
case "Filter_Pump_button":
|
||||
cmd.value = "0x02";
|
||||
break;
|
||||
case "Spa_Mode_button":
|
||||
cmd.value = "0x01";
|
||||
break;
|
||||
case "Aux_1_button":
|
||||
cmd.value = "0x05";
|
||||
break;
|
||||
case "Aux_2_button":
|
||||
cmd.value = "0x0a";
|
||||
break;
|
||||
case "Aux_3_button":
|
||||
cmd.value = "0x0f";
|
||||
break;
|
||||
case "Aux_4_button":
|
||||
if (_panel_size < 12)
|
||||
cmd.value = "0x06";
|
||||
else
|
||||
cmd.value = "0x14"; //Different on RS12+ (0x14)
|
||||
break;
|
||||
case "Aux_5_button":
|
||||
if (_panel_size < 12)
|
||||
cmd.value = "0x0b";
|
||||
else
|
||||
cmd.value = "0x03"; //Different on RS12+ (0x03)
|
||||
break;
|
||||
case "Aux_6_button":
|
||||
if (_panel_size < 12)
|
||||
cmd.value = "0x10";
|
||||
else
|
||||
cmd.value = "0x07"; //Different on RS12+ (0x07)
|
||||
break;
|
||||
case "Aux_7_button":
|
||||
if (_panel_size < 12)
|
||||
cmd.value = "0x15";
|
||||
else
|
||||
cmd.value = "0x06"; //Different on RS12+ (0x06)
|
||||
break;
|
||||
case "Aux_B1_button":
|
||||
cmd.value = "0x0b";
|
||||
break;
|
||||
case "Aux_B2_button":
|
||||
cmd.value = "0x10";
|
||||
break;
|
||||
case "Aux_B3_button":
|
||||
cmd.value = "0x15";
|
||||
break;
|
||||
case "Aux_B4_button":
|
||||
cmd.value = "0x1a";
|
||||
break;
|
||||
case "Aux_B5_button":
|
||||
cmd.value = "0x04";
|
||||
break;
|
||||
case "Aux_B6_button":
|
||||
cmd.value = "0x08";
|
||||
break;
|
||||
case "Aux_B7_button":
|
||||
cmd.value = "0x0d";
|
||||
break;
|
||||
case "Aux_B8_button":
|
||||
cmd.value = "0x0c";
|
||||
break;
|
||||
case "Pool_Heater_button":
|
||||
cmd.value = "0x12";
|
||||
break;
|
||||
case "Spa_Heater_button":
|
||||
cmd.value = "0x17";
|
||||
break;
|
||||
case "Solar_Heater_button":
|
||||
cmd.value = "0x1c";
|
||||
break;
|
||||
case "B_menu":
|
||||
cmd.value = "0x09";
|
||||
break;
|
||||
case "B_cancel":
|
||||
cmd.value = "0x0e";
|
||||
break;
|
||||
case "B_back":
|
||||
cmd.value = "0x13";
|
||||
break;
|
||||
case "B_forward":
|
||||
cmd.value = "0x18";
|
||||
break;
|
||||
case "B_enter":
|
||||
cmd.value = "0x1d";
|
||||
break;
|
||||
case "B_hold":
|
||||
cmd.value = "0x19";
|
||||
break;
|
||||
case "B_overide":
|
||||
cmd.value = "0x1c";
|
||||
break;
|
||||
default:
|
||||
alert("Unknown button");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
cmd.value = todec(cmd.value);
|
||||
send_command(cmd);
|
||||
|
||||
// I know we are converting hex to dec and back to hex, but here for checking.
|
||||
//document.getElementById("messages").innerHTML = "Sent "+tohex(cmd.value)+" please wait for response!";
|
||||
}
|
||||
|
||||
function tohex(value) {
|
||||
var rtn = parseInt(value).toString(16);
|
||||
if (rtn.length <= 1)
|
||||
return "0x0"+rtn;
|
||||
else
|
||||
return "0x"+rtn;
|
||||
}
|
||||
function todec(value) {
|
||||
let number = parseInt(value, 16);
|
||||
return number;
|
||||
}
|
||||
|
||||
function set_panel_size(size)
|
||||
{
|
||||
if (_panel_set == size){
|
||||
return;
|
||||
}
|
||||
|
||||
_panel_set = size;
|
||||
|
||||
switch(size){
|
||||
case 6:
|
||||
document.getElementById("Aux_6_led").classList.add("hidden");
|
||||
document.getElementById("Aux_6_button").classList.add("hidden");
|
||||
document.getElementById("Aux_7_led").classList.add("hidden");
|
||||
document.getElementById("Aux_7_button").classList.add("hidden");
|
||||
case 8:
|
||||
document.getElementById("Aux_B1_led").classList.add("hidden");
|
||||
document.getElementById("Aux_B1_button").classList.add("hidden");
|
||||
document.getElementById("Aux_B2_led").classList.add("hidden");
|
||||
document.getElementById("Aux_B2_button").classList.add("hidden");
|
||||
document.getElementById("Aux_B3_led").classList.add("hidden");
|
||||
document.getElementById("Aux_B3_button").classList.add("hidden");
|
||||
document.getElementById("Aux_B4_led").classList.add("hidden");
|
||||
document.getElementById("Aux_B4_button").classList.add("hidden");
|
||||
case 12:
|
||||
document.getElementById("Aux_B5_button").classList.add("hidden");
|
||||
document.getElementById("Aux_B6_button").classList.add("hidden");
|
||||
document.getElementById("Aux_B7_button").classList.add("hidden");
|
||||
document.getElementById("Aux_B8_button").classList.add("hidden");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function update_status(data) {
|
||||
// Some form of error if PDA only panel.
|
||||
if (data.panel_type.startsWith("PDA")) {
|
||||
document.getElementById("title").innerHTML = ' !!! PDA only panels are not Supported !!! '
|
||||
document.getElementById("title").classList.add("error");
|
||||
document.getElementById("messages").innerHTML = ' !!! PDA Not Supported !!! '
|
||||
document.getElementById("messages").classList.add("error");
|
||||
}
|
||||
/*
|
||||
if (document.getElementById("status").getAttribute("raw") != data.panel_message) {
|
||||
document.getElementById("status_three").innerHTML = document.getElementById("status_two").innerHTML;
|
||||
document.getElementById("status_two").innerHTML = document.getElementById("status").innerHTML;
|
||||
if (data.panel_message == "") {
|
||||
document.getElementById("status").innerHTML = " ";
|
||||
} else {
|
||||
document.getElementById("status").innerHTML = data.panel_message;
|
||||
}
|
||||
document.getElementById("status").setAttribute("raw", data.panel_message);
|
||||
document.getElementById("messages").innerHTML = " ";
|
||||
}
|
||||
*/
|
||||
for (var obj in data.leds) {
|
||||
if ((led = document.getElementById(obj.toString() + "_led")) == null) {
|
||||
//console.log("Error " + obj.toString() + " LED not found");
|
||||
//return;
|
||||
} else {
|
||||
if (data.leds[obj] == "on" || data.leds[obj] == "enabled" || data.leds[obj] == "flash") {
|
||||
//console.log("Set " + obj.toString() + " LED on");
|
||||
led.classList.add("on");
|
||||
led.classList.remove("off");
|
||||
} else {
|
||||
//console.log("Set " + obj.toString() + " LED off");
|
||||
led.classList.add("off");
|
||||
led.classList.remove("on");
|
||||
}
|
||||
}
|
||||
if (obj.toString() == "Aux_4" && _panel_size < 6)
|
||||
_panel_size=6;
|
||||
if (obj.toString() == "Aux_6" && _panel_size < 8)
|
||||
_panel_size=8;
|
||||
if (obj.toString() == "Aux_B1" && _panel_size < 12)
|
||||
_panel_size=12;
|
||||
if (obj.toString() == "Aux_B4")
|
||||
_panel_size=16;
|
||||
}
|
||||
|
||||
set_panel_size(_panel_size);
|
||||
}
|
||||
|
||||
function update_device(data) {
|
||||
for (var obj in data['devices']) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function set_labels(data) {
|
||||
for (var obj in data) {
|
||||
if ((button = document.getElementById(obj + "_button")) != null && data[obj] != "NONE") {
|
||||
button.value = data[obj];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function packet_to_ascii(packet) {
|
||||
var msg="";
|
||||
|
||||
for (i=5; i <= 20; i++) {
|
||||
if (packet[i] >= 31 && packet[i] <= 127) {
|
||||
msg=msg+String.fromCharCode(packet[i]);
|
||||
//console.log("char ("+packet[i]+") = "+msg);
|
||||
} else if (packet[i] == 223) {
|
||||
msg=msg+"°";
|
||||
} else if (packet[i] == 0) {
|
||||
break; // End on a nul
|
||||
} else {
|
||||
console.log("Bad char in string '"+msg+"' next ("+packet[i]+") from ["+packet+"]" );
|
||||
}
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
function lcd_display(line, message) {
|
||||
|
||||
const message_lcd = document.getElementById("status");
|
||||
const message_lcd1 = document.getElementById("status_two");
|
||||
const message_lcd2 = document.getElementById("status_three");
|
||||
|
||||
if (message == "" || message == " "){message = " ";}
|
||||
|
||||
message_lcd2.innerHTML = message_lcd1.innerHTML;
|
||||
message_lcd1.innerHTML = message_lcd.innerHTML;
|
||||
message_lcd.innerHTML = message;
|
||||
}
|
||||
|
||||
function lcd_display_append(line, message) {
|
||||
const message_lcd = document.getElementById("status");
|
||||
message_lcd.innerHTML = message_lcd.innerHTML+message;
|
||||
}
|
||||
|
||||
const PKT_CMD = 3;
|
||||
const PKT_DATA1 = 4;
|
||||
|
||||
const CMD_STATUS = 2
|
||||
const CMD_MSG = 3 // message
|
||||
const CMD_MSG_LONG = 4
|
||||
const CMD_MSG_LOOP_ST = 8 // pda highlight
|
||||
|
||||
function process_packet(data) {
|
||||
switch(data.dec[PKT_CMD]) {
|
||||
case CMD_MSG: // Message
|
||||
console.log("Received Line "+data.dec[PKT_DATA1]+" = "+packet_to_ascii(data.dec));
|
||||
lcd_display(data.dec[PKT_DATA1], packet_to_ascii(data.dec));
|
||||
break;
|
||||
case CMD_MSG_LONG: // Message
|
||||
console.log("Received Line long "+data.dec[PKT_DATA1]+" = "+packet_to_ascii(data.dec));
|
||||
lcd_display_append(data.dec[PKT_DATA1], packet_to_ascii(data.dec));
|
||||
break;
|
||||
|
||||
case CMD_MSG_LOOP_ST:
|
||||
case CMD_STATUS:
|
||||
// Nothing to do for these messages
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log("Received unknown command "+data.dec[PKT_CMD]+" "+tohex(data.dec[PKT_CMD]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function get_appropriate_ws_url() {
|
||||
var pcol;
|
||||
var u = document.URL;
|
||||
/*
|
||||
* We open the websocket encrypted if this page came on an
|
||||
* https:// url itself, otherwise unencrypted
|
||||
*/
|
||||
if (u.substring(0, 5) == "https") {
|
||||
pcol = "wss://";
|
||||
u = u.substr(8);
|
||||
} else {
|
||||
pcol = "ws://";
|
||||
if (u.substring(0, 4) == "http")
|
||||
u = u.substr(7);
|
||||
}
|
||||
u = u.split('/');
|
||||
//alert (pcol + u[0] + ":6500");
|
||||
return pcol + u[0];
|
||||
}
|
||||
/* dumb increment protocol */
|
||||
var socket_di;
|
||||
|
||||
function startWebsockets() {
|
||||
socket_di = new WebSocket(get_appropriate_ws_url());
|
||||
try {
|
||||
socket_di.onopen = function () {
|
||||
// success!
|
||||
start_simulator();
|
||||
get_devices();
|
||||
}
|
||||
socket_di.onmessage = function got_packet(msg) {
|
||||
document.getElementById("status").classList.remove("error");
|
||||
var data = JSON.parse(msg.data);
|
||||
if (data.type == 'simpacket') {
|
||||
process_packet(data);
|
||||
} else if (data.type == 'status') {
|
||||
update_status(data);
|
||||
} else if (data.type == 'devices') {
|
||||
//update_status(data);
|
||||
update_device(data);
|
||||
} else if (data.type == 'aux_labels') {
|
||||
set_labels(data);
|
||||
}
|
||||
}
|
||||
socket_di.onclose = function () {
|
||||
// something went wrong
|
||||
document.getElementById("status").innerHTML = ' !!! Connection error !!! '
|
||||
document.getElementById("status").classList.add("error");
|
||||
// Try to reconnect every 5 seconds.
|
||||
setTimeout(function () {
|
||||
startWebsockets();
|
||||
}, 5000);
|
||||
}
|
||||
} catch (exception) {
|
||||
alert('<p>Error' + exception);
|
||||
}
|
||||
}
|
||||
|
||||
function start_simulator() {
|
||||
var msg = {
|
||||
//command: "simulator"
|
||||
uri: "simulator/allbutton"
|
||||
};
|
||||
socket_di.send(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
function get_devices() {
|
||||
var msg = {
|
||||
uri: "devices"
|
||||
};
|
||||
socket_di.send(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
function send_command(cmd) {
|
||||
socket_di.send(JSON.stringify(cmd));
|
||||
}
|
||||
/*
|
||||
function reset() {
|
||||
socket_di.send("reset\n");
|
||||
}
|
||||
*/
|
||||
function init() {
|
||||
startWebsockets();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<body onload="init();">
|
||||
<div class="wrapper">
|
||||
|
||||
<table border='0' id="deviceList">
|
||||
<tr style="title">
|
||||
<td style="title" colspan="12" align="center"><label id="title"> AqualinkD All Button Simulator </label></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="12" align="center"><label id="status_three"> </label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="12" align="center"><label id="status_two"> </label></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th colspan="12"><label id="status">AqualinkD</label></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
<div id="Filter_Pump_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Filter_Pump_button" type="button" onclick="send(this);" value="Filter Pump">
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Spa_Mode_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Spa_Mode_button" type="button" onclick="send(this);" value="Spa Mode">
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Aux_1_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_1_button" type="button" onclick="send(this);" value="AUX1">
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Aux_2_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_2_button" type="button" onclick="send(this);" value="AUX2">
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Aux_3_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_3_button" type="button" onclick="send(this);" value="AUX3">
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Aux_4_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_4_button" type="button" onclick="send(this);" value="AUX4">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
<div id="Aux_5_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_5_button" type="button" onclick="send(this);" value="AUX5">
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Aux_6_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_6_button" type="button" onclick="send(this);" value="AUX6">
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Aux_7_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_7_button" type="button" onclick="send(this);" value="AUX7">
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Aux_B1_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_B1_button" type="button" onclick="send(this);" value="AUXB1">
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Aux_B2_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_B2_button" type="button" onclick="send(this);" value="AUXB2">
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Aux_B3_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_B3_button" type="button" onclick="send(this);" value="AUXB3">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
<div id="Aux_B4_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_B4_button" type="button" onclick="send(this);" value="AUXB4">
|
||||
</td>
|
||||
<td align="right">
|
||||
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_B5_button" type="button" onclick="send(this);" value="AUXB5">
|
||||
</td>
|
||||
<td align="right">
|
||||
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_B6_button" type="button" onclick="send(this);" value="AUXB6">
|
||||
</td>
|
||||
<td align="right">
|
||||
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_B7_button" type="button" onclick="send(this);" value="AUXB7">
|
||||
</td>
|
||||
<td align="right">
|
||||
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Aux_B8_button" type="button" onclick="send(this);" value="AUXB8">
|
||||
</td>
|
||||
<td align="right">
|
||||
|
||||
</td>
|
||||
<td align="left">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
|
||||
</td>
|
||||
<td align="left">
|
||||
|
||||
</td>
|
||||
<td align="right">
|
||||
|
||||
</td>
|
||||
<td align="left">
|
||||
|
||||
</td>
|
||||
<td align="right">
|
||||
|
||||
</td>
|
||||
<td align="left">
|
||||
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Pool_Heater_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Pool_Heater_button" type="button" onclick="send(this);" value="Pool Heater">
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Spa_Heater_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Spa_Heater_button" type="button" onclick="send(this);" value="Spa Heater">
|
||||
</td>
|
||||
<td align="right">
|
||||
<div id="Solar_Heater_led" class="led off"></div>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input id="Solar_Heater_button" type="button" onclick="send(this);" value="Solar Heater">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<TD> </TD>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" colspan="2">
|
||||
<input type="button" onclick="send(this);" id="B_menu" value="Menu">
|
||||
</td>
|
||||
<td align="center" colspan="2">
|
||||
<input type="button" onclick="send(this);" id="B_cancel" value="Cancel">
|
||||
</td>
|
||||
<td align="center" colspan="2">
|
||||
<input type="button" onclick="send(this);" id="B_back" value="Back <">
|
||||
</td>
|
||||
<td align="center" colspan="2">
|
||||
<input type="button" onclick="send(this);" id="B_forward" value="Forward >">
|
||||
</td>
|
||||
<td align="center" colspan="2">
|
||||
<input type="button" onclick="send(this);" id="B_enter" value="Enter *">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="12" align="center"><label id="messages"> </label></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,542 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang='en'>
|
||||
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=windows-1252'>
|
||||
<title>AqualinkD Simulator</title>
|
||||
<meta name='viewport' content='width=device-width'>
|
||||
<meta name='apple-mobile-web-app-capable' content='yes'>
|
||||
<meta name='apple-mobile-web-app-status-bar-style' content='black'>
|
||||
<meta name='apple-mobile-web-app-status-bar-style' content='black'>
|
||||
<link href="aqualinkd.png" rel="apple-touch-icon">
|
||||
<link href="aqualinkd.png" rel="icon">
|
||||
<style>
|
||||
html {}
|
||||
|
||||
body {
|
||||
font-family: 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif;
|
||||
font-weight: 300;
|
||||
background-color: white;
|
||||
color: #000000;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
/*position: absolute;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;*/
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: rgb(221, 221, 221);
|
||||
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th {
|
||||
/*
|
||||
background-color: white;
|
||||
border-spacing: 10px;*/
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
td {
|
||||
/*
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
*/
|
||||
/*padding: 10px;*/
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
#title {
|
||||
background-color: rgb(200, 200, 200);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
input[type=button],
|
||||
input[type=submit],
|
||||
input[type=reset] {
|
||||
background-color: rgb(165, 165, 165);
|
||||
border: none;
|
||||
color: rgb(0, 0, 0);
|
||||
padding: 2px 2px;
|
||||
text-decoration: none;
|
||||
margin: 0px 0px;
|
||||
min-width: 70px;
|
||||
border-radius: 70px;
|
||||
}
|
||||
|
||||
.led {
|
||||
border-radius: calc(var(--tile_icon-height) / 2);
|
||||
border-radius: 20px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
filter: alpha(opacity=100);
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.on {
|
||||
background-color: rgb(255, 0, 0);
|
||||
}
|
||||
|
||||
.off {
|
||||
background-color: rgb(116, 116, 116);
|
||||
}
|
||||
|
||||
.error {
|
||||
background-color: rgb(255, 0, 0) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.lcd_display {
|
||||
font-family: monospace;
|
||||
background-color: #2b2b2b;
|
||||
color: white;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.lcd_highlight {
|
||||
font-family: monospace;
|
||||
background-color: #8e1e1e !important;
|
||||
color: white !important;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<script type='text/javascript'>
|
||||
|
||||
var _socket_di;
|
||||
|
||||
const PKT_CMD = 3;
|
||||
const PKT_DATA1 = 4;
|
||||
const PKT_DATA2 = 5;
|
||||
const PKT_DATA3 = 6;
|
||||
|
||||
const CMD_MSG_LONG = 4;
|
||||
const CMD_PDA_CLEAR = 9;
|
||||
const CMD_PDA_HIGHLIGHT = 8;
|
||||
const CMD_PDA_HIGHLIGHTCHARS = 16;
|
||||
const CMD_PDA_SHIFTLINES = 15;
|
||||
|
||||
var _hlightcharlineno = -1;
|
||||
var _hlightcharline = "";
|
||||
var _hlightcharstart = -1;
|
||||
var _hlightcharend = -1;
|
||||
|
||||
|
||||
|
||||
function send(source) {
|
||||
console.log("from" + source.id);
|
||||
|
||||
var cmd = {};
|
||||
cmd.uri = "simcmd"
|
||||
switch (source.id) {
|
||||
case "Up":
|
||||
cmd.value = "0x06";
|
||||
break;
|
||||
case "Down":
|
||||
cmd.value = "0x05";
|
||||
break;
|
||||
case "Select":
|
||||
cmd.value = "0x04";
|
||||
break;
|
||||
case "Page_up":
|
||||
cmd.value = "0x03";
|
||||
break;
|
||||
case "Back":
|
||||
cmd.value = "0x02";
|
||||
break;
|
||||
case "Page_down":
|
||||
cmd.value = "0x01";
|
||||
break;
|
||||
|
||||
default:
|
||||
alert("Unknown button");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
cmd.value = todec(cmd.value);
|
||||
send_command(cmd);
|
||||
}
|
||||
|
||||
function tohex(value) {
|
||||
var rtn = parseInt(value).toString(16);
|
||||
if (rtn.length <= 1)
|
||||
return "0x0"+rtn;
|
||||
else
|
||||
return "0x"+rtn;
|
||||
}
|
||||
function todec(value) {
|
||||
let number = parseInt(value, 16);
|
||||
return number;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function lcd_clear() {
|
||||
//var container = document.getElementById("lcd_display");
|
||||
for (i=1; i <= 12; i++) {
|
||||
//container.lastElementChild.remove();
|
||||
//child = container.children[i];
|
||||
//console.log("Line "+i+" replacing "+child.innerHTML)
|
||||
//child.innerHTML = " ";
|
||||
var line = document.getElementById("lcd-l"+i);
|
||||
//console.log("Line "+i+" replacing "+line.innerHTML)
|
||||
line.innerHTML = " ";
|
||||
line.classList.remove("lcd_highlight");
|
||||
line.classList.add("lcd_display");
|
||||
}
|
||||
|
||||
lcd_clear_highlight_chrs(false);
|
||||
}
|
||||
|
||||
function lcd_display(lineno, message) {
|
||||
// We get lines 0,2,3,4,5,6.... no line 1. (so using 0 as 1)
|
||||
if (lineno == 0){lineno=1;}
|
||||
var line = document.getElementById("lcd-l"+lineno);
|
||||
//console.log("Line "+lineno+" replacing '"+line.innerHTML+"' with '"+message+"'");
|
||||
line.innerHTML = message;
|
||||
|
||||
// See if we need to re-highlight any chrs
|
||||
check_rehighlight_chrs(lineno);
|
||||
}
|
||||
|
||||
function lcd_display_highlight(lineno) {
|
||||
// We get lines 0,2,3,4,5,6.... no line 1. (so using 0 as 1)
|
||||
if (lineno == 0){lineno=1;}
|
||||
|
||||
for (i=1; i <= 12; i++) {
|
||||
var line = document.getElementById("lcd-l"+i);
|
||||
if (i != lineno) {
|
||||
line.classList.remove("lcd_highlight");
|
||||
line.classList.add("lcd_display");
|
||||
//console.log("remove highlight to line #"+i+" "+line.innerHTML)
|
||||
} else {
|
||||
line.classList.add("lcd_highlight");
|
||||
line.classList.remove("lcd_display");
|
||||
//console.log("add highlight to line #"+i+" "+line.innerHTML)
|
||||
}
|
||||
}
|
||||
//line.classList.add("lcd_highlight");
|
||||
//line.classList.remove("lcd_display");
|
||||
}
|
||||
|
||||
|
||||
|
||||
function check_rehighlight_chrs(lineno) {
|
||||
if (_hlightcharlineno == lineno && _hlightcharstart >= 0 && _hlightcharend > 0 ) {
|
||||
// We would have received a new line text, so don't preserve old text
|
||||
lcd_display_highlight_chrs(_hlightcharlineno, _hlightcharstart, _hlightcharend, false);
|
||||
}
|
||||
}
|
||||
|
||||
function lcd_clear_highlight_chrs(preserve=true){
|
||||
|
||||
// if preserve, then we put back the old text.
|
||||
if (preserve && _hlightcharlineno >= 0 && _hlightcharline != "") {
|
||||
var line = document.getElementById("lcd-l"+_hlightcharlineno);
|
||||
line.innerHTML = _hlightcharline;
|
||||
}
|
||||
|
||||
_hlightcharlineno = -1;
|
||||
_hlightcharline = "";
|
||||
_hlightcharstart = -1;
|
||||
_hlightcharend = -1;
|
||||
}
|
||||
|
||||
function lcd_display_highlight_chrs(lineno, start, end, preserve=true) {
|
||||
|
||||
lcd_clear_highlight_chrs(preserve);
|
||||
|
||||
var line = document.getElementById("lcd-l"+lineno);
|
||||
text = line.innerHTML;
|
||||
|
||||
var newtxt = text.slice(0, end+1) + "</span>" + text.slice(end+1);
|
||||
var newtxt = newtxt.slice(0, start) + "<span class=\"lcd_highlight\">" + newtxt.slice(start);
|
||||
line.innerHTML = newtxt;
|
||||
|
||||
_hlightcharlineno = lineno;
|
||||
_hlightcharline = text;
|
||||
_hlightcharstart = start;
|
||||
_hlightcharend = end;
|
||||
|
||||
console.log("Line '"+text+"' now '"+newtxt+"'");
|
||||
}
|
||||
|
||||
function packet_to_ascii(packet) {
|
||||
var msg="";
|
||||
|
||||
for (i=5; i <= 20; i++) {
|
||||
if (packet[i] >= 31 && packet[i] <= 127) {
|
||||
msg=msg+String.fromCharCode(packet[i]);
|
||||
} else if (packet[i] == 223) {
|
||||
msg=msg+"°";
|
||||
} else if (packet[i] == 0) {
|
||||
break; // End on a nul
|
||||
} else {
|
||||
console.log("Bad char in string '"+msg+"' next ("+packet[i]+")" );
|
||||
}
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function process_packet(data) {
|
||||
switch(data.dec[PKT_CMD]) {
|
||||
case CMD_PDA_CLEAR: // Clear
|
||||
console.log("Received Clear");
|
||||
lcd_clear();
|
||||
break;
|
||||
case CMD_MSG_LONG: // Message
|
||||
console.log("Received Line "+data.dec[PKT_DATA1]+" = "+packet_to_ascii(data.dec));
|
||||
lcd_display(data.dec[PKT_DATA1], packet_to_ascii(data.dec));
|
||||
break;
|
||||
case CMD_PDA_HIGHLIGHT:
|
||||
console.log("Received Highlight "+data.dec[PKT_DATA1]);
|
||||
// We sometimes get 255 for line number, need to find out why
|
||||
lcd_display_highlight(data.dec[PKT_DATA1]);
|
||||
break;
|
||||
case CMD_PDA_HIGHLIGHTCHARS:
|
||||
console.log("Received Highlight chars, Line="+data.dec[PKT_DATA1]+", Start="+data.dec[PKT_DATA2]+", Stop="+data.dec[PKT_DATA3]);
|
||||
lcd_display_highlight_chrs(data.dec[PKT_DATA1], data.dec[PKT_DATA2], data.dec[PKT_DATA3]);
|
||||
break;
|
||||
default:
|
||||
// 2 is READY for commands
|
||||
console.log("Received unknown command "+data.dec[PKT_CMD]+" "+tohex(data.dec[PKT_CMD]));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function update_status_message(message=null, error=false) {
|
||||
const status = document.getElementById("status");
|
||||
|
||||
if (message != null) {
|
||||
status.innerHTML = message;
|
||||
} else {
|
||||
status.innerHTML = "AqualinkD Onetouch Simulator";
|
||||
}
|
||||
|
||||
if (error) {
|
||||
status.classList.add("error");
|
||||
} else {
|
||||
status.classList.remove("error");
|
||||
}
|
||||
}
|
||||
|
||||
function update_status(data) {
|
||||
// Some form of error if PDA only panel.
|
||||
if (data.panel_type.startsWith("PDA")) {
|
||||
//document.getElementById("status").innerHTML = ' !!! PDA only panels are not Supported !!! '
|
||||
//document.getElementById("status").classList.add("error");
|
||||
update_status_message("PDA only panels are not Supported", true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function get_appropriate_ws_url() {
|
||||
var pcol;
|
||||
var u = document.URL;
|
||||
/*
|
||||
* We open the websocket encrypted if this page came on an
|
||||
* https:// url itself, otherwise unencrypted
|
||||
*/
|
||||
if (u.substring(0, 5) == "https") {
|
||||
pcol = "wss://";
|
||||
u = u.substr(8);
|
||||
} else {
|
||||
pcol = "ws://";
|
||||
if (u.substring(0, 4) == "http")
|
||||
u = u.substr(7);
|
||||
}
|
||||
u = u.split('/');
|
||||
//alert (pcol + u[0] + ":6500");
|
||||
return pcol + u[0];
|
||||
}
|
||||
/* dumb increment protocol */
|
||||
|
||||
|
||||
function startWebsockets() {
|
||||
_socket_di = new WebSocket(get_appropriate_ws_url());
|
||||
try {
|
||||
_socket_di.onopen = function () {
|
||||
// success!
|
||||
start_simulator();
|
||||
//get_devices();
|
||||
}
|
||||
_socket_di.onmessage = function got_packet(msg) {
|
||||
update_status_message();
|
||||
var data = JSON.parse(msg.data);
|
||||
if (data.type == 'simpacket') {
|
||||
process_packet(data);
|
||||
} else if (data.type == 'status') {
|
||||
update_status(data);
|
||||
}
|
||||
}
|
||||
_socket_di.onclose = function () {
|
||||
// something went wrong
|
||||
//document.getElementById("status").innerHTML = ' !!! Connection error !!! '
|
||||
//document.getElementById("status").classList.add("error");
|
||||
update_status_message("!!! Connection error !!!", true);
|
||||
// Try to reconnect every 5 seconds.
|
||||
setTimeout(function () {
|
||||
startWebsockets();
|
||||
}, 5000);
|
||||
}
|
||||
} catch (exception) {
|
||||
alert('<p>Error' + exception);
|
||||
}
|
||||
}
|
||||
|
||||
function start_simulator() {
|
||||
var msg = {
|
||||
//command: "simulator"
|
||||
uri: "simulator/onetouch"
|
||||
};
|
||||
lcd_clear();
|
||||
document.getElementById("lcd-l2").innerHTML = " Connecting ";
|
||||
document.getElementById("lcd-l3").innerHTML = " Please wait! ";
|
||||
|
||||
_socket_di.send(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
function get_devices() {
|
||||
var msg = {
|
||||
uri: "devices"
|
||||
};
|
||||
_socket_di.send(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
function send_command(cmd) {
|
||||
_socket_di.send(JSON.stringify(cmd));
|
||||
}
|
||||
/*
|
||||
function reset() {
|
||||
_socket_di.send("reset\n");
|
||||
}
|
||||
*/
|
||||
function init() {
|
||||
update_status_message();
|
||||
startWebsockets();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<body onload="init();">
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="inner">
|
||||
|
||||
<table border='0' id="deviceList">
|
||||
<tr>
|
||||
<th id="status" align="center" colspan="3"> </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="lcd_display" id="lcd-l1"> </td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input id="Page_up" type="button" onclick="send(this);" value="Page up"></td>
|
||||
<td class="lcd_display" id="lcd-l2"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="lcd_display" id="lcd-l3"> </td>
|
||||
<td><input id="Up" type="button" onclick="send(this);" value="Up"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="lcd_display" id="lcd-l4"> </td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input id="Back" type="button" onclick="send(this);" value="Back"></td>
|
||||
<td class="lcd_display" id="lcd-l5"> </td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="lcd_display" id="lcd-l6"> </td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="lcd_display" id="lcd-l7"> </td>
|
||||
<td><input id="Down" type="button" onclick="send(this);" value="Down"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input id="Page_down" type="button" onclick="send(this);" value="Page Down"></td>
|
||||
<td class="lcd_display" id="lcd-l8"> </td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="lcd_display" id="lcd-l9"> </td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="lcd_display" id="lcd-l10"> </td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="lcd_display"id="lcd-l11"> </td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="lcd_display" id="lcd-l12"> </td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
<th align="center"><input id="Select" type="button" onclick="send(this);" value="Select"></th>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--<div class="inner">END</div>-->
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
|
Loading…
Reference in New Issue