diff --git a/.gitignore b/.gitignore index 6c5c728..bd0cd5f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ src/udi/udi +src/udi/main src/udi/migrate_schema tmp/ ENVDB diff --git a/src/udi/config-test.json b/src/udi/config-test.json index d31c720..e2eb4b4 100644 --- a/src/udi/config-test.json +++ b/src/udi/config-test.json @@ -20,15 +20,11 @@ }, { "topics": [ "zigbee2mqtt/+" ], - "handler": "SVEJ", - "id": "SVEJ1", + "handler": "Z2M", + "id": "Z2M", "config": { "databaseConnStr": "", "attributes": { - "application": "Temperature Multisensor", - "deviceSelector": "L:1", - "valueSelector": "J:$.temperature", - "unitSelector": "C:°C" } } } diff --git a/src/udi/dispatcher/dispatcher.go b/src/udi/dispatcher/dispatcher.go index d8e570e..ae8fbac 100644 --- a/src/udi/dispatcher/dispatcher.go +++ b/src/udi/dispatcher/dispatcher.go @@ -18,6 +18,7 @@ import "udi/handlers/svej" import "udi/handlers/dt1t" import "udi/handlers/locative" import "udi/handlers/snmp" +import "udi/handlers/z2m" var handlerMap map[string]handler.Handler = make(map[string]handler.Handler) @@ -50,6 +51,8 @@ func InitDispatcher() { factory = locative.New case "SNMP": factory = snmp.New + case "Z2M": + factory = z2m.New default: factory = nil log.Printf("No handler %s found, ignore mapping", mapping.Handler) diff --git a/src/udi/handlers/z2m/models/wsdcgq11lm/wsdcgq11lm.go b/src/udi/handlers/z2m/models/wsdcgq11lm/wsdcgq11lm.go new file mode 100644 index 0000000..d9f435b --- /dev/null +++ b/src/udi/handlers/z2m/models/wsdcgq11lm/wsdcgq11lm.go @@ -0,0 +1,48 @@ +package wsdcgq11lm + +import ( + //"log" + "fmt" + "reflect" + "encoding/json" + "udi/database" +) + +type Observation struct { + LinkQuality uint8 `unit:"" json:"linkquality"` + Battery uint8 `unit:"%" json:"battery"` + Humidity float32 `unit:"%H" json:"humidity"` + Pressure float32 `unit:"mbar" json:"pressure"` + Temperature float32 `unit:"°C" json:"temperature"` + Voltage uint16 `unit:"mV" json:"voltage"` +} + + +func Parse(payload string, variables *map[string]database.VariableType, attributes *map[string]interface{}, _ *database.Device) error { + var observation Observation + err := json.Unmarshal([]byte(payload), &observation) + if err != nil { + return fmt.Errorf("Unable to parse payload into Observation struct: %v, %s", err, payload) + } + + observationType := reflect.TypeOf(observation) + observationValue := reflect.ValueOf(observation) + + for i := 0; i < observationType.NumField(); i++ { + field := observationType.Field(i) + name := field.Name + unit := field.Tag.Get("unit") + value := observationValue.Field(i).Interface() + + (*variables)[name] = database.VariableType { + Label: name, + Variable: "y", + Unit: unit, + Value: value, + } + } + + (*attributes)["Status"] = "ok" + + return nil +} diff --git a/src/udi/handlers/z2m/z2m.go b/src/udi/handlers/z2m/z2m.go new file mode 100644 index 0000000..d9427f2 --- /dev/null +++ b/src/udi/handlers/z2m/z2m.go @@ -0,0 +1,74 @@ +package z2m + +import ( + "fmt" + "log" + "time" + "strings" + //"encoding/json" + "udi/config" + "udi/handlers/handler" + "udi/database" + "udi/handlers/z2m/models/wsdcgq11lm" +) + + +type Z2MHandler struct { + handler.CommonHandler + dbh *database.DatabaseHandle +} + + +func New(id string, config config.HandlerConfigT) handler.Handler { + t := &Z2MHandler { + } + t.Id = id + t.dbh = database.NewDatabaseHandle() + return t +} + +func (self *Z2MHandler) Handle(message handler.MessageT) { + log.Printf("Handler Z2M %d processing %s -> %s", self.Id, message.Topic, message.Payload) + + var measurement database.Measurement + measurement.Time = time.Now() + + + subTopics := strings.Split(message.Topic, "/") + deviceId := subTopics[1] + log.Printf("DeviceId: %s", deviceId) + device, err1 := self.dbh.GetDeviceByLabel(deviceId) + if err1 != nil { + self.Lost("Error when loading device", err1, message) + return + } + log.Printf("Device: %s", device) + + measurement.Application = device.Application.Label + measurement.Device = device.Attributes["Label"].(string) + + var parser func(string, *map[string]database.VariableType, *map[string]interface{}, *database.Device) error + switch device.DeviceType.ModelIdentifier { + case "WSDCGQ11LM": + parser = wsdcgq11lm.Parse + default: + self.Lost(fmt.Sprintf("No parser found for %s", device.DeviceType.ModelIdentifier), nil, message) + return + } + + measurement.Values = make(map[string]database.VariableType) + measurement.Attributes = make(map[string]interface{}) + err3 := parser(message.Payload, + &(measurement.Values), + &(measurement.Attributes), + device) + if err3 != nil { + self.Lost("Model parser failed", err3, message) + return + } + log.Printf("Prepared measurement item: %s", measurement) + self.dbh.StoreMeasurement(&measurement) + self.S() +} + +