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:
and python tcp handler:
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
Post a Comment