在上一篇文章中,我們展示如何使用 MQTT 代理從 IoT 設備發送和接收訊息。在這篇文章中,我們將把這個想法擴展到現實世界的例子。
假設您有一個物聯網設備,可以測量溫室中的溫度和濕度(使用 Raspberry Pi 或 Arduino 製作一個並不難)。
我們希望從另一台電腦或中央日誌服務遠端監控溫室條件。在上一篇文章中,我們展示了發送訊息的程式碼的 Go 實現,因此我們將擴展該範例。
我們不只是發送一個字串“溫度是 x,濕度是 y”,而是為訊息和設備定義一個結構。假設您擁有(或想要在將來添加)一台設備來監測濕度或降雨量,並且您也想連接該設備。
為了維持多種設備和類型的可能性,我們需要一個資料模型來處理它。
type Message struct { Time time.Time `json:"time"` Device Device `json:"device"` } type Device interface { ID() string Name() string } type TempRHDevice struct { Id string `json:"id"` DeviceName string `json:"name,omitempty"` Temp float32 `json:"temp,omitempty"` Rh float32 `json:"rh,omitempty"` } func (t TempRHDevice) ID() string { return t.Id } func (t TempRHDevice) Name() string { return t.DeviceName }
Message 結構是將發送到 MQTT 代理的內容。我們建立了一個介面來處理 IoT 設備的通用屬性並抽象化特定設備的詳細資訊。
TempRHDevice 是我們測量溫度和濕度的設備。它實作了Device接口,因此可以在訊息中使用。
接下來,我們需要將訊息發送給經紀人。在此範例中,為了簡單起見,我們將使用 JSON 格式。 請注意,在擁有數千或更多設備的大型系統中,我們可能想要使用更緊湊的格式。
message := generateRandomMessage() payload, err := json.Marshal(message) if err != nil { panic(err) } token := client.Publish(topic, 0, false, payload)
Go 讓編組為 JSON 變得非常容易。編組後,json 訊息將發送到代理。
一旦獲得數據,我們也想對它做什麼:將其儲存到資料庫中,將其顯示在儀表板上,檢查警報條件的值。我們需要轉換 json 才能使其可用。
在接收端,我們只需要把 json 解組到一個結構體。我們將使用與發送端類似的結構;但我們需要一種方法來解組為具體類型而不是 Message 中的 Device 介面。我們將在 Message 上新增一個自訂的 unmarshal 方法,以使程式碼更加簡潔
type rawMessage struct { Time time.Time `json:"time"` Device TempRHDevice `json:"device"` } func (m *Message) UnmarshalJSON(data []byte) error { var raw rawMessage if err := json.Unmarshal(data, &raw); err != nil { return err } m.Time = raw.Time m.Device = &raw.Device return nil } ... func processMsg(ctx context.Context, .... ... case msg, ok :=這裡需要指出的是,當增加更多設備類型時,此方法會變得複雜。例如,UnmarshalJSON 方法如何知道訊息包含什麼裝置類型。我們可以在 UnmarshalJSON 中執行一些巧妙的邏輯來檢測類型。
對於另一個選擇,請記住 MQTT 可用於發佈到多個主題,並且通常的做法是對主題使用分層命名約定。因此,在溫室範例中存在多種設備類型的情況下,建議的方式是讓不同的設備類型發佈到不同的主題。這是我們在新增設備類型時處理該問題的方式。
在溫室範例中,主題名稱的結構可以如下:
/greenhouse/temprh/deviceid /greenhouse/moisture/deviceid在MQTT中,我們可以使用通配符主題來訂閱主題,如:
if token := client.Subscribe("/greenhouse/#", 0, nil); token.Wait() && token.Error() != nil { fmt.Println(token.Error()) os.Exit(1) }它將匹配溫室命名空間中的所有設備。那麼我們只需要在 processMsg() 中加入邏輯來查看傳入訊息的主題,以了解如何對其進行解組。
現在我們有了可用形式的設備訊息,我們應該如何處理它。在本系列的下一篇文章中,我們將示範在 PostGres 中儲存訊息的方法。
像往常一樣,發送者的完整原始碼可以在這裡找到,訂閱者代碼可以在這裡找到。
請在評論中告訴我您的想法。
謝謝!
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3