_threads, sockets and interruption with ESP32
_threads, sockets and interruption with ESP32
Hello,
I am trying to stabilize a FTP server I found here : https://github.com/lemariva/uPyPortal
For that, I loop on client connection.
But, when doing Ctrl + C on the python console, the thread doesn't exit properly. It seems to be running in the background of the os (but in a bad state because FTP client connection gives nothing). And then when the ftp server starts again, it can't bind the socket.
Things I am trying to do thing right. Is there for example a way to cach an interrupt/exit signal and setting a callback in the FTP class (that will properly clothe the sockets) ?
Thank you
I am trying to stabilize a FTP server I found here : https://github.com/lemariva/uPyPortal
For that, I loop on client connection.
But, when doing Ctrl + C on the python console, the thread doesn't exit properly. It seems to be running in the background of the os (but in a bad state because FTP client connection gives nothing). And then when the ftp server starts again, it can't bind the socket.
Things I am trying to do thing right. Is there for example a way to cach an interrupt/exit signal and setting a callback in the FTP class (that will properly clothe the sockets) ?
Thank you
Re: _threads, sockets and interruption with ESP32
Generally speaking (i'm not sure about the ESP32) you can use a try/except handler to grab the KeyboardInterrupt exception and use that to perform cleanup (i.e. close open sockets etc). Here's a simple example for the pyboard:
Code: Select all
import pyb
try:
while 1:
print('hello')
pyb.delay(100)
except KeyboardInterrupt:
print('Caught Control-C')
-
- Posts: 847
- Joined: Mon Nov 20, 2017 10:18 am
Re: _threads, sockets and interruption with ESP32
I normally find that not only do I need to catch keyboard interrupt and deint but I need to catch all errors to deint while debugging my programs. Because if your debugging a program and it crashes and ends then you fix the program and re-run it, all the previous thread, PWM, SPI and anything else created still are live and micropython creates another instance on top of the last one. I have become very good at having a a try and except catch and at the except making sure that I have deint everything or problems will arise.
Re: _threads, sockets and interruption with ESP32
I don't know if I am doing something wrong, but is seems that the except is not reached in a "background" running thread when I do a Ctrl+C on the Python command line...
Re: _threads, sockets and interruption with ESP32
Yes, understood.
I made a mistake, I wanted to speak of Ctrl + D.
Anyway, in a background thread, the Ctrl + C is not caught.
The Ctrl + D is not caught either.
In my example, the previously ran thread is not interrupted, and a next run of the thread fail in binding the sockets.
Do you have an idea ?
I made a mistake, I wanted to speak of Ctrl + D.
Anyway, in a background thread, the Ctrl + C is not caught.
The Ctrl + D is not caught either.
In my example, the previously ran thread is not interrupted, and a next run of the thread fail in binding the sockets.
Do you have an idea ?
-
- Posts: 847
- Joined: Mon Nov 20, 2017 10:18 am
Re: _threads, sockets and interruption with ESP32
In the except you will need to have a line of code that stops the thread. I am using laboris firmware and the code to stop a thread is _thread.stop(th_id) see https://github.com/loboris/MicroPython_ ... dstopth_id
I also suggest that in the except you stop anything else that you have started like SPI, PWM, PIN states
Just remember control C doesn't free all memory it just stop main program but all other allocation is still active
Also FYI laboris also has a FTP server module that I use all the time to transfer/edit files on my ESP32 see https://github.com/loboris/MicroPython_ ... /ftpserver
I also suggest that in the except you stop anything else that you have started like SPI, PWM, PIN states
Just remember control C doesn't free all memory it just stop main program but all other allocation is still active
Also FYI laboris also has a FTP server module that I use all the time to transfer/edit files on my ESP32 see https://github.com/loboris/MicroPython_ ... /ftpserver
Re: _threads, sockets and interruption with ESP32
Ok, thank you for your answers. I am rather new to Python and totally new on Python.
I wrote some test code here under. The filename is "test_threaded_socket.py". I have some questions...
1) Why __name__ returns the python file less ".py" rather than main ?
2) I think it is normal but surprising that using "if __name__ == "test_threaded_socket": main()" trick, it works only one time when doing "import test_threaded_socket".
3) How do you do when developping some code ? Always quit your serial terminal, use ampy, return to your serial terminal and reboot the ESP32 ? Is there a simpler way (I am trying to increase dev speed using FTP server on the ESP32...).
4) The example code show that KeyboardInterrupt is not caught if using "all exception" catching (except Exception as err:), thus I have to declare it specially (except KeyboardInterrupt:).
5) This code should be rock solid and ever work. But with two connection reset (Ctrl + C at client side), it does not restart. I may be missing something. Maybe the "finally" statement is not reentrant, and I should do the restart after the try/catch ?
6) When using Ctrl + D, what sould be a method for that a FTP server thread either still continue to run background, either be stopped and re-run ?
Thank you for your help.
I wrote some test code here under. The filename is "test_threaded_socket.py". I have some questions...
1) Why __name__ returns the python file less ".py" rather than main ?
2) I think it is normal but surprising that using "if __name__ == "test_threaded_socket": main()" trick, it works only one time when doing "import test_threaded_socket".
3) How do you do when developping some code ? Always quit your serial terminal, use ampy, return to your serial terminal and reboot the ESP32 ? Is there a simpler way (I am trying to increase dev speed using FTP server on the ESP32...).
4) The example code show that KeyboardInterrupt is not caught if using "all exception" catching (except Exception as err:), thus I have to declare it specially (except KeyboardInterrupt:).
5) This code should be rock solid and ever work. But with two connection reset (Ctrl + C at client side), it does not restart. I may be missing something. Maybe the "finally" statement is not reentrant, and I should do the restart after the try/catch ?
6) When using Ctrl + D, what sould be a method for that a FTP server thread either still continue to run background, either be stopped and re-run ?
Thank you for your help.
Code: Select all
import socket
import network
import uos
import gc
import _thread
import time
class threaded_socket():
def __init__(self):
self.mysocket = None
self.myclient = None
def start_socket_service(self):
print("Starting socket service, use : \"nc <ESP32 IP address> 23\"")
self.mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.mysocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.mysocket.bind(socket.getaddrinfo("0.0.0.0", 23)[0][4])
self.mysocket.listen(1)
self.mysocket.settimeout(None)
self.wlan = network.WLAN(network.AP_IF)
if self.wlan.active():
ifconfig = self.wlan.ifconfig()
else:
self.wlan = network.WLAN(network.STA_IF)
if self.wlan.active():
ifconfig = self.wlan.ifconfig()
else:
dbg("No active connection")
return
self.myclient, remote_addr = self.mysocket.accept()
self.myclient.settimeout(10)
self.myclient.sendall("Hello, this is the ESP8266/ESP32.\r\n")
line_count = 1
while True:
data = self.myclient.readline().decode("utf-8").rstrip("\r\n")
print(data)
self.myclient.sendall(str(line_count) + ": " + data + "\r\n" )
line_count = line_count +1
def loop_service(self):
try:
self.start_socket_service()
except KeyboardInterrupt:
print("Keyboard interruption caught")
self.cleaning()
except Exception as err:
print("exception caught :" + str(err))
self.cleaning()
finally:
print("Socket service will be restarted in 2 seconds")
time.sleep(2)
self.start_socket_service()
def cleaning(self):
print("Closing socket")
if self.myclient is not None:
self.myclient.close()
if self.mysocket is not None:
self.mysocket.close()
def main():
import test_threaded_socket
thsk = test_threaded_socket.threaded_socket()
thsk.loop_service()
print("This lib name is: " + __name__)
if __name__ == "test_threaded_socket": main()
-
- Posts: 847
- Joined: Mon Nov 20, 2017 10:18 am
Re: _threads, sockets and interruption with ESP32
ok I am using loboris firmware for fast development because it has telent and FTP builtin to the firmware.
I run a Telent repl over putty and use filezilla to edit transfer files. In filezilla you can specify what prograsm you want to open what files. I have specified note++ to open *.py . So I can open filezilla and log on to the ESP32 board then right click on any .py file to edit it with note++ but of course you can use what ever IDE you like.
Once I have edited the .py file and I want to run it I switch to the putty window running telnet to the ESP32 board and execute import file.
I have a function declared in my boot.py file called reload() and when I have executed import file and then edited the file with notye++ and want to re run it i execute reload(file)
This is what I have added to my boot.py, mind I do think that laboris has now added this standard to the boot.py now
I run a Telent repl over putty and use filezilla to edit transfer files. In filezilla you can specify what prograsm you want to open what files. I have specified note++ to open *.py . So I can open filezilla and log on to the ESP32 board then right click on any .py file to edit it with note++ but of course you can use what ever IDE you like.
Once I have edited the .py file and I want to run it I switch to the putty window running telnet to the ESP32 board and execute import file.
I have a function declared in my boot.py file called reload() and when I have executed import file and then edited the file with notye++ and want to re run it i execute reload(file)
This is what I have added to my boot.py, mind I do think that laboris has now added this standard to the boot.py now
Code: Select all
import sys
def reload(mod):
mod_name = mod.__name__
del sys.modules[mod_name]
return __import__(mod_name)
Re: _threads, sockets and interruption with ESP32
Thanks for confirming that I will have less headaches with Loboris micropython Telnet and FTP per default is what I am looking for.
Thank you for the reload code, it helps me !
In return, this is a scipt I use in linux command line with lftp. It uses size of files for syncing. But with loboris and NTP, you can remove "--ignore-time" option I think.
Thank you for the reload code, it helps me !
In return, this is a scipt I use in linux command line with lftp. It uses size of files for syncing. But with loboris and NTP, you can remove "--ignore-time" option I think.
Code: Select all
#!/bin/bash
HOST='192.168.250.179'
USER='myuser'
PASS='myuser'
TARGETFOLDER='/'
SOURCEFOLDER='/home/ghusson/esp32_micropython/'
lftp -f "
open $HOST
user $USER $PASS
lcd $SOURCEFOLDER
mirror --no-recursion --reverse --ignore-time --delete --verbose --include="^.*\.py$" --parallel=1 $SOURCEFOLDER $TARGETFOLDER
bye
"
Re: _threads, sockets and interruption with ESP32
I'm using a different style and do a lot of editing on the device itself with the pye() editor. It is embedded in flash at the loboris port, and for the other devices a made my own image with the editor as frozen bytecode. You'll find it here: https://github.com/robert-hh/Micropython-Editor The files size you can edit is limited by the heap size. On a MP ESP32 port w/lo PSRAM it's at least 500 lines, with PSRAM it's like 20000 lines.
For file tranfer I use ftp. A server is embedded in the Pycom and loboris ports. For esp8266 and the MP esp32 port I use a server which I tailored for my needs: https://github.com/robert-hh/ESP8266-FTP-Server
uftpd.py runs on esp8266 only, while ftp.py runs on the esp32 too. Both variants support active mode, meaning that command line ftp on windows works. As client I use the Firftp extension of Firefox, which is anhow open most of the time. For me, it's easier to use than FileZilla. And you can start editing out of the client too. Pyboard is a little bit different. As long as you enable it's mass storag mode, you can access it with you file manager. But you have to take care when storing that the content has been synched. That's not always obvious. And it you disable mass storage mode to avoid file system corruption, than you're limited to ampy or rshell, or ...., unless you added a LAN/WiFi interface. Then you can use ftp again.
For restarting after code changes I simply press Ctrl-D or the reset button. It's fewer keystrokes, and brings the devices in a well defined state.
For file tranfer I use ftp. A server is embedded in the Pycom and loboris ports. For esp8266 and the MP esp32 port I use a server which I tailored for my needs: https://github.com/robert-hh/ESP8266-FTP-Server
uftpd.py runs on esp8266 only, while ftp.py runs on the esp32 too. Both variants support active mode, meaning that command line ftp on windows works. As client I use the Firftp extension of Firefox, which is anhow open most of the time. For me, it's easier to use than FileZilla. And you can start editing out of the client too. Pyboard is a little bit different. As long as you enable it's mass storag mode, you can access it with you file manager. But you have to take care when storing that the content has been synched. That's not always obvious. And it you disable mass storage mode to avoid file system corruption, than you're limited to ampy or rshell, or ...., unless you added a LAN/WiFi interface. Then you can use ftp again.
For restarting after code changes I simply press Ctrl-D or the reset button. It's fewer keystrokes, and brings the devices in a well defined state.