電子發(fā)燒友App

硬聲App

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示
創(chuàng)作
電子發(fā)燒友網(wǎng)>電子資料下載>電子資料>物聯(lián)網(wǎng)健康馬桶開源分享

物聯(lián)網(wǎng)健康馬桶開源分享

2022-11-07 | zip | 1.11 MB | 次下載 | 2積分

資料介紹

描述

介紹

由于文明的發(fā)展以及工業(yè)和汽車的不潔排放量增加,大氣狀況每年都在惡化。盡管空氣是生命不可缺少的資源,但許多人對空氣污染的嚴(yán)重程度漠不關(guān)心,或者直到最近才意識到這個問題。在水、土壤、熱、噪聲等各類污染物中,空氣污染是最危險、最嚴(yán)重的,它會引起氣候變化和危及生命的疾病。根據(jù)世界衛(wèi)生組織 (WHO) 的數(shù)據(jù),現(xiàn)在 90% 的人口呼吸著被污染的空氣,空氣污染是每年 700 萬人死亡的原因。污染對健康的影響非常嚴(yán)重,會導(dǎo)致中風(fēng)、肺癌和心臟病。此外,空氣污染物對人類和地球生態(tài)系統(tǒng)有負(fù)面影響。

根據(jù)美國環(huán)境保護署 (EPA) 的數(shù)據(jù),室內(nèi)空氣的污染程度是室外空氣的 100 倍。大多數(shù)現(xiàn)代人將 80% 到 90% 的時間花在室內(nèi);在這次 COVID-19 大流行中,發(fā)病率甚至更高,全世界所有人的情況都是一樣的。因此,室內(nèi)空氣比室外空氣對人體健康的直接影響更大。此外,與大氣污染相比,室內(nèi)污染物傳播到肺部的可能性要高出約 1000 倍,從而導(dǎo)致病態(tài)建筑綜合癥、多重化學(xué)敏感性和頭暈等疾病。

廁所是公共設(shè)施之一,是人們經(jīng)常使用的公共設(shè)施之一,位于室內(nèi)。因此,保持廁所良好的空氣質(zhì)量對于保持廁所衛(wèi)生和衛(wèi)生至關(guān)重要。這與威爾克提到的說法一致,“為了創(chuàng)造一個更健康、更安全的環(huán)境,第一步是在洗手間?!?空氣質(zhì)量差的廁所可能是微生物、空氣傳播細(xì)菌的理想場所,最近還添加了 COVID-19 來傳播。

我的健康廁所項目和動機

通風(fēng)不足、人流量大、公廁管理不善是公廁室內(nèi)空氣污染的主要來源。為減少接觸空氣污染,可以采取新措施,包括開發(fā)空氣質(zhì)量測量設(shè)備、持續(xù)監(jiān)測空氣質(zhì)量數(shù)據(jù),以及根據(jù)數(shù)據(jù)采取必要措施。

物聯(lián)網(wǎng)IoT)和云計算揭示了各個領(lǐng)域?qū)崟r監(jiān)控的新能力。由于這些技術(shù)采用無線傳感器網(wǎng)絡(luò)來自動傳輸、處理、分析和可視化數(shù)據(jù),因此融合這些新技術(shù)也可以為改善室內(nèi)空氣質(zhì)量提供巨大優(yōu)勢。

pYYBAGNke9uABCmaAAFWBURt1ec134.jpg
?

必須衡量用戶使用廁所的滿意度,才能對廁所進行適當(dāng)?shù)墓芾怼?/font>通常,馬桶會以固定的時間間隔進行清潔,但有時即使還沒有清潔計劃,馬桶也需要清潔,因為這會給用戶帶來不適。分析空氣質(zhì)量數(shù)據(jù),可以在廁所需要清潔時檢測到這種情況。

通風(fēng)可以通過降低室內(nèi)空氣污染物和 COVID-19 等病毒的濃度來提高舒適度并改善室內(nèi)空氣質(zhì)量 (IAQ)。但通風(fēng)涉及電力消耗,需要高效智能運行以節(jié)省能源。

該項目意義重大,因為它通過通知廁所服務(wù)員或所有者何時需要清潔來幫助保持公共/私人廁所的清潔和良好的空氣質(zhì)量。它還根據(jù)空氣質(zhì)量數(shù)據(jù)智能地操作排氣扇,以保持馬桶內(nèi)的舒適環(huán)境,從而將能耗降至最低。基于云的機器學(xué)習(xí)用于分析數(shù)據(jù)并做出決策。

健康廁所項目特點

  • 將重要的空氣質(zhì)量數(shù)據(jù)(溫度、濕度、氨氣、二氧化硫、一氧化碳、二氧化氮、甲烷和噪音水平)安全地發(fā)布到 AWS。
  • 分析空氣質(zhì)量數(shù)據(jù)并根據(jù)參數(shù)對排氣扇進行無線控制,以保持廁所內(nèi)舒適健康的環(huán)境,并且非常有效地消耗最少的能量。
  • 使用機器學(xué)習(xí),進一步分析數(shù)據(jù)以持續(xù)監(jiān)控排氣扇是否能夠維持健康的環(huán)境。如果污染程度如此之高,以至于排氣扇和通風(fēng)系統(tǒng)無法保持舒適和衛(wèi)生,則會將手動清潔請求發(fā)送到清潔人員或當(dāng)局的電子郵件中。
  • 將機器學(xué)習(xí)應(yīng)用于噪音水平和其他參數(shù),檢測到漏水并向業(yè)主發(fā)送通知。
  • 根據(jù)內(nèi)部空氣的狀況,系統(tǒng)會產(chǎn)生顏色信號,以便用戶知道馬桶是否可以安全使用。綠燈意味著廁所環(huán)境使用起來安全舒適。黃燈表示空氣不夠好,用戶應(yīng)等到排氣扇將其恢復(fù)到更好的狀態(tài)。紅燈表示廁所在有人清理之前無法使用。

健康馬桶如何運作?

該項目的完整框圖如下所示。所有的傳感器都是

pYYBAGNke-aAU8uzAAK2TZ0QqQA681.jpg
物聯(lián)網(wǎng)健康馬桶框圖
?

通過端口 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ù)存儲到 AWS S3,并根據(jù)數(shù)據(jù)準(zhǔn)備數(shù)據(jù)集。AWS SageMaker 使用該數(shù)據(jù)集并構(gòu)建機器學(xué)習(xí)模型,以根據(jù) Core2 發(fā)布的未來數(shù)據(jù)確定廁所狀態(tài)(是否干凈或需要清潔)。一個單獨的規(guī)則調(diào)用 Lambda 函數(shù)來使用 ML 模型讀取新空氣質(zhì)量數(shù)據(jù)的預(yù)測。然后,該規(guī)則會根據(jù)預(yù)測結(jié)果更新設(shè)備影子,并且設(shè)備會收到有關(guān)當(dāng)前狀態(tài)的通知。

如果需要清潔馬桶或有任何漏水,則使用另一個 IoT 規(guī)則使用 AWS SNS 向用戶發(fā)送電子郵件/短信通知。Lambda 函數(shù)用于從原始 JSON 數(shù)據(jù)格式化電子郵件。

按照相同的程序,從噪音數(shù)據(jù)中檢測到漏水,并通過電子郵件/短信通知業(yè)主。

專用的 IoT 規(guī)則用于根據(jù)空氣質(zhì)量數(shù)據(jù)確定排氣扇狀態(tài),IoT Core 將數(shù)據(jù)發(fā)送到排氣扇的單獨主題集。我們對項目現(xiàn)在如何運作有了一個基本的了解,

讓我們成功吧

連接硬件

主要硬件是 Core2 EduKit 和傳感器。我使用 DHT11 傳感器收集溫度和濕度,使用 MICS6814 傳感器檢測一氧化碳、二氧化氮、氨和甲烷。該傳感器通過三個獨立的模擬通道提供數(shù)據(jù)。為了測量二氧化硫,我使用了 2SH12 傳感器,它還提供模擬數(shù)據(jù)。因此,為了將這兩個傳感器連接到 Core2 套件,我使用了 4 通道 16 位 I2C ADC (ADS1115) 模塊。我將此模塊連接到 Core2 Kit 的端口 A。此端口支持 I2C

poYBAGNke-mAO8mmAAGHETvgN9Q215.png
項目中使用的組件
?

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

pYYBAGNke-uAE6nCAABHpXfwSRc645.jpg
格羅夫電纜
?

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

?
?
?
poYBAGNke--ANmHiAAJ-s2MQsNg469.jpg
?
1 / 2
?

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

pYYBAGNke_OAPcP5AATIL3o8Rcs817.jpg
焊接排針
?

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

pYYBAGNke_iAAGuFAAZjYvWDRnQ746.jpg
連接到 PCB 的 AD 傳感器
?

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

poYBAGNke_6AMFCRAAkLcIgaCa8313.jpg
將傳感器連接到 Core2 套件
?

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

poYBAGNkfASAMNOXAARIAV_pUDE347.jpg
原理圖,示意圖
?

通風(fēng)/排氣扇的連接

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

pYYBAGNkfAyAb3vXAAE6B1MAfJk490.jpg
排氣扇示意圖
?

我為什么選擇那些特定的傳感器?

我選擇了一些重要的傳感器來測量廁所內(nèi)的空氣質(zhì)量。對馬桶來說重要的參數(shù)是氨、二氧化硫、二氧化碳、甲烷、溫度、濕度等。

二氧化硫 (SO2):二氧化硫是一種無色、具有強烈氣味的活性空氣污染物。這種氣體可能對人類健康、動物健康和植物生命構(gòu)成威脅。二氧化硫會刺激眼睛、鼻子、喉嚨和肺部的皮膚和粘膜。高濃度的 SO2 會引起呼吸系統(tǒng)的炎癥和刺激,尤其是在劇烈的體力活動期間。由此產(chǎn)生的癥狀可能包括深呼吸時的疼痛、咳嗽、喉嚨發(fā)炎和呼吸困難。高濃度的 SO2 會影響肺功能,加重哮喘發(fā)作,并加重敏感人群現(xiàn)有的心臟病。這種氣體還可以與空氣中的其他化學(xué)物質(zhì)發(fā)生反應(yīng),變成可以進入肺部并造成類似健康影響的小顆粒。超過1.0 ppm被認(rèn)為是不健康的。

氨 (NH3):氨是一種無色氣體,具有強烈、刺鼻的刺激性氣味。它通常用于水溶液、肥料、制冷劑、紡織品等。氨會在吸入時影響您。接觸會嚴(yán)重刺激和灼傷皮膚和眼睛,并可能對眼睛造成傷害。吸入氨水會刺激鼻子、喉嚨和肺部。反復(fù)接觸可能會導(dǎo)致哮喘樣過敏并導(dǎo)致肺損傷。超過25 ppm會產(chǎn)生上述癥狀。

一氧化碳(CO):一氧化碳 (CO) 是一種無色無味的氣體。它存在于加熱器、壁爐、汽車消音器、空間加熱器、木炭烤架、汽車發(fā)動機等產(chǎn)生的燃燒(廢氣)煙霧中。每個人全天都接觸到少量的一氧化碳。然而,吸入過多會導(dǎo)致一氧化碳中毒。當(dāng)燃燒煙霧被困在通風(fēng)不良或封閉的空間(如車庫)時,一氧化碳可能會增加到危險水平。吸入這些煙霧會導(dǎo)致一氧化碳在您的血液中積聚,從而導(dǎo)致嚴(yán)重的組織損傷。一氧化碳中毒非常嚴(yán)重,可能危及生命。如果您吸入大量一氧化碳,您的身體將開始用一氧化碳替換血液中的氧氣。當(dāng)這種情況發(fā)生時,您可能會失去知覺。在這些情況下可能會發(fā)生死亡。一旦 CO 水平增加到百萬分之 70 (ppm)及以上,癥狀變得更加明顯。這些癥狀可能包括惡心、頭暈和無意識。

CO2(二氧化碳)是呼吸的副產(chǎn)品,其生物效應(yīng)與 CO(一氧化碳)非常不同,CO(一氧化碳)是碳?xì)浠衔锶紵母碑a(chǎn)品,例如燃?xì)庠詈腿細(xì)饣蛉加湾仩t。一氧化碳(但不是二氧化碳)會在通風(fēng)不良的家中迅速積聚,而且是致命的。這就是為什么建議對室內(nèi)條件進行 CO(一氧化碳)監(jiān)測的原因。

二氧化氮 (NO2):NO2 是最常見和研究最充分的污染物之一。接觸二氧化氮——即使是短期接觸的小幅增加——也會加劇呼吸系統(tǒng)問題,尤其是哮喘,尤其是兒童。長期接觸二氧化氮會導(dǎo)致“心血管影響、糖尿病、較差的出生結(jié)果、過早死亡和癌癥”。研究已將持續(xù)的二氧化氮暴露與認(rèn)知能力下降聯(lián)系起來,尤其是在兒童中。

為 Core2 AWS EduKit 開發(fā)代碼

完成硬件連接后,下一步是為 Core2 AWS EduKit 開發(fā)固件。為此,請按順序執(zhí)行所有步驟。

第 1 步:完成Cloud Connected Blinky示例

在進一步繼續(xù)之前,您必須從官方鏈接完成Cloud Connected Blinky示例。教程解釋得很好,如果您有嵌入式系統(tǒng)和 AWS 云的基本知識,您應(yīng)該不會遇到任何困難。此處使用的所有步驟和技能將為在本教程中取得成功奠定基礎(chǔ)。具體來說,您將:

第 2 步:完成智能恒溫器示例

下一步是打開、編譯和測試官方智能恒溫器固件。我們將使用此代碼作為我們代碼的模板。因此,在開始修改代碼之前,我們希望通過運行 Core2 套件中的固件來確保一切正常。在進行下一步之前,這也是一個解釋得很好且易于理解的教程。

在該教程結(jié)束時,您將了解:

  • 如何從 Core2 for AWS IoT EduKit 設(shè)備獲取溫度和聲級。
  • MQTT 的工作原理以及如何使用 MQTT 將溫度和聲音測量值從設(shè)備發(fā)布到 AWS IoT Core。
  • 什么是設(shè)備影子以及如何將測量值報告給設(shè)備影子?
  • 如何使用 AWS IoT Core 規(guī)則引擎執(zhí)行消息轉(zhuǎn)換。
  • 如何構(gòu)建響應(yīng)輸入和檢測復(fù)雜事件的無服務(wù)器應(yīng)用程序。
  • 如何通過設(shè)備影子向您的設(shè)備發(fā)送命令。

第 3 步:為 Core2 AWS IoT EduKit 開發(fā)固件

正如我已經(jīng)說過的,我們將使用智能恒溫器固件作為開發(fā)我們自己的固件的模板。因此,我假設(shè)您已經(jīng)成功編譯和測試了該固件。您可以像示例程序一樣直接從 GitHub 下載和使用我修改后的固件(鏈接附在代碼部分),也可以按照以下步驟自行自定義智能恒溫器示例。

由于我們將使用一些外部傳感器,我們需要編寫代碼來連接這些傳感器。我為 Core2 IoT EduKit 開發(fā)了(實際上是修改了現(xiàn)有的 Arduino 庫)兩個庫。一個用于 DHT11 溫度和濕度傳感器,另一個用于 ADS1115 I2C 模數(shù)轉(zhuǎn)換器模塊。按照接下來的步驟了解該過程。

步驟 3.1:創(chuàng)建庫

為了創(chuàng)建一個庫,我們需要創(chuàng)建兩個文件。一個是C頭文件,我們需要將它添加到主目錄的include子目錄中。另一個是C源文件需要添加到主目錄的根目錄。所以,讓我們先創(chuàng)建一個頭文件(.h)文件。

步驟 3.1.1:轉(zhuǎn)到資源管理器->->包含并單擊鼠標(biāo)右鍵并選擇新建文件

poYBAGNkfBCASxDoAAEq-CsY-Nc814.png
?

輸入帶有 ah 擴展名的名稱,然后從鍵盤按 Enter。例如dht11.h.

poYBAGNkfBOAPzHXAABQphC2RPw522.png
?

步驟 3.1.2:單擊文件將其打開并在那里寫入或粘貼您的代碼。

pYYBAGNkfBWAK01KAAEPx7TdVD0885.png
?

例如,我為我的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)在我們將為庫創(chuàng)建 C 源文件。

步驟 3.1.4:轉(zhuǎn)到explorer -> main并單擊鼠標(biāo)右鍵并選擇New File

poYBAGNkfBeAF95UAACgbdSEZ6k815.png
?

輸入一個帶有 ac 擴展名的名稱,然后從鍵盤上按回車鍵。例如dht11.c.

poYBAGNkfBuAeW-MAABfylZOhsI173.png
?

步驟 3.1.5:單擊文件將其打開,然后在編輯器中編寫或粘貼代碼。

poYBAGNkfB6ASJptAAD0nHjGeQk432.png
?

例如,我為我的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保存文件。我們的庫創(chuàng)建完成。

步驟 3.1.7:將新創(chuàng)建的源文件添加到CMakeList. 單擊CMakeLists.txt將其打開并添加您的庫源文件的名稱,如下面的屏幕截圖所示。

pYYBAGNkfCGAF4MiAACVlu3edhc296.png
?

現(xiàn)在,您可以使用您的庫了。按照相同的過程根據(jù)需要創(chuàng)建更多庫。例如我們案例中的 ADS1115 庫。該庫的所有源文件都添加到代碼部分以及 GitHub 存儲庫中。

步驟 3.2:測試庫

讓我們測試我們創(chuàng)建的 dht11 庫以了解它是否正常工作。它還將證明我們的 DHT11 傳感器的工作原理。

步驟 3.2.1:打開main.c文件,使用Ctrl+A選擇整個代碼,然后使用Ctrl+X剪切代碼,使用Ctrl+V將代碼粘貼到記事本文本文件中并保存。我們將再次使用它。

步驟 3.2.2:將以下代碼片段粘貼到main.c文件中。此代碼將使用新創(chuàng)建的 dht11 庫從 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:打開一個新終端并鍵入pio run --environment core2foraws以構(gòu)建程序。

poYBAGNkfCSAfQ_QAADfsKCDkPw580.png
?

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

pYYBAGNkfCeAWZp0AABb21PX6a0526.png
?

步驟 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é)果,那么恭喜!您的磁帶庫和 DHT11 傳感器都運行良好。

poYBAGNkfCqARw1nAACdPNRULew751.png
?

步驟 3.3:修改 main.c 文件

將新的main.c源代碼替換為我們存儲在記事本文件中的原始main.c源代碼。由于我們要發(fā)布比演示項目更多的數(shù)據(jù),我們需要增加 JSON 緩沖區(qū)大小,如下所示:

#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 300

添加了以下變量用于存儲空氣質(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來打包我們所有的傳感器值。因此,已創(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;

以下第一個函數(shù)將我們想要發(fā)布到云的任何值打包到 IoT Core 影子服務(wù)所期望的影子文檔中。第二個函數(shù)實際上將封送的影子文檔作為有效負(fù)載通過網(wǎng)絡(luò)發(fā)布到 IoT Core 的主題上$aws/things/<>/shadow/update,其中<>每個設(shè)備的唯一 ID。這兩個函數(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è)備接收到包含鍵值對的新消息時執(zhí)行的代碼。state.desired.toilet_status廁所狀態(tài)是根據(jù)空氣質(zhì)量數(shù)據(jù)從 ML 模型中確定的。根據(jù) IoT Core 返回的狀態(tài),顏色會發(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();
    }
}

使用以下兩個函數(shù)來讀取溫度和空氣質(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:測試固件

完成所有修改后,構(gòu)建程序并將其上傳到 Core2。將 I2C 傳感器連接到端口 A,將 DHT11 傳感器連接到端口 B,然后運行調(diào)試終端來監(jiān)控輸出。

?
?
?
pYYBAGNkfDCAZF07AAy8Wng_j_8861.jpg
?
1 / 2
?

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

poYBAGNkfDOAdxGiAAF-sGE4Prw263.png
?

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

poYBAGNkfDeAQwhOAACcKQFpY04065.png
?

在 AWS IoT Core 控制臺測試頁面中,單擊 Publish to a topic 選項卡并在該主題上發(fā)布以下新影子消息$aws/things/<>/shadow/update。您應(yīng)該會看到 Core for AWS IoT EduKit 的 LED 條從綠色變?yōu)榧t色。請參閱下面的示例影子消息。每次發(fā)布消息時,通過更改廁所狀態(tài)(設(shè)置為BUSYREADY )和/或fan_status值(設(shè)置為truefalse )來測試效果。

{ "state": { "desired": { "toilet_status": "UNCLEAN", "fan_status": true } } }
poYBAGNkfDmAWuIXAACvwY5IhCE290.png
?

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

pYYBAGNkfDyAFmhOAAFYNFKuy5o502.png
?

從設(shè)備方面來看,一切都很好。現(xiàn)在我們將配置 AWS IoT Cloud 以轉(zhuǎn)換和路由從設(shè)備接收的數(shù)據(jù)。

開發(fā)機器學(xué)習(xí)模型以自動檢測廁所狀態(tài)(UNCLEAN、BUSY、READY)

我們正在為我們的項目考慮廁所的三種狀態(tài)。一種是就緒狀態(tài),表示空氣質(zhì)量數(shù)據(jù)良好,馬桶使用安全舒適。在這種情況下,LED 條顯示綠燈。另一種狀態(tài)是BUSY狀態(tài)。當(dāng)某些空氣質(zhì)量參數(shù)不夠好時,用戶可能會感到不舒服。可能的原因可能是存在較高的濕度、氣味或難聞的氣味。在這種情況下,運行排氣扇幾分鐘可以使情況變得更好。因此,這是不建議使用馬桶時的狀態(tài),系統(tǒng)會通過花一些時間和運行風(fēng)扇來嘗試使其變得更好。在此狀態(tài)下啟用黃燈。另一種狀態(tài)是 UNCLEAN 狀態(tài),此時某些空氣參數(shù)不在可容忍的范圍內(nèi),在這種情況下使用馬桶會產(chǎn)生健康問題。即使只有通風(fēng)也不足以使其變得更好,但需要清潔工手動清潔。設(shè)備在此狀態(tài)下顯示紅燈,并通過電子郵件向相關(guān)人員發(fā)送清潔請求。

問題是這三種狀態(tài)的確定并不容易。沒有公式可以找到廁所處于哪種狀態(tài)。感謝機器學(xué)習(xí)。一個簡單的機器學(xué)習(xí)模型可以幫助從空氣質(zhì)量數(shù)據(jù)的分類中智能地識別狀態(tài)。同樣,訓(xùn)練機器學(xué)習(xí)模型并不容易,構(gòu)建一個好的模型需要專業(yè)知識、對輸入的全面理解,以及經(jīng)過多個周期的努力來優(yōu)化它。但如今,借助現(xiàn)代數(shù)據(jù)科學(xué)工具鏈,無需任何 ML 專業(yè)知識即可制作 ML 模型,而 Amazon SageMaker 工具鏈就是其中之一,但我們不能指望第一次嘗試就能生成一個好的模型。

為了建立一個好的模型,我們需要大量的數(shù)據(jù)。越多越好。構(gòu)建 ML 模型是一個兩步過程,收集數(shù)據(jù)和訓(xùn)練模型。為了準(zhǔn)確檢測,我們需要為每種情況收集大量數(shù)據(jù),之前討論過的三種狀態(tài)。因此,我們需要在干凈的馬桶中部署我們的設(shè)備至少幾個小時(最好是 24 小時),在不舒服的馬桶中部署幾個小時,在不衛(wèi)生的馬桶中部署幾個小時,以收集足夠的數(shù)據(jù)來構(gòu)建準(zhǔn)確的 ML 模型。第二個不干涉步驟是在您收集到足夠的數(shù)據(jù)后,ML 模型正在經(jīng)歷一個自動訓(xùn)練過程。此培訓(xùn)過程可能需要幾個小時,我們建議您在早上開始,下午返回,或者讓它運行一整夜。

我們將使用設(shè)備遙測的聚合數(shù)據(jù)集來支持自動 ML 訓(xùn)練實驗,然后使用從訓(xùn)練的 ML 模型推斷出的新廁所狀態(tài)值對新設(shè)備報告進行分類。

poYBAGNkfD6AIWYXAADJsl2W8No198.png
?

我們將遵循的工作流程具有以下關(guān)鍵組件:

  • 我們將創(chuàng)建一個新的 IoT Core 規(guī)則,它將報告的設(shè)備數(shù)據(jù)轉(zhuǎn)發(fā)到名為 AWS IoT Analytics 的服務(wù)。IoT Analytics 服務(wù)批量存儲原始 IoT 數(shù)據(jù),對其進行轉(zhuǎn)換和清理以將原始數(shù)據(jù)轉(zhuǎn)換為處理后的數(shù)據(jù),并提供查詢引擎來對處理后的數(shù)據(jù)進行切片,以用于分析工作流或 ML 訓(xùn)練。
  • 我們的 IoT Analytics 項目將包含四個鏈接在一起的資源:一個用于存儲來自設(shè)備影子的原始 IoT 數(shù)據(jù)的通道、一個用于轉(zhuǎn)換/過濾/豐富數(shù)據(jù)的管道、一個用于處理數(shù)據(jù)的數(shù)據(jù)存儲,以及一個運行保存的查詢和可以發(fā)送結(jié)果進行處理。
  • Amazon SageMaker Studio 是一個集成的機器學(xué)習(xí)環(huán)境,您可以在其中構(gòu)建、訓(xùn)練、部署和分析您的模型,所有這些都在同一個應(yīng)用程序中進行。
  • 一個 Amazon SageMaker 終端節(jié)點,將您的訓(xùn)練模型作為可使用的 API 托管。
  • 我們將創(chuàng)建一個 AWS Lambda 函數(shù),該函數(shù)將運行一些簡單的代碼來處理已發(fā)布的消息并對我們的新 ML 模型端點進行推理。

步驟 1:創(chuàng)建 IoT Core 規(guī)則以將遙測數(shù)據(jù)轉(zhuǎn)發(fā)到 IoT Analytics

  • 一世。AWS IoT Core 控制臺中,依次選擇Act Rules和Create 。
  • ii. 給你的規(guī)則起一個名字,比如廁所DataToAnalyticsForState和描述。
  • iii. 使用以下查詢。請務(wù)必將?CLIENT_ID?替換為打印在 Core2 for AWS IoT Edukit 參考硬件套件屏幕上的客戶端 ID/序列號。
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è)置一項或多項操作選擇添加操作。
  • v.選擇向 IoT Analytics 發(fā)送消息,然后選擇配置操作
  • 六。選擇快速創(chuàng)建 IoT Analytics 資源并為Resource prefix提供項目名稱。進一步的模塊步驟假設(shè)前綴是toiletAnalyticsResourceForState。選擇快速創(chuàng)建,您的所有 AWS IoT Analytics 資源將自動創(chuàng)建和配置。
  • 七。選擇添加操作以配置此操作并返回到規(guī)則創(chuàng)建表單。
  • 八。選擇創(chuàng)建規(guī)則以創(chuàng)建新規(guī)則。

驗證步驟

在繼續(xù)下一章之前,您可以驗證您的無服務(wù)器應(yīng)用程序是否按預(yù)期配置:

  • 確保您的 Core2 設(shè)備已開機、發(fā)布數(shù)據(jù)并部署在您要訓(xùn)練的廁所中。
  • 使用 AWS IoT Analytics 控制臺,查看最新的數(shù)據(jù)集內(nèi)容,并驗證所有參數(shù)(如溫度、濕度、氨氣、二氧化硫等)的歷史記錄以及時間戳。要檢查這一點,請在IoT Analytics 控制臺中找到您的數(shù)據(jù)集,選擇ActionsRun now ,然后等待查詢完成。在“內(nèi)容”選項卡中,單擊最近創(chuàng)建的包含最新內(nèi)容的內(nèi)容預(yù)覽。您應(yīng)該會看到類似于以下內(nèi)容的結(jié)果:
pYYBAGNkfEKAMyZLAAC2POW2924163.png
?
poYBAGNkfEiAGgUMAAFxQUgNu-o489.png
?

第 2 步:設(shè)置 Amazon SageMaker Studio 以進行自動模型訓(xùn)練

首先,您將設(shè)置 Amazon SageMaker Studio,以便為自動模型訓(xùn)練配置新實驗。

  • 一世。轉(zhuǎn)到 Amazon SageMaker 控制臺并選擇Amazon SageMaker Studio 。
  • ii. 選擇Quick start并可選擇輸入一個新的用戶名,如廁所狀態(tài)用戶。
  • iii. 對于Execution role選擇下拉菜單并選擇Create a new IAM role
  • iv. 對于您指定的 S3 存儲桶,選擇None ,然后選擇Create role 。名稱中帶有“sagemaker”的存儲桶的其他默認(rèn)值足以滿足此項目。
  • v.選擇提交以開始 SageMaker Studio 的配置過程。代表您完成此步驟需要幾分鐘時間。

步驟 3:在 SageMaker Studio中配置新項目

  • 一世。從 SageMaker Studio 控制面板中,為新創(chuàng)建的用戶選擇打開 Studio 。
  • ii. 在 Launcher 選項卡中,選擇New project 。
  • iii. SageMaker 項目模板下,選擇用于模型構(gòu)建、訓(xùn)練和部署的 MLOps 模板,然后選擇選擇項目模板。
pYYBAGNkfEuANBRQAAE4dO1IRts258.png
?
pYYBAGNkfE2AGe8KAAFGG-bXmVs258.png
?
  • iv. 給你的項目起一個名字,比如廁所StateSageMakerProject和描述,然后選擇Create project 。

創(chuàng)建項目后,我們將獲得一個項目儀表板,其中包含存儲庫、管道、實驗等選項卡。讓我們將此瀏覽器選項卡對 SageMaker Studio 保持打開狀態(tài),以便您可以快速返回此頁面。

步驟 4:導(dǎo)出 AWS IoT Analytics 數(shù)據(jù)

  • 一世。打開AWS IoT Analytics 控制臺并選擇您的數(shù)據(jù)集(假定名稱為Toiletanalyticsresourceforstate_dataset)。
  • ii. 數(shù)據(jù)集內(nèi)容交付規(guī)則下選擇編輯。
  • iii. 選擇Add rule ,然后選擇Deliver result to S3 。
  • iv. S3 存儲桶下選擇請選擇一個資源并找到為您的 SageMaker Studio 項目創(chuàng)建的 S3 存儲桶。它將被命名為sagemaker-project-p-wzq6773hm0gv. 如果有多個這樣命名的存儲桶,您需要檢查 SageMaker Studio 項目以獲取項目的隨機哈希 ID。您可以在項目的其他資源(例如存儲庫和管道選項卡)中查看哈希值。
pYYBAGNkfFCALfxiAABgBgmwPgQ493.png
?
  • v.Bucket key 表達(dá)式下使用這個表達(dá)式:data/healthytoilet/Version/!{iotanalytics:scheduleTime}_!{iotanalytics:versionId}.csv
  • 六。Role下,選擇Create new并為 IAM 角色提供一個名稱,該角色將授予 IoT Analytics 訪問權(quán)限以將數(shù)據(jù)寫入您的 S3 存儲桶。選擇創(chuàng)建角色。
  • 七。選擇保存以完成新的遞送規(guī)則。
poYBAGNkfFaAFkrrAADICNq4tdo761.png
?
  • 八。要生成將保存到您的新 Amazon S3 存儲桶以進行訓(xùn)練的數(shù)據(jù)集,請選擇Actions然后Run now 。數(shù)據(jù)集內(nèi)容生成完成后,您應(yīng)該會看到結(jié)果預(yù)覽更新。

我們現(xiàn)在已準(zhǔn)備好在 SageMaker Studio 中開始您的 ML 實驗。實驗將使用我們的 IoT Analytics 數(shù)據(jù)集剛剛導(dǎo)出的報告恒溫器數(shù)據(jù)作為輸入。我們將配置實驗以尋找準(zhǔn)確預(yù)測現(xiàn)有廁所狀態(tài)列的方法。自動訓(xùn)練作業(yè)將分析您的數(shù)據(jù)以嘗試相關(guān)算法,然后運行 ??250 個具有不同超參數(shù)的訓(xùn)練作業(yè),選擇最適合您的輸入訓(xùn)練數(shù)據(jù)的一個。

在開始您的 ML 實驗之前,我們應(yīng)該從我們要分析的馬桶中的設(shè)備報告幾個小時的數(shù)據(jù),并且在那段時間馬桶應(yīng)該有準(zhǔn)備好的、忙碌的和不干凈的情況。一個自動 ML 實驗需要至少 500 行數(shù)據(jù)才能工作,但我們帶來的數(shù)據(jù)越多,結(jié)果就會越好。如果在繼續(xù)之前我們?nèi)孕枰筛鄶?shù)據(jù),我們需要重新運行 IoT Analytics 控制臺中的數(shù)據(jù)集(上一個指令列表的最后一步),以便我們的項目 S3 存儲桶中的 SageMaker 可以使用這些結(jié)果。

第 4 步:在 SageMaker Studio 中啟動 ML 實驗

  • 一世。返回您的 SageMaker Studio,打開您的項目,選擇Experiments選項卡并選擇Create autopilot Experiment 。
pYYBAGNkfFiAXCy7AAB6cvLAcKY797.png
?
  • ii. 為您的實驗命名。
  • iii. 項目下,從列表中選擇您的項目。
  • iv. 連接您的數(shù)據(jù)S3 存儲桶名稱下,在列表中找到并選擇您項目的 S3 存儲桶。這與您在上一步中為 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 存儲桶名稱下,在此列表中查找并選擇您在步驟 4 中選擇的相同項目 S3 存儲桶。
  • 八。Dataset directory name下輸入output/healthytoilet并選擇Use input as S3 object key prefix “output/healthytoilet” 。這會在 S3 存儲桶中定義一個新前綴,用于您的輸出文件。
  • 十四。選擇Create Experiment以啟動自動化 ML 實驗。
poYBAGNkfFuAYS9IAADO2yShQcM645.png
?
pYYBAGNkfF2AReyMAADY4FwD6G4047.png
?

運行實驗可能需要幾分鐘到幾小時。您可以在 SageMaker Studio 瀏覽器選項卡中跟蹤實驗的進度,但關(guān)閉選項卡并稍后返回查看進度也是安全的。

實驗結(jié)束后,結(jié)果輸出是 250 次試驗,SageMaker 使用這些試驗來尋找最佳調(diào)整作業(yè)參數(shù)。對試驗表進行排序以找到標(biāo)記為Best的那一項。下一個里程碑是將此試用版部署為模型端點,以便您可以將其作為 API 調(diào)用。

第 5 步:部署最佳 ML 模型

  • 一世。選擇標(biāo)記為Best的試用版,然后選擇Deploy model 。
poYBAGNkfGSASqDtAAEChho5bs0864.png
?
  • ii. 為您的端點命名。本模塊中的進一步步驟假定名稱 healthToiletStateEndpoint。
  • iii. Inference Response Content下,同時選擇predict_labelprobability 。predict_label可能已經(jīng)添加到列表中。
  • iv. 選擇部署模型以告訴 SageMaker 將您的模型部署為新的可消耗 API 端點。這將需要幾分鐘。
pYYBAGNkfGeAenkHAAChnpJl83o148.png
?

現(xiàn)在,您的機器學(xué)習(xí)模型已部署為 API 終端節(jié)點,由 Amazon SageMaker 管理。在下一章“使用 ML 模型”中,您將使用無服務(wù)器函數(shù)使用 API 端點,并用模型生成的推理替換 IoT Core 規(guī)則中確定值的簡單閾值邏輯。toilet_status

驗證步驟

在繼續(xù)下一步之前,您可以驗證您的無服務(wù)器應(yīng)用程序是否按預(yù)期配置......

poYBAGNkfGmAICEYAADzhYhDMKY176.png
?

第 6 步:設(shè)置 AWS Lambda 并調(diào)用 SageMaker Endpoint

以下步驟將引導(dǎo)我們在 AWS Lambda 中創(chuàng)建無服務(wù)器函數(shù)。該函數(shù)定義了一小段代碼,期望來自 IoT Core 的設(shè)備影子消息,將消息轉(zhuǎn)換為與我們的 ML 端點一起使用的格式,然后調(diào)用 ML 端點以返回廁所狀態(tài)的分類推理的置信度分?jǐn)?shù)。

  • 一世。在 AWS Lambda 控制臺中,選擇Create function 。
  • ii. 輸入函數(shù)的名稱。進一步的步驟假定名稱classifyToiletStatus
  • iii. 運行時,選擇Python 3.8
  • iv. 選擇創(chuàng)建函數(shù)。
poYBAGNkfG6AVWARAAEkkSWvqbk703.png
?
  • 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 選項卡下單擊Environment variables ,然后選擇Edit并添加一個新的環(huán)境變量。
poYBAGNkfHKAIERHAADEpEJAI7I306.png
?
  • 七。對于Key輸入SAGEMAKER_ENDPOINT,對于Value輸入您的 SageMaker 終端節(jié)點的名稱。您將此資源命名為部署模型的最后一步,并且此模塊假定名稱為healthyToiletStateEndpoint.
pYYBAGNkfHWADZ0ZAACNE8OMYRQ156.png
?
  • 八。選擇保存以提交此新環(huán)境變量并返回主 Lambda 編輯器界面。
  • 九。設(shè)計器面板中,選擇+ 添加觸發(fā)器。
  • X。對于觸發(fā)器配置,從列表中選擇AWS IoT 。
  • 十一。對于IoT 類型,選擇自定義 IoT 規(guī)則。
  • 十二。對于Rule ,選擇Create a new rule,提供一個角色名稱,如廁所IotLambdaInvoke并將以下文本粘貼到 Rule 查詢語句中。將 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ū)域,如控制臺標(biāo)題中所示(它必須是格式us-west-2而不是Oregon);將 ACCOUNT_ID 更改為您的 12 位帳戶 ID,不帶連字符,這也顯示在打印您的用戶名的控制臺標(biāo)題菜單中;并將 FUNCTION_NAME 更改為您創(chuàng)建的 AWS Lambda 函數(shù)的名稱(假定名稱為classifyToiletStatus)。不要忘記更新 FROM 主題中的 ?CLIENT_ID? 占位符。

poYBAGNkfHiAYuvNAADWg7KmqCY473.png
?
  • 十三。選擇權(quán)限選項卡,然后選擇角色名稱下的鏈接,以便您可以為此 Lambda 函數(shù)添??加權(quán)限以調(diào)用您的 SageMaker 終端節(jié)點。
  • 十四。從打開到 IAM 控制臺的新選項卡中,在Permissions policies下選擇Add inline policy 。
  • 十五。對于服務(wù),選擇SageMaker 。
  • 十六。對于操作,選擇InvokeEndpoint 。
  • 十七。對于資源,選擇所有資源。
  • 十八。選擇審查政策。
  • 十九。為您的策略命名,invokeSageMakerEndpoint然后選擇Create policy 。您現(xiàn)在可以關(guān)閉這個新的瀏覽器選項卡。

測試 Lambda 函數(shù)

  • 一世。轉(zhuǎn)到您的 Lambda 函數(shù)并選擇代碼選項卡。如果您沒有部署您的 Lambda 代碼,請單擊Deploy
pYYBAGNkfHqAWDVdAACZ7nT-lhA646.png
?
  • ii. 您將收到Changes 已部署的確認(rèn)信息。單擊測試并選擇配置測試事件。
poYBAGNkfH-AezqIAACf7GK2QmE851.png
?
  • 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)建。
poYBAGNkfIKAF8OMAAEF9OYq3jM873.png
?

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

{
  "statusCode": 200,
  "body": {
    "predicted_label": "READY",
    "probability": "0.4254942536354065"
  }
}
pYYBAGNkfISAWP7tAAFPgEcGpNo163.png
?

此時,我們的 IoT 工作流程現(xiàn)在正在使用來自其部署的端點的經(jīng)過訓(xùn)練的機器學(xué)習(xí)模型,以將設(shè)備發(fā)布的消息分類為新的廁所狀態(tài)值!

在廁所IotLambdaInvoke規(guī)則上添加操作

轉(zhuǎn)到toiletIotLambdaInvoke規(guī)則添加一個操作以根據(jù)預(yù)測更新設(shè)備陰影。

  • 選擇添加操作。
  • 選擇將消息重新發(fā)布到 AWS IoT 主題,然后選擇配置操作。
  • 對于主題,使用$$aws/things/<>/shadow/update. 請務(wù)必將?CLIENT_ID?替換為您設(shè)備的客戶端 ID/序列號。
  • 對于選擇或創(chuàng)建角色以授予 AWS IoT 訪問權(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ā)布遙測數(shù)據(jù)時,IoT 規(guī)則會觸發(fā) Lambda 函數(shù)來讀取 SageMaker 預(yù)測并相應(yīng)地更新設(shè)備影子。我們希望在廁所狀態(tài)預(yù)測級別為 UNCLEAN 時向涉及清潔的人員發(fā)送通知(電子郵件)。每次廁所狀態(tài)從另一個狀態(tài)變?yōu)?UNCLEAN 時,我們只想發(fā)送一封電子郵件。因此,我們將訂閱delta主題。

步驟1:創(chuàng)建發(fā)送 SMS 文本消息的 Amazon SNS 主題

創(chuàng)建一個 Amazon SNS 主題。

  • 登錄到Amazon SNS 控制臺。
  • 在左側(cè)導(dǎo)航窗格中,選擇主題。
  • 主題頁面上,選擇創(chuàng)建主題。
  • Details中,選擇Standard類型。默認(rèn)情況下,控制臺會創(chuàng)建一個 FIFO 主題。
  • Name中,輸入 SNS 主題名稱。對于本教程,輸入toiletUncleanNotice
  • 滾動到頁面末尾并選擇Create topic 。控制臺將打開新主題的詳細(xì)信息頁面。

創(chuàng)建 Amazon SNS 訂閱。

  • toiletUncleanNotice主題的詳細(xì)信息頁面中,選擇Create subscription 。
  • Create subscriptionDetails部分的Protocol列表中,選擇SMS 。
  • Endpoint中,輸入可以接收短信的電話號碼。確保輸入以 開頭+,包括國家和地區(qū)代碼,并且不包括任何其他標(biāo)點符號。
  • 選擇創(chuàng)建訂閱

測試 Amazon SNS 通知。

  • Amazon SNS 控制臺的左側(cè)導(dǎo)航窗格中,選擇主題。
  • 要打開主題的詳細(xì)信息頁面,請在主題列表中的主題列表中選擇toiletUncleanNotice。
  • 要打開Publish message to topic頁面,請在high_temp_notice詳細(xì)信息頁面中,選擇Publish message 。
  • Publish message to topicMessage body部分的Message body to send to the endpoint中,輸入一條短消息。
  • 向下滾動到頁面底部并選擇Publish message 。
  • 在您之前創(chuàng)建訂閱時使用的號碼的手機上,確認(rèn)已收到消息。

如果您沒有收到測試消息,請仔細(xì)檢查電話號碼和手機設(shè)置。

步驟2:創(chuàng)建 AWS IoT 規(guī)則以發(fā)送短信

  • AWS IoT Core 控制臺中,依次選擇Act Rules和Create 。
  • 為您的規(guī)則命名,如sendSnsUnclean和描述。
  • 使用以下查詢。請務(wù)必將?CLIENT_ID?替換為打印在 Core2 for AWS IoT Edukit 參考硬件套件屏幕上的客戶端 ID/序列號。
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)從另一個狀態(tài)變?yōu)榱硪粋€狀態(tài)時,上述查詢語句將生成以下 JSON 消息UNCLEAN。

{
  "state": {
    "toilet_status": "UNCLEAN"
  }
}
  • 要打開此規(guī)則的規(guī)則操作列表,請在設(shè)置一個或多個操作中,選擇添加操作。
  • 選擇操作中,選擇將消息作為 SNS 推送通知發(fā)送。
  • 要打開所選操作的配置頁面,請在操作列表底部選擇配置操作。
  • 配置操作中
  • SNS 目標(biāo)中,選擇Select ,找到名為high_temp_notice的 SNS 主題,然后選擇Select 。
  • 消息格式中,選擇RAW 。
  • 選擇或創(chuàng)建角色以授予 AWS IoT 訪問權(quán)限以執(zhí)行此操作中,選擇創(chuàng)建角色
  • Create a new role 中,在Name中,輸入新角色的唯一名稱。對于本教程,使用sns_rule_role.
  • 選擇創(chuàng)建角色。

此規(guī)則將以原始 JSON 格式發(fā)送電子郵件。我們可以使用 Lambda 將其格式化為用戶友好的格式。在這種情況下,我們將選擇向 Lambda 函數(shù)發(fā)送消息,而不是作為規(guī)則操作將消息作為 SNS 推送通知發(fā)送,并且 Lambda 會將消息作為 SNS 發(fā)送。所以讓我們先創(chuàng)建一個 Lambda 函數(shù)。

使用 AWS Lambda 函數(shù)格式化通知

上面的教程是關(guān)于如何發(fā)送 Amazon SNS 通知,由規(guī)則的查詢語句產(chǎn)生的 JSON 文檔作為文本消息的正文發(fā)送。結(jié)果是一條類似于以下示例的文本消息:

{
  "state": {
    "toilet_status": "UNCLEAN"
  }
}

在本教程中,您將使用 AWS Lambda 規(guī)則操作來調(diào)用 AWS Lambda 函數(shù),該函數(shù)將規(guī)則查詢語句中的數(shù)據(jù)格式化為更友好的格式,例如以下示例:

The toilet is very UNCLEAN and need to clean immediately. So, you are requested to take immediate action for cleaning. Thank you.

此項目中的 AWS Lambda 函數(shù)接收規(guī)則查詢語句的結(jié)果,將元素插入文本字符串,并將結(jié)果字符串作為通知中的消息發(fā)送到 Amazon SNS。

創(chuàng)建發(fā)送文本消息的 AWS Lambda 函數(shù)

創(chuàng)建一個新的 AWS Lambda 函數(shù)。

  • AWS Lambda 控制臺中,選擇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)該會看到format-h??igh-temp-notification詳細(xì)信息頁面。如果您不這樣做,請從Lambda函數(shù)頁面打開它。
  • format-h??igh-temp-notification詳細(xì)信息頁面中,選擇Configuration選項卡并滾動到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)到上一個規(guī)則操作,

  • 刪除之前的操作,然后單擊添加操作
  • 選擇操作中,選擇向 Lambda 函數(shù)發(fā)送消息
  • 要打開所選操作的配置頁面,請在操作列表底部選擇配置操作。

配置操作中

  • 函數(shù)名稱中,選擇選擇。
  • 選擇format-h??igh-temp-notification
  • 配置操作的底部,選擇添加操作。
  • 要創(chuàng)建規(guī)則,請在創(chuàng)建規(guī)則底部選擇創(chuàng)建規(guī)則。

?

?

所有步驟的視頻教程

這是到目前為止解釋的所有步驟的屏幕記錄。初學(xué)者遵循上述步驟將很有幫助。視頻中沒有聲音。

?

?

使用 SageMaker 檢測漏水

按照相同的過程,您可以訓(xùn)練模型來檢測漏水。您不需要使用所有參數(shù)來開發(fā)模型。當(dāng)然,在這種情況下,噪聲級將是最有價值的資源。當(dāng)我解釋我如何使用 IoT Analytics、SageMaker 和 Lambda 開發(fā)和訓(xùn)練廁所狀態(tài)的機器學(xué)習(xí)模型時,我不再在這里重復(fù)這個過程。

將 NodeMCU 連接到 AWS IoT Core

在我們的項目中,Node MCU 將根據(jù)從 AWS IoT Core 收到的命令控制排氣扇。IoT Core 規(guī)則將根據(jù)從廁所接收到的空氣質(zhì)量數(shù)據(jù)將控制消息(真或假)發(fā)布到特定的 MQTT 主題。該規(guī)則適用于相關(guān)重要空氣質(zhì)量參數(shù)的預(yù)設(shè)閾值。如果任何參數(shù)超過閾值,則 IoT Core 規(guī)則會向node/mcu/fan/state等主題發(fā)布一條真實消息。節(jié)點 MCU 收到此消息并打開排氣扇,反之亦然。

poYBAGNkfIaAPrjuAABneNMNMa8552.jpg
?

要從 AWS IoT Core 節(jié)點 MCU 接收 MQTT 消息,必須連接到 IoT Core。按照鏈接 ( https://nerdyelectronics.com/iot/how-to-connect-nodemcu-to-aws-iot-core/ ) 中的教程了解如何將節(jié)點 MCU 連接到 AWS IoT Core。這是關(guān)于這個主題的一個非常好的教程。

你也可以關(guān)注視頻:

?

為 Node MCU 開發(fā)固件

將 Node MCU 板成功連接到 AWS IoT Core 后,我們需要開發(fā)板的固件,以便它可以接收來自我們特定主題的消息并可以相應(yīng)地控制排氣扇。

固件是在 Arduino 中開發(fā)的,成功編譯需要以下 Arduino 庫。

#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 后訂閱一個主題

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 的完整源代碼附在代碼部分。

驗證 NodeMCU 固件

為了驗證 Node MCU 正在接收 MQTT 消息并控制風(fēng)扇,請轉(zhuǎn)到 IoT Core 測試客戶端頁面并將以下消息發(fā)布到主題node/mcu/fan/state

{ "state": { "desired": {"fan_status": true } } }
poYBAGNkfImAM542AAC-PaCfR7k867.png
?

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

pYYBAGNkfI6ARZYuAAHCusU2_RY794.png
?

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

poYBAGNkfJOAOt7LAAk7yDkii6Q234.jpg
?

創(chuàng)建 IoT 規(guī)則以發(fā)布粉絲狀態(tài)

我們將創(chuàng)建 IoT Core 主題規(guī)則,接收設(shè)備從廁所發(fā)布的消息,檢查采樣的溫度、濕度、氨氣、二氧化硫和甲烷水平,并更新設(shè)備影子的風(fēng)扇狀態(tài),并重新發(fā)布消息到另一個物聯(lián)網(wǎng)主題。主題規(guī)則將使用 SQL 查詢中的條件邏輯來構(gòu)建新的有效負(fù)載,并使用 IoT Core 重新發(fā)布操作將新的有效負(fù)載發(fā)送到新主題。

  • 轉(zhuǎn)到 AWS IoT Core 管理控制臺,選擇Act ,選擇Rules ,然后選擇Create
  • 為您的規(guī)則命名和描述。名字就像healthryToiletFanStateRepublish
  • 使用以下查詢并確保將?CLIENT_ID?替換為您的設(shè)備客戶端 ID/序列號。
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 主題,然后選擇配置操作。
  • 對于主題,使用node/mcu/fan/state.
  • 對于選擇或創(chuàng)建角色以授予 AWS IoT 訪問權(quán)限以執(zhí)行此操作。選擇Create Role并在彈出窗口中為您的新 IAM 角色命名,然后選擇Create role 。
  • 選擇添加操作以完成操作配置并返回到規(guī)則創(chuàng)建表單。
  • 單擊創(chuàng)建規(guī)則以在 AWS IoT 規(guī)則引擎中創(chuàng)建此規(guī)則。

SELECT 子句使用 CASE 語句來實現(xiàn)我們的簡單閾值帶。如果任何空氣質(zhì)量參數(shù)(如溫度、濕度、氨、二氧化硫或甲烷)超過比較值,則將風(fēng)扇狀態(tài)修改為真 (ON)。您可以根據(jù)自己的情況修改解決方案的閾值或參數(shù)。

CASE 語句的輸出state.desired.fan_status使用 AS 關(guān)鍵字保存到有效負(fù)載鍵。這意味著我們正在創(chuàng)建一個新的有效負(fù)載{"state": {"desired": {"fan_status": false}}},并將此有效負(fù)載發(fā)送到操作。

state.reported.temperature <> Null防止規(guī)則重新觸發(fā),因為新的影子更新有效負(fù)載僅包含state.desired.fan_status密鑰而沒有值state.reported.temperature(可能使用其他參數(shù),例如濕度)。

現(xiàn)在所有的排氣扇都設(shè)置好了,它可以被 IoT Core MQTT 消息控制了。

?

?

?

?


下載該資料的人也在下載 下載該資料的人還在閱讀
更多 >

評論

查看更多

下載排行

本周

  1. 1山景DSP芯片AP8248A2數(shù)據(jù)手冊
  2. 1.06 MB  |  532次下載  |  免費
  3. 2RK3399完整板原理圖(支持平板,盒子VR)
  4. 3.28 MB  |  339次下載  |  免費
  5. 3TC358743XBG評估板參考手冊
  6. 1.36 MB  |  330次下載  |  免費
  7. 4DFM軟件使用教程
  8. 0.84 MB  |  295次下載  |  免費
  9. 5元宇宙深度解析—未來的未來-風(fēng)口還是泡沫
  10. 6.40 MB  |  227次下載  |  免費
  11. 6迪文DGUS開發(fā)指南
  12. 31.67 MB  |  194次下載  |  免費
  13. 7元宇宙底層硬件系列報告
  14. 13.42 MB  |  182次下載  |  免費
  15. 8FP5207XR-G1中文應(yīng)用手冊
  16. 1.09 MB  |  178次下載  |  免費

本月

  1. 1OrCAD10.5下載OrCAD10.5中文版軟件
  2. 0.00 MB  |  234315次下載  |  免費
  3. 2555集成電路應(yīng)用800例(新編版)
  4. 0.00 MB  |  33566次下載  |  免費
  5. 3接口電路圖大全
  6. 未知  |  30323次下載  |  免費
  7. 4開關(guān)電源設(shè)計實例指南
  8. 未知  |  21549次下載  |  免費
  9. 5電氣工程師手冊免費下載(新編第二版pdf電子書)
  10. 0.00 MB  |  15349次下載  |  免費
  11. 6數(shù)字電路基礎(chǔ)pdf(下載)
  12. 未知  |  13750次下載  |  免費
  13. 7電子制作實例集錦 下載
  14. 未知  |  8113次下載  |  免費
  15. 8《LED驅(qū)動電路設(shè)計》 溫德爾著
  16. 0.00 MB  |  6656次下載  |  免費

總榜

  1. 1matlab軟件下載入口
  2. 未知  |  935054次下載  |  免費
  3. 2protel99se軟件下載(可英文版轉(zhuǎn)中文版)
  4. 78.1 MB  |  537798次下載  |  免費
  5. 3MATLAB 7.1 下載 (含軟件介紹)
  6. 未知  |  420027次下載  |  免費
  7. 4OrCAD10.5下載OrCAD10.5中文版軟件
  8. 0.00 MB  |  234315次下載  |  免費
  9. 5Altium DXP2002下載入口
  10. 未知  |  233046次下載  |  免費
  11. 6電路仿真軟件multisim 10.0免費下載
  12. 340992  |  191187次下載  |  免費
  13. 7十天學(xué)會AVR單片機與C語言視頻教程 下載
  14. 158M  |  183279次下載  |  免費
  15. 8proe5.0野火版下載(中文版免費下載)
  16. 未知  |  138040次下載  |  免費