电子说
一、介绍
使用Pi Pico 搭配扩展板以及各种传感器模块,再加上网络相关模块将搜集到的数据上传云端,完成一个简易的云端温湿度监测站。
二、软件安装
安装Thonny IDE以及MircoPython Firmware的刻录。
三、硬件配置
我们这次会使用到的模块有SHT3x温湿度模块、1.3吋 OLED、LED灯模块以及AM7020 NBIoT网络模块,接线方式如下对照图表所示。
实际功能为将读取到的温湿度数据显示到1.3吋 OLED上,以及定时将数据透过AM7020上传云端,并且提供远程网页控制LED灯的功能,除了控制LED灯外也可结合继电器实现控制家电(e.g.电灯、电扇、浇水设备……等)。
四、云端设定
这次我们会使用Adafruit IO做为云端平台,它将会存放温度、湿度,以及LED灯控制讯息相关数据,并且透过内建服务Dashboard将数据以图形化方式呈现。
进到Adafruit IO官网新增三个Feed,分别为「temperature」、「humidity」、「led」,如下图所示。
接着请新增一个Dashboard,名称为「pico」,如下图所示。
继续在pico Dashboard内新增折线图表以及按钮开关,折线图数据源选择Feed「temperature」、「humidity」,按钮开关数据源选择Feed「led」,如下图所示。
五、程序撰写
本篇所用到的范例程序代码可至下列连结下载。
https://github.com/JiekangHuang/pi_pico_adafruitIO_nbiot
(一)加载相关Library
为了简化程序代码复杂度,我们将会使用AM7020、SHT31、OLED 的MicroPython Library 来处理Driver 的部分,请将这三个Library 预先存入Pi Pico内以便之后主程序呼叫。
首先使用Thonny从本机开启要存入的档案,并选择档案>>另存新檔>>Raspberry pi pico>>输入文件名(需与原档名相同)。
Pico Library档案结构如下图所示。
第一层为lib文件夹
lib文件夹里为「am7020」文件夹、「sht31.py」、「ssd1306.py」。
am7020文件夹里为「am7020_modem.py」、「am7020_mqtt.py」、「am7020_nb.py」。
(二)程序设计
开启打开范例「example/adafriotIO_pico.py」并执行。
1 fromutime import ticks_ms, sleep_ms
2 fromam7020.am7020_nb import AM7020NB
3 fromam7020.am7020_mqtt import AM7020MQTT
4
5 importsht31
6 frommachine import Pin, I2C
7 fromssd1306 import SSD1306_I2C
8
9 sht31_i2c= I2C(1, scl=Pin(7), sda=Pin(6), freq=400000)
10sensor = sht31.SHT31(sht31_i2c, addr=0x44)
11
12 WIDTH= 128 # oled 显示宽度
13HEIGHT = 64 #oled 显示高度
14
15 # 初始化 I2C 物件 I2C0 SCL =1, I2C0 SDA = GP0
16oled_i2c = I2C(0, scl=Pin(9), sda=Pin(8), freq=200000)
17
18 oled= SSD1306_I2C(WIDTH, HEIGHT, oled_i2c)
19
20 led =Pin(20, Pin.OUT)
21
22 #NBIoT 相关设定
23 apn ="twm.nbiot" # 存取点名称
24 band= 28 # 通讯频道
25CHECK_NET_INTERVAL_MS = 1000 # 网络检查间隔时间
26
27#相关设定
28MQTT_BROKER = "io.adafruit.com"
29 PORT= 1883
30 MQTT_USERNAME= "
31MQTT_PASSWORD = "
32TEMP_TOPIC = MQTT_USERNAME + "/feeds/pico.temperature"
33HUM_TOPIC = MQTT_USERNAME + "/feeds/pico.humidity"
34LED_TOPIC = MQTT_USERNAME + "/feeds/pico.led"
35UPLOAD_INTERVAL_MS = 30000 # 讯息上传间隔时(毫秒)
36
37 nb =AM7020NB(0, 9600, 0, 1, 3, False) # 建立连接对象
38 mqtt= AM7020MQTT(nb) # 建立 MQTT 通讯对象
39
40
41 defnbConnect(): # ⾃订联机程序
42 print("Initializing modem...")
43 while((not nb.init() or (notnb.nbiotConnect(apn, band)))):
44 print(".")
45
46 print("Waiting for network...")
47 while(not nb.waitForNetwork()):
48 print(".")
49 sleep_ms(5000)
50
51 print(" success")
52
53
54 defreConnBroker(): # MQTT Broker 重新联机程序
55 print("Connecting to",MQTT_BROKER, end="...")
56 if(mqtt.connBroker(MQTT_BROKER, PORT,MQTT_USERNAME, MQTT_PASSWORD, mqtt_id="ICSHOP_AM7020_MQTT_ID")):
57 print(" success")
58 print("subscribe: ",LED_TOPIC, end="")
59 if(mqtt.subscribe(LED_TOPIC,mqttCallback)):
60 print(" success")
61 else:
62 print(" fail")
63 else:
64 print(" fail")
65
66 #MQTT 订阅内容讯息回调函数
67
68
69 defmqttCallback(msg):
70 print(LED_TOPIC, ":", msg)
71 if(msg == "ON"):
72 led.on()
73 else:
74 led.off()
75
76
77chk_net_timer = 0 # 联机状态查询周期定时器
78pub_data_timer = 0 # 讯息发布周期定时器
79
80 oled.fill(0) # 清除画面
81oled.text("Init modem...", 0, 0)
82oled.show()
83
84print("Initializing modem...")
85while(not nb.init()):
86 print(".")
87
88while(True):
89 # show SHT31 data
90 oled.fill(0) # 清除画面
91
92 t = round(sensor.get_temp_humi()[0], 1)
93 h = round(sensor.get_temp_humi()[1], 1)
94 # print("Temperature: {}".format(t))
95 # print("Humidity:{}".format(h))
96
97 if(ticks_ms() > chk_net_timer): # 联机状态查询周期
98 chk_net_timer = ticks_ms() +CHECK_NET_INTERVAL_MS
99 if(not nb.chkNet()):
100 oled.fill(0) # 清除画面
101 oled.text("ISP Connecting", 0, 0)
102 oled.show()
103 nbConnect()
104 oled.fill(0) # 清除画面
105 oled.text("ISPConnected", 0, 0)
106 oled.show()
107 if(not mqtt.chkConnBroker()):
108 oled.fill(0) # 清除画面
109 oled.text("MQTTConnecting", 0, 0)
110 oled.show()
111 reConnBroker()
112 oled.fill(0) # 清除画面
113 oled.text("MQTTConnected", 0, 0)
114 oled.show()
115
116 if(ticks_ms() > pub_data_timer): # 讯息发布周期
117 pub_data_timer = pub_data_timer +UPLOAD_INTERVAL_MS
118 print("publish: ", t,end="")
119 if(mqtt.publish(TEMP_TOPIC, str(t))):
120 print(" success")
121 else:
122 print(" Fail")
123 print("publish: ", h,end="")
124 if(mqtt.publish(HUM_TOPIC, str(h))):
125 print(" success")
126 else:
127 print(" Fail")
128 mqtt.procSubs() # 检查订阅频道状态
129 oled.text("MQTT Connected", 0,0)
130 # 加入文字内容
131 oled.text("Temp: ", 0, 10)
132 oled.text(str(t), 50, 10)
133 oled.text("*C", 90, 10)
134
135 oled.text("Humi: ", 0, 20)
136 oled.text(str(h), 50, 20)
137 oled.text("%", 90, 20)
138 oled.show() # 显示绘制内容
程序代码说明:
1. 引入这次实作所需模块。
2. 建立并传入I2C1建立SHT31对象,用来读取温湿度;建立并传入I2C0建立OLED对象,用来操作OLED,OLED设定宽高为128*64;建立LED对象,pin设定为20,并设为输出,用来显示网页控制开关状态。
3. 设定NBIoT 模块所使用的APN、Band(不同电信商会不一样,此为台湾大哥大,Band 28),设定MQTT相关参数,Broker 使用Adafruit IO,Port 使用1883,账号密码请自行修改,设定温湿度、LED Topic,请务必与云端设定相同,35行设定数据上传云端的间隔,使用者可自行依需求调整,这里设为30秒上传一次;建立AM7020、AM7020MQTT对象,用来将数据发送至云端平台。
4. 定义NBIoT 联机程序,呼叫AM7020对象init 初始化方法以及nbiotConnect 方法直到成功,接着呼叫waitForNetwork 方法等待联机完成。
5. 定义MQTT 重新联机程序,使用AM7020MQTT对象的connBroker 方法联机到指定Broker,这里须注意每个装置的mqtt_id不可相同,若相同Broker 将会剔除上一次的联机,联机完毕后使用AM7020MQTT 对象的subscribe 方法订阅LED的 Topic,并传入callback(于下一段说明),用以接收LED开关状态。
6. 定义LED数据的Callback,当AM7020MQTT对象收到LED主题数据时就会呼叫此方法,在此方法里面判断讯息并控制LED亮灭。
7. 建立检查联机状态、发布数据的定时器;将OLED画面清除并显示初始化讯息,并等待NBIOT模块初始化成功。
8. 进入无穷循环,92~93行读取温湿度数据,97~114定时检查NBIOT以及MQTT的联机状态,若中间有断线便会呼叫上面定义的重新联机方法,并透过OLED显示目前状态。
9. 透过定时器的方式定时发送温湿度数据到云端(默认为30秒上传一次),发送数据使用AM7020MQTT对象的publish方法,参数带入目标Topic以及要发布的讯息。
10. 128行使用AM7020MQTT对象的procSubs方法检查是否有订阅数据到达;将温湿度数据显示到OLED上。
六、执行结果
完成以上步骤,并执行范例程序代码,我们就可以在OLED及云端上看到温湿度数据,并且可以直接透过网页按钮控制Pico 的LED灯,如下图所示。
全部0条评论
快来发表一下你的评论吧 !