Skip to content

Commit e84e3e7

Browse files
committed
esp8266: Rework webrepl_setup to run over wired REPL.
1 parent fa3a108 commit e84e3e7

2 files changed

Lines changed: 101 additions & 75 deletions

File tree

esp8266/modules/webrepl.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,16 @@ def start(port=8266, password=None):
5959
stop()
6060
if password is None:
6161
try:
62-
import port_config
63-
_webrepl.password(port_config.WEBREPL_PASS)
62+
import webrepl_cfg
63+
_webrepl.password(webrepl_cfg.PASS)
6464
setup_conn(port, accept_conn)
6565
print("Started webrepl in normal mode")
6666
except:
67-
import webrepl_setup
68-
setup_conn(port, webrepl_setup.handle_conn)
69-
print("Started webrepl in setup mode")
67+
print("WebREPL is not configured, run 'import webrepl_setup'")
7068
else:
7169
_webrepl.password(password)
7270
setup_conn(port, accept_conn)
73-
print("Started webrepl in normal mode")
71+
print("Started webrepl in manual override mode")
7472

7573

7674
def start_foreground(port=8266):

esp8266/modules/webrepl_setup.py

Lines changed: 97 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,111 @@
11
import sys
2-
import socket
3-
import time
2+
#import uos as os
3+
import os
4+
import machine
45

5-
from websocket import *
6-
import websocket_helper
6+
RC = "./boot.py"
7+
CONFIG = "./webrepl_cfg.py"
78

8-
9-
def setup_server():
10-
s = socket.socket()
11-
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
12-
13-
ai = socket.getaddrinfo("0.0.0.0", 8266)
14-
addr = ai[0][4]
15-
16-
s.bind(addr)
17-
s.listen(1)
18-
return s
19-
20-
def getpass(stream, prompt):
21-
stream.write(prompt)
22-
passwd = b""
9+
def input_choice(prompt, choices):
2310
while 1:
24-
c = stream.read(1)
25-
if c in (b"\r", b"\n"):
26-
stream.write("\r\n")
27-
return passwd
28-
passwd += c
29-
stream.write("*")
30-
31-
def handle_conn(listen_sock):
32-
cl, remote_addr = listen_sock.accept()
33-
34-
print("""
35-
36-
First-time WebREPL connection has been received. WebREPL initial setup
37-
will now start over this connection. During setup, UART REPL will be
38-
non-responsive. After setup finishes, the board will be rebooted. In
39-
case of error during setup, current session will continue.
40-
41-
If you receive this message unexpectedly, it may mean that your WebREPL
42-
connection is being hacked (power off board if unsure).
43-
""")
44-
45-
websocket_helper.server_handshake(cl)
46-
ws = websocket(cl)
47-
48-
ws.write("""\
49-
Welcome to MicroPython WebREPL!\r
50-
\r
51-
This is the first time you connect to WebREPL, so please set a password\r
52-
to use for the following WebREPL sessions. Once you enter the password\r
53-
twice, your board will reboot with WebREPL running in active mode. On\r
54-
some boards, you may need to press reset button or reconnect power.\r
55-
\r
56-
""")
11+
resp = input(prompt)
12+
if resp in choices:
13+
return resp
5714

15+
def getpass(prompt):
16+
return input(prompt)
17+
18+
def input_pass():
5819
while 1:
59-
passwd1 = getpass(ws, "New password: ")
20+
passwd1 = getpass("New password: ")
6021
if len(passwd1) < 4:
61-
ws.write("Password too short\r\n")
22+
print("Password too short")
6223
continue
6324
elif len(passwd1) > 9:
64-
ws.write("Password too long\r\n")
25+
print("Password too long")
6526
continue
66-
passwd2 = getpass(ws, "Confirm password: ")
27+
passwd2 = getpass("Confirm password: ")
6728
if passwd1 == passwd2:
68-
break
69-
ws.write("Passwords do not match\r\n")
70-
71-
with open("port_config.py", "w") as f:
72-
f.write("WEBREPL_PASS = %r\n" % passwd1.decode("ascii"))
29+
return passwd1
30+
print("Passwords do not match")
7331

74-
ws.write("Password successfully set, restarting...\r\n")
75-
cl.close()
76-
time.sleep(2)
77-
import machine
78-
machine.reset()
7932

33+
def exists(fname):
34+
try:
35+
with open(fname):
36+
pass
37+
return True
38+
except OSError:
39+
return False
8040

81-
def test():
82-
s = setup_server()
83-
handle_conn(s)
41+
def copy_stream(s_in, s_out):
42+
buf = bytearray(64)
43+
while 1:
44+
sz = s_in.readinto(buf)
45+
s_out.write(buf, sz)
46+
47+
48+
def get_daemon_status():
49+
with open(RC) as f:
50+
for l in f:
51+
if "webrepl" in l:
52+
if l.startswith("#"):
53+
return False
54+
return True
55+
return None
56+
57+
def add_daemon():
58+
with open(RC) as old_f, open(RC + ".tmp", "w") as new_f:
59+
new_f.write("import webrepl\nwebrepl.start()\n")
60+
copy_stream(old_f, new_f)
61+
62+
def change_daemon(action):
63+
LINES = ("import webrepl", "webrepl.start()")
64+
with open(RC) as old_f, open(RC + ".tmp", "w") as new_f:
65+
for l in old_f:
66+
for patt in LINES:
67+
if patt in l:
68+
if action and l.startswith("#"):
69+
l = l[1:]
70+
elif not action and not l.startswith("#"):
71+
l = "#" + l
72+
new_f.write(l)
73+
# FatFs rename() is not POSIX compliant, will raise OSError if
74+
# dest file exists.
75+
os.remove(RC)
76+
os.rename(RC + ".tmp", RC)
77+
78+
79+
def main():
80+
status = get_daemon_status()
81+
82+
print("WebREPL daemon auto-start status:", "enabled" if status else "disabled")
83+
print("\nWould you like to (E)nable or (D)isable it running on boot?")
84+
print("(Empty line to quit)")
85+
resp = input("> ").upper()
86+
87+
if resp == "E":
88+
if exists(CONFIG):
89+
resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", ""))
90+
else:
91+
print("To enable WebREPL, you must set password for it")
92+
resp2 = "y"
93+
94+
if resp2 == "y":
95+
passwd = input_pass()
96+
with open(CONFIG, "w") as f:
97+
f.write("PASS = %r\n" % passwd)
98+
99+
100+
if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status):
101+
print("No further action required")
102+
sys.exit()
103+
104+
change_daemon(resp == "E")
105+
106+
print("Changes will be activated after reboot")
107+
resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", ""))
108+
if resp == "y":
109+
machine.reset()
110+
111+
main()

0 commit comments

Comments
 (0)