Control your Jandy equipment from your PC with a $15 adapter

Re: Control your Jandy equipment from your PC with a $15 ada

File #16 - Header file for the mini web server.

Code:
/*
 * web_server.h
 *
 *  Created on: Sep 29, 2012
 */

#ifndef WEB_SERVER_H_
#define WEB_SERVER_H_

//FUNCTION PROTOTYPES
void* socket_server(void* arg);
void* handle_socket_request(void* arg);
int handle_http_post(char* uri, char* buffer, unsigned int client_socket);
int send_cmd(char* cmd);
int handle_http_get(char* uri, unsigned int client_socket);
int download_file(char* uri, unsigned int client_socket);
void convert_aqualink_data();
int send_REST_response(char* uri, unsigned int client_socket);
int build_resource_JSON(char* json_buffer, char* uri);
char* build_RS8_JSON(char* buffer);
char* build_leds_JSON(char* buffer);
int get_led_status(int led_id);
char* build_aux_labels_JSON(char* json_buffer);

#endif /* WEB_SERVER_H_ */
 
Re: Control your Jandy equipment from your PC with a $15 ada

Here is an image of the more complete Web app HTML/Javascript client. Note the battery indicator in the upper right flashes the little red bar when the battery needs to be replaced. It is full green when the battery is okay. On the upper left below the device name there is a network status indicator. Green indicates there is a good network connection between the client and server. It flashes yellow when the client is communicating to the server, and will flash red and off (gray) when the connection is broken. In the image the filter pump is on. Note all of the status LEDs behave like the aqualink terminal changing color and blinking depending on state. Also, setting the temperature set points still needs to be coded on both the client and server. Mostly done on the client, though. I will post the HTML and Javascript next. One other note, I no longer use jquery mobile. Mainly to keep it very small. As a consequence it only looks okay in Safari. I tested it in Firefox, and the backgrounds and gradients did not work. No plans to fix this.

[attachment=0:kr83s0sv]ClientScreenGrab.jpg[/attachment:kr83s0sv]
 

Attachments

  • ClientScreenGrab.jpg
    ClientScreenGrab.jpg
    92 KB · Views: 320
Re: Control your Jandy equipment from your PC with a $15 ada

derossi,

Last set of code. Here is the HTML/Javascript source for the Web client. All of the image files are free downloads from the internet. Let me know if you can't find them.

Code:
<!DOCTYPE html> 
<html> 
	<head>
	<title>Aqualink RS8</title> 
	<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
        <style type="text/css">
            .button {
                display: inline-block;
                zoom: 1; /* zoom and *display = ie7 hack for display:inline-block */
                *display: inline;
                vertical-align: baseline;
                margin: 0 2px;
                outline: none;
                cursor: pointer;
                text-align: center;
                text-decoration: none;
                font: 12px/100% Arial, Helvetica, sans-serif;
                padding: .80em 2em;
                width:100%;
                text-shadow: 0 1px 1px rgba(0,0,0,.3);
                -webkit-border-radius: .5em;
                -moz-border-radius: .5em;
                border-radius: .5em;
                -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2);
                -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2);
                box-shadow: 0 1px 2px rgba(0,0,0,.2);
            }
            .button:hover {
                text-decoration: none;
            }
            .button:active {
                position: relative;
                top: 1px;
            }
            
            .bigrounded {
                -webkit-border-radius: 2em;
                -moz-border-radius: 2em;
                border-radius: 2em;
            }
            .medium {
                font-size: 12px;
                padding: .4em 1.5em .42em;
            }
            .small {
                font-size: 11px;
                padding: .2em 1em .275em;
            }
            
            .black {
                color: #d7d7d7;
                border: solid 1px #333;
                background: #333;
                background: -webkit-gradient(linear, left top, left bottom, from(#666), to(#000));
                background: -moz-linear-gradient(top,  #666,  #000);
                filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#666666', endColorstr='#000000');
            }
            .black:hover {
                background: #000;
                background: -webkit-gradient(linear, left top, left bottom, from(#444), to(#000));
                background: -moz-linear-gradient(top,  #444,  #000);
                filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#444444', endColorstr='#000000');
            }
            .black:active {
                color: #666;
                background: -webkit-gradient(linear, left top, left bottom, from(#000), to(#444));
                background: -moz-linear-gradient(top,  #000,  #444);
                filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#000000', endColorstr='#666666');
            }
            
            .bgimg { width:100%;height:250px;background-image:
                -webkit-gradient(
                linear,
                left top,
                left bottom,
                color-stop(0.15, rgb(50,50,50)),
                color-stop(0.58, rgb(0,0,0)),
                color-stop(0.79, rgb(0,0,0))
                );}
            .bgimg_body { width:100%;height:250px;background-image:
                -webkit-gradient(
                linear,
                left top,
                left bottom,
                color-stop(0.15, rgb(75,75,75)),
                color-stop(0.58, rgb(50,50,50)),
                color-stop(0.79, rgb(50,50,50))
                );}
            
            div{border-width:0px; border-style:solid;padding:5px;}
            body,html{margin:0; padding:0;color:#f4f4f4;font-family:Arial,Helvetica,sans-serif;}
            #main_div{width:760px;height:500px;margin-left:0;padding:0px;}
            #header_div{position:relative;height:75px;}
            #footer_div{height:45px;}
            #title_div{position:absolute;top:0;left:0;padding:5px;}
            #air_temp_title_div{position:absolute;top:0;right:215px;font-size:200%;}
            #air_temp{position:absolute;top:0;right:75px;font-size:300%;}
            #date_time{position:absolute;top:55px;right:0;}
            #body_div{position:relative;height:370px;}
            #leds_div{position:absolute;top:5px;right:10px;height:355px;width:225px;}
            #pool_temp_div{position:absolute;top:5px;height:190px;width:225px;right:505px;}
            #spa_temp_div{position:absolute;top:5px;height:190px;width:225px;right:257px;}
            #solar_htr_div{position:absolute;top:215px;height:45px;width:473px;right:257px;}
            #solar_button_div{position:absolute;top:8px;right:5px;width:300px;}
            #frz_protect_div{position:absolute;top:281px;height:79px;width:473px;right:257px;}
            #frz_protect_set_pnt{position:absolute;top:15px;height:50px;right:80px;font-size:300%;}
            #fp_set_pnt_button_div{position:absolute;top:15px;height:0px;right:5px;width:60px;}
            #fp_set_button_div{position:absolute;top:45px;width:110px;}
            .battery_image_div{position:absolute;top:0;right:5px;width:30px;}
            .net_activity_div{position:absolute;top:55px;left:0;}
            .led_button_div{position:relative;top:0;padding:0;height:40px;}
            .led_div{position:absolute;top:2px;left:5px;padding:0;}
            .button_div{position:absolute;top:1px;height:30px;right:5px;width:180px;padding:0;}
            .htr_led_div{position:absolute;top:55px;left:15px;padding:0;}
            .htr_button_div{position:absolute;top:55px;height:45px;right:5px;width:160px;padding:0;margin: 0px auto;}
            .body_sub_div{border:2px solid #a1a1a1;border-radius:15px;}
            .temp_title_div{position:relative;top:0;height:50px;float:left;font-size:175%;}
            .temp_val_div{position:relative;top:0;height:55px;float:right;font-size:250%;}
            .set_pnt_val_div{position:absolute;top:90px;height:50px;right:75px;font-size:300%;}
            .set_pnt_button_div{position:absolute;top:100px;height:0px;right:5px;width:60px;}
            .set_button_div{position:absolute;top:150px;width:110px;}
            .solar_led_div{position:absolute;top:8px;right:325px;}
        </style>
        
    <script type="text/javascript" language="javascript">

        function BlockMove(event) {
            // Tell Safari not to move the window.
            event.preventDefault() ;
        }
        
        // Preload the images.
        var delay = 100;        
        if (document.images) {
            setTimeout(get_batt_ok_img, delay);
        }        
        function get_batt_ok_img() {
            document.getElementById('battery_ok').src = "images/battery_ok.png";
            setTimeout(get_batt_low_img, delay);
        }
        function get_batt_low_img() {
            setTimeout(get_batt_blank_img, delay);
            document.getElementById('battery_low').src = "images/battery_low.png";
        }
        function get_batt_blank_img() {
            setTimeout(get_led_on_img, delay);
            document.getElementById('battery_blank').src = "images/battery_blank.png";
        }        
        function get_led_on_img() {
            setTimeout(get_led_off_img, delay);
            document.getElementById('pump_on_status').src = "images/led_on.png";
            document.getElementById('spa_on_status').src = "images/led_on.png";
            document.getElementById('aux1_on_status').src = "images/led_on.png";
            document.getElementById('aux2_on_status').src = "images/led_on.png";
            document.getElementById('aux3_on_status').src = "images/led_on.png";
            document.getElementById('aux4_on_status').src = "images/led_on.png";
            document.getElementById('aux5_on_status').src = "images/led_on.png";
            document.getElementById('aux6_on_status').src = "images/led_on.png";
            document.getElementById('aux7_on_status').src = "images/led_on.png";
            document.getElementById('pool_htr_on_status').src = "images/led_on.png";
            document.getElementById('spa_htr_on_status').src = "images/led_on.png";
            document.getElementById('solar_htr_on_status').src = "images/led_on.png";
        }
        function get_led_off_img() {
            setTimeout(get_led_enabled_img, delay);
            document.getElementById('pump_off_status').src = "images/led_off.png";
            document.getElementById('spa_off_status').src = "images/led_off.png";
            document.getElementById('aux1_off_status').src = "images/led_off.png";
            document.getElementById('aux2_off_status').src = "images/led_off.png";
            document.getElementById('aux3_off_status').src = "images/led_off.png";
            document.getElementById('aux4_off_status').src = "images/led_off.png";
            document.getElementById('aux5_off_status').src = "images/led_off.png";
            document.getElementById('aux6_off_status').src = "images/led_off.png";
            document.getElementById('aux7_off_status').src = "images/led_off.png";
            document.getElementById('pool_htr_off_status').src = "images/led_off.png";
            document.getElementById('spa_htr_off_status').src = "images/led_off.png";
            document.getElementById('solar_htr_off_status').src = "images/led_off.png";
        }
        function get_led_enabled_img() {
            setTimeout(get_net_off_img, delay);
            document.getElementById('pool_htr_en_status').src = "images/led_enabled.png";
            document.getElementById('spa_htr_en_status').src = "images/led_enabled.png";
        }
        function get_net_off_img() {
            setTimeout(get_net_yellow_img, delay);
            document.getElementById('net_off').src = "images/net_off.png";
        }
        function get_net_yellow_img() {
            setTimeout(get_net_green_img, delay);
            document.getElementById('net_yellow').src = "images/net_yellow.png";
        }
        function get_net_green_img() {
            setTimeout(get_net_red_img, delay);
            document.getElementById('net_green').src = "images/net_green.png";
        }
        function get_net_red_img() {
            document.getElementById('net_red').src = "images/net_red.png";
        }
        
        function LedsData() {
            this.pump = "off";
            this.spa = "off";
            this.aux1 = "off";
            this.aux2 = "off";
            this.aux3 = "off";
            this.aux4 = "off";
            this.aux5 = "off";
            this.aux6 = "off";
            this.aux7 = "off";
        }
        
        function AqualinkData() {
            this.version = "";
            this.date = "09/11/12 TUE";
            this.time = "10:33 AM";
            this.temp_units = "F";
            this.air_temp = "75";
            this.battery = "low";
            this.pool_htr_set_pnt = "0";
            this.spa_htr_set_pnt = "102";
            this.frz_protect_set_pnt = "36";
            this.leds = new LedsData();
        }
        
        function TemperatureSetPoint() {
            this.modified = false;
            this.value = 0;
        }
        
        var pool_htr_set_point = new TemperatureSetPoint();
        var spa_htr_set_point = new TemperatureSetPoint();
        var freeze_protect_set_point = new TemperatureSetPoint();
        
        var aqualink_data = new AqualinkData();
        var aqualink_port = '';
        var poll_count = 0;
        var command_queued = false;
        var command;
        var net_connection = 'red';

        function poll_system() {
            if(command_queued == true) {
                send_command(command);
                command_queued = false;
                poll_count = 9;
                console.log('command: ' + command);
            }
            else {
                if(poll_count >= 10) {
                    get_status();
                }
            }
            poll_count += 1;
            setTimeout("poll_system()", 500);
            //console.log('poll count = ' + poll_count);
        }
        
        function send_command(cmd) {
            var _cmd = {};
            _cmd.command = cmd;
            //alert(JSON.stringify(_cmd));
            var req = new XMLHttpRequest();
            req.open("POST", "/AqualinkRS8/command", true);
            req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
            //req.onreadystatechange = get_status;
            req.send(JSON.stringify(_cmd));
        }
        
        function received_status() {
            if(this.readyState == this.DONE) {
                if(this.status == 200) {
                    // success!
                    net_connection = 'green';
                    var a_data = JSON.parse(this.responseText);
                    update_status(a_data);
                    return;
                }
                // something went wrong
                net_connection = 'red';
            }
        }
        
        function get_status() {
            document.getElementById('net_yellow').style.visibility='visible';
            net_connection = 'yellow';
            poll_count = 0;
            var req = new XMLHttpRequest();
            req.overrideMimeType("application/json");
            req.onreadystatechange = received_status;
            req.open("GET", '/AqualinkRS8', true);
            req.send();
        }
        
        function queue_command(cmd) {
            //alert('queue_command(): ' + cmd);
            command_queued = true;
            command = cmd;
        }
        
        function received_labels() {
            if(this.readyState == this.DONE) {
                if(this.status == 200) {
                    // success!
                    net_connection = 'green';
                    var a_data = JSON.parse(this.responseText);
                    set_aux_button_labels(a_data);
                    return;
                }
                // something went wrong
                //alert("didn't get labels!");
                net_connection = 'red';
            }
        }
        
        function get_aux_labels() {
            document.getElementById('net_yellow').style.visibility='visible';
            net_connection = 'yellow';
            poll_count = 0;
            var req = new XMLHttpRequest();
            req.overrideMimeType("application/json");
            req.onreadystatechange = received_labels;
            req.open("GET", '/Config/aux_labels', true);
            req.send();
        }
        
        function set_aux_button_labels(data) {
            document.getElementById('aux1_button').value = data.aux1_label;
            document.getElementById('aux2_button').value = data.aux2_label;
            document.getElementById('aux3_button').value = data.aux3_label;
            document.getElementById('aux4_button').value = data.aux4_label;
            document.getElementById('aux5_button').value = data.aux5_label;
            document.getElementById('aux6_button').value = data.aux6_label;
            document.getElementById('aux7_button').value = data.aux7_label;
        }
        
        window.onload = function() {
            get_aux_labels();
            poll_system();
        }
        
        function update_temp(id) {
            var el = document.getElementById(id);
            var temp_string = "";
            
            if(id == "air_temp") {
                temp_string = aqualink_data.air_temp;
            }
            else if(id == "pool_temp") {
                temp_string = aqualink_data.pool_temp;
            }
            else if(id == "spa_temp") {
                temp_string = aqualink_data.spa_temp;
            }
            else if(id == "pool_htr_set_pnt") {
                if(pool_htr_set_point.modified == true) {
                    temp_string = pool_htr_set_point.value.toString();
                    el.style.color = "PowderBlue";
                }
                else {
                    temp_string = aqualink_data.pool_htr_set_pnt;
                    pool_htr_set_point.value = parseInt(temp_string);
                    el.style.color = "#f4f4f4";
                }
            }
            else if(id == "spa_htr_set_pnt") {
                if(spa_htr_set_point.modified == true) {
                    temp_string = spa_htr_set_point.value.toString();
                    el.style.color = "PowderBlue";
                }
                else {
                    temp_string = aqualink_data.spa_htr_set_pnt;
                    spa_htr_set_point.value = parseInt(temp_string);
                    el.style.color = "#f4f4f4";
                }
            }
            else if(id == "frz_protect_set_pnt") {
                if(freeze_protect_set_point.modified == true) {
                    temp_string = freeze_protect_set_point.value.toString();
                    el.style.color = "PowderBlue";
                }
                else {
                    temp_string = aqualink_data.frz_protect_set_pnt;
                    freeze_protect_set_point.value = parseInt(temp_string);
                    el.style.color = "#f4f4f4";
                }
            }            
            
            el.innerHTML = temp_string + "°" + aqualink_data.temp_units;
        }
        
        function incr_pool_htr(direction) {
            if(direction == '+') {
                pool_htr_set_point.value++;
            }
            else {
                pool_htr_set_point.value--;
            }
            
            if(pool_htr_set_point.value == parseInt(aqualink_data.pool_htr_set_pnt)) {
                pool_htr_set_point.modified = false;
            }
            else {
                pool_htr_set_point.modified = true;
            }
            
            update_temp("pool_htr_set_pnt");
        }
        
        function incr_spa_htr(direction) {
            if(direction == '+') {
                spa_htr_set_point.value++;
            }
            else {
                spa_htr_set_point.value--;
            }
            
            if(spa_htr_set_point.value == parseInt(aqualink_data.spa_htr_set_pnt)) {
                spa_htr_set_point.modified = false;
            }
            else {
                spa_htr_set_point.modified = true;
            }
            
            update_temp("spa_htr_set_pnt");
        }
        
        function incr_frz_protect(direction) {
            if(direction == '+') {
                freeze_protect_set_point.value++;
            }
            else {
                freeze_protect_set_point.value--;
            }
            
            if(freeze_protect_set_point.value == parseInt(aqualink_data.frz_protect_set_pnt)) {
                freeze_protect_set_point.modified = false;
            }
            else {
                freeze_protect_set_point.modified = true;
            }
            
            update_temp("frz_protect_set_pnt");
        }

        function net_connection_icon() {
            if(net_connection == "red") {
                document.getElementById('net_green').style.visibility='hidden';
                document.getElementById('net_yellow').style.visibility='hidden';
                if(document.getElementById('net_red').style.visibility=='visible') {
                    document.getElementById('net_red').style.visibility='hidden';
                }
                else {
                    document.getElementById('net_red').style.visibility='visible';
                }
            }
            else if(net_connection == "green") {
                document.getElementById('net_green').style.visibility='visible';
                document.getElementById('net_red').style.visibility='hidden';
                document.getElementById('net_yellow').style.visibility='hidden';
            }
            else if(net_connection == "yellow") {
                document.getElementById('net_green').style.visibility='hidden';
                document.getElementById('net_red').style.visibility='hidden';
                document.getElementById('net_yellow').style.visibility='visible';
            }
        }
        setInterval(net_connection_icon, 500);
        
        function flash_battery_icon() {
            if(aqualink_data.battery == "low") {
                if(document.getElementById('battery_low').style.visibility=='visible') {
                    document.getElementById('battery_low').style.visibility='hidden';
                }
                else {
                    document.getElementById('battery_low').style.visibility='visible';
                }
            }
        }
        setInterval(flash_battery_icon, 500);
        
        function update_date_time() {
            var el = document.getElementById("date_time");
            
            el.innerHTML = aqualink_data.time + " - " + aqualink_data.date;
        }
        
        function blink_filter_pump() {
            if(aqualink_data.leds.pump == "enabled") {
                document.getElementById("pump_status").src = (document.getElementById("pump_status").src.indexOf("images/led_on.png") == -1)?"images/led_on.png":"images/led_off.png";
            }
        }
        setInterval(blink_filter_pump, 500);
        
        function update_leds() {
            
            if(aqualink_data.leds.pump == "on") {
                document.getElementById('pump_off_status').style.visibility='hidden';
                document.getElementById('pump_on_status').style.visibility='visible';
            }
            else {
                document.getElementById('pump_on_status').style.visibility='hidden';
                document.getElementById('pump_off_status').style.visibility='visible';
            }
            
            if(aqualink_data.leds.spa == "on") {
                document.getElementById('spa_off_status').style.visibility='hidden';
                document.getElementById('spa_on_status').style.visibility='visible';
            }
            else {
                document.getElementById('spa_on_status').style.visibility='hidden';
                document.getElementById('spa_off_status').style.visibility='visible';
            }
            
            if(aqualink_data.leds.aux1 == "on") {
                document.getElementById('aux1_off_status').style.visibility='hidden';
                document.getElementById('aux1_on_status').style.visibility='visible';
            }
            else {
                document.getElementById('aux1_on_status').style.visibility='hidden';
                document.getElementById('aux1_off_status').style.visibility='visible';
            }
            
            if(aqualink_data.leds.aux2 == "on") {
                document.getElementById('aux2_off_status').style.visibility='hidden';
                document.getElementById('aux2_on_status').style.visibility='visible';
            }
            else {
                document.getElementById('aux2_on_status').style.visibility='hidden';
                document.getElementById('aux2_off_status').style.visibility='visible';
            }
            
            if(aqualink_data.leds.aux3 == "on") {
                document.getElementById('aux3_off_status').style.visibility='hidden';
                document.getElementById('aux3_on_status').style.visibility='visible';
            }
            else {
                document.getElementById('aux3_on_status').style.visibility='hidden';
                document.getElementById('aux3_off_status').style.visibility='visible';
            }
            
            if(aqualink_data.leds.aux4 == "on") {
                document.getElementById('aux4_off_status').style.visibility='hidden';
                document.getElementById('aux4_on_status').style.visibility='visible';
            }
            else {
                document.getElementById('aux4_on_status').style.visibility='hidden';
                document.getElementById('aux4_off_status').style.visibility='visible';
            }
            
            if(aqualink_data.leds.aux5 == "on") {
                document.getElementById('aux5_off_status').style.visibility='hidden';
                document.getElementById('aux5_on_status').style.visibility='visible';
            }
            else {
                document.getElementById('aux5_on_status').style.visibility='hidden';
                document.getElementById('aux5_off_status').style.visibility='visible';
            }
            
            if(aqualink_data.leds.aux6 == "on") {
                document.getElementById('aux6_off_status').style.visibility='hidden';
                document.getElementById('aux6_on_status').style.visibility='visible';
            }
            else {
                document.getElementById('aux6_on_status').style.visibility='hidden';
                document.getElementById('aux6_off_status').style.visibility='visible';
            }
            
            if(aqualink_data.leds.aux7 == "on") {
                document.getElementById('aux7_off_status').style.visibility='hidden';
                document.getElementById('aux7_on_status').style.visibility='visible';
            }
            else {
                document.getElementById('aux7_on_status').style.visibility='hidden';
                document.getElementById('aux7_off_status').style.visibility='visible';
            }
            
            if(aqualink_data.leds.pool_heater == "off") {
                document.getElementById('pool_htr_on_status').style.visibility='hidden';
                document.getElementById('pool_htr_en_status').style.visibility='hidden';
                document.getElementById('pool_htr_off_status').style.visibility='visible';
            }
            else if(aqualink_data.leds.pool_heater == "on") {
                document.getElementById('pool_htr_on_status').style.visibility='visible';
                document.getElementById('pool_htr_en_status').style.visibility='hidden';
                document.getElementById('pool_htr_off_status').style.visibility='hidden';
            }
            else if(aqualink_data.leds.pool_heater == "enabled") {
                document.getElementById('pool_htr_on_status').style.visibility='hidden';
                document.getElementById('pool_htr_en_status').style.visibility='visible';
                document.getElementById('pool_htr_off_status').style.visibility='hidden';
            }
            
            if(aqualink_data.leds.spa_heater == "off") {
                document.getElementById('spa_htr_on_status').style.visibility='hidden';
                document.getElementById('spa_htr_en_status').style.visibility='hidden';
                document.getElementById('spa_htr_off_status').style.visibility='visible';
            }
            else if(aqualink_data.leds.spa_heater == "on") {
                document.getElementById('spa_htr_on_status').style.visibility='visible';
                document.getElementById('spa_htr_en_status').style.visibility='hidden';
                document.getElementById('spa_htr_off_status').style.visibility='hidden';
            }
            else if(aqualink_data.leds.spa_heater == "enabled") {
                document.getElementById('spa_htr_on_status').style.visibility='hidden';
                document.getElementById('spa_htr_en_status').style.visibility='visible';
                document.getElementById('spa_htr_off_status').style.visibility='hidden';
            }
            
            if(aqualink_data.leds.solar_heater == "off") {
                document.getElementById('solar_htr_on_status').style.visibility='hidden';
                document.getElementById('solar_htr_en_status').style.visibility='hidden';
                document.getElementById('solar_htr_off_status').style.visibility='visible';
            }
            else if(aqualink_data.leds.solar_heater == "on") {
                document.getElementById('solar_htr_on_status').style.visibility='visible';
                document.getElementById('solar_htr_en_status').style.visibility='hidden';
                document.getElementById('solar_htr_off_status').style.visibility='hidden';
            }
            else if(aqualink_data.leds.solar_heater == "enabled") {
                document.getElementById('solar_htr_on_status').style.visibility='hidden';
                document.getElementById('solar_htr_en_status').style.visibility='visible';
                document.getElementById('solar_htr_off_status').style.visibility='hidden';
            }
        }
        
        function update_status(data) {
            aqualink_data = data;
            console.log(aqualink_data.version);
            console.log('updating status...');
            if(aqualink_data.battery == "ok") {
                document.getElementById('battery_low').style.visibility='hidden';
                document.getElementById('battery_ok').style.visibility='visible';
            }
            else {
                document.getElementById('battery_ok').style.visibility='hidden';
            }
            
            update_temp("air_temp");
            update_temp("pool_temp");
            update_temp("spa_temp");
            update_temp("pool_htr_set_pnt");
            update_temp("spa_htr_set_pnt");
            update_temp("frz_protect_set_pnt");
            
            update_date_time();
            
            update_leds();
        }
        
    </script>
</head>
<body ontouchmove="BlockMove(event);" > 

<div id="main_div">

    <div id="header_div" class='bgimg'>
        <div id="line1">
            <div id="title_div">Aqualink RS8</div>
            <div id="air_temp_title_div">Air Temp:</div>
            <div id="air_temp">000 F</div>
            <div id="battery_ok_div" class="battery_image_div">[img][/img]</div>
            <div id="battery_low_div" class="battery_image_div">[img][/img]</div>
            <div id="battery_blank_div" class="battery_image_div">[img][/img]</div>
        </div>
        <div id="line2">
            <div id="net_off_div" class="net_activity_div">[img][/img]</div>
            <div id="net_green_div" class="net_activity_div">[img][/img]</div>
            <div id="net_yellow_div" class="net_activity_div">[img][/img]</div>
            <div id="net_red_div" class="net_activity_div">[img][/img]</div>
            <div id="date_time">00:00 PM 00/00/00 DDD</div>
        </div>
    </div>
    
    <div id="body_div" class="bgimg_body">
        <div id="pool_temp_div" class="body_sub_div">
            <div id="pool_temp_title" class="temp_title_div">Pool:</div>
            <div id="pool_temp" class="temp_val_div">000 F</div>
            <div class="led_button_div" id="pool_htr">
                <div class="htr_led_div">[img][/img]</div>
                <div class="htr_led_div">[img][/img]</div>
                <div class="htr_led_div">[img][/img]</div>
                <div class="htr_button_div"><input class='button black' type="button" onclick="queue_command('KEY_HTR_POOL')" value="Heater"/></div>
            </div>
            <div id="pool_htr_set_pnt" class="set_pnt_val_div">000 F</div>
            <div class="set_pnt_button_div">
                <input class='button black' type="button" onclick="incr_pool_htr('+')" value="+"/>
                <input class='button black' type="button" onclick="incr_pool_htr('-')" value="-"/>
            </div>
            <div class="set_button_div"><input class='button black' type="button" onclick="set_pool_htr" value="Set"/></div>
        </div>
        <div id="spa_temp_div" class="body_sub_div">
            <div id="spa_temp_title" class="temp_title_div">Spa:</div>
            <div id="spa_temp" class="temp_val_div">000 F</div>
            <div class="led_button_div" id="pool_htr">
                <div class="htr_led_div">[img][/img]</div>
                <div class="htr_led_div">[img][/img]</div>
                <div class="htr_led_div">[img][/img]</div>
                <div class="htr_button_div"><input class='button black' type="button" onclick="queue_command('KEY_HTR_SPA')" value="Heater"/></div>
            </div>
            <div id="spa_htr_set_pnt" class="set_pnt_val_div">000 F</div>
            <div class="set_pnt_button_div">
                <input class='button black' type="button" onclick="incr_spa_htr('+')" value="+"/>
                <input class='button black' type="button" onclick="incr_spa_htr('-')" value="-"/>
            </div>
            <div class="set_button_div"><input class='button black' type="button" onclick="set_spa_htr" value="Set"/></div>
        </div>
        <div id="solar_htr_div" class="body_sub_div">
            <div class="temp_title_div">Solar:</div>
            <div class="solar_led_div">[img][/img]</div>
            <div class="solar_led_div">[img][/img]</div>
            <div class="solar_led_div">[img][/img]</div>
            <div id="solar_button_div"><input class='button black' type="button" onclick="queue_command('KEY_HTR_SOLAR')" value="Heater"/></div>
        </div>
        <div id="frz_protect_div" class="body_sub_div">
            <div class="temp_title_div">Freeze Protection:</div>
            <div id="frz_protect_set_pnt">000 F</div>
            <div id="fp_set_pnt_button_div">
                <input class='button black' type="button" onclick="incr_frz_protect('+')" value="+"/>
                <input class='button black' type="button" onclick="incr_frz_protect('-')" value="-"/>
            </div>
            <div id="fp_set_button_div"><input class='button black' type="button" onclick="set_frz_protect" value="Set"/></div>
        </div>
        <div id="leds_div" class="body_sub_div">
            <div class="led_button_div" id="filter_pump">
                <div class="led_div">[img][/img]</div>
                <div class="led_div">[img][/img]</div>
                <div class="button_div"><input class='button black' type="button" onclick="queue_command('KEY_PUMP')" value="Filter Pump"/></div>
            </div>
            <div class="led_button_div" id="spa_mode">
                <div class="led_div">[img][/img]</div>
                <div class="led_div">[img][/img]</div>
                <div class="button_div"><input class='button black' type="button" onclick="queue_command('KEY_SPA')" value="Spa"/></div>
            </div>
            <div class="led_button_div" id="aux1">
                <div class="led_div">[img][/img]</div>
                <div class="led_div">[img][/img]</div>
                <div class="button_div"><input id="aux1_button" class='button black' type="button" onclick="queue_command('KEY_AUX1')" value="Aux 1"/></div>
            </div>
            <div class="led_button_div" id="aux2">
                <div class="led_div">[img][/img]</div>
                <div class="led_div">[img][/img]</div>
                <div class="button_div"><input id="aux2_button" class='button black' type="button" onclick="queue_command('KEY_AUX2')" value="Aux 2"/></div>
            </div>
            <div class="led_button_div" id="aux3">
                <div class="led_div">[img][/img]</div>
                <div class="led_div">[img][/img]</div>
                <div class="button_div"><input id="aux3_button" class='button black' type="button" onclick="queue_command('KEY_AUX3')" value="Aux 3"/></div>
            </div>
            <div class="led_button_div" id="aux4">
                <div class="led_div">[img][/img]</div>
                <div class="led_div">[img][/img]</div>
                <div class="button_div"><input id="aux4_button" class='button black' type="button" onclick="queue_command('KEY_AUX4')" value="Aux 4"/></div>
            </div>
            <div class="led_button_div" id="aux5">
                <div class="led_div">[img][/img]</div>
                <div class="led_div">[img][/img]</div>
                <div class="button_div"><input id="aux5_button" class='button black' type="button" onclick="queue_command('KEY_AUX5')" value="Aux 5"/></div>
            </div>
            <div class="led_button_div" id="aux6">
                <div class="led_div">[img][/img]</div>
                <div class="led_div">[img][/img]</div>
                <div class="button_div"><input id="aux6_button" class='button black' type="button" onclick="queue_command('KEY_AUX6')" value="Aux 6"/></div>
            </div>
            <div class="led_button_div" id="aux7">
                <div class="led_div">[img][/img]</div>
                <div class="led_div">[img][/img]</div>
                <div class="button_div"><input id="aux7_button" class='button black' type="button" onclick="queue_command('KEY_AUX7')" value="Aux 7"/></div>
            </div>
        </div>
    </div>

    <div id="footer_div" class="bgimg">
    </div>

</div>

</body>
</html>
 
Re: Control your Jandy equipment from your PC with a $15 ada

civicturbo,

Let me know what you find out. My Aqualink RS8 is about 20 years old. It was about $1200.00, for the complete system including terminals, back then, but that was through the pool builder. I am sure there was considerable mark up. One of the reasons I started this project was that I wanted to replace the terminal for aesthetic reasons. The replacement terminals I found ranged in price from $650.00 to $1100.00 and none of them had the look or behavior I was looking for. For that kind of money I could replace it with a wall mounted dedicated iPad. I think everyone would agree that would be overkill.
I am currently looking for a really inexpensive 7" Android pad to replace the terminal on the wall. I have seen them for as cheap as $60.00 online. When I finish this project I will document it so anyone can build one.
One word of caution on the code I posted. It is incomplete, barely at beta stage. And as I stated in one of my earlier posts, the current code has problems running for long periods of time. The part that talks to the Aqualink Power Center is pretty bullet proof. It has run for weeks without issue, but the mini web server has a memory leak, and possibly some other issues. I haven't had time to completely debug it. Good luck, and let me know if you find any other bugs. I will be more than happy to incorporate any fixes into my code, and post a package. By the way, I built the project in Eclipse CDT on Fedora Core 14 (Linux). I have a project file if you are interested. Let me know and I will post it. Have fun.

agent-p
 
Re: Control your Jandy equipment from your PC with a $15 ada

agent-P said:
derossi,

Here is the main source file. There are a total of 16 files. I broke up the functionality into logical groupings to make it easier to work on and extend. I was in a hurry so it is a little sloppy. In any case, here is the first one.

For some reason, I didn't get notified when this was posted :( I just decided to check back today. Thanks!
 
Re: Control your Jandy equipment from your PC with a $15 ada

derossi,

As I stated in one of my previous posts, the mini web server code that serves the REST services is broken, and doesn't work for long durations. It is really the wrong way to do it for this application, in any case. I will be rewriting it using web sockets, which will give the web app much better behavior, and limit the number of threads the server needs. I will post the updated code when I have it working. If you find the bug in my mini web server please post the solution, or at least the location in the code. I am very curious where I messed up.

agent-p
 
Re: Control your Jandy equipment from your PC with a $15 ada

For anyone who is interested. I rewrote the integrated mini-webserver using web sockets. Very stable so far. I have it in duration testing. Going to let it run for about a week to make sure it is relatively bullet proof. Also, reworked the interface for the web app to make it fit in the browser of a 7in. Android pad. See attached image. Working in both FireFox and Chrome now. Also tested on Safari for iPad and desktop Mac OS 10.7.x. Also, interface is now completely functional. All three set points are working.
 

Attachments

  • screenshot.jpg
    screenshot.jpg
    89.8 KB · Views: 285
Re: Control your Jandy equipment from your PC with a $15 ada

Agent-P Wow great work! You must write software for a living nice interface, I'll keep watching this thread then when it's ready I may give this a try on my pool. Thanks for sharing w/ us!
 
Re: Control your Jandy equipment from your PC with a $15 ada

Okay here it is. I zipped it up into a nice clean package with everything in it. Daemon is completely stable. Web client is a little finicky on touch screens. Tried google fast buttons which support touch and block "onclick", but it seemed to be only as good as using "onclick". Looking into writing a native Android app for the controller on the wall, but the web controller works great for the desktop browsers where you actually have a mouse to click the buttons.

I included the conf file, and web client in their respective directories for anyone who wants to try it. Also, included full source. You will need some libraries which are easily downloadable. Read the "ReadMe" file, and post here if you have any questions or need help building it. Note that I will post an executable for Linux FC14 if anyone wants it. Simply let me know.

agent-P
 

Attachments

  • AqualinkRS8.zip
    93 KB · Views: 168

Enjoying this content?

Support TFP with a donation.

Give Support
Re: Control your Jandy equipment from your PC with a $15 ada

Agent-p, thanks for your hard work on this! I'm going to give it a try here soon; my solution works, but is pretty tragically old school and could use something new, especially something that's multiplatform.

Brad
 
Re: Control your Jandy equipment from your PC with a $15 ada

Brad,

No sweat. It was kind of fun, even if it was a little frustrating at times. By the way, I just got the whole daemon management working in Linux FC14. I am not sure what OS you plan to use, but I can send you the config file if you want.

agent-P
 
Re: Control your Jandy equipment from your PC with a $15 ada

Brad,

Found a bug in the time setting thread. Not sure how i missed it. I remember testing the heck out of it. Anyway, here is the fix:
Code:
/*
 * aqualink_time.c
 *
 *  Created on: Sep 22, 2012
 */

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>

#include "aqualink.h"
#include "globals.h"

int check_aqualink_time(char* _date, char* _time)
{
	time_t now;
	struct tm *tmptr;
	int time_date_correct = FALSE;

	int a_hour;
	int a_min;
	int a_day;
	int a_month;
	int a_year;
	char a_pm[3];

	// Get the current time.
	time(&now);
	tmptr = localtime(&now);

	// Make sure time is at least 2 minutes apart to prevent HI/LO toggling.
	// Get the minutes for each time for a comparison.
	struct tm str_time;
	time_t aqualink_time;

	// Parse the time and date components to create a time value for
	// comparison to the current time.
	sscanf(_time, "%d:%d %s", &a_hour, &a_min, a_pm);
	sscanf(_date, "%d/%d/%d", &a_month, &a_day, &a_year);

	// Build a time structure from the Aqualink time.
	str_time.tm_year = a_year + 2000 - 1900;  // adjust for correct century
	str_time.tm_mon = a_month - 1;     // adjust or correct date 0-based index
	str_time.tm_mday = a_day;
	if(a_hour < 12 && (strstr(a_pm, "PM") != NULL)) {
		str_time.tm_hour =  a_hour + 12;
	}
	else if(a_hour == 12 && (strstr(a_pm, "AM") != NULL)) {
		str_time.tm_hour =  0;
	}
	else {
		str_time.tm_hour = a_hour;
	}
	str_time.tm_min = a_min;
	str_time.tm_sec = 0;       // Aqualink time doesn't have seconds.
	str_time.tm_isdst = 0;     // always standard time in AZ

	// Make the Aqualink time value.
	aqualink_time = mktime(&str_time);
	log_message(DEBUG, "s", ctime(&now));
	log_message(DEBUG, "s", ctime(&aqualink_time));

	// Calculate the time difference between Aqualink time and local time.
	int time_difference = (int)difftime(now, aqualink_time);

	log_message(DEBUG, "sis", "Aqualink time is off by ",  time_difference, " seconds...");

	if(abs(time_difference) <= 90) {
		// Time difference is less than or equal to 90 seconds (1 1/2 minutes).
		// Set the return value to TRUE.
		time_date_correct = TRUE;
	}

	return time_date_correct;
}


/* Set the Aqualink RS8's time's year to the local time's year.
 *
 */
void set_aqualink_time_field(int field, char* field_string)
{
	log_message(DEBUG, "s", "Attempting to set aqualink time field...");

	int local_field;
	char local_mod[MAX_TIME_FIELD_LENGTH];
	int aqualink_field;
	char field_id[MAX_TIME_FIELD_LENGTH];
	char field_mod[MAX_TIME_FIELD_LENGTH];

	// Parse the local time field string.
	sscanf(field_string, "%d %s", &local_field, local_mod);

	if(strstr(aqualink_data.last_message, TIME_FIELD_TEXT[field]) != NULL) {
		do {
			// Parse the numeric field from the Aqualink data string.
			sscanf(aqualink_data.last_message, "%s %d %s", field_id, &aqualink_field, field_mod);

			if(strcmp(local_mod, "AM") == 0 || strcmp(local_mod, "PM") == 0) {
				if(strcmp(local_mod, field_mod) == 0 && local_field == aqualink_field) {
					// Field is set correctly. Send the ENTER command
					// to move to the next time field, and break out
					// of the loop.
					send_cmd("KEY_ENTER");
					break;
				}
				else {
					// Increment the field.
					send_cmd("KEY_RIGHT");
				}
			}
			else {
				log_message(DEBUG, "sisi", "current value: ", aqualink_field, "  -  set value: ", local_field);
				if(aqualink_field < local_field) {
					// Increment the field.
					send_cmd("KEY_RIGHT");
				}
				else if(aqualink_field > local_field) {
					// Decrement the field.
					send_cmd("KEY_LEFT");
				}
				else {
					// Field is set correctly. Send the ENTER command
					// to move to the next time field, and break out
					// of the loop.
					send_cmd("KEY_ENTER");
					break;
				}
			}

			// Wait one second.
			sleep(1);
		} while(aqualink_field != local_field);
	}
}


/* Set the Aqualink RS8's time to the local time.
 *
 */
void* set_aqualink_time(void* arg)
{
	log_message(INFO, "s", "Attempting to set aqualink time...");

	if(!PROGRAMMING) {
		// Set the flag to let the daemon know a program of multiple
		// commands is being sent to the Aqualink RS8.
		PROGRAMMING = TRUE;

		const int YEAR_LENGTH = 5;
		const int MONTH_LENGTH = 3;
		const int DAY_LENGTH = 3;
		const int HOUR_LENGTH = 6;
		const int MINUTE_LENGTH = 3;

		int set_time_mode = FALSE;

		time_t now;
		struct tm *tmptr;
		char year[YEAR_LENGTH];
		char month[MONTH_LENGTH];
		char day[DAY_LENGTH];
		char hour[HOUR_LENGTH];
		char minute[MINUTE_LENGTH];

		// Detach the thread so that it cleans up as it exits. Memory leak without it.
		pthread_detach(pthread_self());

		// Get the current time.
		time(&now);
		tmptr = localtime(&now);

		// Convert to time and date strings compatible with the Aqualink
		// time and date strings.
		strftime(year, YEAR_LENGTH, "%y", tmptr);
		strftime(month, MONTH_LENGTH, "%m", tmptr);
		strftime(day, DAY_LENGTH, "%d", tmptr);
		strftime(hour, HOUR_LENGTH, "%I %p", tmptr);
		strftime(minute, MINUTE_LENGTH, "%M", tmptr);

		// Select the MENU and wait 1 second to give the RS8 time to respond.
		send_cmd("KEY_MENU");
		sleep(1);

		// Select the SET TIME mode. Note only 10 attempts to enter the mode
		// are made.
		int iterations = 0;
		while(!set_time_mode && iterations < 10) {
			//log_message(DEBUG, aqualink_data.last_message);
			if(strstr(aqualink_data.last_message, "SET TIME") != NULL) {
				// We found SET TIME mode. Set the flag to break out of the
				// loop.
				set_time_mode = TRUE;

				// Enter SET TIME mode.
				send_cmd("KEY_ENTER");
				sleep(1);
			}
			else {
				// Next menu item and wait 1 second to give the RS8 time
				// to respond.
				send_cmd("KEY_RIGHT");
				sleep(1);
			}
			iterations++;
		}

		// If we are in set time mode, attempt to set the time, else the
		// function just falls through and returns. A warning is logged.
		if(set_time_mode) {

			while(set_time_mode) {
				if(strstr(aqualink_data.last_message, TIME_FIELD_TEXT[YEAR]) != NULL) {
					set_aqualink_time_field(YEAR, year);
				}
				else if(strstr(aqualink_data.last_message, TIME_FIELD_TEXT[MONTH]) != NULL) {
					set_aqualink_time_field(MONTH, month);
				}
				else if(strstr(aqualink_data.last_message, TIME_FIELD_TEXT[DAY]) != NULL) {
					set_aqualink_time_field(DAY, day);
				}
				else if(strstr(aqualink_data.last_message, TIME_FIELD_TEXT[HOUR]) != NULL) {
					set_aqualink_time_field(HOUR, hour);
				}
				else if(strstr(aqualink_data.last_message, TIME_FIELD_TEXT[MINUTE]) != NULL) {
					set_aqualink_time_field(MINUTE, minute);
				}
				else {
					set_time_mode = FALSE;
				}
				sleep(1);
			}
			log_message(INFO, "ssssssssss", "Aqualink time set to: ",
					year, "-",
					month, "-",
					day, "  ",
					hour, ":",
					minute
			);
		}
		else {
			log_message(WARNING, "s", "Could not enter SET TIME mode.");
		}

		// Reset the programming state flag.
		PROGRAMMING = FALSE;
	}
	else {
		// A multiple command program is currently being sent to the aqualink
		// controller. Just log it, and fall through to the function return.
		// Time set will be retried by the main program loop that checks that
		// aqualink time is correct.
		log_message(INFO, "s", "Aqualink Programming in progress. Could not set time.");
	}

	return 0;
}
 
Re: Control your Jandy equipment from your PC with a $15 ada

New to the board. Thanks for posting this info. I've actually been looking at doing this same exact thing: put away the slooooowwww Jandy PDA I have and tie in to the main Aqualink wirelessly so I can write an iPhone app to control the pool gear. I am considering an Electric Imp to handle the wireless comms, or an Arduino and medium-range wireless. Glad to see others are shooting at the same target. Not sure if I can do it with my system...I inherited it with the house I bought. The house is only 8 years old, so I imagine the system can't be that old.
 
Re: Control your Jandy equipment from your PC with a $15 ada

I just started hacking my Aqualink 2 days ago. I am using a $14 HSXP-2108F RS485 to USB adapter and a $35 Raspberry Pi running Arch Linux. The Arch distro has the driver for the serial adapter, so there were no issues with the hardware. In about half a day I was able to write a Python program to read and parse the messages using hints from this program http://www.3waylabs.com/nw/software/aqualink.c. Then I found agent-P's code on this forum which does much of what I want to do, which is to be able to control and monitor my spa from an iPhone or laptop. What I may do is to write a different web front end on top of that code, since it seems pretty robust.
 
Re: Control your Jandy equipment from your PC with a $15 ada

Hi jbuehl,

I like the sound of your hardware setup. I thought about something similar, but had a bunch of old mother boards laying around, and FC14 was a very nice development environment. Pretty small package and only using about 1% of the CPU, and lots of room for logging. I am using a dual serial adapter. So, I was considering setting up a second channel for a separate programming channel, or for high rate monitoring on an individual parameter. My air temp sensor is a little flakey, and I wanted to see how bad over time and temp range.

Currently, though, I am identifying all of the failure modes, and documenting and processing the associated error messages like "OPEN" and "SHORTED" temp sensors. Also looking for a good way to display the errors if you have any suggestions.

I have made some major upgrades and bug fixes since I posted the code. I should wrap the next version of both client and server in a couple of weeks. I will post an update when it is done.

I am using a cheap 7" android pad right now for pool side. Nice fit for the current web app. I expect to write a full featured multi page web app for a large format display so I won't need the ugly control terminal on the wall any longer. So, I am not sure I will have the time to write a version of the web app that will work well on an iPhone. You could try simply modifying my html and css files to remove and rearrage some of the controls. Please post your iPhone version here. I would love to see some one else's perspective on what works well. Anyway, good luck with your project. Hope my code is helpful.

Agent-P
 
Re: Control your Jandy equipment from your PC with a $15 ada

Note to aaplmike, your power center should have an RS485 network built in. I recommend running a twisted pair from it to a serial adapter (lots of different kinds) to a very small Linux box that you can run a mini web server like my daemon on. (Once you have the server working the variations and simplicity of the web clients are fantastic. By the way, use web sockets to connect your web client to the server. I tried a couple of other techniques, but nothing was as good.) That way you can use your home wifi to control it from a browser from any wireless device you might have. Also, at that point it is pretty much a no brainer to control it from anywhere on the planet through a VPN connection to your home LAN. My two cents, hope it is helpful.
I have done a lot of research and discovery on what does and doesn't work, and what is easy and what is difficult. I would be happy to answer any questions you might have.

agent-P
 
Re: Control your Jandy equipment from your PC with a $15 ada

@agent-p & jbuhel thanks for the awesome information. I have been watching this thread and like what I am seeing. I think I may move in the same direction you all are. I have a powered waterproof box w/ a router by my equipment ready for the autelis controller but haven't pulled the trigger due to price. I like the cheaper alternatives.

I should still have enough room in the box possibly for the raspberry pi if not another box on the fence won't hut anything. Not sure about programming but I am willing to learn. I have the hardware side of thing being an electronic tech for a living so I maybe asking alot of question on the software side of the house.

Jerry

Sent from my HTC One X using Tapatalk 2
 
Re: Control your Jandy equipment from your PC with a $15 ada

I would like to take a look at what you've done. Have you seen the Autelis adapter? I sprung for that and the wifi kit and so far it seems pretty good, without having to go too DIY crazy... But I do need to upgrade my RS FW... still on PS6/PDA3.0, the Autelis mod is way sweeter on the the upgraded FW. Auto send Twitter feeds, email etc...
 
Re: Control your Jandy equipment from your PC with a $15 ada

agent-P, I haven't been able to build your project successfully on arch linux yet. I need to find source for libwebsockets that includes libwebsocket_internal_extensions, which is showing up as an undefined reference. I built libwebsockets from source that I got from here http://git.warmcat.com/cgi-bin/cgit/libwebsockets/, but the 0.5 release doesn't define that symbol and the 0.6 release, which does, is missing the Makefile stuff from the tarball. I see that Fedora 17 has a package available called jetty-websocket, but I haven't located the source for that one yet. Any suggestions?
 

Enjoying this content?

Support TFP with a donation.

Give Support
Thread Status
Hello , This thread has been inactive for over 60 days. New postings here are unlikely to be seen or responded to by other members. For better visibility, consider Starting A New Thread.