如果搭建好硬件平臺(tái)后,這一次我們的任務(wù)主要是調(diào)試好智能電燈,并且連接到騰訊云的物聯(lián)網(wǎng)平臺(tái)。
騰訊云物聯(lián)網(wǎng)平臺(tái)
騰訊物聯(lián)網(wǎng)平臺(tái)的優(yōu)勢(shì):
騰訊云鏈接: link. 到物聯(lián)網(wǎng)平臺(tái)的原因這是因?yàn)槲锫?lián)網(wǎng)平臺(tái)提供了基本的設(shè)備管理功能,可以幫助我們更快速地實(shí)現(xiàn)設(shè)備的遠(yuǎn)程控制功能。比如說,我們可以通過“騰訊連連”小程序,來控制電燈的狀態(tài),而不用自己花費(fèi)時(shí)間和精力去寫相應(yīng)的代碼等工作。
1.它的平臺(tái)是開放注冊(cè)的,我們普通的用戶也可以注冊(cè)來使用,不像很多平臺(tái)那樣需要企業(yè)用戶才能注冊(cè)。 2.另一方面是,騰訊云提供的交互方式非常方便,不需要編譯,或者下載其他 App,在微信上用小程序就可以進(jìn)行。
注冊(cè)與登錄
創(chuàng)建項(xiàng)目和產(chǎn)品
登錄之后,我們直接進(jìn)入準(zhǔn)備工作的第二步,創(chuàng)建項(xiàng)目和產(chǎn)品。我們先在物聯(lián)網(wǎng)開發(fā)平臺(tái)創(chuàng)建一個(gè)新項(xiàng)目“智能家居”。

創(chuàng)建一個(gè)新產(chǎn)品“智能電燈”。
簡(jiǎn)單設(shè)置幾個(gè)參數(shù):
產(chǎn)品品類:直接選擇“智能生活”–>“電工照明”–>“燈”。 認(rèn)證方式選擇:密鑰認(rèn)證,適合我們的開發(fā)板 NodeMCU。 通信方式:選擇 Wi-Fi。 數(shù)據(jù)協(xié)議選擇:“數(shù)據(jù)模板”,也就是基于物模型來解析數(shù)據(jù)。 
定義物模型
點(diǎn)擊進(jìn)入產(chǎn)品,我們可以看到“數(shù)據(jù)模板”界面中列出了“電燈開關(guān)”“亮度”“顏色”和“色溫”等屬性和事件。這些都是平臺(tái)根據(jù)上一步選擇的產(chǎn)品品類,自動(dòng)生成的。

完成“交互開發(fā)”配置
在“交互開發(fā)”界面中,我們需要關(guān)注兩個(gè)配置項(xiàng):“使用官方小程序控制產(chǎn)品”的選項(xiàng)要保持打開,因?yàn)槲覀兒竺嬉ㄟ^小程序來控制智能電燈;在“掃一掃產(chǎn)品介紹”配置項(xiàng)中,設(shè)置產(chǎn)品圖片和備注信息。  其他項(xiàng)目,比如“配置引導(dǎo)”“面板配置”和“快捷入口配置”,我們保持默認(rèn)配置就行,當(dāng)然你也可以根據(jù)自己的喜好進(jìn)行調(diào)整。 這些都配置好之后,我們就可以開始準(zhǔn)備“調(diào)試設(shè)備”的配置了。 為調(diào)試設(shè)備做準(zhǔn)備 在“設(shè)備調(diào)試”界面中,我們創(chuàng)建一個(gè)測(cè)試設(shè)備。點(diǎn)擊“新建設(shè)備”,輸入設(shè)備名稱“Led_1”。  創(chuàng)建成功后,在測(cè)試設(shè)備列表中,點(diǎn)擊“Led_1”,進(jìn)入設(shè)備的詳情頁(yè)面:  在這個(gè)“設(shè)備信息”標(biāo)簽頁(yè),我們可以看到“設(shè)備名稱”“設(shè)備秘鑰”和“產(chǎn)品 ID”的信息。我們需要把這些信息記錄下來,因?yàn)樵诤竺嬖O(shè)備的開發(fā)中需要用到。 設(shè)備名稱、設(shè)備秘鑰和產(chǎn)品 ID也經(jīng)常被稱為設(shè)備三元組。它完整地標(biāo)識(shí)了一個(gè)設(shè)備。在調(diào)試階段,設(shè)備名稱可以手動(dòng)命名,不過在正式應(yīng)用中,為了保證設(shè)備名稱的唯一性,平臺(tái)會(huì)幫你自動(dòng)生成設(shè)備名稱。 另外,在“設(shè)備調(diào)試”標(biāo)簽頁(yè),你需要點(diǎn)擊下圖中“二維碼”,獲取這個(gè)設(shè)備的二維碼,并保存好。因?yàn)樵诤竺娴牟襟E中,你需要使用“騰訊連連”小程序掃描這個(gè)二維碼,將設(shè)備添加到小程序中。  這是我在這個(gè)配置界面中定義的產(chǎn)品的二維碼。 這個(gè)二維碼的信息內(nèi)容,如下所示:
{"DeviceName":"Led_1","ProductId":"XNXP231VQA","Signature":"2aa86e4e826b49b2a93949955f50761"}
可以看到,這個(gè)鏈接中主要包含了產(chǎn)品 ID 的信息。每個(gè)產(chǎn)品 ID 是唯一的,所以你的產(chǎn)品 ID 與這個(gè)不同。 到這里,我們就完成了騰訊云的物聯(lián)網(wǎng)開發(fā)平臺(tái)的準(zhǔn)備工作。接下來,我們就要實(shí)打?qū)嵉卦陂_發(fā)板上,實(shí)現(xiàn)一個(gè)功能更加完善的智能電燈產(chǎn)品了。 如何打造智能電燈設(shè)備? 在上一講,我們用代碼實(shí)現(xiàn)了開發(fā)板上 LED 的控制。不過那個(gè)功能非常簡(jiǎn)單,為了讓我們的智能電燈功能更完善,效果更酷炫,我們可以開發(fā)更多的功能,主要包括控制 LED 燈的顏色、開關(guān),并能夠?qū)崿F(xiàn)遠(yuǎn)程控制。 我們先看看如何控制燈的顏色。 如何控制 LED 燈的顏色? 我們使用的 RGB LED 燈模塊,是使用 PWM 來實(shí)現(xiàn)控制 LED 的顏色和亮度的。PWM 的原理是,通過芯片的數(shù)字管腳(GPIO)來獲得模擬電路信號(hào)的輸出,它會(huì)控制芯片管腳在高電平和低電平之間進(jìn)行快速切換。
硬件調(diào)配
這里有g(shù)ithub上的對(duì)這個(gè)詳細(xì)介紹:鏈接: link. 這里通過的開發(fā)板 NodeMCU 上的 GPIO 管腳來控制 LED 等的顏色。這里有好多個(gè)顏色,不用管這么多,只要關(guān)注帶淺黃色背景的“**GPIO”**的幾個(gè)管腳就夠了。 選擇 D1、D2 和 D3 這三個(gè)接口,分別連接 RGB LED 模組的紅色、綠色和藍(lán)色通道。 
這個(gè)是老師創(chuàng)建的 LED 類文件
from machine import PWM
from machine import Pin
class Led():
"""
創(chuàng)建LED類
"""
def __init__(self, rpin, gpin, bpin, freq=1000):
"""
構(gòu)造函數(shù)
:param pin: 接LED的管腳,必須支持PWM
:param freq: PWM的默認(rèn)頻率是1000
"""
self.pin_red = Pin(rpin)
self.pin_green = Pin(gpin)
self.pin_blue = Pin(bpin)
self.led_red = PWM(self.pin_red, freq = freq)
self.led_green = PWM(self.pin_green, freq = freq)
self.led_blue = PWM(self.pin_blue, freq = freq)
def rgb_light(self, red, green, blue, brightness):
if red in range(256) and green in range(256) and blue in range(256) and 0.0 <= brightness and brightness <=1.0:
self.led_red.duty(int(red/255*brightness*1023))
self.led_green.duty(int(green/255*brightness*1023))
self.led_blue.duty(int(blue/255*brightness*1023))
else:
print("red green blue must between 0 and 255, and brightness from 0.0 to 1.0")
def deinit(self):
"""
析構(gòu)函數(shù)
"""
self.led_red.deinit()
self.led_green.deinit()
self.led_blue.deinit()
使用繼電器控制電燈的開關(guān)
繼電器分為弱電(小電流、低電壓)和強(qiáng)電(大電流、高電壓)兩個(gè)部分。其中,弱電的部分可以接微處理芯片;強(qiáng)電部分可以連接交流電設(shè)備,比如電風(fēng)扇、冰箱和燈泡等。繼電器其實(shí)就像是我們現(xiàn)實(shí)生活中“中間人”的角色,它通過電磁器件、或者光耦單元將弱電和強(qiáng)電聯(lián)系起來,以完成微處理芯片對(duì)強(qiáng)電設(shè)備的控制。 這里使用的一款基于 SRD-05VDC-SL-C 型號(hào)的電磁繼電器。使用中,模塊的控制接口,需要連接 NodeMCU 開發(fā)板的 GPIO 管腳。我們通過設(shè)置這個(gè) GPIO 的輸出電平高、低狀態(tài),實(shí)現(xiàn)控制繼電器強(qiáng)電部分電路的“通”和“斷”。 弱電部分的供電,不要使用電腦的 USB 接口;為了電腦設(shè)備安全,建議使用獨(dú)立的電源為開發(fā)板供電。 這個(gè)是創(chuàng)建的 Relay 類文件,提供參考
from machine import ADC
from machine import Pin
class Relay():
def __init__(self, pin):
self.relaypin = Pin(pin, Pin.OUT)
self.last_status = 1
def set_state(self, state):
self.relaypin.value(state)
self.last_status = state
智能電燈的整體電路如何搭建? 確定了 LED 的技術(shù)方案和繼電器后,我們就可以搭建出智能電燈的電路。電路中各模塊的連線情況,在連接電路的時(shí)候按照這個(gè)連線來就行。

電路搭建完成后,你可以運(yùn)行下面的代碼測(cè)試一下:
from machine import PWM, Pin
import time
#設(shè)置對(duì)應(yīng)紅、綠、藍(lán)的三個(gè)GPIO管腳
led_red = PWM(Pin(5), freq = 1000)
led_green = PWM(Pin(4), freq = 1000)
led_blue = PWM(Pin(0), freq = 1000)
#繼電器的GPIO管腳
relaypin = Pin(16, Pin.OUT)#
#通過PWM的占空比設(shè)置顏色
def rgb_light(red, green, blue, brightness):
pwm_red = led_red.duty(int(red/255*brightness*1023))
pwm_green = led_green.duty(int(green/255*brightness*1023))
pwm_blue = led_blue.duty(int(blue/255*brightness*1023))
rgb_light(255, 255, 0, 1.0)
#周期點(diǎn)亮、熄滅
while True:
relaypin.on()
time.sleep(2)
relaypin.off()
time.sleep(2)
使用MQTT實(shí)現(xiàn)遠(yuǎn)程控制
準(zhǔn)備好了智能電燈設(shè)備后,要實(shí)現(xiàn)遠(yuǎn)程控制,我們還需要讓智能電燈連接到物聯(lián)網(wǎng)平臺(tái)這里就要用到 MQTT 通信協(xié)議了。 首先,你需要在 NodeMCU 開發(fā)板上安裝一個(gè) MQTT 客戶端代碼庫(kù) umqtt.simple 庫(kù)。它來自 MicroPython 官方維護(hù)的非內(nèi)核標(biāo)準(zhǔn)庫(kù) micropython-lib,可以使用 upip 包管理器來安裝。在串口 REPL 中運(yùn)行下面的命令,就可以完成安裝:
>>> import upip
>>> upip.install('micropython-umqtt.simple')
這里有一個(gè)前提要求,就是 NodeMCU 需要連接到 Wi-Fi 路由器上,也就是能夠訪問網(wǎng)絡(luò),因?yàn)檫@個(gè)安裝過程是從網(wǎng)絡(luò)下載安裝文件。 NodeMCU 連接到 Wi-Fi 路由器可以通過串口 REPL 來完成,可以在 REPL 中依次輸入下面的命令來接入網(wǎng)絡(luò):
>>> import network
>>> wifi = network.WLAN(network.STA_IF)
>>> wifi.active(True)
>>> wifi.scan()
>>> wifi.isconnected()
>>> wifi.connect('你家中Wi-Fi的SSID', '你家中Wi-Fi密碼')
>>> wifi.isconnected()
安裝好 umqtt.simple 庫(kù)之后,我們需要再設(shè)置一下物聯(lián)網(wǎng)平臺(tái)的 MQTT 協(xié)議交互的 Topic 和具體的連接參數(shù)。 我們用到的 MQTT Topic 主要有兩個(gè):一個(gè)用于發(fā)布消息,即消息流向是從設(shè)備到物聯(lián)網(wǎng)平臺(tái);另一個(gè)用于接收訂閱消息,即消息流向是從物聯(lián)網(wǎng)平臺(tái)到設(shè)備。
#發(fā)布消息
$thing/up/property/ProductID/DeviceName
#接收訂閱消息
$thing/down/property/ProductID/DeviceName
需要注意的是,ProductID 和 DeviceName 需要替換為我們?cè)谏厦鎰?chuàng)建設(shè)備的具體值。 設(shè)備與物聯(lián)網(wǎng)平臺(tái)建立 MQTT 連接,涉及 Broker 服務(wù)器地址、端口號(hào)、設(shè)備 ID、用戶名和密碼。我把這些參數(shù)整理到了一張表里  用戶名和密碼不太好手動(dòng)生成,我們可以借助網(wǎng)頁(yè)工具(百度下在線生成用戶名和密碼)來生成。下載完成后,你可以解壓縮,得到一些網(wǎng)頁(yè)原文件,雙擊打開 sign.html,然后在頁(yè)面輸入設(shè)備三元組,點(diǎn)擊“Generate”即可生成用戶名和密碼。  有了這些信息,我們就可以開始為智能電燈設(shè)備編寫 MQTT 代碼了:
from LED import Led
from Button import Button
from Relay import Relay
import time
import uasyncio
import network
import ujson
from umqtt.simple import MQTTClient
"""
Wi-Fi Gateway : SSID and Password
"""
WIFI_AP_SSID = "你家的Wi-Fi SSID"
WIFI_AP_PSW = "你家的Wi-Fi密碼"
"""
QCloud Device Info
"""
DEVICE_NAME = "你的設(shè)備名稱"
PRODUCT_ID = "你的產(chǎn)品ID"
DEVICE_KEY = "你的設(shè)備密鑰"
"""
MQTT topic
"""
MQTT_CONTROL_TOPIC = "$thing/down/property/"+PRODUCT_ID+"/"+DEVICE_NAME
MQTT_CONTROL_REPLY_TOPIC = "$thing/up/property/"+PRODUCT_ID+"/"+DEVICE_NAME
led = Led(5, 4, 0)
relay = Relay(16)
button = Button(14)
mqtt_client = None
color = 0 #enum 0=red, 1=green, 2=blue
name= "" #light name. it is optional
brightness = 100 # 0%~100%
light_changed = False
async def wifi_connect(ssid, pwd):
sta = network.WLAN(network.STA_IF)
sta.active(True)
sta.connect(ssid, pwd)
while not sta.isconnected():
print("Wi-Fi Connecting...")
time.sleep_ms(500)
def mqtt_callback(topic, msg):
global led, relay, button
global color, name, brightness, light_changed
print((topic, msg))
msg_json = ujson.loads(msg)
if msg_json['method'] == 'control':
params = msg_json['params']
power_switch_tmp = params.get('power_switch')
if power_switch_tmp is not None:
power_switch = power_switch_tmp
relay.set_state(power_switch)
brightness_tmp = params.get('brightness')
if brightness_tmp is not None:
brightness = brightness_tmp
color_tmp = params.get('color')
if color_tmp is not None:
color = color_tmp
name_tmp = params.get('name')
if name_tmp is not None:
name = name_tmp
if brightness_tmp is not None or color_tmp is not None:
light_changed = True
async def mqtt_connect():
global mqtt_client
MQTT_SERVER = PRODUCT_ID + ".iotcloud.tencentdevices.com"
MQTT_PORT = 1883
MQTT_CLIENT_ID = PRODUCT_ID+DEVICE_NAME
MQTT_USER_NAME = "你的用戶名"
MQTTT_PASSWORD = "你的密碼"
mqtt_client = MQTTClient(MQTT_CLIENT_ID, MQTT_SERVER, MQTT_PORT,MQTT_USER_NAME, MQTTT_PASSWORD, 60)
mqtt_client.set_callback(mqtt_callback)
mqtt_client.connect()
def mqtt_report(client, color, name, switch, brightness):
msg = {
"method": "report",
"clientToken": "clientToken-2444532211",
"params": {
"color": color,
"color_temp": 0,
"name": name,
"power_switch": switch,
"brightness": brightness
}
}
client.publish(MQTT_CONTROL_REPLY_TOPIC.encode(), ujson.dumps(msg).encode())
async def light_loop():
global led, relay, button
global color, name, brightness, light_changed
switch_status_last = 1
LED_status = 1
color = 2 #blue
brightness = 100 #here 100% == 1
led.rgb_light(0, 0, 255, brightness/100.0)
time_cnt = 0
mqtt_client.subscribe(MQTT_CONTROL_TOPIC.encode())
while True:
mqtt_client.check_msg()
switch_status = button.state()
LED_status = relay.state()
if switch_status != switch_status_last:
if switch_status == 0 and switch_status_last == 1:
LED_status = 0 if LED_status else 1
relay.set_state(LED_status)
switch_status_last = switch_status
if light_changed:
light_changed = False
led.rgb_light(255 if color==0 else 0, 255 if color==1 else 0, 255 if color==2 else 0, brightness/100.0)
if time_cnt >= 20:
mqtt_report(mqtt_client, color, name, LED_status, brightness)
time_cnt = 0
time_cnt = time_cnt+1
uasyncio.sleep_ms(50)
async def main():
global mqtt_client
# Wi-Fi connection
try:
await uasyncio.wait_for(wifi_connect(WIFI_AP_SSID, WIFI_AP_PSW), 20)
except uasyncio.TimeoutError:
print("wifi connected timeout!")
# MQTT connection
try:
await uasyncio.wait_for(mqtt_connect(), 20)
except uasyncio.TimeoutError:
print("mqtt connected timeout!")
await uasyncio.gather(light_loop())
uasyncio.run(main())
通過手機(jī)遠(yuǎn)程控制
在完成代碼后,我們通過 ampy 工具或者 pyboard.py 工具,將這些源代碼上傳到 NodeMCU 開發(fā)板中。程序開始自動(dòng)執(zhí)行,智能電燈自動(dòng)接入物聯(lián)網(wǎng)平臺(tái)。打開物聯(lián)網(wǎng)平臺(tái)的設(shè)備調(diào)試頁(yè)面,我們就可以看到設(shè)備顯示“在線”。 點(diǎn)擊“調(diào)試”,通過調(diào)試界面發(fā)送 MQTT 消息來控制智能電燈。
 點(diǎn)擊“發(fā)送”,物聯(lián)網(wǎng)平臺(tái)會(huì)向設(shè)備發(fā)送下面這樣的消息內(nèi)容:
{
"method": "control",
"clientToken": "clientToken-e9d920ea-a1f4-4a53-aada-a1d36fbbdd20",
"params": {
"power_switch": 1,
"brightness": 50,
"color": 0,
"color_temp": 0,
"name": ""
}
}
通過手機(jī)小程序控制電燈
這也很好實(shí)現(xiàn),我們只需要在小程序上添加設(shè)備,就可以使用小程序界面控制了。 打開“騰訊連連”小程序,點(diǎn)擊“+”按鈕,掃描我們?cè)凇霸O(shè)備調(diào)試”界面保存的二維碼,就完成添加動(dòng)作了。

然后,點(diǎn)擊設(shè)備卡片,進(jìn)入設(shè)備交互界面,就可以進(jìn)行遠(yuǎn)程控制了。 
這里可以用手機(jī)來遠(yuǎn)程控制智能電燈的開關(guān)狀態(tài)和顏色了。到這里,我們就可以用手機(jī)來遠(yuǎn)程控制智能電燈的開關(guān)狀態(tài)和顏色了。
|