上一次我们对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        [LuoYufeng](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)[0][-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)[0]
 -     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[1] = 10 + 2 + len(_client_id)
 -   msg[9] = clean_session << 1
 -   if _user is not None:
 -     msg[1] += 2 + len(_user) + 2 + len(_pswd)
 -     msg[9] |= 0xC0
 -   if _keepalive:
 -     assert _keepalive < 65536
 -     msg[10] |= _keepalive >> 8
 -     msg[11] |= _keepalive & 0x00FF
 -   if lw_topic:
 -     msg[1] += 2 + len(lw_topic) + 2 + len(lw_msg)
 -     msg[9] |= 0x4 | (lw_qos & 0x1) << 3 | (lw_qos & 0x2) << 3
 -     msg[9] |= 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[0] == 0x20 and resp[1] == 0x02
 -   if resp[3] != 0:
 -     raise MQTTException(resp[3])
 -   return resp[2] & 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[0] |= qos << 1 | retain
 -   sz = 2 + len(topic) + len(msg)
 -   if qos > 0:
 -     sz += 2
 -   assert sz < 2097152
 -   i = 1
 -   while sz > 0x7f:
 -     pkt[i] = (sz & 0x7f) | 0x80
 -     sz >>= 7
 -     i += 1
 -   pkt[i] = 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[0] << 8 | rcv_pid[1]
 -         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[1] == pkt[2] and resp[2] == pkt[3]
 -       if resp[3] == 0x80:
 -         raise MQTTException(resp[3])
 -       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)[0]
 -     assert sz == 0
 -     return None
 -   op = res[0]
 -   if op & 0xf0 != 0x30:
 -     return op
 -   sz = _recv_len()
 -   topic_len = _sock.read(2)
 -   topic_len = (topic_len[0] << 8) | topic_len[1]
 -   topic = _sock.read(topic_len)
 -   sz -= topic_len + 2
 -   if op & 6:
 -     pid = _sock.read(2)
 -     pid = pid[0] << 8 | pid[1]
 -     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个按钮,一个按钮是亮灯,另一个是关灯,实现消息的发送。[/md] 
 
 |