Unmarshal JSON-объект, опубликованный через MQTT в Go - PullRequest
0 голосов
/ 04 июля 2018

Я получаю данные датчика через MQTT. Я хочу проверить, если температура превышает 20 градусов, и если это так, отправьте сообщение.

var f MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
    type Data struct {
        Sensor string        `json:"sensor"`
        Temp []int           `json: "temperature"`
        Hum []int           `json: "humidity"`
    }
    var sensorData []Data
    message := ""
    err := json.Unmarshal(msg.Payload(), &sensorData)
    if err != nil {
        panic(err)
    }else {

    //access certain element in the Data struct
        for _, i := range sensorData {
            if i.Temp[2] > 20 { //where the temperature is stored
                fmt.Println("Temperature too high")
                message = "Temperature too high"
            }else{
                fmt.Println("Perfect temperature")
                message = "Perfect temperature"
        }
    }

    }

    // Publish further instructions to "sensor/instruction"
    token := client.Publish("sensor/instruction", 0, false, message)
    token.Wait()
}

В настоящее время я публикую два объекта JSON, которые будут получены. Я думаю, что часть проблемы заключается в различении двух объектов. Это ошибка, которую я получаю panic: json: cannot unmarshal object into Go value of type []main.Data. Это объекты JSON, которые я публикую в теме:

{'sensor': 'DHT22', 'temperature': [22.7, 22.7, 22.8], 'humidity': [51.9, 52.0, 52.0]}
{'actuator': 'arduinoLED', 'blink': ['false', 'false', 'false']}

msg.Payload() дает

{"sensor": "DHT22", "temperature": [22.9, 22.9, 22.9], "humidity": [50.9, 50.9, 50.9]}
{"actuator": "arduinoLED", "blink": ["false", "false", "false"]

Эти объекты постоянно публикуются в цикле . Я хочу разархивировать первый объект и получить доступ к определенному элементу.

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

Существует две основные причины вашей ошибки. Одна из них: у вас есть float значение для температуры и влажности, но вы передаете кусочек int

type Data struct {
    Sensor string        `json:"sensor"`
    Temp []int           `json: "temperature"` // this should be []float64
    Hum []int           `json: "humidity"` // this should be []float64
}

Другое - это два объекта в msg.Payload, который не является частью структуры Data. Рабочий код.

package main

import (
    "encoding/json"
    "fmt"
)

type Data struct {
    Sensor string    `json:"sensor"`
    Temp   []float64 `json:"temperature"`
    Hum    []float64 `json:"humidity"`
}

func main() {
    bytes := []byte(`{
        "sensor": "DHT22", 
        "temperature": [22.7, 22.7, 22.8], 
        "humidity": [51.9, 52.0, 52.0]
    }`)

    var sensorData Data
    if err := json.Unmarshal(bytes, &sensorData); err != nil {
        fmt.Println(err)
    }
    fmt.Println(sensorData)

}

Проверить рабочий код на Перейти на игровую площадку

0 голосов
/ 04 июля 2018

Срез против отдельного объекта

Вы объявляете фрагмент:

var sensorData []Data

Но тогда ваша полезная нагрузка - это не массив, а только один объект:

{'sensor': 'DHT22', 'temperature': [22.7, 22.7, 22.8], 'humidity': [51.9, 52.0, 52.0]}

Таким образом, это сообщение об ошибке говорит о том, что он не может демонтировать один объект как срез.

Попробуйте изменить это объявление на:

var sensorData Data

Затем, вместо того, чтобы перебирать его, вам нужно просто проверить один экземпляр данных.

Дополнительные несоответствия между полезной нагрузкой и типом структуры

После этого вы, вероятно, получите еще одну ошибку, поскольку массивы temperature и humidity содержат десятичные числа:

`{'sensor': 'DHT22', 'temperature': [22.7, 22.7, 22.8], 'humidity': [51.9, 52.0, 52.0]`

Но вы объявляете их как int фрагментов в вашем коде:

Temp []int           `json: "temperature"`
Hum []int           `json: "humidity"`

Так что вам нужно изменить их на []float64

Различение двух разных полезных нагрузок

Что касается разграничения двух типов объектов, было бы лучше, если бы вы попытались это сделать, но даже если вы этого не сделаете, библиотека Go json будет игнорировать проблемы, если имена полей не совпадают, так что произойдет: что при десериализации ваших actuator полезных нагрузок в Data все поля будут иметь значения по умолчанию, но ошибки не будет получено.

Эта проверка, вероятно, выдаст panic, потому что в этом случае массив будет пустым:

if i.Temp[2] > 20

Один "хакерский" способ решения этой проблемы - обработать данные, только если поле sensor не является пустой строкой.

При условии, что вы всегда получаете имя датчика в сообщениях sensor, единственный случай, когда это приведет к пустой строке, - это если вы только что обработали одно из других сообщений.

...