This commit is contained in:
23
src/udi/config-level.json
Normal file
23
src/udi/config-level.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
61
src/udi/handlers/ttn/models/draginoLdds75/draginoLdds75.go
Normal file
61
src/udi/handlers/ttn/models/draginoLdds75/draginoLdds75.go
Normal 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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
src/udi/handlers/ttn/models/draginoLmds200/draginoLmds200.go
Normal file
59
src/udi/handlers/ttn/models/draginoLmds200/draginoLmds200.go
Normal 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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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)
|
//log.Printf("Parse input: %d, %s", fPort, decodedPayload)
|
||||||
switch fPort {
|
switch fPort {
|
||||||
case 1:
|
case 1:
|
||||||
var emuMessage1 emuMessage1
|
var emuMessage1 emuMessage1
|
||||||
err := json.Unmarshal(decodedPayload, &emuMessage1)
|
err := json.Unmarshal(decodedPayload, &emuMessage1)
|
||||||
if err != nil {
|
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",
|
Variable: "ActivePowerL1",
|
||||||
Unit: emuMessage1.ActivePowerL1.Unit,
|
Unit: emuMessage1.ActivePowerL1.Unit,
|
||||||
Value: emuMessage1.ActivePowerL1.Value,
|
Value: emuMessage1.ActivePowerL1.Value,
|
||||||
}
|
}
|
||||||
variables["ActivePowerL2"] = database.VariableType {
|
(*variables)["ActivePowerL2"] = database.VariableType {
|
||||||
Variable: "ActivePowerL2",
|
Variable: "ActivePowerL2",
|
||||||
Unit: emuMessage1.ActivePowerL2.Unit,
|
Unit: emuMessage1.ActivePowerL2.Unit,
|
||||||
Value: emuMessage1.ActivePowerL2.Value,
|
Value: emuMessage1.ActivePowerL2.Value,
|
||||||
}
|
}
|
||||||
variables["ActivePowerL3"] = database.VariableType {
|
(*variables)["ActivePowerL3"] = database.VariableType {
|
||||||
Variable: "ActivePowerL3",
|
Variable: "ActivePowerL3",
|
||||||
Unit: emuMessage1.ActivePowerL3.Unit,
|
Unit: emuMessage1.ActivePowerL3.Unit,
|
||||||
Value: emuMessage1.ActivePowerL3.Value,
|
Value: emuMessage1.ActivePowerL3.Value,
|
||||||
}
|
}
|
||||||
variables["ActivePowerL123"] = database.VariableType {
|
(*variables)["ActivePowerL123"] = database.VariableType {
|
||||||
Variable: "ActivePowerL123",
|
Variable: "ActivePowerL123",
|
||||||
Unit: emuMessage1.ActivePowerL123.Unit,
|
Unit: emuMessage1.ActivePowerL123.Unit,
|
||||||
Value: emuMessage1.ActivePowerL123.Value,
|
Value: emuMessage1.ActivePowerL123.Value,
|
||||||
}
|
}
|
||||||
variables["PowerfactorL1"] = database.VariableType {
|
(*variables)["PowerfactorL1"] = database.VariableType {
|
||||||
Variable: "PowerfactorL1",
|
Variable: "PowerfactorL1",
|
||||||
Unit: emuMessage1.PowerfactorL1.Unit,
|
Unit: emuMessage1.PowerfactorL1.Unit,
|
||||||
Value: emuMessage1.PowerfactorL1.Value,
|
Value: emuMessage1.PowerfactorL1.Value,
|
||||||
}
|
}
|
||||||
variables["PowerfactorL2"] = database.VariableType {
|
(*variables)["PowerfactorL2"] = database.VariableType {
|
||||||
Variable: "PowerfactorL2",
|
Variable: "PowerfactorL2",
|
||||||
Unit: emuMessage1.PowerfactorL2.Unit,
|
Unit: emuMessage1.PowerfactorL2.Unit,
|
||||||
Value: emuMessage1.PowerfactorL2.Value,
|
Value: emuMessage1.PowerfactorL2.Value,
|
||||||
}
|
}
|
||||||
variables["PowerfactorL3"] = database.VariableType {
|
(*variables)["PowerfactorL3"] = database.VariableType {
|
||||||
Variable: "PowerfactorL3",
|
Variable: "PowerfactorL3",
|
||||||
Unit: emuMessage1.PowerfactorL3.Unit,
|
Unit: emuMessage1.PowerfactorL3.Unit,
|
||||||
Value: emuMessage1.PowerfactorL3.Value,
|
Value: emuMessage1.PowerfactorL3.Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
return variables, nil
|
return nil
|
||||||
case 2:
|
case 2:
|
||||||
var emuMessage2 emuMessage2
|
var emuMessage2 emuMessage2
|
||||||
err := json.Unmarshal(decodedPayload, &emuMessage2)
|
err := json.Unmarshal(decodedPayload, &emuMessage2)
|
||||||
if err != nil {
|
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",
|
Variable: "ActiveEnergyExport",
|
||||||
Unit: emuMessage2.ActiveEnergyExport.Unit,
|
Unit: emuMessage2.ActiveEnergyExport.Unit,
|
||||||
Value: emuMessage2.ActiveEnergyExport.Value,
|
Value: emuMessage2.ActiveEnergyExport.Value,
|
||||||
}
|
}
|
||||||
variables["ActiveEnergyImport"] = database.VariableType {
|
(*variables)["ActiveEnergyImport"] = database.VariableType {
|
||||||
Variable: "ActiveEnergyImport",
|
Variable: "ActiveEnergyImport",
|
||||||
Unit: emuMessage2.ActiveEnergyImport.Unit,
|
Unit: emuMessage2.ActiveEnergyImport.Unit,
|
||||||
Value: emuMessage2.ActiveEnergyImport.Value,
|
Value: emuMessage2.ActiveEnergyImport.Value,
|
||||||
}
|
}
|
||||||
variables["ReactiveEnergyExport"] = database.VariableType {
|
(*variables)["ReactiveEnergyExport"] = database.VariableType {
|
||||||
Variable: "ReactiveEnergyExport",
|
Variable: "ReactiveEnergyExport",
|
||||||
Unit: emuMessage2.ReactiveEnergyExport.Unit,
|
Unit: emuMessage2.ReactiveEnergyExport.Unit,
|
||||||
Value: emuMessage2.ReactiveEnergyExport.Value,
|
Value: emuMessage2.ReactiveEnergyExport.Value,
|
||||||
}
|
}
|
||||||
variables["ReactiveEnergyImport"] = database.VariableType {
|
(*variables)["ReactiveEnergyImport"] = database.VariableType {
|
||||||
Variable: "ReactiveEnergyImport",
|
Variable: "ReactiveEnergyImport",
|
||||||
Unit: emuMessage2.ReactiveEnergyImport.Unit,
|
Unit: emuMessage2.ReactiveEnergyImport.Unit,
|
||||||
Value: emuMessage2.ReactiveEnergyImport.Value,
|
Value: emuMessage2.ReactiveEnergyImport.Value,
|
||||||
}
|
}
|
||||||
return variables, nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Unexpected fPort %d", fPort)
|
return fmt.Errorf("Unexpected fPort %d", fPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
package ttn
|
package ttn
|
||||||
|
|
||||||
import "log"
|
import (
|
||||||
import "fmt"
|
"log"
|
||||||
import "time"
|
"fmt"
|
||||||
import "encoding/json"
|
"time"
|
||||||
import "udi/config"
|
"encoding/json"
|
||||||
import "udi/handlers/handler"
|
"udi/config"
|
||||||
import "udi/handlers/ttn/models/emuProfIILoRaCfg1"
|
"udi/handlers/handler"
|
||||||
import "udi/database"
|
"udi/handlers/ttn/models/emuProfIILoRaCfg1"
|
||||||
|
"udi/handlers/ttn/models/draginoLdds75"
|
||||||
|
"udi/handlers/ttn/models/draginoLmds200"
|
||||||
|
"udi/database"
|
||||||
|
)
|
||||||
|
|
||||||
var idSeq int = 0
|
var idSeq int = 0
|
||||||
|
|
||||||
@ -134,24 +138,29 @@ func (self *TTNHandler) Handle(message handler.MessageT) {
|
|||||||
}
|
}
|
||||||
measurement.Application = attributes.ApplicationId
|
measurement.Application = attributes.ApplicationId
|
||||||
measurement.Device = attributes.DeviceId
|
measurement.Device = attributes.DeviceId
|
||||||
|
measurement.Attributes["DeviceType"] = device.DeviceType.ModelIdentifier
|
||||||
|
|
||||||
//log.Printf("DeviceLabel: %s, DeviceType: %s", device.Label, 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 {
|
switch device.DeviceType.ModelIdentifier {
|
||||||
case "emu-prof-ii-lora-cfg1":
|
case "emu-prof-ii-lora-cfg1":
|
||||||
parser = emuProfIILoRaCfg1.Parse
|
parser = emuProfIILoRaCfg1.Parse
|
||||||
|
case "dragino-ldds75":
|
||||||
|
parser = draginoLdds75.Parse
|
||||||
|
case "dragino-lmds200":
|
||||||
|
parser = draginoLmds200.Parse
|
||||||
default:
|
default:
|
||||||
lost(fmt.Sprintf("No parser found for %s", device.DeviceType.ModelIdentifier), message)
|
lost(fmt.Sprintf("No parser found for %s", device.DeviceType.ModelIdentifier), message)
|
||||||
return
|
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 {
|
if err3 != nil {
|
||||||
lost(fmt.Sprintf("Model parser failed: %s", err3), message)
|
lost(fmt.Sprintf("Model parser failed: %s", err3), message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
measurement.Values = variables
|
|
||||||
log.Printf("Prepared measurement item: %s", measurement)
|
log.Printf("Prepared measurement item: %s", measurement)
|
||||||
self.dbh.StoreMeasurement(&measurement)
|
self.dbh.StoreMeasurement(&measurement)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user