Pyboard利用NB-IoT模块通过MQTT协议发送dht11传感器的温湿度数据 实战

1.试验材料

Pyboard板、dht11温湿度传感器、NB-IoT模块、4G天线、已激活的物联网卡、0.96寸4P的OLED屏和安卓数据线各一个

接线方式

如有不明白的可看下图

配件接口 pyboard板接口
USB安卓数据线 DFU
DHT11温湿度传感器 PB13-Y6引脚
NB-IoT的RX PC6-Y1
NB-IoT的TX PC7-Y2
NB-IoT的3.3V 3.3V
NB-IoT的GND GND
OLED屏的SCL PB10-Y9引脚
OLED屏的SDA PB11-Y10引脚

DHT11连接引脚图

NB-IoT TX和RX连接引脚图

NB-IoT TX和RX连接引脚图

2.程序烧录

开发软件uPyCraft_V1.1.exe

将以下4个程序创建并下载至Pyboard板中

main.py 主函数

import pyb
from pyb import Timer,LED 
from machine import I2C,Pin
from ssd1306 import SSD1306_I2C
from pyb import Accel 
import time
from pyb import UART
import dht

#初始化OLED
i2c = I2C(sda=Pin("Y10"), scl=Pin("Y9"))  
oled = SSD1306_I2C(128, 64, i2c, addr=0x3c)

#初始化DHT11
dht = dht.DHT11(Pin("B13"))

time.sleep(1)
accel=Accel() 

#初始化串口uart6
uart6 = UART(6,115200)
uart6.init(115200, bits=8, parity=None, stop=1)
time.sleep(1)
connectStatus="0"

#呼吸灯
ia =1                          #定义变量 
da =1  
def fa(t):                         #定义回调函数 
  global ia,  da                  #声明全局变量 
  if (ia==0) or (ia==255):         #判断亮度方向 
    da = 256 -da 
  ia = (ia + da) % 256            #改变亮度参数 
  LED(3).intensity(ia)


tm=Timer(1, freq=50, callback=fa)  #设置定时器 1,50Hz,回调函数 fa 
start = time.time()  #启动计时
words=('\r','\n',' ')
oled.fill(0)  # 清屏,背景黑色
oled.text('Initializing...', 0, 0)
oled.show()
time.sleep(60) #等待BC26初始化

uart6.write('AT\r\n')  #测试AT指令
time.sleep(1)
buf=uart6.read().decode()
for word in words:
  if word in buf:
    buf = buf.replace(word,'')
print(buf)

if buf.find('ATOK') > -1 :
  uart6.write('AT+CGATT?\r\n')  #测试网络是否附着
  oled.fill(0)  # 清屏,背景黑色
  oled.text('AT Succ', 0, 0)
  oled.show()
  time.sleep(1)
  buf=uart6.read().decode()
  for word in words:
    if word in buf:
      buf = buf.replace(word,'')
  print(buf)
else:
  print('AT Fail')
  oled.fill(0)  # 清屏,背景黑色
  oled.text('AT Fail', 0, 0)
  oled.show()
  time.sleep(0.5)

if buf.find('AT+CGATT?+CGATT:1OK') > -1 :
  uart6.write('AT+QMTOPEN=0,"mq.tongxinmao.com",18830\r\n')  #打开MQTT客户端网络
  oled.fill(0)  # 清屏,背景黑色
  oled.text('CGATT Succ', 0, 0)
  oled.show()
  time.sleep(8)
  buf=uart6.read().decode()
  for word in words:
    if word in buf:
      buf = buf.replace(word,'')
  print(buf)
  if buf.find('AT+QMTOPEN=0,"mq.tongxinmao.com",18830OK+QMTOPEN:0,0') > -1 :
    uart6.write('AT+QMTCONN=0,"BC26"\r\n')
    oled.fill(0)  # 清屏,背景黑色
    oled.text('QMTOPEN Succ', 0, 0)
    oled.show()
    time.sleep(2)
    buf=uart6.read().decode()
    for word in words:
      if word in buf:
        buf = buf.replace(word,'')
    print(buf)
  elif buf.find('AT+QMTOPEN=0,"mq.tongxinmao.com",18830OK') > -1 :  #有时候会连接很长时间,需要循环判断是否收到消息
    while True:
      testdata=uart6.read()
      if testdata:
        buf=testdata.decode()
        for word in words:
          if word in buf:
            buf = buf.replace(word,'')
        if buf.find('+QMTOPEN:0,0') > -1 :
          uart6.write('AT+QMTCONN=0,"BC26"\r\n')  #将BC26连接至MQTT服务器
          oled.fill(0)  # 清屏,背景黑色
          oled.text('QMTOPEN Succ', 0, 0)
          oled.show()
          time.sleep(2)
          buf=uart6.read().decode()
          for word in words:
            if word in buf:
              buf = buf.replace(word,'')
          print(buf)
          break
        else:
          print('QMTOPEN Fail')
          oled.fill(0)  # 清屏,背景黑色
          oled.text('QMTOPEN Fail', 0, 0)
          oled.show()         
      else:
        print("waiting for conn")
        oled.fill(0)  # 清屏,背景黑色
        oled.text('waiting for conn', 0, 0)
        oled.show()
      time.sleep(5)
  else:
    print('QMTOPEN Fail')
    oled.fill(0)  # 清屏,背景黑色
    oled.text('QMTOPEN Fail', 0, 0)
    oled.show()

else:
  print('CGATT Fail')
  oled.fill(0)  # 清屏,背景黑色
  oled.text('CGATT Fail', 0, 0)
  oled.show()

if buf.find('AT+QMTCONN=0,"BC26"OK+QMTCONN:0,0,0') > -1 :
  connectStatus="1"
  oled.fill(0)  # 清屏,背景黑色
  oled.text('QMTCONN Succ', 0, 0)
  oled.show()
  time.sleep(2)

else:
  print('QMTCONN Fail')
  oled.fill(0)  # 清屏,背景黑色
  oled.text('QMTCONN Fail', 0, 0)
  oled.show()


while connectStatus=="1":
  dht.measure()  #读取温湿度
  Tem=dht.temperature()
  Hum=dht.humidity()
  uart6.write('AT+QMTPUB=0,1,1,0,"/mqtt/pub","{"tem":%s'%Tem+',"hum":%s'%Hum+'}"\r\n') #秒传温湿度
  oled.fill(0)  # 清屏,背景黑色
  oled.text('Send Succ', 0, 0)
  oled.text('t:%s' %Tem+'C h:%s' %Hum+'%', 0,  12) #oled显示收到的温湿度
  oled.text('Acceleration:', 0,  24) 
  oled.text("x:%d, y:%d, z:%d"%(accel.x(),accel.y(),accel.z()), 0,  36) #oled显示加速度数值
  end = time.time() 
  oled.text('T:'+str(end-start)+'s', 0, 48) #oled显示程序运行时间
  oled.show()
  time.sleep(1)

boot.py

import machine
import pyb

dht.py dht11温湿度传感器驱动

from pyb import dht_readinto

class DHTBase:
    def __init__(self, pin):
        self.pin = pin
        self.buf = bytearray(5)

    def measure(self):
        buf = self.buf
        dht_readinto(self.pin, buf)
        if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]:
            raise Exception("checksum error")

class DHT11(DHTBase):
    def humidity(self):
        return self.buf[0]

    def temperature(self):
        return self.buf[2]

ssd1306.py OLED屏驱动

from micropython import const
import framebuf

# register definitions
SET_CONTRAST        = const(0x81)
SET_ENTIRE_ON       = const(0xa4)
SET_NORM_INV        = const(0xa6)
SET_DISP            = const(0xae)
SET_MEM_ADDR        = const(0x20)
SET_COL_ADDR        = const(0x21)
SET_PAGE_ADDR       = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP       = const(0xa0)
SET_MUX_RATIO       = const(0xa8)
SET_COM_OUT_DIR     = const(0xc0)
SET_DISP_OFFSET     = const(0xd3)
SET_COM_PIN_CFG     = const(0xda)
SET_DISP_CLK_DIV    = const(0xd5)
SET_PRECHARGE       = const(0xd9)
SET_VCOM_DESEL      = const(0xdb)
SET_CHARGE_PUMP     = const(0x8d)

class SSD1306(framebuf.FrameBuffer):
    def __init__(self, width, height, external_vcc):
        self.width = width
        self.height = height
        self.external_vcc = external_vcc
        self.pages = self.height // 8
        self.buffer = bytearray(self.pages * self.width)
        super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
        self.init_display()

    def init_display(self):
        for cmd in (
            SET_DISP | 0x00, # off
            # address setting
            SET_MEM_ADDR, 0x00, # horizontal
            # resolution and layout
            SET_DISP_START_LINE | 0x00,
            SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
            SET_MUX_RATIO, self.height - 1,
            SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
            SET_DISP_OFFSET, 0x00,
            SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
            # timing and driving scheme
            SET_DISP_CLK_DIV, 0x80,
            SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
            SET_VCOM_DESEL, 0x30, # 0.83*Vcc
            # display
            SET_CONTRAST, 0xff, # maximum
            SET_ENTIRE_ON, # output follows RAM contents
            SET_NORM_INV, # not inverted
            # charge pump
            SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
            SET_DISP | 0x01): # on
            self.write_cmd(cmd)
        self.fill(0)
        self.show()

    def poweroff(self):
        self.write_cmd(SET_DISP | 0x00)

    def poweron(self):
        self.write_cmd(SET_DISP | 0x01)

    def contrast(self, contrast):
        self.write_cmd(SET_CONTRAST)
        self.write_cmd(contrast)

    def invert(self, invert):
        self.write_cmd(SET_NORM_INV | (invert & 1))

    def show(self):
        x0 = 0
        x1 = self.width - 1
        if self.width == 64:
            # displays with width of 64 pixels are shifted by 32
            x0 += 32
            x1 += 32
        self.write_cmd(SET_COL_ADDR)
        self.write_cmd(x0)
        self.write_cmd(x1)
        self.write_cmd(SET_PAGE_ADDR)
        self.write_cmd(0)
        self.write_cmd(self.pages - 1)
        self.write_data(self.buffer)

class SSD1306_I2C(SSD1306):
    def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
        self.i2c = i2c
        self.addr = addr
        self.temp = bytearray(2)
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.temp[0] = 0x80 # Co=1, D/C#=0
        self.temp[1] = cmd
        self.i2c.writeto(self.addr, self.temp)

    def write_data(self, buf):
        self.temp[0] = self.addr << 1
        self.temp[1] = 0x40 # Co=0, D/C#=1
        self.i2c.start()
        self.i2c.write(self.temp)
        self.i2c.write(buf)
        self.i2c.stop()

class SSD1306_SPI(SSD1306):
    def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
        self.rate = 10 * 1024 * 1024
        dc.init(dc.OUT, value=0)
        res.init(res.OUT, value=0)
        cs.init(cs.OUT, value=1)
        self.spi = spi
        self.dc = dc
        self.res = res
        self.cs = cs
        
        import time
        
        self.res(1)
        time.sleep_ms(1)
        self.res(0)
        time.sleep_ms(10)
        self.res(1)
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs(1)
        self.dc(0)
        self.cs(0)
        self.spi.write(bytearray([cmd]))
        self.cs(1)

    def write_data(self, buf):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs(1)
        self.dc(1)
        self.cs(0)
        self.spi.write(buf)
        self.cs(1)

3.使用java建立MQTT客户端,监听温湿度数据

使用通信猫(提取码:3j0l)等MQTT监听软件来监听温湿度数据均可

代码参考自JAVA连接MQTT服务器

pom.xml中引入maven依赖,里面的ip地址更改为MQTT部署的服务器地址

<!-- MQTT依赖 -->
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-mqtt</artifactId>
</dependency>

MQTT工具类代码

import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * MQTT工具类操作
 */

@Slf4j
@Component
public class MQTTConnect {
    
    
    private String HOST = "tcp://mq.tongxinmao.com:18830"; //mqtt服务器的地址和端口号
    private final String clientId = "DC" + (int) (Math.random() * 100000000);
    private MqttClient mqttClient;

    /**
     * 客户端connect连接mqtt服务器
     *
     * @param userName     用户名
     * @param passWord     密码
     * @param mqttCallback 回调函数
     **/
    public void setMqttClient(String userName, String passWord, MqttCallback mqttCallback) throws MqttException {
    
    
        MqttConnectOptions options = mqttConnectOptions(userName, passWord);
        if (mqttCallback == null) {
    
    
            mqttClient.setCallback(new Callback());
        } else {
    
    
            mqttClient.setCallback(mqttCallback);
        }
        mqttClient.connect(options);
    }

    /**
     * MQTT连接参数设置
     */
    private MqttConnectOptions mqttConnectOptions(String userName, String passWord) throws MqttException {
    
    
        mqttClient = new MqttClient(HOST, clientId, new MemoryPersistence());
        MqttConnectOptions options = new MqttConnectOptions();
        options.setUserName(userName);
        options.setPassword(passWord.toCharArray());
        options.setConnectionTimeout(10);///默认:30
        options.setAutomaticReconnect(true);//默认:false
        options.setCleanSession(false);//默认:true
        //options.setKeepAliveInterval(20);//默认:60
        return options;
    }

    /**
     * 关闭MQTT连接
     */
    public void close() throws MqttException {
    
    
        mqttClient.close();
        mqttClient.disconnect();
    }

    /**
     * 向某个主题发布消息 默认qos:1
     *
     * @param topic:发布的主题
     * @param msg:发布的消息
     */
    public void pub(String topic, String msg) throws MqttException {
    
    
        MqttMessage mqttMessage = new MqttMessage();
        //mqttMessage.setQos(2);
        mqttMessage.setPayload(msg.getBytes());
        MqttTopic mqttTopic = mqttClient.getTopic(topic);
        MqttDeliveryToken token = mqttTopic.publish(mqttMessage);
        token.waitForCompletion();
    }

    /**
     * 向某个主题发布消息
     *
     * @param topic: 发布的主题
     * @param msg:   发布的消息
     * @param qos:   消息质量    Qos:0、1、2
     */
    public void pub(String topic, String msg, int qos) throws MqttException {
    
    
        MqttMessage mqttMessage = new MqttMessage();
        mqttMessage.setQos(qos);
        mqttMessage.setPayload(msg.getBytes());
        MqttTopic mqttTopic = mqttClient.getTopic(topic);
        MqttDeliveryToken token = mqttTopic.publish(mqttMessage);
        token.waitForCompletion();
    }

    /**
     * 订阅某一个主题 ,此方法默认的的Qos等级为:1
     *
     * @param topic 主题
     */
    public void sub(String topic) throws MqttException {
    
    
        mqttClient.subscribe(topic);
    }

    /**
     * 订阅某一个主题,可携带Qos
     *
     * @param topic 所要订阅的主题
     * @param qos   消息质量:0、1、2
     */
    public void sub(String topic, int qos) throws MqttException {
    
    
        mqttClient.subscribe(topic, qos);
    }

    /**
     * main函数自己测试用
     */
    public static void main(String[] args) throws MqttException {
    
    
        MQTTConnect mqttConnect = new MQTTConnect();
        mqttConnect.setMqttClient("", "", new Callback());
        mqttConnect.sub("/mqtt/pub");
        //mqttConnect.pub("/mqtt/sub", "can you hear me?" + (int) (Math.random() * 100000000));
    }

}

MQTT的回调函数代码

import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;

/**
 * MQTT回调函数
 */

@Slf4j
public class Callback implements MqttCallback {
    
    
    /**
     * MQTT 断开连接会执行此方法
     */
    @Override
    public void connectionLost(Throwable throwable) {
    
    
        log.info("断开了MQTT连接 :{}", throwable.getMessage());
        log.error(throwable.getMessage(), throwable);
    }

    /**
     * publish发布成功后会执行到这里
     */
    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
    
    
        log.info("发布消息成功");
    }

    /**
     * subscribe订阅后得到的消息会执行到这里
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
    
    
        //  TODO    此处可以将订阅得到的消息进行业务处理、数据存储
        log.info("收到来自 " + topic + " 的消息:{}", new String(message.getPayload()));
    }

}

MQTT监听器代码

import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

/**
 * 项目启动 监听主题
 */

@Slf4j
@Component
public class MQTTListener implements ApplicationListener<ContextRefreshedEvent> {
    
    
    private final MQTTConnect server;

    @Autowired
    public MQTTListener(MQTTConnect server) {
    
    
        this.server = server;
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
    
    
        try {
    
    
            server.setMqttClient("", "", new Callback());
            server.sub("/mqtt/sub");
        } catch (MqttException e) {
    
    
            log.error(e.getMessage(), e);
        }
    }

}

4.程序测试

Pyboard板上电运行,经过初始化→AT测试→网络是否附着→打开MQTT客户端网络→将BC26连接至MQTT服务器→读取温湿度数据→发送温湿度数据

运行MQTT工具类代码中的main函数,开始监听/mqtt/pub主题的消息

Pyboard利用NB-IoT模块通过MQTT协议发送dht11传感器的温湿度数据完成,在JAVA项目中对数据进行解析,编写存储数据的业务逻辑即可将数据存储至数据库中。

欢迎小伙伴的讨论,若有问题请在评论区评论或私信,谢谢你。

猜你喜欢

转载自blog.csdn.net/bean_business/article/details/109029702