2021-12-16 9元8266带继电器模块\ micropython\ 单网页服务器 \MQTT \烧写\串口重定向\mac地址获取 \等等经验贴

最近没有更新博客,专注于项目设计,制作了一个智能养殖的项目。实现功能:电池式多点温度检测 电池式定时拍摄 定时投喂以及PID温度湿度调节。项目做完了本来想记录一下,又觉得项目这东西做完了以后索然无味,没啥好记录,那么我们今天记录下9元钱的8266带继电器的控制板的使用吧。

之所以记录这个玩意,有以下原因:

  1. 价格足够便宜,9元钱带WIFI,带继电器,带电源管理,还能连上MQTT ,而且使用MICROPYTHON ,还能自己做为单体的WIFI网页控制器,也能进MQTT组成控制节点,功能可以说很是可以了。
  2. 功能强大,坑也是不少,价格低廉用的肯定不是什么最新的货色,老货自然坑多,闭坑需要经验,经验需要记录~~~~、
  3. 做上面说的项目的时候用了几个,当时觉得很是便宜方便,不小心备货了几十个。。。这么多的备货不开贴记录似乎说不过去,万一忘记呢。
    请添加图片描述
    整体长这样,9块全下来。
    请添加图片描述
    坑一:这俩块很像,几乎一毛一样,左边是ESP01S 右边是ESP01 ,在卖家看来这俩模块通用,很多买家也是这么认为的,ESP01S的标识在哪?主要看右上角天线旁边那个白色的大LED灯,有这个就是01S没有这个大的就是01.。
    坑二:烧写
    1.先擦除: esptool.py --port com20 erase_flash (com20是端口号,记得改了) 如果没有esptool或者pyserial都要用pip安装一个
    2.烧写 esptool.py --port com20 --baud 460800 write_flash --flash_size=detect 0 esp8266-20170108-v1.8.7.bin
    3.据说特殊的片子要用着 esptool.py --port com20 --baud 460800 write_flash --flash_size=detect -fm dio 0 esp8266-20170108-v1.8.7.bin
    4.以上的烧写和擦除部分 ,记得改端口号最后那部分固件路径

也可以直接使用THONNY的烧写选项,也很好用。

在这里插入图片描述

坑的位置是:ESP01S对固件支持不高,我测试最高支持到V1.12,而我实际部署的项目使用的是V1.10版本的,我倒是觉得1.10挺稳定的,个人感觉。高版本固件烧写后无法连接文件系统。。。 而且ESP8266的固件分512K 1M 2M其中 512K、1M不支持MQTT,2K OTA不支持MQTT,高于1.13版本进不去文件系统。esp01的模块烧写V1.10失败了,不排除我操作问题。但是我烧写V1.12的时候是成功的,那ESP01我以后就烧写V1.12的版本了,反正也是一样用,目前其实V1.12可以说是ESP01和ESP01S都是可以使用的,高版本我也不打算测试了,反正基本功能啥都有了折腾它还干啥。嗯,目前1.10版本不能执行省电睡眠,1.12的可以machine.lightsleep(5000)这么用。深度睡眠还是不行。

坑三:烧写模式
请添加图片描述
烧写的时候要保证GPIO0一直处于下拉的状态再重启才能进入烧写模式,在中断输入并启动烧写命令后会等待模块重启,这时要保持gpio0下拉的同时下拉一下RST引脚,才能执行烧写命令。
请添加图片描述
请添加图片描述
几年前买了这个,按说是个专业烧写模块,结果。。。。。。。。这个设计的没有复位也没有0引脚下拉于是接个保持按钮下拉0引脚,镊子充当复位开关。。。。

烧写完毕说下使用:

  1. 电流要求倒是不高有个1A的旧的手机充电器就能客串这个继电器模块的电源。我甚至觉得可以挑战下500MA的,不过可能有点点悬毕竟是个WIFI模块,但是800MA我觉得绝对是够用的。
  2. 8266和32在使用的时候有细微区别要多看手册,比如:这个模块WDT不能指定时间,可使用但定时间隔由底层实现。深度睡眠可以睡但是也不能指定睡眠时间。需要逐步了解。没有多线程方式,连实验性质的都没有。
  3. GPIO0下拉继电器吸合。也就是取值为0的时候触发接通,可是用信号反转执行调整。
  4. 没有引出的输入引脚,基本就是靠网络,GPIO2引脚连着LED灯,拉低灯亮,恩这个脚可以用用输入或者输出啥的,。 两个rx,tx也算是能用的引脚,确实需要再研究。
    在这里插入图片描述

下面: 如何作为一个自带热点、网页、服务器的继电器控制器

###########################
#引入模块
############################
try:
    import usocket as socket
except:
    import socket
import network
import machine,time
from machine import Pin
###########################
#登录HTML,支持所有的INPUT标签,其他标签慎用,可用中文,由浏览器自行解析
##########################
login_html = """
<html>
    <html>
    <head>
        <title>登录平台</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <style type="text/css">
            h2
            {
                margin-top:4%;
                margin-bottom:40px;
            }
        </style>
    </head>
    <body>
        <center>
        <h2>登录服务器</h2>
            <form action="/" method="get" accept-charset="utf-8">
                <p>账号:&nbsp;<input type="text" name="name"  /></p>  
                <p>密码:&nbsp;&nbsp;<input type="text" name="pwd"  /></p>
                <p>
                灯号:&nbsp;&nbsp;
                <input type="radio" name="led" value="1"  />1
                <input type="radio" name="led" value="2"  />2
                <input type="radio" name="led" value="3"  />3
                </p>
                <input type="Submit" value="登录"  />         
                
            </form>
        </center>
    </body>
</html>
"""
##########################################
#跳转到的HTML
#########################################
html="""
<html>
    <html>
    <head>
        <title>服务平台</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <style type="text/css">
            h2
            {
                margin-top:4%;
                margin-bottom:40px;
            }
        </style>
    </head>
    <body>
        <center>
        <h2>欢迎,欢迎</h2>
        </center>
    </body>
</html>
"""
###################################
#设置AP模式同时输入热点名字和密码
####################################
def CreatNetwork(ssid,pwd):
    ap_if = network.WLAN(network.AP_IF)#AP 模式
    ap_if.active(True)
    ap_if.config(essid=ssid,password=pwd)
    return ap_if.ifconfig()[0]
def main(ip):
    ############################
    #设置TCP套接字,保持监听数量5
    ############################
    s = socket.socket()
    ai = socket.getaddrinfo(ip, 80)
    addr = ai[0][-1]
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(addr)
    s.listen(5)
    print("Listening, connect your browser to http://",ip,":80/")
    ###########################
    #默认的登录用户,密码之类,简单服务器写死就行
    ###########################
    username='v202'
    userpwd='123456k'
    userpwd1='123456g'
    while True:
        ##########################
        #循环有链接传入则提供初始化握手服务
        ########################
        res = s.accept()
        client_s = res[0]
        client_addr = res[1]
        req =client_s.readline()
        while True:
            ################
            #循环接收,判断结束后跳出
            ##################
            h = client_s.readline()
            if h == b"" or h == b"\r\n":
                break
            req+=(h.decode('utf-8').lower())
        print("Request:")
        s_data=login_html#默认页面为登录页面
        req=req.decode('utf-8').lower().split('\r\n')
        #http header 解析
        req_data=req[0].lstrip().rstrip().replace(' ','')
        print(req_data)
        if req_data.find('favicon.ico')>-1:
            client_s.send(s_data)
            client_s.close()
            continue
        else:
            ####################
            #如果存在GET数据,则查找位置
            ####################
            if len(req_data)>12:
                print('-----',req_data)
                req_data=req_data.replace('get/?','').replace('http/1.1','')
                _name=req_data.find('name')
                _pwd=req_data.find('pwd')
                print('++++++++',_name,_pwd,req_data)
                if _name>-1 and _pwd>-1:# 查找位置,关键字都找到了进入
                    ###############################################
                    #判断是否是用户登录,以下为业务逻辑过程,可按需修改
                    ###############################################
                    if req_data.find(username)>-1 and req_data.find(userpwd)>-1: #和预留的账号密码查找,找到了则执行
                        s_data=html
                        p0=Pin(0,Pin.OUT)
                 
                        p0.value (0)
                        print('Login Success!')
                    if req_data.find(username)>-1 and req_data.find(userpwd1)>-1:
                        s_data=html
                        p0=Pin(0,Pin.OUT)
                      
                        p0.value (1)
                        print('Login Success!')
            client_s.send(s_data)
            client_s.close()
        
myip=CreatNetwork('TPYBoard v202','tpyboard')#建立一个AP
main(myip)#搭建web服务器

下面是:如何作为一个WiFi接入的MQTT物联网节点控制器进行工作

##########################
#模块引入
######################
import network
import time
from machine import Pin,Signal
import machine
from umqtt.simple import MQTTClient
###################
#启动延时10秒避免连接不上死锁
####################
time.sleep(10)
####################
#继电器引脚定义并反转信号
#################
led_ctrl = Pin(0,Pin.OUT)
led_ctrl= Signal(led_ctrl, invert=True)
led_ctrl.value(0)
##########################
#wifi 联网的类
########################
class Sta(): #传入账号密码
   wlan = None
   def __init__(self, wifi_ssid, wifi_pwd):
      self.wifi_ssid = wifi_ssid
      self.wifi_pwd = wifi_pwd

   def connect(self):  #连接动作
      network.WLAN(network.AP_IF).active(False) # disable access point
      self.wlan = network.WLAN(network.STA_IF)
      self.wlan.active(True)
      self.wlan.disconnect()
      if not self.wlan.isconnected(): 
        self.wlan.connect(self.wifi_ssid, self.wifi_pwd)

   def status(self): #网络存活指示
      if self.wlan.isconnected():
        return self.wlan.ifconfig()
      else:
        return ()

   def wait(self): #连接后判断是否成功的等待
      cnt = 40
      while cnt > 0:
         print("Waiting ..." )
         # con(self.wifi_ssid, self.wifi_pwd) # Connect to an WIFI_SSID
         if self.wlan.isconnected():
           print("Connected to %s" % self.wifi_ssid)
           print('network config:', self.wlan.ifconfig())
           cnt = 0
         else:
           time.sleep(5)
           cnt -= 5
      return
   def scan(self): #扫描
      return self.wlan.scan()   # Scan for available access points
   def CreatNetwork(self): #AP模式
      cnt = 40
      ap_if = network.WLAN(network.AP_IF)#AP 模式
      ap_if.active(True)
      ap_if.config(essid=self.wifi_ssid,password=self.wifi_pwd,authmode=2)
      while cnt > 0:
         print("Waiting ..." )
         # con(self.wifi_ssid, self.wifi_pwd) # Connect to an WIFI_SSID
         if ap_if.ifconfig()[0]!='0.0.0.0':
           print("start  %s" % self.wifi_ssid)
           print('network config:',ap_if.ifconfig()[0])
           cnt = 0
           return ap_if.ifconfig()[0]
         else:
           sleep(5)
           cnt -= 5
# if __name__=='__main__': #以上网络的具体用法实例
#     #####联网调用
#     #热点模式
#     a=Sta('201king','13704677369')
#     ip=a.CreatNetwork()
#     port = 9999    #端口号

#     WiFi接入模式
#     a=Sta('300king','13704677369')
#     a.connect()
#     a.wait()


#################################
#物联网的类
#############################
class Mqtt_run():
    def __init__(self,dev_name,ip,name_id,password,list_sub):# 设备名 , 服务器地址,端口 , 账号, 密码,订阅列表
        self.mqtt_mast=MQTTClient(dev_name,ip,1883,name_id,password)
        self.mqtt_mast.connect()
        self.mqtt_mast.set_callback(self.recdate1)# 绑定回调函数,名字别错
        for i in list_sub:
            self.mqtt_mast.subscribe(i)#设置订阅的主体,这里是123
    def recdate1(self,t,m):#这是回调函数,有信息并触发后都在这里执行
      ###############我就是填充业务逻辑的地方###############
      print("我在这里运行",t,m)
      if t==b'led':
          if m == b'1':
              led_ctrl.value(1)
          else:
              led_ctrl.value(0)

###################################################
              
              
######主程########              
try:
    print('开始')
    ########################
    #务必先联网
    ########################
    w=Sta('300king','13704677369')
    w.connect()
    w.wait()
    if w.status():
        pass
    else:
        w.connect()
        w.wait()
    a=Mqtt_run('led','47.105.72.112','esp32','esp32',['led']) #设备名 , 服务器地址,端口 , 账号, 密码,订阅列表

    print('配置完毕')

    while 1:
        if w.status() :
            a.mqtt_mast.check_msg() #轮询消息,主函数中周期越快越好,没这个就听不叫了
            a.mqtt_mast.publish('ledtopc','ok') # *****前边是发往哪个主题,后面是内容 发送数据*****************************
            time.sleep(5) #延时,别刷屏
            print(led_ctrl.value())
            pass
        else:
            w.connect()
            w.wait()
except:
    ############################
    #用看门狗充当复位指令
    ###########################
    machine.WDT()



串口重定向:之前提到了rx tx可以用,现在说下使用办法,8266有1个半串口,这个9元01S模块只有一个串口还被调试占用着,那么如何解放这唯一的串口呢?代码如下:

import sys,time
print('启动等待2秒') 
time.sleep(5)# 延时防卡死
####################################
#如何取消掉RELP交互:
##################################
import uos
print('取消调试串口输出5秒后开始成为普通串口')
uos.dupterm(None, 1) #核心命令,前面表示取消,后面是固定的号
time.sleep(5)
############################
#下面是对串口进行了重新定义和使用,现在他是一个普通串口了
###########################
from machine import UART
uart = UART(0, baudrate=9600)
for i in range(10):
    uart.write('hello')
    time.sleep(1)
uart.read(5) # 读5个字节
#######################################
#如果使用完毕,还要变回调试串口?  注意:8266波特率是115200的
#######################################
import uos, machine
uart = machine.UART(0, 115200)
uos.dupterm(uart, 1)

经我后续实际测试,tx(1) ,rx(3) , io0 , io2 四个引脚都可以设置为输出引脚,唯独RX引脚输出为3.6v其余输出为3.3V 也就是说这个脚电压高0.3V。嗯,天知道我会在几年后回来看这个博客找什么答案呢,不管了,把愚蠢的测试代码也放底下,反正是CSDN存,不是我的服务器存。
import sys,time
print('启动等待2秒') 
time.sleep(5)# 延时防卡死

     #sys.stdin.read() #这玩意可以卡住输入,CTRL+D结束输入,但是和THONNY编辑器热键冲突,也没啥用,放着得了
####################################
#如何取消掉RELP交互:
##################################
import uos
print('取消调试串口输出10秒后开始成为普通串口')
uos.dupterm(None, 1) #核心命令,前面表示取消,后面是号
time.sleep(5)
############################
#下面是对串口进行了重新定义和使用,现在他是一个普通串口了
###########################
# from machine import UART
# uart = UART(0, baudrate=9600)
# for i in range(10):
#     uart.write('hello')
#     time.sleep(1)
# uart.read(5) # 读5个字节
from machine import Pin
tx =Pin(1,Pin.OUT)
rx =Pin(3,Pin.OUT)
io0 =Pin(0,Pin.OUT)
io2 =Pin(2,Pin.OUT)

while 1:
    tx.value(1)
    io0.value(1)
    io2.value(1)
    rx.value(1)
    time.sleep(1)
    tx.value(0)
    io0.value(0)
    io2.value(0)
    rx.value(0)
    time.sleep(1)
    
#######################################
#如果使用完毕,还要变回调试串口?  注意:8266波特率是115200的
#######################################
import uos, machine
uart = machine.UART(0, 115200)
uos.dupterm(uart, 1)




关于深度休眠唤醒:一般来说开发板类型的8266深度睡眠采用以下方式,以下例程来自管方文档。

import machine
rtc = machine.RTC()
rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP)
# set RTC.ALARM0 to fire after 60 seconds (waking the device)
rtc.alarm(rtc.ALARM0, 10000)
# put the device to sleep
machine.deepsleep()

但是,这个ESP01S模块8个引脚在使用例程的时候,唤醒动作执行但没有按照预期工作,不清楚是这个模块问题,还是通病,是16号引脚没接复位?还是版本固件问题?反正没有深追,只留一个记录在这备查。

请添加图片描述
请添加图片描述

原理上肯定是这样的,实际上我没焊接上芯片上的引脚。哎,需要很尖的烙铁和技术。。。。 算了 ,先这样,起码方向应该没问题,原理图上也显示了,就是XPD_DCDC(16号引脚)这个RTC唤醒引脚没有接复位上,能接上就行。话说8266低功耗做的确实不算好,真要求低功耗还是上32比较好。实际测试了一下这个9元模块的电流,正常使用平均100MA左右,使网络关闭状态功耗降低到35MA左右,采用LIGHTSLEEP模式降低到30MA左右,看来即使采用深度睡眠也不会怎么乐观,因为这个9元模块本身耗电就不是低功耗设计的,ESP01小型是小型了但是也应该不是作为电池设备设计的,所以ESP01索性没接RTC唤醒引脚,不能深度睡眠自动唤醒。,那只能使用外部唤醒了。。。这个更简单了,如上图,复位和GND来一下,唔,连中断都免了。。。。


最后,再写个MAC地址的获取,这个比较特殊单独记录下,他和IP啥的不在一个地方。

import network
sta_if = network.WLAN(network.STA_IF)
s = sta_if.config('mac')
mymac = ('%02x%02x%02x%02x%02x%02x') %(s[0],s[1],s[2],s[3],s[4],s[5])
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值