package influxdb import ( "fmt" "time" client "github.com/influxdata/influxdb1-client/v2" "github.com/sirupsen/logrus" "src.dualinventive.com/go/dinet/rpc" ) // Fetch the state and error fields from m.Result for device:data func processDeviceDataFields(m *rpc.Msg) (map[string]interface{}, error) { var result []map[string]interface{} err := m.Result.Unmarshal(&result) if err != nil { return nil, fmt.Errorf("device:data error while unmarshalling result: %v", err) } if len(result) != 1 { return nil, fmt.Errorf("device:data invalid number of items") } fields := make(map[string]interface{}) if state, ok := result[0]["state"].(string); ok { fields["state"] = state } else { logrus.Warnf("Missing state in device:data, UID: %s", m.DeviceUID) } if resError, ok := result[0]["error"].(bool); ok { fields["error"] = resError } else { logrus.Warnf("Missing error in device:data, UID: %s", m.DeviceUID) } if resErrors, ok := result[0]["errors"]; ok { if errors, ok := resErrors.([]interface{}); ok { fields["errors"] = errors } else { logrus.Warnf("device:data errors isn't a slice, T: %T, UID: %s", resErrors, m.DeviceUID) } } return fields, nil } func (i *Influx) processDeviceData(m *rpc.Msg) error { fields, err := processDeviceDataFields(m) if err != nil { return err } d, err := i.devCache.Device(m.DeviceUID) if err != nil { logrus.Warnf("cannot get device '%s' from cache: %v", m.DeviceUID, err) } keys := map[string]string{ "uid": m.DeviceUID, "group": m.DeviceUID[0:2], } if d != nil && len(d.Type) != 0 { keys["type"] = d.Type } if errors, ok := fields["errors"].([]interface{}); ok { i.writeErrors(keys, errors, m.Time.ToTime()) } rpcPt, err := client.NewPoint( measurementDevice, keys, fields, m.Time.ToTime(), ) if err != nil { logrus.Errorf("error while creating new samplepoint: %v", err) return err } i.writer.Add(rpcPt) return nil } func (i *Influx) writeResultValuesItem(rvi *rpc.ResultValueItem, class string, label string, keys map[string]string) { time := rvi.Time.ToTime() for _, sample := range rvi.Values.Samples { pt, err := client.NewPoint( class, keys, map[string]interface{}{label: sample}, time, ) if err != nil { logrus.Errorf("error while creating new samplepoint: %v", err) continue } i.writer.Add(pt) time = time.Add(rvi.Values.Interval) } } func (i *Influx) processResultValueItems(m *rpc.Msg, class rpc.Class) error { var items []rpc.ResultValueItem err := m.Result.Unmarshal(&items) if err != nil { return err } d, err := i.devCache.Device(m.DeviceUID) if err != nil { logrus.Warnf("cannot get device '%s' from cache: %v", m.DeviceUID, err) } keys := map[string]string{ "uid": m.DeviceUID, "group": m.DeviceUID[0:2], } // add the device type when this is known if d != nil { keys["type"] = d.Type } for _, data := range items { _data := data fieldInfo, err := d.FieldInfo(class, _data.UID) // err is not nil when the field info is not found if err != nil { logrus.Warnf("cannot find %s info uid %d for device '%s' err: %v", class, _data.UID, m.DeviceUID, err) continue } if data.Values != nil { i.writeResultValuesItem(&_data, string(class), fieldInfo.Label, keys) continue } fields, err := fieldInfo.Parse(&_data) if err != nil { logrus.Errorf("cannot use %v as type %s: %v", data.Value, fieldInfo.Type, err) continue } pt, err := client.NewPoint( string(class), keys, fields, data.Time.ToTime(), ) if err != nil { logrus.Errorf("error while creating new samplepoint: %v", err) continue } i.writer.Add(pt) } return nil } func (i *Influx) writeErrors(keys map[string]string, errors []interface{}, t time.Time) { for _, diError := range errors { if iErr, ok := diError.(float64); ok { keys["error"] = fmt.Sprintf("%v", diError) pt, err := client.NewPoint( measurementDeviceError, keys, map[string]interface{}{ "code": int(iErr), }, t, ) if err != nil { logrus.Errorf("error while creating new samplepoint: %v", err) continue } i.writer.Add(pt) } else { logrus.Warnf("errors doesn't contain an int error, T: %T", diError) } } delete(keys, "error") }