Toggle Arduino LED/relay from external webserver


hi,

i want control led/relay external webserver arduino nano , w5500 ethernet chip in realtime (latency button click on website ---> led toggle should lower 1sec). task simple udp arduino behind nat/router dynamic ip , port forwarding not possible can't send udp packets external webserver arduino.

arduino <---> nat/router <---> webserver

to solve this, establish tcp connection arduino webserver. it's python webserver , handle connection in own thread. when presses button toggle led, webserver appends command ('0' or '1') tcp handler thread sends command via established tcp connection arduino.
problem: works many minutes/hours tcp connection stucks. arduino thinks connection established , don't timeout exception or on python thread no data received/transmitted.

has idea how can solve problem?


this arduino code:

code: [select]
#include <spi.h>
#include <ethernet2.h>
#include "utility/w5500.h"

// enter mac address controller below.
// newer ethernet shields have mac address printed on sticker on shield
byte mac[] = {
        0x00, 0xaa, 0xbb, 0xcc, 0xde, 0x02
};

unsigned int tcpport = 8080;
ipaddress server(192, 168, 100, 28);

ethernetclient client;

// status led
const int pin_led_tcp = 4;

// relais pins
const int pin_relais1 = 5;

void setup() {
    // open serial communications , wait port open:
    serial.begin(9600);

    // init , turn off relais
    pinmode(pin_relais1, output);
    digitalwrite(pin_relais1, high);

    // init , turn off status led
    pinmode(pin_led_tcp, output);
    digitalwrite(pin_led_tcp, low);

    // start ethernet connection:
    if (ethernet.begin(mac) == 0) {
        serial.println("failed configure ethernet using dhcp");
        // no point in carrying on, nothing forevermore:
        (;;);
    }

    // connect tcp
    connecttcp();
}

void loop() {
    uint8_t status = client.status();
    if(status != snsr::established){
        serial.println("connection lost...");
        digitalwrite(pin_led_tcp, low);
        serial.println(status, hex);
        for(size_t i=0; i<max_sock_num; i++){
            serial.print("state ");
            serial.print(i);
            serial.print(": ");
            serial.println(ethernet._state[i]);
        }

        client.stop();
        //reconnect
        connecttcp();
    } else {
        // turn led on if arduino connected
        digitalwrite(pin_led_tcp, high);
    }

    char cmd = -1;

    if (client.available()) {
        cmd = client.read();
    }

    // execute command
    switch (cmd) {
        case '1':
            serial.println("turn lights on...");
            digitalwrite(pin_relais1, low);
            break;
        case '0':
            serial.println("turn lights off...");
            digitalwrite(pin_relais1, high);
            break;
        case 'p': // ping
            serial.println("got ping");
            client.write('p');
            break;
        case -1: // no command
            break;
        default:
            serial.println("unknown command");
            serial.println(cmd);
            break;

    }
}

bool connecttcp(){
    // if connection, report via serial:
    if (client.connect(server, tcpport)) {
        serial.println("connected");
        return true;
    } else {
        // if didn't connection server:
        serial.println("connection failed");
    }

    return false;
}



and python tcp handler:

code: [select]

class arduinosocket(object):

    def __init__(self, port, logger):
        self.port = port
        self.logger = logger
        self.sock = self.__create_socket()
        self.running = true
        self.commands = []
        self.send_timeout = 5.0

        # start loop
        self.thread = thread(target=self.loop)
        self.thread.start()

    def __create_socket(self):
        self.logger.debug("create new socket")
        sock = socket.socket(socket.af_inet, socket.sock_stream)
        sock.settimeout(2.0)
        sock.setsockopt(socket.sol_socket, socket.so_reuseaddr, 1)
        """set tcp keepalive on open socket.
        activates after 1 second (after_idle_sec) of idleness,
        sends keepalive ping once every 3 seconds (interval_sec),
        , closes connection after 5 failed ping (max_fails), or 15 seconds
        """
        #sock.setsockopt(socket.sol_socket, socket.so_keepalive, 1)
        #sock.setsockopt(socket.ipproto_tcp, socket.tcp_keepidle, 1)
        #sock.setsockopt(socket.ipproto_tcp, socket.tcp_keepintvl, 3)
        #sock.setsockopt(socket.ipproto_tcp, socket.tcp_keepcnt, 5)
        sock.bind(("0.0.0.0", self.port))
        sock.listen(8)
        return sock

    def loop(self):
        clientsocket = none
        last_ping = time.time()

        while self.running:
            if clientsocket none:
                try:
                    (clientsocket, address) = self.sock.accept()
                    self.logger.debug("got connection {}".format(address))
                except ioerror, e:
                    self.logger.error("ioerror {}".format(e))
                    continue
                except socket.timeout:
                    self.logger.error("timeout {}".format(e))
                    continue
                except exception e:
                    self.logger.error("unknown error {}".format(e))
           
            if len(self.commands) > 0 , clientsocket not none:
                try:
                    t, cmd = self.commands[0]
                    if time.time() - t < self.send_timeout:
                        self.logger.debug("send command {}".format(cmd))
                        clientsocket.send(str(cmd))
                    self.commands.pop(0)
                except ioerror e:
                    self.logger.error("clientsocket.send() ioerror {}".format(e))
                    if clientsocket not none:
                        clientsocket.close()
                        clientsocket = none
                except exception e:
                    self.logger.error("clientsocket.send() unknown error {}".format(e))
                    if clientsocket not none:
                        clientsocket.close()
                        clientsocket = none
            elif time.time() - last_ping > 5:
                try:
                    if clientsocket not none:
                        self.logger.debug("send ping")
                        clientsocket.send("p")
                        last_ping = time.time()
                    else:
                        self.logger.debug("no clientsocket send ping")
                except ioerror e:
                    self.logger.error("clientsocket.send() ioerror {}".format(e))
                    if clientsocket not none:
                        clientsocket.close()
                        clientsocket = none
                except exception e:
                    self.logger.error("clientsocket.send() unknown error {}".format(e))
                    if clientsocket not none:
                        clientsocket.close()
                        clientsocket = none             

    def send(self, cmd):
        self.commands.append((time.time(), cmd))

i guess nat device forgets connection when no data transmitted time. might have insert keep-alive signal protocol.


Arduino Forum > Using Arduino > Networking, Protocols, and Devices (Moderator: fabioc84) > Toggle Arduino LED/relay from external webserver


arduino

Comments

Popular posts from this blog

Error compiling for board Arduino/Genuino Uno.

Installation database is corrupt

esp8266 (nodemcu 0.9) client.write très lent ???