-
Notifications
You must be signed in to change notification settings - Fork 1
/
ESP8266-Serial2Net.py
245 lines (207 loc) · 8.71 KB
/
ESP8266-Serial2Net.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# ESP8266 Receives data on UART, and sends out via Wifi (network socket)
# as client. This presumes a remote server is listening already on the socket.
# (eg. 'nc -l <port>' on remote host)
# See: stackoverflow.com/questions/21233340/sending-string-via-socket-python
# save this file as 'main.py' on ESP8266 FLASH device, eg. with Thonny
# to automatically run at powerup or hard reset
# J.Beale March 18 2021
import machine # hardware pins
import socket, errno # NTP via wifi
import time # RTC time/date stamp
import utime # msec() and usec()
import uerrno # list of symbolic OSError codes
#import ntptime # stock version fixed to 'pool.ntp.org'
import uos # disable REPL on uart
import network # check on network status
# ----------------------------------------------------------------------
server = '192.168.1.105' # LAN server to send data (rp49.local)
port = 8889 # network port to communicate through
NTP_host = '192.168.1.212' # local NTP server with fixed IP address
VERSION = 'Serial-Wifi Transfer v0.2 JPB 2021-03-18'
led = machine.Pin(2, machine.Pin.OUT) # onboard LED
# ----------------------------------------------------------------------
# Modified version of ntptime.py to use local NTP server
# https://github.com/micropython/micropython-infineon/blob/master/esp8266/scripts/ntptime.py
try:
import ustruct as struct
except:
import struct
# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60
NTP_DELTA = 3155673600
def NTP_time(nhost):
NTP_QUERY = bytearray(48)
NTP_QUERY[0] = 0x1b
#addr = socket.getaddrinfo(NTP_host, 123)[0][-1]
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(1)
#res = s.sendto(NTP_QUERY, addr)
res = s.sendto(NTP_QUERY, (nhost, 123))
msg = s.recv(48)
s.close()
val = struct.unpack("!I", msg[40:44])[0]
return val - NTP_DELTA
# --------------------------------------------------------
# There's currently no timezone support in MicroPython, so
# utime.localtime() will return UTC time (as if it was .gmtime())
def NTP_settime(nhost):
t = NTP_time(nhost)
import machine
import utime
tm = utime.localtime(t)
tm = tm[0:3] + (0,) + tm[3:6] + (0,)
machine.RTC().datetime(tm)
#print(utime.localtime())
# -------------------------------------------------------
def vBlink(t): # variable-length blink of duration t seconds
led.value(0) # 0 means LED on
time.sleep(t)
led.value(1)
time.sleep(t)
def shortBlink():
led.value(0) # 0 means LED on
time.sleep(0.15)
led.value(1)
time.sleep(0.15)
def longBlink():
led.value(0) # 0 means LED on
time.sleep(0.4)
led.value(1)
time.sleep(0.4)
def startNet(): # make sure we're online, check IP address
wlan = network.WLAN(network.STA_IF) # create station interface
while True:
cFlag = wlan.isconnected() # check if the station is connected to an AP
if cFlag: # continue if so; loop if not
break
longBlink() # slow blinks indicate WLAN not connected
utime.sleep(2) # allow time to remove signal on ESP UART Rx pin
config = wlan.ifconfig() # get (IP, netmask, gateway, DNS)
myIP = config[0]
#print("My IP = %s" % myIP)
for _ in range(2): # fast blinks indicate successful connection
shortBlink()
def getTS(): # get a timestamp with current date & time
t=time.localtime() # wlan = network.WLAN(network.STA_IF)
ts = '# START {:02d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}'.format(
t[0], t[1], t[2], t[3], t[4], t[5])
return(ts)
def openNet(): # open network port
s = socket.socket()
try:
s.connect((server,port))
return(s)
except OSError as err: # errno.ECONNRESET:
uos.dupterm(machine.UART(0, 115200), 1) # restore REPL
utime.sleep(5) # allow time to remove signal on ESP UART Rx pin
if err.args[0] == uerrno.ECONNRESET:
longBlink()
#print("Unable to connect to %s" % server)
longBlink()
#print("UART-Network test stopped.")
utime.sleep(30)
machine.reset() # hard reset
# -----------------------------------------------------------
def main():
ts = getTS()
#print("%s" % ts)
#print("ESP8266-UART Receive to Network Socket starting")
NTP_settime(NTP_host) # custom version, using my local NTP server
shortBlink() # show NTP call returned
ts = getTS() # Date/Time string at program start
#print("Current time: %s" % ts)
#print("Y2K epoch: ", time.time() )
# -----------------------------------------------------
try:
stm = openNet() # open network stream & send data
stm.send(("# %s\n" % VERSION).encode())
stm.send(("%s Y2K epoch: %d\n" % (ts,time.time())).encode())
utime.sleep_ms(50)
shortBlink() # show Network call returned
stm.close()
except Exception:
longBlink()
utime.sleep(30) # wait for awhile in case server comes back online
stm.close()
machine.reset() # start over with hard reset
# -----------------------------------------------------
# stm.close(); return # ============ DEBUG ============================
time.sleep(2)
uos.dupterm(None, 1) # disable REPL on UART(0), allowing ext. input
uart = machine.UART(0, rxbuf=64)
uart.init(115200, timeout=100) # timeout in msec
pktNumber = 0
shortBlink() # show Network call returned
while True: # overall main loop, alternating UART Rx & Net Tx
recLines = [] # list to hold input lines from UART
try:
loopCnt = 0
while True: # ======= loop to check for UART input =====
if uart.any():
hostMsg = uart.readline(120)
if hostMsg is not None:
rawMsg = hostMsg.decode().rstrip()
if (loopCnt == 0):
ts = getTS() # get current timestamp on 1st line
loopCnt += 1
strMsg = str(time.time()) + "," + rawMsg
if rawMsg[0:6] == "**HALT":
break # end of serial input packet
if rawMsg[0:6] == "**EXIT": # only used when debugging, with USB connected
uos.dupterm(machine.UART(0, 115200), 1) # restore local REPL
utime.sleep_ms(500)
return
else:
recLines.append(strMsg)
utime.sleep_ms(15)
if (loopCnt > 20000): # <== TIMEOUT sets max duration UART packet (20k = 5 minutes)
stm.close() # close the port and quit.
longBlink()
longBlink()
utime.sleep(60) # don't reboot too quickly
machine.reset() # hard reset, like Reset button
break
except Exception as ex: # (in practice, haven't seen UART exceptions)
stm.close()
uos.dupterm(machine.UART(0, 115200), 1) # restore local REPL
longBlink()
utime.sleep(5) # allow time to remove signal on ESP UART Rx pin
#machine.soft_reset() # stop
# ---------------------------------------------------------------------
# Done with UART, either error, timeout, or end of packet signal
vBlink(0.1)
if (len(recLines) > 0): # if there was any UART data received
try:
pktNumber += 1
# -----------------------------------------------------
stm = openNet() # open network stream & send data
vBlink(0.1) # short delay may be needed here?
stm.send((ts+'\n').encode())
for outs in recLines: # transmit each stored line
outs1 = outs + '\n'
stm.send(outs1.encode())
stm.send(("# END_PACKET %d\n" % pktNumber).encode())
stm.close()
# -----------------------------------------------------
except Exception as err: # errno.ECONNRESET:
stm.close()
uos.dupterm(machine.UART(0, 115200), 1)
#utime.sleep(5) # allow time to remove signal on ESP UART Rx pin
if err.args[0] == uerrno.ECONNRESET:
#print("Connection to %s reset by remote host." % server)
longBlink()
machine.soft_reset() # stop. Micropython has no exit() as there is no OS
# ----- end of main ---------------------------------------------------
startNet() # check we're online; wait if we aren't
main()
"""
One-line server on host using netcat:
while true; do nc -l 8889; done
Example output to network port:
# Serial-Wifi Transfer v0.1 JPB 2021-03-17
# START 2021-03-18 17:01:18 Y2K epoch: 669402078
# START 2021-03-18 17:01:21
669402085,8, 0.015, 0.0163, 641877536, 3905201192, 2714268494, 2488562100
669402086,9, 0.016, 0.0163, 2030968062, 968025008, 2613939105, 3481190652
669402086,10, 0.016, 0.0162, 3177975081, 3659030163, 4095404096, 347380111
# END_PACKET 1
"""