190 lines
4.2 KiB
Go
190 lines
4.2 KiB
Go
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")
|
|
}
|