feat(inputs.knx_listener): Allow usage of DPT string representation (#15069)

This commit is contained in:
Sven Rebhan 2024-03-27 16:28:34 +01:00 committed by GitHub
parent 8c4fd53bc0
commit 212822e85d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 85 additions and 53 deletions

View File

@ -43,6 +43,9 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
# name = "temperature" # name = "temperature"
# ## Datapoint-Type (DPT) of the KNX messages # ## Datapoint-Type (DPT) of the KNX messages
# dpt = "9.001" # dpt = "9.001"
# ## Use the string representation instead of the numerical value for the
# ## datapoint-type and the addresses below
# # as_string = false
# ## List of Group-Addresses (GAs) assigned to the measurement # ## List of Group-Addresses (GAs) assigned to the measurement
# addresses = ["5/5/1"] # addresses = ["5/5/1"]

View File

@ -26,13 +26,15 @@ type KNXInterface interface {
type addressTarget struct { type addressTarget struct {
measurement string measurement string
datapoint dpt.DatapointValue asstring bool
datapoint dpt.Datapoint
} }
type Measurement struct { type Measurement struct {
Name string Name string `toml:"name"`
Dpt string Dpt string `toml:"dpt"`
Addresses []string AsString bool `toml:"as_string"`
Addresses []string `toml:"addresses"`
} }
type KNXListener struct { type KNXListener struct {
@ -83,7 +85,7 @@ func (kl *KNXListener) Init() error {
if !ok { if !ok {
return fmt.Errorf("cannot create datapoint-type %q for address %q", m.Dpt, ga) return fmt.Errorf("cannot create datapoint-type %q for address %q", m.Dpt, ga)
} }
kl.gaTargetMap[ga] = addressTarget{m.Name, d} kl.gaTargetMap[ga] = addressTarget{measurement: m.Name, asstring: m.AsString, datapoint: d}
} }
} }
@ -164,8 +166,7 @@ func (kl *KNXListener) listen(acc telegraf.Accumulator) {
} }
// Extract the value from the data-frame // Extract the value from the data-frame
err := target.datapoint.Unpack(msg.Data) if err := target.datapoint.Unpack(msg.Data); err != nil {
if err != nil {
kl.Log.Errorf("Unpacking data failed: %v", err) kl.Log.Errorf("Unpacking data failed: %v", err)
continue continue
} }
@ -175,6 +176,7 @@ func (kl *KNXListener) listen(acc telegraf.Accumulator) {
// as otherwise telegraf will not push out the metrics and eat it // as otherwise telegraf will not push out the metrics and eat it
// silently. // silently.
var value interface{} var value interface{}
if !target.asstring {
vi := reflect.Indirect(reflect.ValueOf(target.datapoint)) vi := reflect.Indirect(reflect.ValueOf(target.datapoint))
switch vi.Kind() { switch vi.Kind() {
case reflect.Bool: case reflect.Bool:
@ -189,6 +191,9 @@ func (kl *KNXListener) listen(acc telegraf.Accumulator) {
kl.Log.Errorf("Type conversion %v failed for address %q", vi.Kind(), ga) kl.Log.Errorf("Type conversion %v failed for address %q", vi.Kind(), ga)
continue continue
} }
} else {
value = target.datapoint.String()
}
// Compose the actual data to be pushed out // Compose the actual data to be pushed out
fields := map[string]interface{}{"value": value} fields := map[string]interface{}{"value": value}

View File

@ -60,41 +60,62 @@ func produceKnxEvent(t *testing.T, address string, datapoint string, value inter
func TestRegularReceives_DPT(t *testing.T) { func TestRegularReceives_DPT(t *testing.T) {
// Define the test-cases // Define the test-cases
var testcases = []message{ var testcases = []struct {
{"1/0/1", "1.001", true}, address string
{"1/0/2", "1.002", false}, dpt string
{"1/0/3", "1.003", true}, asstring bool
{"1/0/9", "1.009", false}, value interface{}
{"1/1/0", "1.010", true}, expected interface{}
{"5/0/1", "5.001", 12.157}, }{
{"5/0/3", "5.003", 121.412}, {"1/0/1", "1.001", false, true, true},
{"5/0/4", "5.004", uint64(25)}, {"1/0/2", "1.002", false, false, false},
{"9/0/1", "9.001", 18.56}, {"1/0/3", "1.003", false, true, true},
{"9/0/4", "9.004", 243.84}, {"1/0/9", "1.009", false, false, false},
{"9/0/5", "9.005", 12.01}, {"1/1/0", "1.010", false, true, true},
{"9/0/7", "9.007", 59.32}, {"1/1/1", "1.001", true, true, "On"},
{"13/0/1", "13.001", int64(-15)}, {"1/1/2", "1.001", true, false, "Off"},
{"13/0/2", "13.002", int64(183)}, {"1/1/3", "1.002", true, true, "True"},
{"13/1/0", "13.010", int64(-141)}, {"1/1/4", "1.002", true, false, "False"},
{"13/1/1", "13.011", int64(277)}, {"1/1/5", "1.003", true, true, "Enable"},
{"13/1/2", "13.012", int64(-4096)}, {"1/1/6", "1.003", true, false, "Disable"},
{"13/1/3", "13.013", int64(8192)}, {"1/1/7", "1.009", true, true, "Close"},
{"13/1/4", "13.014", int64(-65536)}, {"1/1/8", "1.009", true, false, "Open"},
{"13/1/5", "13.015", int64(2147483647)}, {"1/2/0", "1.010", true, true, "Start"},
{"14/0/0", "14.000", -1.31}, {"1/2/1", "1.010", true, false, "Stop"},
{"14/0/1", "14.001", 0.44}, {"5/0/1", "5.001", false, 12.157, 12.157},
{"14/0/2", "14.002", 32.08}, {"5/0/3", "5.003", false, 121.412, 121.412},
// {"14/0/3", "14.003", 92.69}, {"5/0/4", "5.004", false, uint64(25), uint64(25)},
// {"14/0/4", "14.004", 1.00794}, {"9/0/1", "9.001", false, 18.56, 18.56},
{"14/1/0", "14.010", 5963.78}, {"9/0/4", "9.004", false, 243.84, 243.84},
{"14/1/1", "14.011", 150.95}, {"9/0/5", "9.005", false, 12.01, 12.01},
{"9/0/7", "9.007", false, 59.32, 59.32},
{"13/0/1", "13.001", false, int64(-15), int64(-15)},
{"13/0/2", "13.002", false, int64(183), int64(183)},
{"13/1/0", "13.010", false, int64(-141), int64(-141)},
{"13/1/1", "13.011", false, int64(277), int64(277)},
{"13/1/2", "13.012", false, int64(-4096), int64(-4096)},
{"13/1/3", "13.013", false, int64(8192), int64(8192)},
{"13/1/4", "13.014", false, int64(-65536), int64(-65536)},
{"13/1/5", "13.015", false, int64(2147483647), int64(2147483647)},
{"14/0/0", "14.000", false, -1.31, -1.31},
{"14/0/1", "14.001", false, 0.44, 0.44},
{"14/0/2", "14.002", false, 32.08, 32.08},
{"14/0/3", "14.003", false, 92.69, 92.69},
{"14/0/4", "14.004", false, 1.00794, 1.00794},
{"14/1/0", "14.010", false, 5963.78, 5963.78},
{"14/1/1", "14.011", false, 150.95, 150.95},
} }
acc := &testutil.Accumulator{} acc := &testutil.Accumulator{}
// Setup the unit-under-test // Setup the unit-under-test
measurements := make([]Measurement, 0, len(testcases)) measurements := make([]Measurement, 0, len(testcases))
for _, testcase := range testcases { for _, testcase := range testcases {
measurements = append(measurements, Measurement{"test", testcase.dpt, []string{testcase.address}}) measurements = append(measurements, Measurement{
Name: "test",
Dpt: testcase.dpt,
AsString: testcase.asstring,
Addresses: []string{testcase.address},
})
} }
listener := KNXListener{ listener := KNXListener{
ServiceType: "dummy", ServiceType: "dummy",
@ -129,8 +150,8 @@ func TestRegularReceives_DPT(t *testing.T) {
require.Equal(t, "test", m.Measurement) require.Equal(t, "test", m.Measurement)
require.Equal(t, testcases[i].address, m.Tags["groupaddress"]) require.Equal(t, testcases[i].address, m.Tags["groupaddress"])
require.Len(t, m.Fields, 1) require.Len(t, m.Fields, 1)
switch v := testcases[i].value.(type) { switch v := testcases[i].expected.(type) {
case bool, int64, uint64: case string, bool, int64, uint64:
require.Equal(t, v, m.Fields["value"]) require.Equal(t, v, m.Fields["value"])
case float64: case float64:
require.InDelta(t, v, m.Fields["value"], epsilon) require.InDelta(t, v, m.Fields["value"], epsilon)
@ -144,7 +165,7 @@ func TestRegularReceives_MultipleMessages(t *testing.T) {
listener := KNXListener{ listener := KNXListener{
ServiceType: "dummy", ServiceType: "dummy",
Measurements: []Measurement{ Measurements: []Measurement{
{"temperature", "1.001", []string{"1/1/1"}}, {Name: "temperature", Dpt: "1.001", Addresses: []string{"1/1/1"}},
}, },
Log: testutil.Logger{Name: "knx_listener"}, Log: testutil.Logger{Name: "knx_listener"},
} }
@ -197,7 +218,7 @@ func TestReconnect(t *testing.T) {
listener := KNXListener{ listener := KNXListener{
ServiceType: "dummy", ServiceType: "dummy",
Measurements: []Measurement{ Measurements: []Measurement{
{"temperature", "1.001", []string{"1/1/1"}}, {Name: "temperature", Dpt: "1.001", Addresses: []string{"1/1/1"}},
}, },
Log: testutil.Logger{Name: "knx_listener"}, Log: testutil.Logger{Name: "knx_listener"},
} }

View File

@ -13,6 +13,9 @@
# name = "temperature" # name = "temperature"
# ## Datapoint-Type (DPT) of the KNX messages # ## Datapoint-Type (DPT) of the KNX messages
# dpt = "9.001" # dpt = "9.001"
# ## Use the string representation instead of the numerical value for the
# ## datapoint-type and the addresses below
# # as_string = false
# ## List of Group-Addresses (GAs) assigned to the measurement # ## List of Group-Addresses (GAs) assigned to the measurement
# addresses = ["5/5/1"] # addresses = ["5/5/1"]