資料介紹
描述
介紹
由于文明的發(fā)展以及工業(yè)和汽車的不潔排放量增加,大氣狀況每年都在惡化。盡管空氣是生命不可缺少的資源,但許多人對(duì)空氣污染的嚴(yán)重程度漠不關(guān)心,或者直到最近才意識(shí)到這個(gè)問(wèn)題。在水、土壤、熱、噪聲等各類污染物中,空氣污染是最危險(xiǎn)、最嚴(yán)重的,它會(huì)引起氣候變化和危及生命的疾病。根據(jù)世界衛(wèi)生組織 (WHO) 的數(shù)據(jù),現(xiàn)在 90% 的人口呼吸著被污染的空氣,空氣污染是每年 700 萬(wàn)人死亡的原因。污染對(duì)健康的影響非常嚴(yán)重,會(huì)導(dǎo)致中風(fēng)、肺癌和心臟病。此外,空氣污染物對(duì)人類和地球生態(tài)系統(tǒng)有負(fù)面影響。
根據(jù)美國(guó)環(huán)境保護(hù)署 (EPA) 的數(shù)據(jù),室內(nèi)空氣的污染程度是室外空氣的 100 倍。大多數(shù)現(xiàn)代人將 80% 到 90% 的時(shí)間花在室內(nèi);在這次 COVID-19 大流行中,發(fā)病率甚至更高,全世界所有人的情況都是一樣的。因此,室內(nèi)空氣比室外空氣對(duì)人體健康的直接影響更大。此外,與大氣污染相比,室內(nèi)污染物傳播到肺部的可能性要高出約 1000 倍,從而導(dǎo)致病態(tài)建筑綜合癥、多重化學(xué)敏感性和頭暈等疾病。
廁所是公共設(shè)施之一,是人們經(jīng)常使用的公共設(shè)施之一,位于室內(nèi)。因此,保持廁所良好的空氣質(zhì)量對(duì)于保持廁所衛(wèi)生和衛(wèi)生至關(guān)重要。這與威爾克提到的說(shuō)法一致,“為了創(chuàng)造一個(gè)更健康、更安全的環(huán)境,第一步是在洗手間。” 空氣質(zhì)量差的廁所可能是微生物、空氣傳播細(xì)菌的理想場(chǎng)所,最近還添加了 COVID-19 來(lái)傳播。
我的健康廁所項(xiàng)目和動(dòng)機(jī)
通風(fēng)不足、人流量大、公廁管理不善是公廁室內(nèi)空氣污染的主要來(lái)源。為減少接觸空氣污染,可以采取新措施,包括開(kāi)發(fā)空氣質(zhì)量測(cè)量設(shè)備、持續(xù)監(jiān)測(cè)空氣質(zhì)量數(shù)據(jù),以及根據(jù)數(shù)據(jù)采取必要措施。
物聯(lián)網(wǎng)(IoT)和云計(jì)算揭示了各個(gè)領(lǐng)域?qū)崟r(shí)監(jiān)控的新能力。由于這些技術(shù)采用無(wú)線傳感器網(wǎng)絡(luò)來(lái)自動(dòng)傳輸、處理、分析和可視化數(shù)據(jù),因此融合這些新技術(shù)也可以為改善室內(nèi)空氣質(zhì)量提供巨大優(yōu)勢(shì)。

必須衡量用戶使用廁所的滿意度,才能對(duì)廁所進(jìn)行適當(dāng)?shù)墓芾怼?/font>通常,馬桶會(huì)以固定的時(shí)間間隔進(jìn)行清潔,但有時(shí)即使還沒(méi)有清潔計(jì)劃,馬桶也需要清潔,因?yàn)檫@會(huì)給用戶帶來(lái)不適。分析空氣質(zhì)量數(shù)據(jù),可以在廁所需要清潔時(shí)檢測(cè)到這種情況。
通風(fēng)可以通過(guò)降低室內(nèi)空氣污染物和 COVID-19 等病毒的濃度來(lái)提高舒適度并改善室內(nèi)空氣質(zhì)量 (IAQ)。但通風(fēng)涉及電力消耗,需要高效智能運(yùn)行以節(jié)省能源。
該項(xiàng)目意義重大,因?yàn)樗ㄟ^(guò)通知廁所服務(wù)員或所有者何時(shí)需要清潔來(lái)幫助保持公共/私人廁所的清潔和良好的空氣質(zhì)量。它還根據(jù)空氣質(zhì)量數(shù)據(jù)智能地操作排氣扇,以保持馬桶內(nèi)的舒適環(huán)境,從而將能耗降至最低。基于云的機(jī)器學(xué)習(xí)用于分析數(shù)據(jù)并做出決策。
健康廁所項(xiàng)目特點(diǎn)
- 將重要的空氣質(zhì)量數(shù)據(jù)(溫度、濕度、氨氣、二氧化硫、一氧化碳、二氧化氮、甲烷和噪音水平)安全地發(fā)布到 AWS。
- 分析空氣質(zhì)量數(shù)據(jù)并根據(jù)參數(shù)對(duì)排氣扇進(jìn)行無(wú)線控制,以保持廁所內(nèi)舒適健康的環(huán)境,并且非常有效地消耗最少的能量。
- 使用機(jī)器學(xué)習(xí),進(jìn)一步分析數(shù)據(jù)以持續(xù)監(jiān)控排氣扇是否能夠維持健康的環(huán)境。如果污染程度如此之高,以至于排氣扇和通風(fēng)系統(tǒng)無(wú)法保持舒適和衛(wèi)生,則會(huì)將手動(dòng)清潔請(qǐng)求發(fā)送到清潔人員或當(dāng)局的電子郵件中。
- 將機(jī)器學(xué)習(xí)應(yīng)用于噪音水平和其他參數(shù),檢測(cè)到漏水并向業(yè)主發(fā)送通知。
- 根據(jù)內(nèi)部空氣的狀況,系統(tǒng)會(huì)產(chǎn)生顏色信號(hào),以便用戶知道馬桶是否可以安全使用。綠燈意味著廁所環(huán)境使用起來(lái)安全舒適。黃燈表示空氣不夠好,用戶應(yīng)等到排氣扇將其恢復(fù)到更好的狀態(tài)。紅燈表示廁所在有人清理之前無(wú)法使用。
健康馬桶如何運(yùn)作?
該項(xiàng)目的完整框圖如下所示。所有的傳感器都是

通過(guò)端口 A 和端口 B 連接到 Core2 EduKit。Core2 EduKit 讀取傳感器并使用 MQTT 將所有傳感器的值發(fā)送到 AWS IoT Core。IoT 規(guī)則將數(shù)據(jù)轉(zhuǎn)發(fā)到 IoT Analytics。IoT Analytics 預(yù)處理數(shù)據(jù),將數(shù)據(jù)存儲(chǔ)到 AWS S3,并根據(jù)數(shù)據(jù)準(zhǔn)備數(shù)據(jù)集。AWS SageMaker 使用該數(shù)據(jù)集并構(gòu)建機(jī)器學(xué)習(xí)模型,以根據(jù) Core2 發(fā)布的未來(lái)數(shù)據(jù)確定廁所狀態(tài)(是否干凈或需要清潔)。一個(gè)單獨(dú)的規(guī)則調(diào)用 Lambda 函數(shù)來(lái)使用 ML 模型讀取新空氣質(zhì)量數(shù)據(jù)的預(yù)測(cè)。然后,該規(guī)則會(huì)根據(jù)預(yù)測(cè)結(jié)果更新設(shè)備影子,并且設(shè)備會(huì)收到有關(guān)當(dāng)前狀態(tài)的通知。
如果需要清潔馬桶或有任何漏水,則使用另一個(gè) IoT 規(guī)則使用 AWS SNS 向用戶發(fā)送電子郵件/短信通知。Lambda 函數(shù)用于從原始 JSON 數(shù)據(jù)格式化電子郵件。
按照相同的程序,從噪音數(shù)據(jù)中檢測(cè)到漏水,并通過(guò)電子郵件/短信通知業(yè)主。
專用的 IoT 規(guī)則用于根據(jù)空氣質(zhì)量數(shù)據(jù)確定排氣扇狀態(tài),IoT Core 將數(shù)據(jù)發(fā)送到排氣扇的單獨(dú)主題集。我們對(duì)項(xiàng)目現(xiàn)在如何運(yùn)作有了一個(gè)基本的了解,
讓我們成功吧
連接硬件
主要硬件是 Core2 EduKit 和傳感器。我使用 DHT11 傳感器收集溫度和濕度,使用 MICS6814 傳感器檢測(cè)一氧化碳、二氧化氮、氨和甲烷。該傳感器通過(guò)三個(gè)獨(dú)立的模擬通道提供數(shù)據(jù)。為了測(cè)量二氧化硫,我使用了 2SH12 傳感器,它還提供模擬數(shù)據(jù)。因此,為了將這兩個(gè)傳感器連接到 Core2 套件,我使用了 4 通道 16 位 I2C ADC (ADS1115) 模塊。我將此模塊連接到 Core2 Kit 的端口 A。此端口支持 I2C

通信并且與 Grove 兼容。因此,我使用 Grove 電纜將傳感器模塊連接到 Core2。

DHT11 傳感器提供數(shù)字?jǐn)?shù)據(jù)。因此,我通過(guò) Grove 電纜將此傳感器連接到端口 B 的 GPIO 26 引腳。如果您使用 Grove DHT11 模塊,您需要將信號(hào)線與 NC 線交替使用,以使其連接到 GPIO 26。

要將 MISC6814 和 2SH12 與 ADS1115 連接,我使用了一塊穿孔板并將三個(gè)公對(duì)母排針焊接到穿孔板上。連接

將此 PCB 傳感器板連接到 Core2 EduKit 我將 Grove 電纜焊接到 PCB 上,以維持 Grove I2C 端口的 I2C 接線順序。最后,我把 DHT11

傳感器連接到端口 B,I2C 傳感器連接到 Core2 套件的端口 A,如下圖所示。如果您注意到 PCB,您會(huì)發(fā)現(xiàn) PCB 上焊接了三個(gè)電阻器。

MICS6814 傳感器需要這些電阻器,您可以在代碼部分所附的MICS6814.odt文件中找到傳感器的詳細(xì)信息和電阻器所需的值計(jì)算。有關(guān)詳細(xì)連接,請(qǐng)參見(jiàn)下面的示意圖。

通風(fēng)/排氣扇的連接
為了無(wú)線控制排氣扇,我使用了 Node MCU 和繼電器板。節(jié)點(diǎn) MCU 將通過(guò) MQTT 主題從 AWS IoT Core 接收風(fēng)扇狀態(tài),并根據(jù)狀態(tài)打開(kāi)或關(guān)閉繼電器。Realy 用于通過(guò)來(lái)自 Node MCU 的低壓信號(hào)來(lái)控制大功率排氣扇。下面的 Fritzing 草圖顯示了連接。

我為什么選擇那些特定的傳感器?
我選擇了一些重要的傳感器來(lái)測(cè)量廁所內(nèi)的空氣質(zhì)量。對(duì)馬桶來(lái)說(shuō)重要的參數(shù)是氨、二氧化硫、二氧化碳、甲烷、溫度、濕度等。
二氧化硫 (SO2):二氧化硫是一種無(wú)色、具有強(qiáng)烈氣味的活性空氣污染物。這種氣體可能對(duì)人類健康、動(dòng)物健康和植物生命構(gòu)成威脅。二氧化硫會(huì)刺激眼睛、鼻子、喉嚨和肺部的皮膚和粘膜。高濃度的 SO2 會(huì)引起呼吸系統(tǒng)的炎癥和刺激,尤其是在劇烈的體力活動(dòng)期間。由此產(chǎn)生的癥狀可能包括深呼吸時(shí)的疼痛、咳嗽、喉嚨發(fā)炎和呼吸困難。高濃度的 SO2 會(huì)影響肺功能,加重哮喘發(fā)作,并加重敏感人群現(xiàn)有的心臟病。這種氣體還可以與空氣中的其他化學(xué)物質(zhì)發(fā)生反應(yīng),變成可以進(jìn)入肺部并造成類似健康影響的小顆粒。超過(guò)1.0 ppm被認(rèn)為是不健康的。
氨 (NH3):氨是一種無(wú)色氣體,具有強(qiáng)烈、刺鼻的刺激性氣味。它通常用于水溶液、肥料、制冷劑、紡織品等。氨會(huì)在吸入時(shí)影響您。接觸會(huì)嚴(yán)重刺激和灼傷皮膚和眼睛,并可能對(duì)眼睛造成傷害。吸入氨水會(huì)刺激鼻子、喉嚨和肺部。反復(fù)接觸可能會(huì)導(dǎo)致哮喘樣過(guò)敏并導(dǎo)致肺損傷。超過(guò)25 ppm會(huì)產(chǎn)生上述癥狀。
一氧化碳(CO):一氧化碳 (CO) 是一種無(wú)色無(wú)味的氣體。它存在于加熱器、壁爐、汽車消音器、空間加熱器、木炭烤架、汽車發(fā)動(dòng)機(jī)等產(chǎn)生的燃燒(廢氣)煙霧中。每個(gè)人全天都接觸到少量的一氧化碳。然而,吸入過(guò)多會(huì)導(dǎo)致一氧化碳中毒。當(dāng)燃燒煙霧被困在通風(fēng)不良或封閉的空間(如車庫(kù))時(shí),一氧化碳可能會(huì)增加到危險(xiǎn)水平。吸入這些煙霧會(huì)導(dǎo)致一氧化碳在您的血液中積聚,從而導(dǎo)致嚴(yán)重的組織損傷。一氧化碳中毒非常嚴(yán)重,可能危及生命。如果您吸入大量一氧化碳,您的身體將開(kāi)始用一氧化碳替換血液中的氧氣。當(dāng)這種情況發(fā)生時(shí),您可能會(huì)失去知覺(jué)。在這些情況下可能會(huì)發(fā)生死亡。一旦 CO 水平增加到百萬(wàn)分之 70 (ppm)及以上,癥狀變得更加明顯。這些癥狀可能包括惡心、頭暈和無(wú)意識(shí)。
CO2(二氧化碳)是呼吸的副產(chǎn)品,其生物效應(yīng)與 CO(一氧化碳)非常不同,CO(一氧化碳)是碳?xì)浠衔锶紵母碑a(chǎn)品,例如燃?xì)庠詈腿細(xì)饣蛉加湾仩t。一氧化碳(但不是二氧化碳)會(huì)在通風(fēng)不良的家中迅速積聚,而且是致命的。這就是為什么建議對(duì)室內(nèi)條件進(jìn)行 CO(一氧化碳)監(jiān)測(cè)的原因。
二氧化氮 (NO2):NO2 是最常見(jiàn)和研究最充分的污染物之一。接觸二氧化氮——即使是短期接觸的小幅增加——也會(huì)加劇呼吸系統(tǒng)問(wèn)題,尤其是哮喘,尤其是兒童。長(zhǎng)期接觸二氧化氮會(huì)導(dǎo)致“心血管影響、糖尿病、較差的出生結(jié)果、過(guò)早死亡和癌癥”。研究已將持續(xù)的二氧化氮暴露與認(rèn)知能力下降聯(lián)系起來(lái),尤其是在兒童中。
為 Core2 AWS EduKit 開(kāi)發(fā)代碼
完成硬件連接后,下一步是為 Core2 AWS EduKit 開(kāi)發(fā)固件。為此,請(qǐng)按順序執(zhí)行所有步驟。
第 1 步:完成Cloud Connected Blinky示例
在進(jìn)一步繼續(xù)之前,您必須從官方鏈接完成Cloud Connected Blinky示例。該教程解釋得很好,如果您有嵌入式系統(tǒng)和 AWS 云的基本知識(shí),您應(yīng)該不會(huì)遇到任何困難。此處使用的所有步驟和技能將為在本教程中取得成功奠定基礎(chǔ)。具體來(lái)說(shuō),您將:
- 在您的主機(jī)上安裝和配置AWS CLI以遠(yuǎn)程管理您的 AWS 服務(wù)并使用提供的幫助程序腳本。
- 使用板載安全元件上預(yù)先配置的安全證書(shū)在 AWS IoT Core 中注冊(cè)“事物” 。
- 配置您的參考硬件以連接到 Wi-Fi,連接到您賬戶的AWS IoT 終端節(jié)點(diǎn),并將 MQTT 消息發(fā)送到 AWS IoT Core。
- 在指定的參考硬件上接收來(lái)自云端的 MQTT 消息以觸發(fā) LED 閃爍。
第 2 步:完成智能恒溫器示例
下一步是打開(kāi)、編譯和測(cè)試官方智能恒溫器固件。我們將使用此代碼作為我們代碼的模板。因此,在開(kāi)始修改代碼之前,我們希望通過(guò)運(yùn)行 Core2 套件中的固件來(lái)確保一切正常。在進(jìn)行下一步之前,這也是一個(gè)解釋得很好且易于理解的教程。
在該教程結(jié)束時(shí),您將了解:
- 如何從 Core2 for AWS IoT EduKit 設(shè)備獲取溫度和聲級(jí)。
- MQTT 的工作原理以及如何使用 MQTT 將溫度和聲音測(cè)量值從設(shè)備發(fā)布到 AWS IoT Core。
- 什么是設(shè)備影子以及如何將測(cè)量值報(bào)告給設(shè)備影子?
- 如何使用 AWS IoT Core 規(guī)則引擎執(zhí)行消息轉(zhuǎn)換。
- 如何構(gòu)建響應(yīng)輸入和檢測(cè)復(fù)雜事件的無(wú)服務(wù)器應(yīng)用程序。
- 如何通過(guò)設(shè)備影子向您的設(shè)備發(fā)送命令。
第 3 步:為 Core2 AWS IoT EduKit 開(kāi)發(fā)固件
正如我已經(jīng)說(shuō)過(guò)的,我們將使用智能恒溫器固件作為開(kāi)發(fā)我們自己的固件的模板。因此,我假設(shè)您已經(jīng)成功編譯和測(cè)試了該固件。您可以像示例程序一樣直接從 GitHub 下載和使用我修改后的固件(鏈接附在代碼部分),也可以按照以下步驟自行自定義智能恒溫器示例。
由于我們將使用一些外部傳感器,我們需要編寫(xiě)代碼來(lái)連接這些傳感器。我為 Core2 IoT EduKit 開(kāi)發(fā)了(實(shí)際上是修改了現(xiàn)有的 Arduino 庫(kù))兩個(gè)庫(kù)。一個(gè)用于 DHT11 溫度和濕度傳感器,另一個(gè)用于 ADS1115 I2C 模數(shù)轉(zhuǎn)換器模塊。按照接下來(lái)的步驟了解該過(guò)程。
步驟 3.1:創(chuàng)建庫(kù)
為了創(chuàng)建一個(gè)庫(kù),我們需要?jiǎng)?chuàng)建兩個(gè)文件。一個(gè)是C頭文件,我們需要將它添加到主目錄的include子目錄中。另一個(gè)是C源文件需要添加到主目錄的根目錄。所以,讓我們先創(chuàng)建一個(gè)頭文件(.h)文件。
步驟 3.1.1:轉(zhuǎn)到資源管理器->主->包含并單擊鼠標(biāo)右鍵并選擇新建文件

輸入帶有 ah 擴(kuò)展名的名稱,然后從鍵盤(pán)按 Enter。例如dht11.h
.

步驟 3.1.2:單擊文件將其打開(kāi)并在那里寫(xiě)入或粘貼您的代碼。

例如,我為我的dht11.h
頭文件添加了以下代碼。
#pragma once
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
/**
* Sensor type
*/
typedef enum
{
DHT_TYPE_DHT11 = 0, //!< DHT11
DHT_TYPE_AM2301, //!< AM2301 (DHT21, DHT22, AM2302, AM2321)
DHT_TYPE_SI7021 //!< Itead Si7021
} dht_sensor_type_t;
esp_err_t dht_read_data(dht_sensor_type_t sensor_type, gpio_num_t pin,
int16_t *humidity, int16_t *temperature);
esp_err_t dht_read_float_data(dht_sensor_type_t sensor_type, gpio_num_t pin,
float *humidity, float *temperature);
#ifdef __cplusplus
}
#endif
步驟 3.1.3:按Ctrl+S保存文件。我們的頭文件創(chuàng)建完成。現(xiàn)在我們將為庫(kù)創(chuàng)建 C 源文件。
步驟 3.1.4:轉(zhuǎn)到explorer -> main并單擊鼠標(biāo)右鍵并選擇New File

輸入一個(gè)帶有 ac 擴(kuò)展名的名稱,然后從鍵盤(pán)上按回車鍵。例如dht11.c
.

步驟 3.1.5:單擊文件將其打開(kāi),然后在編輯器中編寫(xiě)或粘貼代碼。

例如,我為我的dht11.c
文件使用了以下代碼行
#include
#include
#include
#include
#include
#include "dht.h"
// DHT timer precision in microseconds
#define DHT_TIMER_INTERVAL 2
#define DHT_DATA_BITS 40
#define DHT_DATA_BYTES (DHT_DATA_BITS / 8)
/*
* Note:
* A suitable pull-up resistor should be connected to the selected GPIO line
*
* __ ______ _______ ___________________________
* \ A / \ C / \ DHT duration_data_low / \
* \_______/ B \______/ D \__________________________/ DHT duration_data_high \__
*
*
* Initializing communications with the DHT requires four 'phases' as follows:
*
* Phase A - MCU pulls signal low for at least 18000 us
* Phase B - MCU allows signal to float back up and waits 20-40us for DHT to pull it low
* Phase C - DHT pulls signal low for ~80us
* Phase D - DHT lets signal float back up for ~80us
*
* After this, the DHT transmits its first bit by holding the signal low for 50us
* and then letting it float back high for a period of time that depends on the data bit.
* duration_data_high is shorter than 50us for a logic '0' and longer than 50us for logic '1'.
*
* There are a total of 40 data bits transmitted sequentially. These bits are read into a byte array
* of length 5. The first and third bytes are humidity (%) and temperature (C), respectively. Bytes 2 and 4
* are zero-filled and the fifth is a checksum such that:
*
* byte_5 == (byte_1 + byte_2 + byte_3 + byte_4) & 0xFF
*
*/
static const char *TAG = "DHT";
static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
#define PORT_ENTER_CRITICAL() portENTER_CRITICAL(&mux)
#define PORT_EXIT_CRITICAL() portEXIT_CRITICAL(&mux)
#define CHECK_ARG(VAL) do { if (!(VAL)) return ESP_ERR_INVALID_ARG; } while (0)
#define CHECK_LOGE(x, msg, ...) do { \
esp_err_t __; \
if ((__ = x) != ESP_OK) { \
PORT_EXIT_CRITICAL(); \
ESP_LOGE(TAG, msg, ## __VA_ARGS__); \
return __; \
} \
} while (0)
/**
* Wait specified time for pin to go to a specified state.
* If timeout is reached and pin doesn't go to a requested state
* false is returned.
* The elapsed time is returned in pointer 'duration' if it is not NULL.
*/
static esp_err_t dht_await_pin_state(gpio_num_t pin, uint32_t timeout,
int expected_pin_state, uint32_t *duration)
{
/* XXX dht_await_pin_state() should save pin direction and restore
* the direction before return. however, the SDK does not provide
* gpio_get_direction().
*/
gpio_set_direction(pin, GPIO_MODE_INPUT);
// Enabling pull-up is required if the sensor has no physical pull-up resistor
gpio_set_pull_mode(pin, GPIO_PULLUP_ONLY);
for (uint32_t i = 0; i < timeout; i += DHT_TIMER_INTERVAL)
{
// need to wait at least a single interval to prevent reading a jitter
ets_delay_us(DHT_TIMER_INTERVAL);
if (gpio_get_level(pin) == expected_pin_state)
{
if (duration)
*duration = i;
return ESP_OK;
}
}
return ESP_ERR_TIMEOUT;
}
/**
* Request data from DHT and read raw bit stream.
* The function call should be protected from task switching.
* Return false if error occurred.
*/
static inline esp_err_t dht_fetch_data(dht_sensor_type_t sensor_type, gpio_num_t pin, uint8_t data[DHT_DATA_BYTES])
{
uint32_t low_duration;
uint32_t high_duration;
// Phase 'A' pulling signal low to initiate read sequence
gpio_set_direction(pin, GPIO_MODE_OUTPUT_OD);
gpio_set_level(pin, 0);
ets_delay_us(sensor_type == DHT_TYPE_SI7021 ? 500 : 20000);
gpio_set_level(pin, 1);
// Step through Phase 'B', 40us
CHECK_LOGE(dht_await_pin_state(pin, 40, 0, NULL),
"Initialization error, problem in phase 'B'");
// Step through Phase 'C', 88us
CHECK_LOGE(dht_await_pin_state(pin, 88, 1, NULL),
"Initialization error, problem in phase 'C'");
// Step through Phase 'D', 88us
CHECK_LOGE(dht_await_pin_state(pin, 88, 0, NULL),
"Initialization error, problem in phase 'D'");
// Read in each of the 40 bits of data...
for (int i = 0; i < DHT_DATA_BITS; i++)
{
CHECK_LOGE(dht_await_pin_state(pin, 65, 1, &low_duration),
"LOW bit timeout");
CHECK_LOGE(dht_await_pin_state(pin, 75, 0, &high_duration),
"HIGH bit timeout");
uint8_t b = i / 8;
uint8_t m = i % 8;
if (!m)
data[b] = 0;
data[b] |= (high_duration > low_duration) << (7 - m);
}
return ESP_OK;
}
/**
* Pack two data bytes into single value and take into account sign bit.
*/
static inline int16_t dht_convert_data(dht_sensor_type_t sensor_type, uint8_t msb, uint8_t lsb)
{
int16_t data;
if (sensor_type == DHT_TYPE_DHT11)
{
data = msb * 10;
}
else
{
data = msb & 0x7F;
data <<= 8;
data |= lsb;
if (msb & BIT(7))
data = -data; // convert it to negative
}
return data;
}
esp_err_t dht_read_data(dht_sensor_type_t sensor_type, gpio_num_t pin,
int16_t *humidity, int16_t *temperature)
{
CHECK_ARG(humidity || temperature);
uint8_t data[DHT_DATA_BYTES] = { 0 };
gpio_set_direction(pin, GPIO_MODE_OUTPUT_OD);
gpio_set_level(pin, 1);
PORT_ENTER_CRITICAL();
esp_err_t result = dht_fetch_data(sensor_type, pin, data);
if (result == ESP_OK)
PORT_EXIT_CRITICAL();
/* restore GPIO direction because, after calling dht_fetch_data(), the
* GPIO direction mode changes */
gpio_set_direction(pin, GPIO_MODE_OUTPUT_OD);
gpio_set_level(pin, 1);
if (result != ESP_OK)
return result;
if (data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF))
{
ESP_LOGE(TAG, "Checksum failed, invalid data received from sensor");
return ESP_ERR_INVALID_CRC;
}
if (humidity)
*humidity = dht_convert_data(sensor_type, data[0], data[1]);
if (temperature)
*temperature = dht_convert_data(sensor_type, data[2], data[3]);
ESP_LOGD(TAG, "Sensor data: humidity=%d, temp=%d", *humidity, *temperature);
return ESP_OK;
}
esp_err_t dht_read_float_data(dht_sensor_type_t sensor_type, gpio_num_t pin,
float *humidity, float *temperature)
{
CHECK_ARG(humidity || temperature);
int16_t i_humidity, i_temp;
esp_err_t res = dht_read_data(sensor_type, pin, humidity ? &i_humidity : NULL, temperature ? &i_temp : NULL);
if (res != ESP_OK)
return res;
if (humidity)
*humidity = i_humidity / 10.0;
if (temperature)
*temperature = i_temp / 10.0;
return ESP_OK;
}
步驟 3.1.6:按Ctrl+S保存文件。我們的庫(kù)創(chuàng)建完成。
步驟 3.1.7:將新創(chuàng)建的源文件添加到CMakeList
. 單擊CMakeLists.txt將其打開(kāi)并添加您的庫(kù)源文件的名稱,如下面的屏幕截圖所示。

現(xiàn)在,您可以使用您的庫(kù)了。按照相同的過(guò)程根據(jù)需要?jiǎng)?chuàng)建更多庫(kù)。例如我們案例中的 ADS1115 庫(kù)。該庫(kù)的所有源文件都添加到代碼部分以及 GitHub 存儲(chǔ)庫(kù)中。
步驟 3.2:測(cè)試庫(kù)
讓我們測(cè)試我們創(chuàng)建的 dht11 庫(kù)以了解它是否正常工作。它還將證明我們的 DHT11 傳感器的工作原理。
步驟 3.2.1:打開(kāi)main.c文件,使用Ctrl+A選擇整個(gè)代碼,然后使用Ctrl+X剪切代碼,使用Ctrl+V將代碼粘貼到記事本文本文件中并保存。我們將再次使用它。
步驟 3.2.2:將以下代碼片段粘貼到main.c文件中。此代碼將使用新創(chuàng)建的 dht11 庫(kù)從 dht11 傳感器讀取溫度和濕度,并在終端中打印結(jié)果。
#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_err.h"
#include "core2forAWS.h"
#include "dht.h"
static const dht_sensor_type_t sensor_type = DHT_TYPE_DHT11;
static const gpio_num_t dht_gpio = GPIO_NUM_26;
void temperature_task(void *arg) {
int16_t temperature = 0;
int16_t humidity = 0;
while (1)
{
if (dht_read_data(sensor_type, dht_gpio, &humidity, &temperature) == ESP_OK)
printf("Humidity: %d%% Temp: %dC\n", humidity / 10, temperature / 10);
else
printf("Could not read data from sensor\n");
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
void app_main()
{
Core2ForAWS_Init();
xTaskCreatePinnedToCore(&temperature_task, "temperature_task", 4096, NULL, 5, NUL, 1);
}
步驟 3.2.3:打開(kāi)一個(gè)新終端并鍵入pio run --environment core2foraws
以構(gòu)建程序。

如果一切正常,您將收到成功消息。

步驟 3.2.4:使用以下命令將固件上傳到 Core2 AWS IoT EduKit
pio run --environment core2foraws --target upload
步驟 3.2.5:將 DHT11 傳感器連接到 Core2 Kit 的端口 B 并使用以下命令監(jiān)控結(jié)果
pio run --environment core2foraws --target monitor
如果您從終端得到以下結(jié)果,那么恭喜!您的磁帶庫(kù)和 DHT11 傳感器都運(yùn)行良好。

步驟 3.3:修改 main.c 文件
將新的main.c源代碼替換為我們存儲(chǔ)在記事本文件中的原始main.c源代碼。由于我們要發(fā)布比演示項(xiàng)目更多的數(shù)據(jù),我們需要增加 JSON 緩沖區(qū)大小,如下所示:
#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 300
添加了以下變量用于存儲(chǔ)空氣質(zhì)量參數(shù)。
float temperature = STARTING_ROOMTEMPERATURE;
float humidity = STARTING_ROOMHUMIDITY;
float nitrogen_dioxide = STARTING_ROOMNO2;
float ammonia = STARTING_ROOMNH3;
float carbon_monoxide = STARTING_ROOMCO;
float sulfur_dioxide = STARTING_ROOMSO2;
float methane = STARTING_ROOMCH4;
uint8_t soundBuffer = STARTING_SOUNDLEVEL;
uint8_t reportedSound = STARTING_SOUNDLEVEL;
bool fan_status = STARTING_FANSTATUS;
char toilet_status[14] = STARTING_TOILETSTATUS;
我們需要更多類型的處理程序變量jsonStruct_t
來(lái)打包我們所有的傳感器值。因此,已創(chuàng)建以下處理程序變量。
jsonStruct_t temperatureHandler;
temperatureHandler.cb = NULL;
temperatureHandler.pKey = "temperature";
temperatureHandler.pData = &temperature;
temperatureHandler.type = SHADOW_JSON_FLOAT;
temperatureHandler.dataLength = sizeof(float);
jsonStruct_t humidityHandler;
humidityHandler.cb = NULL;
humidityHandler.pKey = "humidity";
humidityHandler.pData = &humidity;
humidityHandler.type = SHADOW_JSON_FLOAT;
humidityHandler.dataLength = sizeof(float);
jsonStruct_t carbonMonoxideHandler;
carbonMonoxideHandler.cb = NULL;
carbonMonoxideHandler.pKey = "carbon_monoxide";
carbonMonoxideHandler.pData = &carbon_monoxide;
carbonMonoxideHandler.type = SHADOW_JSON_FLOAT;
carbonMonoxideHandler.dataLength = sizeof(float);
jsonStruct_t ammoniaHandler;
ammoniaHandler.cb = NULL;
ammoniaHandler.pKey = "ammonia";
ammoniaHandler.pData = &ammonia;
ammoniaHandler.type = SHADOW_JSON_FLOAT;
ammoniaHandler.dataLength = sizeof(float);
jsonStruct_t nitrogenDioxideHandler;
nitrogenDioxideHandler.cb = NULL;
nitrogenDioxideHandler.pKey = "nitrogen_dioxide";
nitrogenDioxideHandler.pData = &nitrogen_dioxide;
nitrogenDioxideHandler.type = SHADOW_JSON_FLOAT;
nitrogenDioxideHandler.dataLength = sizeof(float);
jsonStruct_t sulfurDioxideHandler;
sulfurDioxideHandler.cb = NULL;
sulfurDioxideHandler.pKey = "sulfur_dioxide";
sulfurDioxideHandler.pData = &sulfur_dioxide;
sulfurDioxideHandler.type = SHADOW_JSON_FLOAT;
sulfurDioxideHandler.dataLength = sizeof(float);
jsonStruct_t methaneHandler;
methaneHandler.cb = NULL;
methaneHandler.pKey = "methane";
methaneHandler.pData = &methane;
methaneHandler.type = SHADOW_JSON_FLOAT;
methaneHandler.dataLength = sizeof(float);
jsonStruct_t soundHandler;
soundHandler.cb = NULL;
soundHandler.pKey = "sound";
soundHandler.pData = &reportedSound;
soundHandler.type = SHADOW_JSON_UINT8;
soundHandler.dataLength = sizeof(uint8_t);
jsonStruct_t exhaustFanActuator;
exhaustFanActuator.cb = exhaustFan_Callback;
exhaustFanActuator.pKey = "fan_status";
exhaustFanActuator.pData = &fan_status;
exhaustFanActuator.type = SHADOW_JSON_BOOL;
exhaustFanActuator.dataLength = sizeof(bool);
jsonStruct_t toiletStatusActuator;
toiletStatusActuator.cb = toilet_status_Callback;
toiletStatusActuator.pKey = "toilet_status";
toiletStatusActuator.pData = &toilet_status;
toiletStatusActuator.type = SHADOW_JSON_STRING;
toiletStatusActuator.dataLength = strlen(toilet_status)+1;
以下第一個(gè)函數(shù)將我們想要發(fā)布到云的任何值打包到 IoT Core 影子服務(wù)所期望的影子文檔中。第二個(gè)函數(shù)實(shí)際上將封送的影子文檔作為有效負(fù)載通過(guò)網(wǎng)絡(luò)發(fā)布到 IoT Core 的主題上$aws/things/<
,其中<
每個(gè)設(shè)備的唯一 ID。這兩個(gè)函數(shù)修改如下。
if(SUCCESS == rc) {
rc = aws_iot_shadow_add_reported(JsonDocumentBuffer,
sizeOfJsonDocumentBuffer, 10, &temperatureHandler,
&humidityHandler, &carbonMonoxideHandler,
&ammoniaHandler, &nitrogenDioxideHandler, &sulfurDioxideHandler,
&methaneHandler, &soundHandler, &toiletStatusActuator, &exhaustFanActuator);
if(SUCCESS == rc) {
rc = aws_iot_finalize_json_document(JsonDocumentBuffer,
sizeOfJsonDocumentBuffer);
if(SUCCESS == rc) {
ESP_LOGI(TAG, "Update Shadow: %s", JsonDocumentBuffer);
rc = aws_iot_shadow_update(&iotCoreClient, client_id, JsonDocumentBuffer,
ShadowUpdateStatusCallback, NULL, 10, true);
shadowUpdateInProgress = true;
}
}
}
以下代碼表示我們的馬桶狀態(tài)執(zhí)行器的回調(diào)函數(shù)。這是當(dāng)設(shè)備接收到包含鍵值對(duì)的新消息時(shí)執(zhí)行的代碼。state.desired.toilet_status
廁所狀態(tài)是根據(jù)空氣質(zhì)量數(shù)據(jù)從 ML 模型中確定的。根據(jù) IoT Core 返回的狀態(tài),顏色會(huì)發(fā)生變化。
void toilet_status_Callback(const char *pJsonString, uint32_t JsonStringDataLen,
jsonStruct_t *pContext) {
IOT_UNUSED(pJsonString);
IOT_UNUSED(JsonStringDataLen);
char * status = (char *) (pContext->pData);
if(pContext != NULL) {
ESP_LOGI(TAG, "Delta - toiletStatus state changed to %s", status);
}
if(strcmp(status, BUSY) == 0) {
ESP_LOGI(TAG, "setting side LEDs to Yellow");
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_LEFT, 0xFFFF00);
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_RIGHT, 0xFFFF00);
Core2ForAWS_Sk6812_Show();
} else if(strcmp(status, UNCLEAN) == 0) {
ESP_LOGI(TAG, "setting side LEDs to Red");
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_LEFT, 0xFF0000);
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_RIGHT, 0xFF0000);
Core2ForAWS_Sk6812_Show();
} else if(strcmp(status, READY) == 0) {
ESP_LOGI(TAG, "clearing side Green");
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_LEFT, 0x00FF00);
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_RIGHT, 0x00FF00);
//Core2ForAWS_Sk6812_Clear();
Core2ForAWS_Sk6812_Show();
}
}
使用以下兩個(gè)函數(shù)來(lái)讀取溫度和空氣質(zhì)量。
void read_temperature(){
int16_t temperature_data = 0;
int16_t humidity_data = 0;
if (dht_read_data(sensor_type, dht_gpio, &humidity_data,
&temperature_data) == ESP_OK){
temperature = (float) temperature_data/10;
humidity = (float) humidity_data/10;
}
}
void read_airquality(){
int16_t adc0, adc1, adc2;
//float nitrogen_dioxide, ammonia, carbon_monoxide;
adc0 = ADS1115_readADC_SingleEnded(CO_CHNNEL);
carbon_monoxide = ADS1115_computeVolts(adc0);
adc1 = ADS1115_readADC_SingleEnded(NH3_CHNNEL);
ammonia = ADS1115_computeVolts(adc1);
adc2 = ADS1115_readADC_SingleEnded(NO2_CHNNEL);
nitrogen_dioxide = ADS1115_computeVolts(adc2);
}
以下函數(shù)將空氣質(zhì)量數(shù)據(jù)的 ppm 值接收到全局變量中。
void read_airquality_ppm(){
carbon_monoxide = measure_in_ppm(CO);
nitrogen_dioxide = measure_in_ppm(NO2);
ammonia = measure_in_ppm(NH3);
methane = measure_in_ppm(CH4);
}
app_main() 函數(shù)更新如下
void app_main()
{
Core2ForAWS_Init();
Core2ForAWS_Display_SetBrightness(80);
Core2ForAWS_LED_Enable(1);
ADS1115_I2CInit();
ADS1115_setGain(GAIN_TWOTHIRDS);
airquality_calibrate ();
xMaxNoiseSemaphore = xSemaphoreCreateMutex();
ui_init();
initialise_wifi();
xTaskCreatePinnedToCore(&aws_iot_task, "aws_iot_task", 4096*2, NULL, 5, NULL, 1);
}
完整的main.c程序附在代碼部分和 GitHub ripo 中。
步驟 3.4:測(cè)試固件
完成所有修改后,構(gòu)建程序并將其上傳到 Core2。將 I2C 傳感器連接到端口 A,將 DHT11 傳感器連接到端口 B,然后運(yùn)行調(diào)試終端來(lái)監(jiān)控輸出。

如果一切順利,您將從終端獲得以下輸出。

打開(kāi) AWS IoT Core 控制臺(tái)測(cè)試頁(yè)面,訂閱主題$aws/things/<
,您應(yīng)該會(huì)看到新消息與您的vTaskDelay()一起及時(shí)到達(dá)。(用屏幕上打印的設(shè)備客戶端 ID/序列號(hào)替換 ?CLIENT_ID?。)輸出如下圖所示。

在 AWS IoT Core 控制臺(tái)測(cè)試頁(yè)面中,單擊 Publish to a topic 選項(xiàng)卡并在該主題上發(fā)布以下新影子消息$aws/things/<
。您應(yīng)該會(huì)看到 Core for AWS IoT EduKit 的 LED 條從綠色變?yōu)榧t色。請(qǐng)參閱下面的示例影子消息。每次發(fā)布消息時(shí),通過(guò)更改廁所狀態(tài)(設(shè)置為BUSY或READY )和/或fan_status值(設(shè)置為true或false )來(lái)測(cè)試效果。
{ "state": { "desired": { "toilet_status": "UNCLEAN", "fan_status": true } } }

效果也會(huì)出現(xiàn)在終端中,如下所示。

從設(shè)備方面來(lái)看,一切都很好。現(xiàn)在我們將配置 AWS IoT Cloud 以轉(zhuǎn)換和路由從設(shè)備接收的數(shù)據(jù)。
開(kāi)發(fā)機(jī)器學(xué)習(xí)模型以自動(dòng)檢測(cè)廁所狀態(tài)(UNCLEAN、BUSY、READY)
我們正在為我們的項(xiàng)目考慮廁所的三種狀態(tài)。一種是就緒狀態(tài),表示空氣質(zhì)量數(shù)據(jù)良好,馬桶使用安全舒適。在這種情況下,LED 條顯示綠燈。另一種狀態(tài)是BUSY狀態(tài)。當(dāng)某些空氣質(zhì)量參數(shù)不夠好時(shí),用戶可能會(huì)感到不舒服。可能的原因可能是存在較高的濕度、氣味或難聞的氣味。在這種情況下,運(yùn)行排氣扇幾分鐘可以使情況變得更好。因此,這是不建議使用馬桶時(shí)的狀態(tài),系統(tǒng)會(huì)通過(guò)花一些時(shí)間和運(yùn)行風(fēng)扇來(lái)嘗試使其變得更好。在此狀態(tài)下啟用黃燈。另一種狀態(tài)是 UNCLEAN 狀態(tài),此時(shí)某些空氣參數(shù)不在可容忍的范圍內(nèi),在這種情況下使用馬桶會(huì)產(chǎn)生健康問(wèn)題。即使只有通風(fēng)也不足以使其變得更好,但需要清潔工手動(dòng)清潔。設(shè)備在此狀態(tài)下顯示紅燈,并通過(guò)電子郵件向相關(guān)人員發(fā)送清潔請(qǐng)求。
問(wèn)題是這三種狀態(tài)的確定并不容易。沒(méi)有公式可以找到廁所處于哪種狀態(tài)。感謝機(jī)器學(xué)習(xí)。一個(gè)簡(jiǎn)單的機(jī)器學(xué)習(xí)模型可以幫助從空氣質(zhì)量數(shù)據(jù)的分類中智能地識(shí)別狀態(tài)。同樣,訓(xùn)練機(jī)器學(xué)習(xí)模型并不容易,構(gòu)建一個(gè)好的模型需要專業(yè)知識(shí)、對(duì)輸入的全面理解,以及經(jīng)過(guò)多個(gè)周期的努力來(lái)優(yōu)化它。但如今,借助現(xiàn)代數(shù)據(jù)科學(xué)工具鏈,無(wú)需任何 ML 專業(yè)知識(shí)即可制作 ML 模型,而 Amazon SageMaker 工具鏈就是其中之一,但我們不能指望第一次嘗試就能生成一個(gè)好的模型。
為了建立一個(gè)好的模型,我們需要大量的數(shù)據(jù)。越多越好。構(gòu)建 ML 模型是一個(gè)兩步過(guò)程,收集數(shù)據(jù)和訓(xùn)練模型。為了準(zhǔn)確檢測(cè),我們需要為每種情況收集大量數(shù)據(jù),之前討論過(guò)的三種狀態(tài)。因此,我們需要在干凈的馬桶中部署我們的設(shè)備至少幾個(gè)小時(shí)(最好是 24 小時(shí)),在不舒服的馬桶中部署幾個(gè)小時(shí),在不衛(wèi)生的馬桶中部署幾個(gè)小時(shí),以收集足夠的數(shù)據(jù)來(lái)構(gòu)建準(zhǔn)確的 ML 模型。第二個(gè)不干涉步驟是在您收集到足夠的數(shù)據(jù)后,ML 模型正在經(jīng)歷一個(gè)自動(dòng)訓(xùn)練過(guò)程。此培訓(xùn)過(guò)程可能需要幾個(gè)小時(shí),我們建議您在早上開(kāi)始,下午返回,或者讓它運(yùn)行一整夜。
我們將使用設(shè)備遙測(cè)的聚合數(shù)據(jù)集來(lái)支持自動(dòng) ML 訓(xùn)練實(shí)驗(yàn),然后使用從訓(xùn)練的 ML 模型推斷出的新廁所狀態(tài)值對(duì)新設(shè)備報(bào)告進(jìn)行分類。

我們將遵循的工作流程具有以下關(guān)鍵組件:
- 我們將創(chuàng)建一個(gè)新的 IoT Core 規(guī)則,它將報(bào)告的設(shè)備數(shù)據(jù)轉(zhuǎn)發(fā)到名為 AWS IoT Analytics 的服務(wù)。IoT Analytics 服務(wù)批量存儲(chǔ)原始 IoT 數(shù)據(jù),對(duì)其進(jìn)行轉(zhuǎn)換和清理以將原始數(shù)據(jù)轉(zhuǎn)換為處理后的數(shù)據(jù),并提供查詢引擎來(lái)對(duì)處理后的數(shù)據(jù)進(jìn)行切片,以用于分析工作流或 ML 訓(xùn)練。
- 我們的 IoT Analytics 項(xiàng)目將包含四個(gè)鏈接在一起的資源:一個(gè)用于存儲(chǔ)來(lái)自設(shè)備影子的原始 IoT 數(shù)據(jù)的通道、一個(gè)用于轉(zhuǎn)換/過(guò)濾/豐富數(shù)據(jù)的管道、一個(gè)用于處理數(shù)據(jù)的數(shù)據(jù)存儲(chǔ),以及一個(gè)運(yùn)行保存的查詢和可以發(fā)送結(jié)果進(jìn)行處理。
- Amazon SageMaker Studio 是一個(gè)集成的機(jī)器學(xué)習(xí)環(huán)境,您可以在其中構(gòu)建、訓(xùn)練、部署和分析您的模型,所有這些都在同一個(gè)應(yīng)用程序中進(jìn)行。
- 一個(gè) Amazon SageMaker 終端節(jié)點(diǎn),將您的訓(xùn)練模型作為可使用的 API 托管。
- 我們將創(chuàng)建一個(gè) AWS Lambda 函數(shù),該函數(shù)將運(yùn)行一些簡(jiǎn)單的代碼來(lái)處理已發(fā)布的消息并對(duì)我們的新 ML 模型端點(diǎn)進(jìn)行推理。
步驟 1:創(chuàng)建 IoT Core 規(guī)則以將遙測(cè)數(shù)據(jù)轉(zhuǎn)發(fā)到 IoT Analytics
- 一世。在AWS IoT Core 控制臺(tái)中,依次選擇Act 、Rules和Create 。
- ii. 給你的規(guī)則起一個(gè)名字,比如廁所DataToAnalyticsForState和描述。
- iii. 使用以下查詢。請(qǐng)務(wù)必將?CLIENT_ID?替換為打印在 Core2 for AWS IoT Edukit 參考硬件套件屏幕上的客戶端 ID/序列號(hào)。
SELECT current.state.reported.temperature, current.state.reported.humidity, current.state.reported.carbon_monoxide, current.state.reported.ammonia, current.state.reported.nitrogen_dioxide, current.state.reported.sulfur_dioxide, current.state.reported.methane, current.state.reported.sound, current.state.reported.toilet_status, current.state.reported.fan_status, timestamp FROM '$aws/things/< >/shadow/update/documents'
- iv. 為設(shè)置一項(xiàng)或多項(xiàng)操作選擇添加操作。
- v.選擇向 IoT Analytics 發(fā)送消息,然后選擇配置操作。
- 六。選擇快速創(chuàng)建 IoT Analytics 資源并為Resource prefix提供項(xiàng)目名稱。進(jìn)一步的模塊步驟假設(shè)前綴是toiletAnalyticsResourceForState。選擇快速創(chuàng)建,您的所有 AWS IoT Analytics 資源將自動(dòng)創(chuàng)建和配置。
- 七。選擇添加操作以配置此操作并返回到規(guī)則創(chuàng)建表單。
- 八。選擇創(chuàng)建規(guī)則以創(chuàng)建新規(guī)則。
驗(yàn)證步驟
在繼續(xù)下一章之前,您可以驗(yàn)證您的無(wú)服務(wù)器應(yīng)用程序是否按預(yù)期配置:
- 確保您的 Core2 設(shè)備已開(kāi)機(jī)、發(fā)布數(shù)據(jù)并部署在您要訓(xùn)練的廁所中。
- 使用 AWS IoT Analytics 控制臺(tái),查看最新的數(shù)據(jù)集內(nèi)容,并驗(yàn)證所有參數(shù)(如溫度、濕度、氨氣、二氧化硫等)的歷史記錄以及時(shí)間戳。要檢查這一點(diǎn),請(qǐng)?jiān)?/font>IoT Analytics 控制臺(tái)中找到您的數(shù)據(jù)集,選擇Actions和Run now ,然后等待查詢完成。在“內(nèi)容”選項(xiàng)卡中,單擊最近創(chuàng)建的包含最新內(nèi)容的內(nèi)容預(yù)覽。您應(yīng)該會(huì)看到類似于以下內(nèi)容的結(jié)果:


第 2 步:設(shè)置 Amazon SageMaker Studio 以進(jìn)行自動(dòng)模型訓(xùn)練
首先,您將設(shè)置 Amazon SageMaker Studio,以便為自動(dòng)模型訓(xùn)練配置新實(shí)驗(yàn)。
- 一世。轉(zhuǎn)到 Amazon SageMaker 控制臺(tái)并選擇Amazon SageMaker Studio 。
- ii. 選擇Quick start并可選擇輸入一個(gè)新的用戶名,如廁所狀態(tài)用戶。
- iii. 對(duì)于Execution role選擇下拉菜單并選擇Create a new IAM role 。
- iv. 對(duì)于您指定的 S3 存儲(chǔ)桶,選擇None ,然后選擇Create role 。名稱中帶有“sagemaker”的存儲(chǔ)桶的其他默認(rèn)值足以滿足此項(xiàng)目。
- v.選擇提交以開(kāi)始 SageMaker Studio 的配置過(guò)程。代表您完成此步驟需要幾分鐘時(shí)間。
步驟 3:在 SageMaker Studio中配置新項(xiàng)目
- 一世。從 SageMaker Studio 控制面板中,為新創(chuàng)建的用戶選擇打開(kāi) Studio 。
- ii. 在 Launcher 選項(xiàng)卡中,選擇New project 。
- iii. 在SageMaker 項(xiàng)目模板下,選擇用于模型構(gòu)建、訓(xùn)練和部署的 MLOps 模板,然后選擇選擇項(xiàng)目模板。


- iv. 給你的項(xiàng)目起一個(gè)名字,比如廁所StateSageMakerProject和描述,然后選擇Create project 。
創(chuàng)建項(xiàng)目后,我們將獲得一個(gè)項(xiàng)目?jī)x表板,其中包含存儲(chǔ)庫(kù)、管道、實(shí)驗(yàn)等選項(xiàng)卡。讓我們將此瀏覽器選項(xiàng)卡對(duì) SageMaker Studio 保持打開(kāi)狀態(tài),以便您可以快速返回此頁(yè)面。
步驟 4:導(dǎo)出 AWS IoT Analytics 數(shù)據(jù)
- 一世。打開(kāi)AWS IoT Analytics 控制臺(tái)并選擇您的數(shù)據(jù)集(假定名稱為Toiletanalyticsresourceforstate_dataset)。
- ii. 在數(shù)據(jù)集內(nèi)容交付規(guī)則下選擇編輯。
- iii. 選擇Add rule ,然后選擇Deliver result to S3 。
-
iv. 在S3 存儲(chǔ)桶下選擇請(qǐng)選擇一個(gè)資源并找到為您的 SageMaker Studio 項(xiàng)目創(chuàng)建的 S3 存儲(chǔ)桶。它將被命名為
sagemaker-project-p-wzq6773hm0gv
. 如果有多個(gè)這樣命名的存儲(chǔ)桶,您需要檢查 SageMaker Studio 項(xiàng)目以獲取項(xiàng)目的隨機(jī)哈希 ID。您可以在項(xiàng)目的其他資源(例如存儲(chǔ)庫(kù)和管道選項(xiàng)卡)中查看哈希值。

-
v.在Bucket key 表達(dá)式下使用這個(gè)表達(dá)式:
data/healthytoilet/Version/!{iotanalytics:scheduleTime}_!{iotanalytics:versionId}.csv
- 六。在Role下,選擇Create new并為 IAM 角色提供一個(gè)名稱,該角色將授予 IoT Analytics 訪問(wèn)權(quán)限以將數(shù)據(jù)寫(xiě)入您的 S3 存儲(chǔ)桶。選擇創(chuàng)建角色。
- 七。選擇保存以完成新的遞送規(guī)則。

- 八。要生成將保存到您的新 Amazon S3 存儲(chǔ)桶以進(jìn)行訓(xùn)練的數(shù)據(jù)集,請(qǐng)選擇Actions然后Run now 。數(shù)據(jù)集內(nèi)容生成完成后,您應(yīng)該會(huì)看到結(jié)果預(yù)覽更新。
我們現(xiàn)在已準(zhǔn)備好在 SageMaker Studio 中開(kāi)始您的 ML 實(shí)驗(yàn)。實(shí)驗(yàn)將使用我們的 IoT Analytics 數(shù)據(jù)集剛剛導(dǎo)出的報(bào)告恒溫器數(shù)據(jù)作為輸入。我們將配置實(shí)驗(yàn)以尋找準(zhǔn)確預(yù)測(cè)現(xiàn)有廁所狀態(tài)列的方法。自動(dòng)訓(xùn)練作業(yè)將分析您的數(shù)據(jù)以嘗試相關(guān)算法,然后運(yùn)行 ??250 個(gè)具有不同超參數(shù)的訓(xùn)練作業(yè),選擇最適合您的輸入訓(xùn)練數(shù)據(jù)的一個(gè)。
在開(kāi)始您的 ML 實(shí)驗(yàn)之前,我們應(yīng)該從我們要分析的馬桶中的設(shè)備報(bào)告幾個(gè)小時(shí)的數(shù)據(jù),并且在那段時(shí)間馬桶應(yīng)該有準(zhǔn)備好的、忙碌的和不干凈的情況。一個(gè)自動(dòng) ML 實(shí)驗(yàn)需要至少 500 行數(shù)據(jù)才能工作,但我們帶來(lái)的數(shù)據(jù)越多,結(jié)果就會(huì)越好。如果在繼續(xù)之前我們?nèi)孕枰筛鄶?shù)據(jù),我們需要重新運(yùn)行 IoT Analytics 控制臺(tái)中的數(shù)據(jù)集(上一個(gè)指令列表的最后一步),以便我們的項(xiàng)目 S3 存儲(chǔ)桶中的 SageMaker 可以使用這些結(jié)果。
第 4 步:在 SageMaker Studio 中啟動(dòng) ML 實(shí)驗(yàn)
- 一世。返回您的 SageMaker Studio,打開(kāi)您的項(xiàng)目,選擇Experiments選項(xiàng)卡并選擇Create autopilot Experiment 。

- ii. 為您的實(shí)驗(yàn)命名。
- iii. 在項(xiàng)目下,從列表中選擇您的項(xiàng)目。
- iv. 在連接您的數(shù)據(jù)和S3 存儲(chǔ)桶名稱下,在列表中找到并選擇您項(xiàng)目的 S3 存儲(chǔ)桶。這與您在上一步中為 IoT Analytics 數(shù)據(jù)集內(nèi)容交付規(guī)則選擇的規(guī)則相同。
-
v.在數(shù)據(jù)集文件名下找到并選擇您的 IoT Analytics 數(shù)據(jù)集內(nèi)容,例如
data/healthytoilet/Version/1607276270943_3b4eb6bb-8533-4ac0-b8fd-1b62ac0020a2.csv
. -
六。在目標(biāo)下選擇
toilet_status
。 - 七。在輸出數(shù)據(jù)位置和S3 存儲(chǔ)桶名稱下,在此列表中查找并選擇您在步驟 4 中選擇的相同項(xiàng)目 S3 存儲(chǔ)桶。
-
八。在Dataset directory name下輸入
output/healthytoilet
并選擇Use input as S3 object key prefix “output/healthytoilet” 。這會(huì)在 S3 存儲(chǔ)桶中定義一個(gè)新前綴,用于您的輸出文件。 - 十四。選擇Create Experiment以啟動(dòng)自動(dòng)化 ML 實(shí)驗(yàn)。


運(yùn)行實(shí)驗(yàn)可能需要幾分鐘到幾小時(shí)。您可以在 SageMaker Studio 瀏覽器選項(xiàng)卡中跟蹤實(shí)驗(yàn)的進(jìn)度,但關(guān)閉選項(xiàng)卡并稍后返回查看進(jìn)度也是安全的。
實(shí)驗(yàn)結(jié)束后,結(jié)果輸出是 250 次試驗(yàn),SageMaker 使用這些試驗(yàn)來(lái)尋找最佳調(diào)整作業(yè)參數(shù)。對(duì)試驗(yàn)表進(jìn)行排序以找到標(biāo)記為Best的那一項(xiàng)。下一個(gè)里程碑是將此試用版部署為模型端點(diǎn),以便您可以將其作為 API 調(diào)用。
第 5 步:部署最佳 ML 模型
- 一世。選擇標(biāo)記為Best的試用版,然后選擇Deploy model 。

- ii. 為您的端點(diǎn)命名。本模塊中的進(jìn)一步步驟假定名稱 healthToiletStateEndpoint。
- iii. 在Inference Response Content下,同時(shí)選擇predict_label和probability 。predict_label可能已經(jīng)添加到列表中。
- iv. 選擇部署模型以告訴 SageMaker 將您的模型部署為新的可消耗 API 端點(diǎn)。這將需要幾分鐘。

現(xiàn)在,您的機(jī)器學(xué)習(xí)模型已部署為 API 終端節(jié)點(diǎn),由 Amazon SageMaker 管理。在下一章“使用 ML 模型”中,您將使用無(wú)服務(wù)器函數(shù)使用 API 端點(diǎn),并用模型生成的推理替換 IoT Core 規(guī)則中確定值的簡(jiǎn)單閾值邏輯。toilet_status
驗(yàn)證步驟
在繼續(xù)下一步之前,您可以驗(yàn)證您的無(wú)服務(wù)器應(yīng)用程序是否按預(yù)期配置......
- 使用Amazon SageMaker 控制臺(tái)在Endpoints頁(yè)面上查看狀態(tài)為InService的新終端節(jié)點(diǎn)。

第 6 步:設(shè)置 AWS Lambda 并調(diào)用 SageMaker Endpoint
以下步驟將引導(dǎo)我們?cè)?AWS Lambda 中創(chuàng)建無(wú)服務(wù)器函數(shù)。該函數(shù)定義了一小段代碼,期望來(lái)自 IoT Core 的設(shè)備影子消息,將消息轉(zhuǎn)換為與我們的 ML 端點(diǎn)一起使用的格式,然后調(diào)用 ML 端點(diǎn)以返回廁所狀態(tài)的分類和推理的置信度分?jǐn)?shù)。
- 一世。在 AWS Lambda 控制臺(tái)中,選擇Create function 。
-
ii. 輸入函數(shù)的名稱。進(jìn)一步的步驟假定名稱
classifyToiletStatus
。 - iii. 在運(yùn)行時(shí),選擇Python 3.8 。
- iv. 選擇創(chuàng)建函數(shù)。

- v.在Function code下,在文件lambda_function.py中,復(fù)制并粘貼以下代碼以替換占位符代碼:
import json
import boto3
import os
# Receives a device shadow Accepted document from IoT Core rules engine.
# Event has signature like {"state": {"reported": {"sound": 5}}}.
# See expectedAttributes for full list of attributes expected in state.reported.
# Builds CSV input to send to SageMaker endpoint, name of which stored in
# environment variable SAGEMAKER_ENDPOINT.
#
# Returns the prediction and confidence score from the ML model endpoint.
def lambda_handler(event, context):
client = boto3.client('sagemaker-runtime')
print('event received: {}'.format(event))
# Order of attributes must match order expected by ML model endpoint. E.g.
# the same order of columns used to train the model.
expectedAttributes = ['temperature', 'humidity', 'carbon_monoxide', 'ammonia', 'nitrogen_dioxide', 'sulfur_dioxide', 'methane', 'sound', 'toilet_status', 'fan_status', 'timestamp']
reported = event['state']['reported']
reported['timestamp'] = event['timestamp']
reportedAttributes = reported.keys()
# Validates the input event has all the expected attributes.
if(len(set(expectedAttributes) & set(reportedAttributes)) < len(expectedAttributes)):
return {
'statusCode': 400,
'body': 'Error: missing attributes from event. Expected: {}. Received: {}.'.format(','.join(expectedAttributes), ','.join(reportedAttributes))
}
# Build the input CSV string to send to the ML model endpoint.
reportedValues = []
for attr in expectedAttributes:
reportedValues.append(str(reported[attr]))
input = ','.join(reportedValues)
print('sending this input for inference: {}'.format(input))
endpoint_name = os.environ['SAGEMAKER_ENDPOINT']
content_type = "text/csv"
accept = "application/json"
payload = input
response = client.invoke_endpoint(
EndpointName=endpoint_name,
ContentType=content_type,
Accept=accept,
Body=payload
)
body = response['Body'].read()
print('received this response from inference endpoint: {}'.format(body))
return {
'statusCode': 200,
'body': json.loads(body)['predictions'][0]
}
- 六。在 Configuration 選項(xiàng)卡下單擊Environment variables ,然后選擇Edit并添加一個(gè)新的環(huán)境變量。

-
七。對(duì)于Key輸入
SAGEMAKER_ENDPOINT
,對(duì)于Value輸入您的 SageMaker 終端節(jié)點(diǎn)的名稱。您將此資源命名為部署模型的最后一步,并且此模塊假定名稱為healthyToiletStateEndpoint
.

- 八。選擇保存以提交此新環(huán)境變量并返回主 Lambda 編輯器界面。
- 九。在設(shè)計(jì)器面板中,選擇+ 添加觸發(fā)器。
- X。對(duì)于觸發(fā)器配置,從列表中選擇AWS IoT 。
- 十一。對(duì)于IoT 類型,選擇自定義 IoT 規(guī)則。
- 十二。對(duì)于Rule ,選擇Create a new rule,提供一個(gè)角色名稱,如廁所IotLambdaInvoke并將以下文本粘貼到 Rule 查詢語(yǔ)句中。將 DEVICE_ID 替換為您自己的設(shè)備 ID,然后單擊Add 。
SELECT cast(get(get(aws_lambda("arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME", *), "body"),
"predicted_label") AS String) AS state.desired.toilet_status
FROM '$aws/things/< >/shadow/update/accepted' WHERE state.reported.temperature <> Null
確保替換占位符:將 REGION 更改為您當(dāng)前的區(qū)域,如控制臺(tái)標(biāo)題中所示(它必須是格式us-west-2
而不是Oregon
);將 ACCOUNT_ID 更改為您的 12 位帳戶 ID,不帶連字符,這也顯示在打印您的用戶名的控制臺(tái)標(biāo)題菜單中;并將 FUNCTION_NAME 更改為您創(chuàng)建的 AWS Lambda 函數(shù)的名稱(假定名稱為classifyToiletStatus
)。不要忘記更新 FROM 主題中的 ?CLIENT_ID? 占位符。

- 十三。選擇權(quán)限選項(xiàng)卡,然后選擇角色名稱下的鏈接,以便您可以為此 Lambda 函數(shù)添??加權(quán)限以調(diào)用您的 SageMaker 終端節(jié)點(diǎn)。
- 十四。從打開(kāi)到 IAM 控制臺(tái)的新選項(xiàng)卡中,在Permissions policies下選擇Add inline policy 。
- 十五。對(duì)于服務(wù),選擇SageMaker 。
- 十六。對(duì)于操作,選擇InvokeEndpoint 。
- 十七。對(duì)于資源,選擇所有資源。
- 十八。選擇審查政策。
-
十九。為您的策略命名,
invokeSageMakerEndpoint
然后選擇Create policy 。您現(xiàn)在可以關(guān)閉這個(gè)新的瀏覽器選項(xiàng)卡。
測(cè)試 Lambda 函數(shù)
-
一世。轉(zhuǎn)到您的 Lambda 函數(shù)并選擇代碼選項(xiàng)卡。如果您沒(méi)有部署您的 Lambda 代碼,請(qǐng)單擊
Deploy

- ii. 您將收到Changes 已部署的確認(rèn)信息。單擊測(cè)試并選擇配置測(cè)試事件。

- iii. 給出配置的名稱,如 prediction_test 并在代碼編輯器中粘貼示例 JSON 數(shù)據(jù)(如設(shè)備上傳的 JSON),刪除之前的數(shù)據(jù):
{
"state": {
"reported": {
"temperature": 29,
"humidity": 39,
"carbon_monoxide": 4.384765,
"ammonia": 0.687,
"nitrogen_dioxide": 0.141511,
"sulfur_dioxide": 0.441511,
"methane": 837.172485,
"sound": 23,
"toilet_status": "BUSY",
"fan_status": false
}
},
"metadata": {
"reported": {
"temperature": {
"timestamp": 1630912876
},
"humidity": {
"timestamp": 1630912876
},
"carbon_monoxide": {
"timestamp": 1630912876
},
"ammonia": {
"timestamp": 1630912876
},
"nitrogen_dioxide": {
"timestamp": 1630912876
},
"sulfur_dioxide": {
"timestamp": 1630912876
},
"methane": {
"timestamp": 1630912876
},
"sound": {
"timestamp": 1630912876
},
"toiletStatus": {
"timestamp": 1630912876
},
"fanStatus": {
"timestamp": 1630912876
}
}
},
"version": 560,
"timestamp": 1630912876,
"clientToken": "01231c94f550fe1c01-3"
}
- iv. 單擊以創(chuàng)建。

v.現(xiàn)在單擊測(cè)試,您將獲得以下 JSON 響應(yīng)。它返回帶有概率的廁所狀態(tài)的預(yù)測(cè)標(biāo)簽。請(qǐng)注意,在我們提供的數(shù)據(jù)中,廁所狀態(tài)為 BUSY,但 ML 模型根據(jù)空氣質(zhì)量數(shù)據(jù)預(yù)測(cè)它為 READY。
{
"statusCode": 200,
"body": {
"predicted_label": "READY",
"probability": "0.4254942536354065"
}
}

此時(shí),我們的 IoT 工作流程現(xiàn)在正在使用來(lái)自其部署的端點(diǎn)的經(jīng)過(guò)訓(xùn)練的機(jī)器學(xué)習(xí)模型,以將設(shè)備發(fā)布的消息分類為新的廁所狀態(tài)值!
在廁所IotLambdaInvoke規(guī)則上添加操作
轉(zhuǎn)到toiletIotLambdaInvoke
規(guī)則添加一個(gè)操作以根據(jù)預(yù)測(cè)更新設(shè)備陰影。
- 選擇添加操作。
- 選擇將消息重新發(fā)布到 AWS IoT 主題,然后選擇配置操作。
-
對(duì)于主題,使用
$$aws/things/<
. 請(qǐng)務(wù)必將?CLIENT_ID?替換為您設(shè)備的客戶端 ID/序列號(hào)。>/shadow/update - 對(duì)于選擇或創(chuàng)建角色以授予 AWS IoT 訪問(wèn)權(quán)限以執(zhí)行此操作。選擇Create Role并在彈出窗口中為您的新 IAM 角色命名,然后選擇Create role 。
- 選擇添加操作以完成操作配置并返回到規(guī)則創(chuàng)建表單。
- 單擊創(chuàng)建規(guī)則以在 AWS IoT 規(guī)則引擎中創(chuàng)建此規(guī)則。
這將更新設(shè)備影子,如下所示:
{
"state": {
"desired": {
"toilet_status": "UNCLEAN",
"fan_status": false
}
},
"metadata": {
"desired": {
"toilet_status": {
"timestamp": 1632032337
},
"fan_status": {
"timestamp": 1632032337
}
}
},
"version": 6735,
"timestamp": 1632032337
}
發(fā)送廁所不干凈的通知
當(dāng)設(shè)備發(fā)布遙測(cè)數(shù)據(jù)時(shí),IoT 規(guī)則會(huì)觸發(fā) Lambda 函數(shù)來(lái)讀取 SageMaker 預(yù)測(cè)并相應(yīng)地更新設(shè)備影子。我們希望在廁所狀態(tài)預(yù)測(cè)級(jí)別為 UNCLEAN 時(shí)向涉及清潔的人員發(fā)送通知(電子郵件)。每次廁所狀態(tài)從另一個(gè)狀態(tài)變?yōu)?UNCLEAN 時(shí),我們只想發(fā)送一封電子郵件。因此,我們將訂閱delta主題。
步驟1:創(chuàng)建發(fā)送 SMS 文本消息的 Amazon SNS 主題
創(chuàng)建一個(gè) Amazon SNS 主題。
- 登錄到Amazon SNS 控制臺(tái)。
- 在左側(cè)導(dǎo)航窗格中,選擇主題。
- 在主題頁(yè)面上,選擇創(chuàng)建主題。
- 在Details中,選擇Standard類型。默認(rèn)情況下,控制臺(tái)會(huì)創(chuàng)建一個(gè) FIFO 主題。
-
在Name中,輸入 SNS 主題名稱。對(duì)于本教程,輸入
toiletUncleanNotice
- 滾動(dòng)到頁(yè)面末尾并選擇Create topic 。控制臺(tái)將打開(kāi)新主題的詳細(xì)信息頁(yè)面。
創(chuàng)建 Amazon SNS 訂閱。
-
在
toiletUncleanNotice
主題的詳細(xì)信息頁(yè)面中,選擇Create subscription 。 - 在Create subscription的Details部分的Protocol列表中,選擇SMS 。
-
在Endpoint中,輸入可以接收短信的電話號(hào)碼。確保輸入以 開(kāi)頭
+
,包括國(guó)家和地區(qū)代碼,并且不包括任何其他標(biāo)點(diǎn)符號(hào)。 - 選擇創(chuàng)建訂閱。
測(cè)試 Amazon SNS 通知。
- 在Amazon SNS 控制臺(tái)的左側(cè)導(dǎo)航窗格中,選擇主題。
-
要打開(kāi)主題的詳細(xì)信息頁(yè)面,請(qǐng)?jiān)?/font>主題列表中的主題列表中選擇
toiletUncleanNotice
。 - 要打開(kāi)Publish message to topic頁(yè)面,請(qǐng)?jiān)?/font>high_temp_notice詳細(xì)信息頁(yè)面中,選擇Publish message 。
- 在Publish message to topic的Message body部分的Message body to send to the endpoint中,輸入一條短消息。
- 向下滾動(dòng)到頁(yè)面底部并選擇Publish message 。
- 在您之前創(chuàng)建訂閱時(shí)使用的號(hào)碼的手機(jī)上,確認(rèn)已收到消息。
如果您沒(méi)有收到測(cè)試消息,請(qǐng)仔細(xì)檢查電話號(hào)碼和手機(jī)設(shè)置。
步驟2:創(chuàng)建 AWS IoT 規(guī)則以發(fā)送短信
- 在AWS IoT Core 控制臺(tái)中,依次選擇Act 、Rules和Create 。
- 為您的規(guī)則命名,如sendSnsUnclean和描述。
- 使用以下查詢。請(qǐng)務(wù)必將?CLIENT_ID?替換為打印在 Core2 for AWS IoT Edukit 參考硬件套件屏幕上的客戶端 ID/序列號(hào)。
SELECT state.toilet_status AS state.toilet_status FROM '$aws/things/?CLIENT_ID?/shadow/update/delta' WHERE state.toilet_status = "UNCLEAN"
當(dāng)馬桶狀態(tài)從另一個(gè)狀態(tài)變?yōu)榱硪粋€(gè)狀態(tài)時(shí),上述查詢語(yǔ)句將生成以下 JSON 消息UNCLEAN
。
{
"state": {
"toilet_status": "UNCLEAN"
}
}
- 要打開(kāi)此規(guī)則的規(guī)則操作列表,請(qǐng)?jiān)?/font>設(shè)置一個(gè)或多個(gè)操作中,選擇添加操作。
- 在選擇操作中,選擇將消息作為 SNS 推送通知發(fā)送。
- 要打開(kāi)所選操作的配置頁(yè)面,請(qǐng)?jiān)诓僮髁斜淼撞窟x擇配置操作。
- 在配置操作中:
- 在SNS 目標(biāo)中,選擇Select ,找到名為high_temp_notice的 SNS 主題,然后選擇Select 。
- 在消息格式中,選擇RAW 。
- 在選擇或創(chuàng)建角色以授予 AWS IoT 訪問(wèn)權(quán)限以執(zhí)行此操作中,選擇創(chuàng)建角色。
-
在Create a new role 中,在Name中,輸入新角色的唯一名稱。對(duì)于本教程,使用
sns_rule_role
. - 選擇創(chuàng)建角色。
此規(guī)則將以原始 JSON 格式發(fā)送電子郵件。我們可以使用 Lambda 將其格式化為用戶友好的格式。在這種情況下,我們將選擇向 Lambda 函數(shù)發(fā)送消息,而不是作為規(guī)則操作將消息作為 SNS 推送通知發(fā)送,并且 Lambda 會(huì)將消息作為 SNS 發(fā)送。所以讓我們先創(chuàng)建一個(gè) Lambda 函數(shù)。
使用 AWS Lambda 函數(shù)格式化通知
上面的教程是關(guān)于如何發(fā)送 Amazon SNS 通知,由規(guī)則的查詢語(yǔ)句產(chǎn)生的 JSON 文檔作為文本消息的正文發(fā)送。結(jié)果是一條類似于以下示例的文本消息:
{
"state": {
"toilet_status": "UNCLEAN"
}
}
在本教程中,您將使用 AWS Lambda 規(guī)則操作來(lái)調(diào)用 AWS Lambda 函數(shù),該函數(shù)將規(guī)則查詢語(yǔ)句中的數(shù)據(jù)格式化為更友好的格式,例如以下示例:
The toilet is very UNCLEAN and need to clean immediately. So, you are requested to take immediate action for cleaning. Thank you.
此項(xiàng)目中的 AWS Lambda 函數(shù)接收規(guī)則查詢語(yǔ)句的結(jié)果,將元素插入文本字符串,并將結(jié)果字符串作為通知中的消息發(fā)送到 Amazon SNS。
創(chuàng)建發(fā)送文本消息的 AWS Lambda 函數(shù)
創(chuàng)建一個(gè)新的 AWS Lambda 函數(shù)。
- 在AWS Lambda 控制臺(tái)中,選擇Create function 。
-
在創(chuàng)建函數(shù)中,選擇使用藍(lán)圖。搜索并選擇
hello-world-python
藍(lán)圖,然后選擇配置。 -
在Function name中,輸入此函數(shù)的名稱,
formatUncleanToiletNotification
。 - 在執(zhí)行角色中,選擇從 AWS 策略模板創(chuàng)建新角色。
-
在角色名稱中,輸入新角色的名稱
formatUncleanToiletNotificationRole
。 - 在Policy templates - optional中,搜索并選擇Amazon SNS 發(fā)布策略。
- 選擇創(chuàng)建函數(shù)。
修改藍(lán)圖代碼以格式化并發(fā)送 Amazon SNS 通知。
- 創(chuàng)建函數(shù)后,您應(yīng)該會(huì)看到format-h??igh-temp-notification詳細(xì)信息頁(yè)面。如果您不這樣做,請(qǐng)從Lambda函數(shù)頁(yè)面打開(kāi)它。
- 在format-h??igh-temp-notification詳細(xì)信息頁(yè)面中,選擇Configuration選項(xiàng)卡并滾動(dòng)到Function code面板。
-
在函數(shù)代碼窗口的環(huán)境窗格中,選擇 Python 文件
lambda_function.py
. -
在Function code窗口中,從藍(lán)圖中刪除所有原始程序代碼,并用此代碼替換它。將 替換為
notify_topic_arn
通知主題中的 ARN。
import boto3
def lambda_handler(event, context):
# Create an SNS client to send notification
sns = boto3.client('sns')
# Format text message from data
message_text = "The toilet is very {0} and need to clean immediately.".format(
str(event['state']['toilet_status'])
)
# Publish the formatted message
response = sns.publish(
TopicArn = event['notify_topic_arn'],
Message = message_text
)
return response
- 選擇部署。
現(xiàn)在再次轉(zhuǎn)到上一個(gè)規(guī)則操作,
- 刪除之前的操作,然后單擊添加操作
- 在選擇操作中,選擇向 Lambda 函數(shù)發(fā)送消息。
- 要打開(kāi)所選操作的配置頁(yè)面,請(qǐng)?jiān)诓僮髁斜淼撞窟x擇配置操作。
在配置操作中:
- 在函數(shù)名稱中,選擇選擇。
- 選擇format-h??igh-temp-notification 。
- 在配置操作的底部,選擇添加操作。
- 要?jiǎng)?chuàng)建規(guī)則,請(qǐng)?jiān)趧?chuàng)建規(guī)則底部選擇創(chuàng)建規(guī)則。
?
?
所有步驟的視頻教程
這是到目前為止解釋的所有步驟的屏幕記錄。初學(xué)者遵循上述步驟將很有幫助。視頻中沒(méi)有聲音。
?
使用 SageMaker 檢測(cè)漏水
按照相同的過(guò)程,您可以訓(xùn)練模型來(lái)檢測(cè)漏水。您不需要使用所有參數(shù)來(lái)開(kāi)發(fā)模型。當(dāng)然,在這種情況下,噪聲級(jí)將是最有價(jià)值的資源。當(dāng)我解釋我如何使用 IoT Analytics、SageMaker 和 Lambda 開(kāi)發(fā)和訓(xùn)練廁所狀態(tài)的機(jī)器學(xué)習(xí)模型時(shí),我不再在這里重復(fù)這個(gè)過(guò)程。
將 NodeMCU 連接到 AWS IoT Core
在我們的項(xiàng)目中,Node MCU 將根據(jù)從 AWS IoT Core 收到的命令控制排氣扇。IoT Core 規(guī)則將根據(jù)從廁所接收到的空氣質(zhì)量數(shù)據(jù)將控制消息(真或假)發(fā)布到特定的 MQTT 主題。該規(guī)則適用于相關(guān)重要空氣質(zhì)量參數(shù)的預(yù)設(shè)閾值。如果任何參數(shù)超過(guò)閾值,則 IoT Core 規(guī)則會(huì)向node/mcu/fan/state等主題發(fā)布一條真實(shí)消息。節(jié)點(diǎn) MCU 收到此消息并打開(kāi)排氣扇,反之亦然。

要從 AWS IoT Core 節(jié)點(diǎn) MCU 接收 MQTT 消息,必須連接到 IoT Core。按照鏈接 ( https://nerdyelectronics.com/iot/how-to-connect-nodemcu-to-aws-iot-core/ ) 中的教程了解如何將節(jié)點(diǎn) MCU 連接到 AWS IoT Core。這是關(guān)于這個(gè)主題的一個(gè)非常好的教程。
你也可以關(guān)注視頻:
為 Node MCU 開(kāi)發(fā)固件
將 Node MCU 板成功連接到 AWS IoT Core 后,我們需要開(kāi)發(fā)板的固件,以便它可以接收來(lái)自我們特定主題的消息并可以相應(yīng)地控制排氣扇。
固件是在 Arduino 中開(kāi)發(fā)的,成功編譯需要以下 Arduino 庫(kù)。
#include "FS.h"
#include //tested esp8266 core version: 2.5.2
#include //tested version: 2.7.0
#include //tested version: 3.2.0
#include
#include //tested version: 6.18.4
為了接收消息,我們需要像這樣在成功連接到 IoT Core 后訂閱一個(gè)主題
void reconnect()
{
// Loop until we're reconnected
while (!client.connected())
{
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("ESPthing"))
{
Serial.println("connected");
client.subscribe("node/mcu/fan/state");
Serial.println("subscribed");
}
else
{
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
char buf[256];
espClient.getLastSSLError(buf, 256);
Serial.print("WiFiClientSecure SSL error: ");
Serial.println(buf);
// Wait 5 seconds before retrying
delay(5000);
}
}
}
以下回調(diào)函數(shù)接收MQTT消息并控制風(fēng)扇
void callback(char* topic, byte* payload, unsigned int length)
{
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++)
{
message.concat((char)payload[i]);
}
Serial.print(message);
deserializeJson(doc, message);
bool fan_status = doc["state"]["desired"]["fan_status"];
Serial.println();
if(fan_status == true){
//turn on fan
digitalWrite(RELAY, HIGH);
Serial.println("Fan is ON");
}
else if(fan_status == false){
//turn off fan
digitalWrite(RELAY, LOW);
Serial.println("Fan is OFF");
}
message = "";
}
Node MCU 的完整源代碼附在代碼部分。
驗(yàn)證 NodeMCU 固件
為了驗(yàn)證 Node MCU 正在接收 MQTT 消息并控制風(fēng)扇,請(qǐng)轉(zhuǎn)到 IoT Core 測(cè)試客戶端頁(yè)面并將以下消息發(fā)布到主題。node/mcu/fan/state
{ "state": { "desired": {"fan_status": true } } }

您還可以通過(guò)將 fan_status 更改為 false 來(lái)進(jìn)行檢查。打開(kāi) Arduino 串口監(jiān)視器,您將得到以下響應(yīng)。

恭喜!它正在工作。為了控制風(fēng)扇,您需要通過(guò)繼電器將排氣扇連接到節(jié)點(diǎn) MCU 的數(shù)字引腳。我使用了 D3,但您可以使用任何其他引腳。請(qǐng)參閱以下連接圖以獲得更好的理解。

創(chuàng)建 IoT 規(guī)則以發(fā)布粉絲狀態(tài)
我們將創(chuàng)建 IoT Core 主題規(guī)則,接收設(shè)備從廁所發(fā)布的消息,檢查采樣的溫度、濕度、氨氣、二氧化硫和甲烷水平,并更新設(shè)備影子的風(fēng)扇狀態(tài),并重新發(fā)布消息到另一個(gè)物聯(lián)網(wǎng)主題。主題規(guī)則將使用 SQL 查詢中的條件邏輯來(lái)構(gòu)建新的有效負(fù)載,并使用 IoT Core 重新發(fā)布操作將新的有效負(fù)載發(fā)送到新主題。
- 轉(zhuǎn)到 AWS IoT Core 管理控制臺(tái),選擇Act ,選擇Rules ,然后選擇Create 。
-
為您的規(guī)則命名和描述。名字就像
healthryToiletFanStateRepublish
。 - 使用以下查詢并確保將?CLIENT_ID?替換為您的設(shè)備客戶端 ID/序列號(hào)。
SELECT CASE state.reported.temperature > 35 OR state.reported.humidity > 50 OR
state.reported.ammonia > 3 OR state.reported.sulfur_dioxide > 2 OR
state.reported.methane > 7 WHEN true THEN true ELSE false END AS
state.desired.fan_status FROM '$aws/things/< >/shadow/update/accepted'
WHERE state.reported.temperature <> Null
- 選擇添加操作。
- 選擇將消息重新發(fā)布到 AWS IoT 主題,然后選擇配置操作。
-
對(duì)于主題,使用
node/mcu/fan/state
. - 對(duì)于選擇或創(chuàng)建角色以授予 AWS IoT 訪問(wèn)權(quán)限以執(zhí)行此操作。選擇Create Role并在彈出窗口中為您的新 IAM 角色命名,然后選擇Create role 。
- 選擇添加操作以完成操作配置并返回到規(guī)則創(chuàng)建表單。
- 單擊創(chuàng)建規(guī)則以在 AWS IoT 規(guī)則引擎中創(chuàng)建此規(guī)則。
SELECT 子句使用 CASE 語(yǔ)句來(lái)實(shí)現(xiàn)我們的簡(jiǎn)單閾值帶。如果任何空氣質(zhì)量參數(shù)(如溫度、濕度、氨、二氧化硫或甲烷)超過(guò)比較值,則將風(fēng)扇狀態(tài)修改為真 (ON)。您可以根據(jù)自己的情況修改解決方案的閾值或參數(shù)。
CASE 語(yǔ)句的輸出state.desired.fan_status
使用 AS 關(guān)鍵字保存到有效負(fù)載鍵。這意味著我們正在創(chuàng)建一個(gè)新的有效負(fù)載{"state": {"desired": {"fan_status": false}}}
,并將此有效負(fù)載發(fā)送到操作。
state.reported.temperature <> Null
防止規(guī)則重新觸發(fā),因?yàn)樾碌挠白痈掠行ж?fù)載僅包含state.desired.fan_status
密鑰而沒(méi)有值state.reported.temperature
(可能使用其他參數(shù),例如濕度)。
現(xiàn)在所有的排氣扇都設(shè)置好了,它可以被 IoT Core MQTT 消息控制了。
?
?
?
?
- 燈光物聯(lián)網(wǎng)開(kāi)源項(xiàng)目
- MuSa物聯(lián)網(wǎng)開(kāi)源案例
- 新物聯(lián)網(wǎng)設(shè)備開(kāi)源分享
- 物聯(lián)網(wǎng)增強(qiáng)現(xiàn)實(shí)開(kāi)源項(xiàng)目
- 物聯(lián)網(wǎng)自動(dòng)喂狗器開(kāi)源分享
- 基于物聯(lián)網(wǎng)的健康監(jiān)測(cè)系統(tǒng)
- 基于物聯(lián)網(wǎng)的智能健康監(jiān)測(cè)手套
- 智能表物聯(lián)網(wǎng)開(kāi)源
- 物聯(lián)網(wǎng)溫度監(jiān)測(cè)設(shè)備開(kāi)源
- 螺栓物聯(lián)網(wǎng)開(kāi)源項(xiàng)目
- 壓縮機(jī)和物聯(lián)網(wǎng)開(kāi)源分享
- 基于物聯(lián)網(wǎng)的智能健康監(jiān)護(hù)系統(tǒng)
- 物聯(lián)網(wǎng)開(kāi)源項(xiàng)目
- 如何使用物聯(lián)網(wǎng)操作系統(tǒng)Zephyr實(shí)現(xiàn)“連續(xù)集成”開(kāi)源軟件的詳細(xì)說(shuō)明
- 10大物聯(lián)網(wǎng)開(kāi)源軟件的介紹 7次下載
- 低功耗主從一體藍(lán)牙模塊在智能馬桶中的應(yīng)用 353次閱讀
- 工控機(jī)在物聯(lián)網(wǎng)中的應(yīng)用 998次閱讀
- CW32單片機(jī)在智能馬桶的應(yīng)用介紹 826次閱讀
- 基于啟明RA6M5的物聯(lián)網(wǎng)居家環(huán)境健康監(jiān)控設(shè)備設(shè)計(jì) 954次閱讀
- 基于R5F100LE MCU的智能馬桶方案 4134次閱讀
- 基于物聯(lián)網(wǎng)的智慧家庭健康管理系統(tǒng) 4587次閱讀
- 物聯(lián)網(wǎng)是什么和物聯(lián)網(wǎng)基本架構(gòu) 6087次閱讀
- 智能馬桶蓋的基礎(chǔ)知識(shí)和選購(gòu)指南 2606次閱讀
- dfrobot光子物聯(lián)網(wǎng)開(kāi)發(fā)板簡(jiǎn)介 2231次閱讀
- 源創(chuàng)通信 BPI-P2 Zero 四核開(kāi)源物聯(lián)網(wǎng)開(kāi)發(fā)板介紹 2716次閱讀
- 物聯(lián)網(wǎng)十大經(jīng)典開(kāi)源操作系統(tǒng) 1w次閱讀
- 農(nóng)業(yè)物聯(lián)網(wǎng)的意義_農(nóng)業(yè)物聯(lián)網(wǎng)的功能_農(nóng)業(yè)物聯(lián)網(wǎng)的應(yīng)用 9899次閱讀
- 工業(yè)物聯(lián)網(wǎng)的意義_工業(yè)物聯(lián)網(wǎng)前景分析 1.2w次閱讀
- 蜂窩物聯(lián)網(wǎng)是什么_蜂窩物聯(lián)網(wǎng)建設(shè)意義 1.4w次閱讀
- 分析智能馬桶蓋的電子組件和電路圖 4.5w次閱讀
下載排行
本周
- 1山景DSP芯片AP8248A2數(shù)據(jù)手冊(cè)
- 1.06 MB | 532次下載 | 免費(fèi)
- 2RK3399完整板原理圖(支持平板,盒子VR)
- 3.28 MB | 339次下載 | 免費(fèi)
- 3TC358743XBG評(píng)估板參考手冊(cè)
- 1.36 MB | 330次下載 | 免費(fèi)
- 4DFM軟件使用教程
- 0.84 MB | 295次下載 | 免費(fèi)
- 5元宇宙深度解析—未來(lái)的未來(lái)-風(fēng)口還是泡沫
- 6.40 MB | 227次下載 | 免費(fèi)
- 6迪文DGUS開(kāi)發(fā)指南
- 31.67 MB | 194次下載 | 免費(fèi)
- 7元宇宙底層硬件系列報(bào)告
- 13.42 MB | 182次下載 | 免費(fèi)
- 8FP5207XR-G1中文應(yīng)用手冊(cè)
- 1.09 MB | 178次下載 | 免費(fèi)
本月
- 1OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費(fèi)
- 2555集成電路應(yīng)用800例(新編版)
- 0.00 MB | 33566次下載 | 免費(fèi)
- 3接口電路圖大全
- 未知 | 30323次下載 | 免費(fèi)
- 4開(kāi)關(guān)電源設(shè)計(jì)實(shí)例指南
- 未知 | 21549次下載 | 免費(fèi)
- 5電氣工程師手冊(cè)免費(fèi)下載(新編第二版pdf電子書(shū))
- 0.00 MB | 15349次下載 | 免費(fèi)
- 6數(shù)字電路基礎(chǔ)pdf(下載)
- 未知 | 13750次下載 | 免費(fèi)
- 7電子制作實(shí)例集錦 下載
- 未知 | 8113次下載 | 免費(fèi)
- 8《LED驅(qū)動(dòng)電路設(shè)計(jì)》 溫德?tīng)栔?/a>
- 0.00 MB | 6656次下載 | 免費(fèi)
總榜
- 1matlab軟件下載入口
- 未知 | 935054次下載 | 免費(fèi)
- 2protel99se軟件下載(可英文版轉(zhuǎn)中文版)
- 78.1 MB | 537798次下載 | 免費(fèi)
- 3MATLAB 7.1 下載 (含軟件介紹)
- 未知 | 420027次下載 | 免費(fèi)
- 4OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費(fèi)
- 5Altium DXP2002下載入口
- 未知 | 233046次下載 | 免費(fèi)
- 6電路仿真軟件multisim 10.0免費(fèi)下載
- 340992 | 191187次下載 | 免費(fèi)
- 7十天學(xué)會(huì)AVR單片機(jī)與C語(yǔ)言視頻教程 下載
- 158M | 183279次下載 | 免費(fèi)
- 8proe5.0野火版下載(中文版免費(fèi)下載)
- 未知 | 138040次下載 | 免費(fèi)
評(píng)論