Beetle ESP32 C3 物联网亮板载灯
上一次我们对Beetle ESP32 C3进行了亮灯操作,初试尝试了对该主控板进行MicroPython编程。这次我们将在原来点灯的基础上,增加一点点难度,利用物联网控制板载LED灯的开关。
通过上图我们发现,行空板作为物联网服务器,发送开关灯指令,然后将指令通过无线网络发送给ESP32 C3,从而实现板载灯的开或关。
一、物联网服务器的选择
本例采用行空板自带的Siot服务器,因上次测试云雀气象仪,已经将行空板上的Siot版本升级成V2,当然也可以利用一台电脑作为Siot服务器。此外,由于已经使用Siot V2,因此适于用MicroPython的siot.py文件可能会出现一些差异。
行空板通过USB连接电脑,在电脑上打开浏览器,地址栏输入10.1.2.3,然后单击左侧的**应用开关**,在右侧确定将SIoT服务打开,然后单击**打开页面**按钮进入SIoT服务器管理界面。
输入账号和密码,默认是siot和dfrobot,单击登录。
然后创建一个名为**c3**的主题,设备名称为siot,注意在编程时,需要输入"**siot/c3**"
单击**查看详情**进入该主题,通过输入信息字符串,勾选**保存到数据库**,然后单击**发送**按钮将消息发送。后面我们可以通过发送1来点灯,发送0实现灭灯。
二、无线AP
由于ESP32对无线和蓝牙的支持,因此本例通过无线网络进行物联网数据交换,我们可以直接使用家庭无线网络,将行空板(所在电脑)与Beetle ESP32 C3接入同一网络,如没有网络环境,也可以打开手机热点,将行空板和ESP32 C3连上手机热点。
1. 行空板连接无线网络
行空板通过USB连接电脑,在电脑上打开浏览器,地址栏输入10.1.2.3,然后单击左侧的**网络设置**,在右侧通过选择无线网络的名称,并输入密码进行连接,连接成功后,WiFi状态会显示相关信息,需要将IP地址记下来,供后面使用。
2. ESP32 C3连接无线网络
MicroPython中默认提供了network模块用于无线网络的通信,我们Python程序中定义一个函数用于无线网络连接。
def WIFIconnect():
import network
ssid='Mi10'#无线网络名称
password='********'#填写自己的无线网络密码
station=network.WLAN(network.STA_IF)
if station.isconnected() == True:
print("WiFi already connected")
print(station.ifconfig())#这里显示一下ESP C3连接无线网络后的动态IP地址
return
station.active(True)
station.connect(ssid,password)
while station.isconnected() == False:
pass
print("Connection successful")
print(station.ifconfig())
三、ESP32 C3上编程
使用Thonny为ESP32 C3编写程序,用于接收SIoT服务器发送过来的消息,并根据消息实现开灯和关灯。要使ESP32 C3能使用SIoT,我们需要将soit.py库文件上传到ESP32 C3上去。
在Thonny中新建文件,并将下面的代码复制到Thonny中,保存时选择**保存到MicroPython设备**。
# file siot.py
# brief download into mpython and run the demo
# Copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
# licence The MIT License (MIT)
# author (yufeng.luo@dfrobot.com)
# version V1.0
# date 2019-10-8
'''
import usocket as socket
import ustruct as struct
from machine import Timer
#from ubinascii import hexlify
class MQTTException(Exception):
pass
tim = None
_sock = None
_pid = 0
_cb = None
lw_topic = None
lw_msg = None
lw_qos = 0
lw_retain = False
def init(client_id, server, port=0, user=None, password=None, keepalive=0,ssl=False, ssl_params={}):
global _client_id, _addr, _ssl, _ssl_params, _user, _pswd, _keepalive
if port == 0:
port = 8883 if ssl else 1883
_client_id = client_id
_addr = socket.getaddrinfo(server, port)[-1]
_ssl = ssl
_ssl_params = ssl_params
_user = user
_pswd = password
_keepalive = keepalive
def _send_str(s):
global _sock
_sock.write(struct.pack("!H", len(s)))
_sock.write(s)
def _recv_len():
global _sock
n = 0
sh = 0
while 1:
b = _sock.read(1)
n |= (b & 0x7f) << sh
if not b & 0x80:
return n
sh += 7
def set_callback(f):
global _cb
_cb = f
def subscribe(topic, callback):
global _cb
_cb = callback
getsubscribe(topic)
def loop():
global tim
if tim !=None:
tim.deinit()
tim = Timer(1)
tim.init(period=50,mode=Timer.PERIODIC, callback=check_msg)
def set_last_will(topic, msg, retain=False, qos=0):
global lw_topic, lw_msg, lw_qos, lw_retain
assert 0 <= qos <= 2
assert topic
lw_topic = topic
lw_msg = msg
lw_qos = qos
lw_retain = retain
def connect(clean_session=True):
global _sock, _ssl, _user, _keepalive, lw_topic
_sock = socket.socket()
_sock.connect(_addr)
if _ssl:
import ussl
_sock = ussl.wrap_socket(_sock, **_ssl_params)
msg = bytearray(b"\x10\0\0\x04MQTT\x04\x02\0\0")
msg = 10 + 2 + len(_client_id)
msg = clean_session << 1
if _user is not None:
msg += 2 + len(_user) + 2 + len(_pswd)
msg |= 0xC0
if _keepalive:
assert _keepalive < 65536
msg |= _keepalive >> 8
msg |= _keepalive & 0x00FF
if lw_topic:
msg += 2 + len(lw_topic) + 2 + len(lw_msg)
msg |= 0x4 | (lw_qos & 0x1) << 3 | (lw_qos & 0x2) << 3
msg |= lw_retain << 5
_sock.write(msg)
#print(hex(len(msg)), hexlify(msg, ":"))
_send_str(_client_id)
if lw_topic:
_send_str(lw_topic)
_send_str(lw_msg)
if _user is not None:
_send_str(_user)
_send_str(_pswd)
resp = _sock.read(4)
assert resp == 0x20 and resp == 0x02
if resp != 0:
raise MQTTException(resp)
return resp & 1
def stop():
global _sock, tim
_sock.write(b"\xe0\0")
_sock.close()
if tim !=None:
tim.deinit()
def ping():
global _sock
_sock.write(b"\xc0\0")
def publish(topic, msg, retain=False, qos=0):
global _sock, _pid
pkt = bytearray(b"\x30\0\0\0")
pkt |= qos << 1 | retain
sz = 2 + len(topic) + len(msg)
if qos > 0:
sz += 2
assert sz < 2097152
i = 1
while sz > 0x7f:
pkt = (sz & 0x7f) | 0x80
sz >>= 7
i += 1
pkt = sz
#print(hex(len(pkt)), hexlify(pkt, ":"))
_sock.write(pkt, i + 1)
_send_str(topic)
if qos > 0:
_pid += 1
pid = _pid
struct.pack_into("!H", pkt, 0, pid)
_sock.write(pkt, 2)
_sock.write(msg)
if qos == 1:
while 1:
op = wait_msg()
if op == 0x40:
sz = _sock.read(1)
assert sz == b"\x02"
rcv_pid = _sock.read(2)
rcv_pid = rcv_pid << 8 | rcv_pid
if pid == rcv_pid:
return
elif qos == 2:
assert 0
def getsubscribe(topic, qos=0):
global _sock, _pid
assert _cb is not None, "getsubscribe callback is not set"
pkt = bytearray(b"\x82\0\0\0")
_pid += 1
struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, _pid)
#print(hex(len(pkt)), hexlify(pkt, ":"))
_sock.write(pkt)
_send_str(topic)
_sock.write(qos.to_bytes(1, "little"))
while 1:
op = wait_msg()
if op == 0x90:
resp = _sock.read(4)
#print(resp)
assert resp == pkt and resp == pkt
if resp == 0x80:
raise MQTTException(resp)
return
# Wait for a single incoming MQTT message and process it.
# Subscribed messages are delivered to a callback previously
# set by .set_callback() method. Other (internal) MQTT
# messages processed internally.
def wait_msg():
global _sock
res = _sock.read(1)
_sock.setblocking(True)
if res is None:
return None
if res == b"":
raise OSError(-1)
if res == b"\xd0":# PINGRESP
sz = _sock.read(1)
assert sz == 0
return None
op = res
if op & 0xf0 != 0x30:
return op
sz = _recv_len()
topic_len = _sock.read(2)
topic_len = (topic_len << 8) | topic_len
topic = _sock.read(topic_len)
sz -= topic_len + 2
if op & 6:
pid = _sock.read(2)
pid = pid << 8 | pid
sz -= 2
msg = _sock.read(sz)
_cb(topic, msg)
if op & 6 == 2:
pkt = bytearray(b"\x40\x02\0\0")
struct.pack_into("!H", pkt, 2, pid)
_sock.write(pkt)
elif op & 6 == 4:
assert 0
# Checks whether a pending message from server is available.
# If not, returns immediately with None. Otherwise, does
# the same processing as wait_msg.
def check_msg(msg = ""):
global _sock
_sock.setblocking(False)
return wait_msg()
下面是ESP32 C3上保存的main.py程序代码:
import time
from machine import Pin
import siot #导入同目录下的siot.py
led=Pin(10,Pin.OUT)
SERVER="192.168.75.163"#行空板的IP地址
CLIENT_ID=""
IOT_pubTopic='siot/c3'
IOT_UserName='siot'
IOT_PassWord='dfrobot'
siot.init(CLIENT_ID,SERVER,user=IOT_UserName,password=IOT_PassWord)
def WIFIconnect(): #无线链接
import network
ssid='Mi10'#无线名称
password='********'#修改为无线密码
station=network.WLAN(network.STA_IF)
if station.isconnected() == True:
print("WiFi already connected")
print(station.ifconfig())
return
station.active(True)
station.connect(ssid,password)
while station.isconnected() == False:
pass
print("Connection successful")
print(station.ifconfig())
def sub_cp(topic,msg): # 回调函数
s=msg.decode()#对接收到的信息解码
print(s)
if s=='1':#接收的消息1就亮灯
led.value(1)
else:
led.value(0)
WIFIconnect()
siot.connect()
siot.set_callback(sub_cp)
siot.subscribe(IOT_pubTopic,sub_cp)
while True:
time.sleep(1)
siot.check_msg()
此时,我们可能通过向行空板上的SIoT发送1或0,实现ESP32 C3板载灯的亮或灭。我们也可以进一步在行空板上编写一个控制程序,如设置2个按钮,一个按钮是亮灯,另一个是关灯,实现消息的发送。
页:
[1]