给ESP8266用上MicroPython

还是ESP8266,这次使用的是安信可公司生产的开发板。由于项目需要使用这块板子向aprs-is.net报告APRS信息,通过调查发现了ESP8266可以使用MicroPython来做APRS POST(虽然也有别的各种各样的方法啦)。
MicroPython简单的使用方法如下:

烧录MicroPython到ESP8266上

首先下载ESP8266用的MicroPython固件,这里选择最新版的esp8266-20170108-v1.8.7.bin
需要说明的是,MicroPython使用的是 Python3 ,嗯,Python3。

然后安装烧写工具esptool,可以使用pip安装:

1
pip install esptool

安装完成后,先清空flash,再烧入固件。macOS下,CP2102安装驱动后串口在/dev/cu.SLAB_USBtoUART

1
2
esptool.py --port /dev/cu.SLAB_USBtoUART erase_flash
esptool.py --port /dev/cu.SLAB_USBtoUART --baud 115200 write_flash --flash_size=detect 0 esp8266-20170108-v1.8.7.bin

对于某些8266固件,可能需要加上-fm dio参数。

或者可以在Windows下直接使用NodeMCU Flasher刷写,在“Config”中选择下载好的固件,然后点击“Flash”就可以了。

安装完成后,可以通过串口调试器连接到MicroPython的REPL上。macOS下可以使用screen:

1
screen /dev/cu.SLAB_USBtoUART 115200

需要注意,在REPL里粘贴多行代码的时候需要使用“粘贴模式”,按下Ctrl+E即可。

WiFi设置

STA_IF是8266连接到其他AP用,AP_IF是8266自己做无线AP用。也就是8266可以同时有两个IP,很帅是不是(不)。

1
2
3
4
5
6
7
8
9
10
11
12
13
import network
sta_if = network.WLAN(network.STA_IF)
ap_if = network.WLAN(network.AP_IF)
sta_if.active(True)
ap_if.active(True)
// 连接其他AP
sta_if.connect('<essid>', '<password>')
sta_if.isconnected()
// 查看连接情况
sta_if.ifconfig()
ap_if.ifconfig()

或者把sta这一段直接丢到boot.py里(传送文件方法见WebREPL部分):

1
2
3
4
5
6
7
8
9
10
def do_connect():
import network
sta_if = network.WLAN(network.STA_IF)
if not sta_if.isconnected():
print('connecting to network...')
sta_if.active(True)
sta_if.connect('<essid>', '<password>')
while not sta_if.isconnected():
pass
print('network config:', sta_if.ifconfig())

这样ESP8266就可以在每次启动时自动连接到设定的WiFi上了。

使用WebREPL

8266连接上网后,就可以通过一个Web的REPL使用,这就叫WebREPL:http://micropython.org/webrepl,也可以从GitHub上自己部署。
只需要:

1
import webrepl_setup

之后按照串口给出的提示设置一个密码,就会自动设置好。然后WebREPL自动启动的代码会被写入boot.py,reset板子,之后每次上电时WebREPL就会自动运行。或者不想reset的话手动输入这两行:

1
2
import webrepl
webrepl.start()

终端设备可以连接到8266的同一个局域网下连接到8266上,也可以连接到8266自己生成的WiFi(MicroPython-<MAC Address>,默认密码micropythoN)上,两种方式都可以。输入密码后就可以通过WebREPL了,再也不用串口调试工具了,美滋滋。

使用socket

为了实现HTTP请求,这里使用socket。

1
2
3
4
5
6
7
8
9
10
11
12
import socket
addr_info = socket.getaddrinfo("<domain>", <length>)
// Get IP address and port
addr = addr_info[0][-1]
s = socket.socket()
s.connect(addr)
while True:
data = s.recv(500)
print(str(data, 'utf8'), end='')

接下来试着做一个HTTP GET

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def http_get(url):
_, _, host, path = url.split('/', 3)
addr = socket.getaddrinfo(host, 80)[0][-1]
s = socket.socket()
s.connect(addr)
s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))
while True:
data = s.recv(100)
if data:
print(str(data, 'utf8'), end='')
else:
break
s.close()
http_get('http://micropython.org/ks/test.html')

如果看到了HTTP header和It's working if you can read this!,就说明get成功啦。

实现上传

举个栗子,传到杭州APRS服务器上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import socket
HOST = '116.236.128.220'
PORT = 14580
while 1:
msg = input("Please input position:")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((HOST, PORT))
except OSError:
print("OSError, check the Internet connection")
continue
s.send(msg+"\r\n")
data = s.recv(1024)
print(data)
s.close()

这里使用了一个Try,因为如果连接失败会丢一个异常,导致线程终止。捕捉之后continue就不会有事了。