Dragino parser
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2023-12-15 11:44:35 +01:00
parent 084f9fbf31
commit 7ee7d4df89
7 changed files with 263 additions and 30 deletions

23
src/udi/config-level.json Normal file
View File

@ -0,0 +1,23 @@
{
"mqtt": {
"broker": "ssl://eu1.cloud.thethings.network:8883",
"username": "de-hottis-level-monitoring@ttn",
"password": "ENV",
"tlsEnable": "true"
},
"topicMappings": [
{
"topics": [ "v3/#" ],
"handler": "TTN",
"id": "TTN0",
"config": {
"databaseConnStr": "",
"attributes": {
}
}
}
],
"archiver": {
"dir": "./tmp/udi"
}
}

View File

@ -0,0 +1,61 @@
package draginoLdds75
import (
"fmt"
"strings"
"strconv"
"encoding/json"
"udi/database"
)
/*
"decoded_payload": {
"Bat": 3.299,
"Distance": "352 mm",
"Interrupt_flag": 0,
"Sensor_flag": 1,
"TempC_DS18B20": "0.00"
},
*/
type message struct {
Bat float32 `json:"Bat"`
Distance string `json:"Distance"`
Interrupt_flag int `json:"Interrupt_flag"`
Sensor_flag int `json:"Sensor_flag"`
TempC_DS18B20 string `json:"TempC_DS18B20"`
}
func Parse(fPort int, decodedPayload []byte, variables *map[string]database.VariableType) error {
if fPort != 2 {
return fmt.Errorf("Unexpected fPort %d", fPort)
}
var message message
err := json.Unmarshal(decodedPayload, &message)
if err != nil {
return fmt.Errorf("Unable to parse payload, fPort %d, error %s", fPort, err)
}
distanceParts := strings.Split(message.Distance, " ")
if len(distanceParts) != 2 && distanceParts[1] != "mm" {
return fmt.Errorf("Invalid format for distance value: %s", message.Distance)
}
distance, err2 := strconv.Atoi(distanceParts[0])
if err2 != nil {
return fmt.Errorf("Distance value is no number: %s -> %s", message.Distance, err2)
}
(*variables)["Battery"] = database.VariableType {
Label: "Battery",
Variable: "Voltage",
Unit: "V",
Value: message.Bat,
}
(*variables)["Distance"] = database.VariableType {
Label: "Distance",
Variable: "Level",
Unit: "mm",
Value: distance,
}
return nil
}

View File

@ -0,0 +1,83 @@
{
"end_device_ids": {
"device_id": "eui-a84041a14185f67f",
"application_ids": {
"application_id": "de-hottis-level-monitoring"
},
"dev_eui": "A84041A14185F67F",
"join_eui": "A840410000000101",
"dev_addr": "260B3987"
},
"correlation_ids": [
"gs:uplink:01HHP8EVC1N78FGTNBTNZYGCVY"
],
"received_at": "2023-12-15T08:11:04.142793605Z",
"uplink_message": {
"session_key_id": "AYZ/cI2YeDLCZr4urRDzCw==",
"f_port": 2,
"f_cnt": 27758,
"frm_payload": "DOMBYAAAAAE=",
"decoded_payload": {
"Bat": 3.299,
"Distance": "352 mm",
"Interrupt_flag": 0,
"Sensor_flag": 1,
"TempC_DS18B20": "0.00"
},
"rx_metadata": [
{
"gateway_ids": {
"gateway_id": "eui-00005813d35e3021",
"eui": "00005813D35E3021"
},
"timestamp": 3654294763,
"rssi": -85,
"channel_rssi": -85,
"snr": 8.8,
"location": {
"latitude": 52.17065267448476,
"longitude": 7.629437184774199,
"source": "SOURCE_REGISTRY"
},
"uplink_token": "CiIKIAoUZXVpLTAwMDA1ODEzZDM1ZTMwMjESCAAAWBPTXjAhEOu5wM4NGgwIl5TwqwYQ5Z/7vgMg+OvDp63eBA==",
"channel_index": 2,
"received_at": "2023-12-15T08:11:03.937349093Z"
}
],
"settings": {
"data_rate": {
"lora": {
"bandwidth": 125000,
"spreading_factor": 7,
"coding_rate": "4/5"
}
},
"frequency": "867500000",
"timestamp": 3654294763
},
"received_at": "2023-12-15T08:11:03.938112475Z",
"consumed_airtime": "0.056576s",
"locations": {
"user": {
"latitude": 52.1710648323742,
"longitude": 7.62751003482794,
"altitude": 37,
"source": "SOURCE_REGISTRY"
}
},
"version_ids": {
"brand_id": "dragino",
"model_id": "ldds75",
"hardware_version": "_unknown_hw_version_",
"firmware_version": "1.1.4",
"band_id": "EU_863_870"
},
"network_ids": {
"net_id": "000013",
"ns_id": "EC656E0000000181",
"tenant_id": "ttn",
"cluster_id": "eu1",
"cluster_address": "eu1.cloud.thethings.network"
}
}
}

View File

@ -0,0 +1,59 @@
package draginoLmds200
import (
"fmt"
"encoding/json"
"udi/database"
)
/*
"decoded_payload": {
"Bat": 3.082,
"DALARM_count": 0,
"Distance_alarm": 0,
"Interrupt_alarm": 0,
"dis1": 105,
"dis2": 201
},
*/
type message struct {
Bat float32 `json:"Bat"`
DALARM_count int `json:"DALARM_count"`
Distance_alarm int `json:"Distance_alarm"`
Interrupt_alarm int `json:"Interrupt_alarm"`
Dis1 int `json:"dis1"`
Dis2 int `json:"dis2"`
}
func Parse(fPort int, decodedPayload []byte, variables *map[string]database.VariableType) error {
if fPort != 2 {
return fmt.Errorf("Unexpected fPort %d", fPort)
}
var message message
err := json.Unmarshal(decodedPayload, &message)
if err != nil {
return fmt.Errorf("Unable to parse payload, fPort %d, error %s", fPort, err)
}
(*variables)["Battery"] = database.VariableType {
Label: "Battery",
Variable: "Voltage",
Unit: "V",
Value: message.Bat,
}
(*variables)["Distance1"] = database.VariableType {
Label: "Distance1",
Variable: "Level",
Unit: "mm",
Value: (message.Dis1 * 10),
}
(*variables)["Distance2"] = database.VariableType {
Label: "Distance2",
Variable: "Level",
Unit: "mm",
Value: (message.Dis2 * 10),
}
return nil
}

View File

@ -177,83 +177,81 @@ type emuMessage1 struct {
func Parse(fPort int, decodedPayload []byte) (map[string]database.VariableType, error) {
func Parse(fPort int, decodedPayload []byte, variables *map[string]database.VariableType) error {
//log.Printf("Parse input: %d, %s", fPort, decodedPayload)
switch fPort {
case 1:
var emuMessage1 emuMessage1
err := json.Unmarshal(decodedPayload, &emuMessage1)
if err != nil {
return nil, fmt.Errorf("Unable to parse payload, fPort %d, error %s", fPort, err)
return fmt.Errorf("Unable to parse payload, fPort %d, error %s", fPort, err)
}
variables := make(map[string]database.VariableType)
variables["ActivePowerL1"] = database.VariableType {
(*variables)["ActivePowerL1"] = database.VariableType {
Variable: "ActivePowerL1",
Unit: emuMessage1.ActivePowerL1.Unit,
Value: emuMessage1.ActivePowerL1.Value,
}
variables["ActivePowerL2"] = database.VariableType {
(*variables)["ActivePowerL2"] = database.VariableType {
Variable: "ActivePowerL2",
Unit: emuMessage1.ActivePowerL2.Unit,
Value: emuMessage1.ActivePowerL2.Value,
}
variables["ActivePowerL3"] = database.VariableType {
(*variables)["ActivePowerL3"] = database.VariableType {
Variable: "ActivePowerL3",
Unit: emuMessage1.ActivePowerL3.Unit,
Value: emuMessage1.ActivePowerL3.Value,
}
variables["ActivePowerL123"] = database.VariableType {
(*variables)["ActivePowerL123"] = database.VariableType {
Variable: "ActivePowerL123",
Unit: emuMessage1.ActivePowerL123.Unit,
Value: emuMessage1.ActivePowerL123.Value,
}
variables["PowerfactorL1"] = database.VariableType {
(*variables)["PowerfactorL1"] = database.VariableType {
Variable: "PowerfactorL1",
Unit: emuMessage1.PowerfactorL1.Unit,
Value: emuMessage1.PowerfactorL1.Value,
}
variables["PowerfactorL2"] = database.VariableType {
(*variables)["PowerfactorL2"] = database.VariableType {
Variable: "PowerfactorL2",
Unit: emuMessage1.PowerfactorL2.Unit,
Value: emuMessage1.PowerfactorL2.Value,
}
variables["PowerfactorL3"] = database.VariableType {
(*variables)["PowerfactorL3"] = database.VariableType {
Variable: "PowerfactorL3",
Unit: emuMessage1.PowerfactorL3.Unit,
Value: emuMessage1.PowerfactorL3.Value,
}
return variables, nil
return nil
case 2:
var emuMessage2 emuMessage2
err := json.Unmarshal(decodedPayload, &emuMessage2)
if err != nil {
return nil, fmt.Errorf("Unable to parse payload, fPort %d, error %s", fPort, err)
return fmt.Errorf("Unable to parse payload, fPort %d, error %s", fPort, err)
}
variables := make(map[string]database.VariableType)
variables["ActiveEnergyExport"] = database.VariableType {
(*variables)["ActiveEnergyExport"] = database.VariableType {
Variable: "ActiveEnergyExport",
Unit: emuMessage2.ActiveEnergyExport.Unit,
Value: emuMessage2.ActiveEnergyExport.Value,
}
variables["ActiveEnergyImport"] = database.VariableType {
(*variables)["ActiveEnergyImport"] = database.VariableType {
Variable: "ActiveEnergyImport",
Unit: emuMessage2.ActiveEnergyImport.Unit,
Value: emuMessage2.ActiveEnergyImport.Value,
}
variables["ReactiveEnergyExport"] = database.VariableType {
(*variables)["ReactiveEnergyExport"] = database.VariableType {
Variable: "ReactiveEnergyExport",
Unit: emuMessage2.ReactiveEnergyExport.Unit,
Value: emuMessage2.ReactiveEnergyExport.Value,
}
variables["ReactiveEnergyImport"] = database.VariableType {
(*variables)["ReactiveEnergyImport"] = database.VariableType {
Variable: "ReactiveEnergyImport",
Unit: emuMessage2.ReactiveEnergyImport.Unit,
Value: emuMessage2.ReactiveEnergyImport.Value,
}
return variables, nil
return nil
default:
return nil, fmt.Errorf("Unexpected fPort %d", fPort)
return fmt.Errorf("Unexpected fPort %d", fPort)
}
}

View File

@ -1,13 +1,17 @@
package ttn
import "log"
import "fmt"
import "time"
import "encoding/json"
import "udi/config"
import "udi/handlers/handler"
import "udi/handlers/ttn/models/emuProfIILoRaCfg1"
import "udi/database"
import (
"log"
"fmt"
"time"
"encoding/json"
"udi/config"
"udi/handlers/handler"
"udi/handlers/ttn/models/emuProfIILoRaCfg1"
"udi/handlers/ttn/models/draginoLdds75"
"udi/handlers/ttn/models/draginoLmds200"
"udi/database"
)
var idSeq int = 0
@ -134,24 +138,29 @@ func (self *TTNHandler) Handle(message handler.MessageT) {
}
measurement.Application = attributes.ApplicationId
measurement.Device = attributes.DeviceId
measurement.Attributes["DeviceType"] = device.DeviceType.ModelIdentifier
//log.Printf("DeviceLabel: %s, DeviceType: %s", device.Label, device.DeviceType.ModelIdentifier)
var parser func(int, []byte) (map[string]database.VariableType, error)
var parser func(int, []byte, *map[string]database.VariableType) error
switch device.DeviceType.ModelIdentifier {
case "emu-prof-ii-lora-cfg1":
parser = emuProfIILoRaCfg1.Parse
case "dragino-ldds75":
parser = draginoLdds75.Parse
case "dragino-lmds200":
parser = draginoLmds200.Parse
default:
lost(fmt.Sprintf("No parser found for %s", device.DeviceType.ModelIdentifier), message)
return
}
variables, err3 := parser(uplinkMessage.UplinkMessage.FPort, uplinkMessage.UplinkMessage.DecodedPayload.Payload)
measurement.Values = make(map[string]database.VariableType)
err3 := parser(uplinkMessage.UplinkMessage.FPort, uplinkMessage.UplinkMessage.DecodedPayload.Payload, &(measurement.Values))
if err3 != nil {
lost(fmt.Sprintf("Model parser failed: %s", err3), message)
return
}
measurement.Values = variables
log.Printf("Prepared measurement item: %s", measurement)
self.dbh.StoreMeasurement(&measurement)
}