在上一篇文章中,我們展示如何使用 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 := <-input: if !ok { return } logger.Info().Msg(fmt.Sprintf("Received message: %s from topic: %s\n", msg.Payload(), msg.Topic())) var iotMsg Message err := json.Unmarshal(msg.Payload(), &iotMsg) if err != nil { logger.Error().Err(err).Msg("Error unmarshalling Message") } else { out <- iotMsg } ...
這裡需要指出的是,當增加更多設備類型時,此方法會變得複雜。例如,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 中儲存訊息的方法。
像往常一樣,發送者的完整原始碼可以在這裡找到,訂閱者代碼可以在這裡找到。
請在評論中告訴我你的想法。
謝謝!
以上是透過 MQTT 代理程式發送 IoT 設備資料。的詳細內容。更多資訊請關注PHP中文網其他相關文章!