From 7c40b15a3f04e24dac5c5ebe7e24ce4463a4b63a Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 24 Apr 2016 23:04:21 +0300 Subject: esp8266/scripts/webrepl: WebREPL based on C-level websocket object. --- esp8266/scripts/webrepl.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 esp8266/scripts/webrepl.py (limited to 'esp8266/scripts/webrepl.py') diff --git a/esp8266/scripts/webrepl.py b/esp8266/scripts/webrepl.py new file mode 100644 index 0000000000..37c98c6bc6 --- /dev/null +++ b/esp8266/scripts/webrepl.py @@ -0,0 +1,42 @@ +# This module should be imported from REPL, not run from command line. +import socket +import uos +import websocket +import websocket_helper + +listen_s = None +client_s = None + +def wait_connection(): + global listen_s, client_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", 8266) + print("Bind address info:", ai) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + client_s, remote_addr = listen_s.accept() + print(client_s) + return client_s + + +def start(): + global listen_s, client_s + uos.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + cl = wait_connection() + websocket_helper.server_handshake(cl) + ws = websocket.websocket(cl, True) + cl.setblocking(False) + # notify REPL on socket incoming data + cl.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify) + uos.dupterm(ws) + print("Connected") + +start() -- cgit v1.2.3 From 8db4f363e9028218278c33cc2eeb97a4c30734dd Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 25 Apr 2016 00:31:43 +0300 Subject: esp8266/scripts/webrepl: Convert to persistent daemon. --- esp8266/scripts/webrepl.py | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'esp8266/scripts/webrepl.py') diff --git a/esp8266/scripts/webrepl.py b/esp8266/scripts/webrepl.py index 37c98c6bc6..1a8fbe8795 100644 --- a/esp8266/scripts/webrepl.py +++ b/esp8266/scripts/webrepl.py @@ -7,7 +7,7 @@ import websocket_helper listen_s = None client_s = None -def wait_connection(): +def setup_conn(): global listen_s, client_s listen_s = socket.socket() listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -18,25 +18,35 @@ def wait_connection(): listen_s.bind(addr) listen_s.listen(1) - client_s, remote_addr = listen_s.accept() - print(client_s) - return client_s + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_conn) + print("WebREPL daemon started on port 8266") -def start(): - global listen_s, client_s - uos.dupterm(None) - if client_s: - client_s.close() - if listen_s: - listen_s.close() - cl = wait_connection() +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + client_s = cl websocket_helper.server_handshake(cl) ws = websocket.websocket(cl, True) cl.setblocking(False) # notify REPL on socket incoming data cl.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify) uos.dupterm(ws) - print("Connected") + print("WebREPL connected\n>>> ", end="") + + +def stop(): + global listen_s, client_s + uos.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(): + stop() + setup_conn() + start() -- cgit v1.2.3 From bd66b09512a9b6a4449a176845f1a10554575640 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 25 Apr 2016 00:33:27 +0300 Subject: esp8266/scripts/webrepl: Don't start on import. Explicit .start() is required now. --- esp8266/scripts/webrepl.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'esp8266/scripts/webrepl.py') diff --git a/esp8266/scripts/webrepl.py b/esp8266/scripts/webrepl.py index 1a8fbe8795..f304b4e98b 100644 --- a/esp8266/scripts/webrepl.py +++ b/esp8266/scripts/webrepl.py @@ -47,6 +47,3 @@ def stop(): def start(): stop() setup_conn() - - -start() -- cgit v1.2.3 From 4296a8dc5c58df24988ef0deb51519b2cdb6141f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 25 Apr 2016 18:44:37 +0300 Subject: esp8266/scripts/webrepl: Allow to override port. --- esp8266/scripts/webrepl.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'esp8266/scripts/webrepl.py') diff --git a/esp8266/scripts/webrepl.py b/esp8266/scripts/webrepl.py index f304b4e98b..e837e760d3 100644 --- a/esp8266/scripts/webrepl.py +++ b/esp8266/scripts/webrepl.py @@ -7,19 +7,19 @@ import websocket_helper listen_s = None client_s = None -def setup_conn(): +def setup_conn(port): global listen_s, client_s listen_s = socket.socket() listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - ai = socket.getaddrinfo("0.0.0.0", 8266) + ai = socket.getaddrinfo("0.0.0.0", port) print("Bind address info:", ai) addr = ai[0][4] listen_s.bind(addr) listen_s.listen(1) listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_conn) - print("WebREPL daemon started on port 8266") + print("WebREPL daemon started on port %d" % port) def accept_conn(listen_sock): @@ -44,6 +44,6 @@ def stop(): listen_s.close() -def start(): +def start(port=8266): stop() - setup_conn() + setup_conn(port) -- cgit v1.2.3 From c88883141072cbc2efc9e4af2115d64423f4f89f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 26 Apr 2016 00:59:21 +0300 Subject: esp8266/scripts/webrepl: Print connection address. Based on active network interfaces. --- esp8266/scripts/webrepl.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'esp8266/scripts/webrepl.py') diff --git a/esp8266/scripts/webrepl.py b/esp8266/scripts/webrepl.py index e837e760d3..df742408da 100644 --- a/esp8266/scripts/webrepl.py +++ b/esp8266/scripts/webrepl.py @@ -1,6 +1,7 @@ # This module should be imported from REPL, not run from command line. import socket import uos +import network import websocket import websocket_helper @@ -13,13 +14,15 @@ def setup_conn(port): listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) ai = socket.getaddrinfo("0.0.0.0", port) - print("Bind address info:", ai) addr = ai[0][4] listen_s.bind(addr) listen_s.listen(1) listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_conn) - print("WebREPL daemon started on port %d" % port) + for i in (network.AP_IF, network.STA_IF): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL daemon started on %s:%d" % (iface.ifconfig()[0], port)) def accept_conn(listen_sock): -- cgit v1.2.3 From ef2ffc0e4ec9aee2d773e051980d8149534a7347 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 26 Apr 2016 01:00:28 +0300 Subject: esp8266/scripts/webrepl: Print client address for incoming connections. --- esp8266/scripts/webrepl.py | 1 + 1 file changed, 1 insertion(+) (limited to 'esp8266/scripts/webrepl.py') diff --git a/esp8266/scripts/webrepl.py b/esp8266/scripts/webrepl.py index df742408da..759ebeb838 100644 --- a/esp8266/scripts/webrepl.py +++ b/esp8266/scripts/webrepl.py @@ -28,6 +28,7 @@ def setup_conn(port): def accept_conn(listen_sock): global client_s cl, remote_addr = listen_sock.accept() + print("\nWebREPL connection from:", remote_addr) client_s = cl websocket_helper.server_handshake(cl) ws = websocket.websocket(cl, True) -- cgit v1.2.3 From 90b2cfe644339d2c869900dd2d3373071eef0a5f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 26 Apr 2016 12:47:24 +0300 Subject: esp8266/scripts/webrepl: Add "ws://" to "daemon started at" message. To remind people it's not HTTP. --- esp8266/scripts/webrepl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'esp8266/scripts/webrepl.py') diff --git a/esp8266/scripts/webrepl.py b/esp8266/scripts/webrepl.py index 759ebeb838..62f46d9745 100644 --- a/esp8266/scripts/webrepl.py +++ b/esp8266/scripts/webrepl.py @@ -22,7 +22,7 @@ def setup_conn(port): for i in (network.AP_IF, network.STA_IF): iface = network.WLAN(i) if iface.active(): - print("WebREPL daemon started on %s:%d" % (iface.ifconfig()[0], port)) + print("WebREPL daemon started on ws://%s:%d" % (iface.ifconfig()[0], port)) def accept_conn(listen_sock): -- cgit v1.2.3 From 006ffe1561f1ba8606758c326b608f27c65adb75 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 30 Apr 2016 01:00:14 +0300 Subject: esp8266/scripts/webrepl: Connection ack prompt is now printed by modwebrepl. After password is checked. --- esp8266/scripts/webrepl.py | 1 - 1 file changed, 1 deletion(-) (limited to 'esp8266/scripts/webrepl.py') diff --git a/esp8266/scripts/webrepl.py b/esp8266/scripts/webrepl.py index 62f46d9745..ec0ee4e1d9 100644 --- a/esp8266/scripts/webrepl.py +++ b/esp8266/scripts/webrepl.py @@ -36,7 +36,6 @@ def accept_conn(listen_sock): # notify REPL on socket incoming data cl.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify) uos.dupterm(ws) - print("WebREPL connected\n>>> ", end="") def stop(): -- cgit v1.2.3 From 962d5a987f363853ae6dc63572370c84cfd99448 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 30 Apr 2016 20:39:35 +0300 Subject: esp8266/scripts/webrepl: Switch to using _webrepl object wrapper. Handling of binary protocol is untested on esp8266 so far. --- esp8266/scripts/webrepl.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'esp8266/scripts/webrepl.py') diff --git a/esp8266/scripts/webrepl.py b/esp8266/scripts/webrepl.py index ec0ee4e1d9..18c991287d 100644 --- a/esp8266/scripts/webrepl.py +++ b/esp8266/scripts/webrepl.py @@ -4,6 +4,7 @@ import uos import network import websocket import websocket_helper +import _webrepl listen_s = None client_s = None @@ -32,6 +33,7 @@ def accept_conn(listen_sock): client_s = cl websocket_helper.server_handshake(cl) ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) cl.setblocking(False) # notify REPL on socket incoming data cl.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify) -- cgit v1.2.3 From c1d1c562f3a1e4922711f0584e99ef074c5ce0f1 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 30 Apr 2016 20:41:09 +0300 Subject: esp8266/scripts/webrepl: Add "first connection" mode to setup password. If there's no port_config.py file, or it lacks WEBREPL_PASS variable, "initial setup mode" will be entered on first WebREPLconnection. User will be asked for password, which will be written to port_config.WEBREPL_PASS, and system restarted to work in normal mode with password active. --- esp8266/scripts/webrepl.py | 14 ++++++-- esp8266/scripts/webrepl_setup.py | 77 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 esp8266/scripts/webrepl_setup.py (limited to 'esp8266/scripts/webrepl.py') diff --git a/esp8266/scripts/webrepl.py b/esp8266/scripts/webrepl.py index 18c991287d..1a2c82277e 100644 --- a/esp8266/scripts/webrepl.py +++ b/esp8266/scripts/webrepl.py @@ -9,7 +9,7 @@ import _webrepl listen_s = None client_s = None -def setup_conn(port): +def setup_conn(port, accept_handler): global listen_s, client_s listen_s = socket.socket() listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -19,7 +19,7 @@ def setup_conn(port): listen_s.bind(addr) listen_s.listen(1) - listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_conn) + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) for i in (network.AP_IF, network.STA_IF): iface = network.WLAN(i) if iface.active(): @@ -51,4 +51,12 @@ def stop(): def start(port=8266): stop() - setup_conn(port) + try: + import port_config + _webrepl.password(port_config.WEBREPL_PASS) + setup_conn(port, accept_conn) + print("Started webrepl in normal mode") + except: + import webrepl_setup + setup_conn(port, webrepl_setup.handle_conn) + print("Started webrepl in setup mode") diff --git a/esp8266/scripts/webrepl_setup.py b/esp8266/scripts/webrepl_setup.py new file mode 100644 index 0000000000..b912a4aa61 --- /dev/null +++ b/esp8266/scripts/webrepl_setup.py @@ -0,0 +1,77 @@ +import sys +import socket +import time + +from websocket import * +import websocket_helper + + +def setup_server(): + s = socket.socket() + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", 8266) + addr = ai[0][4] + + s.bind(addr) + s.listen(1) + return s + +def getpass(stream, prompt): + stream.write(prompt) + passwd = b"" + while 1: + c = stream.read(1) + if c in (b"\r", b"\n"): + stream.write("\r\n") + return passwd + passwd += c +# stream.write("*") + +def handle_conn(listen_sock): + cl, remote_addr = listen_sock.accept() + + print(""" + +First-time WebREPL connection has been received. WebREPL initial setup +will now start over this connection. During setup, UART REPL will be +non-responsive. After setup finishes, the board will be rebooted. In +case of error during setup, current session will continue. + +If you receive this message unexpectedly, it may mean that your WebREPL +connection is being hacked (power off board if unsure). +""") + + websocket_helper.server_handshake(cl) + ws = websocket(cl) + + ws.write("""\ +Welcome to MicroPython WebREPL!\r +\r +This is the first time you connect to WebREPL, so please set a password\r +to use for the following WebREPL sessions. Once you enter the password\r +twice, your board will reboot with WebREPL running in active mode. On\r +some boards, you may need to press reset button or reconnect power.\r +\r +""") + + while 1: + passwd1 = getpass(ws, "New password: ") + passwd2 = getpass(ws, "Confirm password: ") + if passwd1 == passwd2: + break + ws.write("Passwords do not match\r\n") + + with open("port_config.py", "w") as f: + f.write("WEBREPL_PASS = %r\n" % passwd1.decode("ascii")) + + ws.write("Password successfully set, restarting...\r\n") + cl.close() + time.sleep(2) + import machine + machine.reset() + + +def test(): + s = setup_server() + handle_conn(s) -- cgit v1.2.3