Skip to content

Commit

Permalink
feat(inputs.knx_listener): Allow usage of DPT string representation (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
srebhan authored Mar 27, 2024
1 parent 8c4fd53 commit 212822e
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 53 deletions.
3 changes: 3 additions & 0 deletions plugins/inputs/knx_listener/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
# name = "temperature"
# ## Datapoint-Type (DPT) of the KNX messages
# 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
# addresses = ["5/5/1"]

Expand Down
45 changes: 25 additions & 20 deletions plugins/inputs/knx_listener/knx_listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ type KNXInterface interface {

type addressTarget struct {
measurement string
datapoint dpt.DatapointValue
asstring bool
datapoint dpt.Datapoint
}

type Measurement struct {
Name string
Dpt string
Addresses []string
Name string `toml:"name"`
Dpt string `toml:"dpt"`
AsString bool `toml:"as_string"`
Addresses []string `toml:"addresses"`
}

type KNXListener struct {
Expand Down Expand Up @@ -83,7 +85,7 @@ func (kl *KNXListener) Init() error {
if !ok {
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}
}
}

Expand Down Expand Up @@ -164,8 +166,7 @@ func (kl *KNXListener) listen(acc telegraf.Accumulator) {
}

// Extract the value from the data-frame
err := target.datapoint.Unpack(msg.Data)
if err != nil {
if err := target.datapoint.Unpack(msg.Data); err != nil {
kl.Log.Errorf("Unpacking data failed: %v", err)
continue
}
Expand All @@ -175,19 +176,23 @@ func (kl *KNXListener) listen(acc telegraf.Accumulator) {
// as otherwise telegraf will not push out the metrics and eat it
// silently.
var value interface{}
vi := reflect.Indirect(reflect.ValueOf(target.datapoint))
switch vi.Kind() {
case reflect.Bool:
value = vi.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
value = vi.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
value = vi.Uint()
case reflect.Float32, reflect.Float64:
value = vi.Float()
default:
kl.Log.Errorf("Type conversion %v failed for address %q", vi.Kind(), ga)
continue
if !target.asstring {
vi := reflect.Indirect(reflect.ValueOf(target.datapoint))
switch vi.Kind() {
case reflect.Bool:
value = vi.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
value = vi.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
value = vi.Uint()
case reflect.Float32, reflect.Float64:
value = vi.Float()
default:
kl.Log.Errorf("Type conversion %v failed for address %q", vi.Kind(), ga)
continue
}
} else {
value = target.datapoint.String()
}

// Compose the actual data to be pushed out
Expand Down
87 changes: 54 additions & 33 deletions plugins/inputs/knx_listener/knx_listener_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,41 +60,62 @@ func produceKnxEvent(t *testing.T, address string, datapoint string, value inter

func TestRegularReceives_DPT(t *testing.T) {
// Define the test-cases
var testcases = []message{
{"1/0/1", "1.001", true},
{"1/0/2", "1.002", false},
{"1/0/3", "1.003", true},
{"1/0/9", "1.009", false},
{"1/1/0", "1.010", true},
{"5/0/1", "5.001", 12.157},
{"5/0/3", "5.003", 121.412},
{"5/0/4", "5.004", uint64(25)},
{"9/0/1", "9.001", 18.56},
{"9/0/4", "9.004", 243.84},
{"9/0/5", "9.005", 12.01},
{"9/0/7", "9.007", 59.32},
{"13/0/1", "13.001", int64(-15)},
{"13/0/2", "13.002", int64(183)},
{"13/1/0", "13.010", int64(-141)},
{"13/1/1", "13.011", int64(277)},
{"13/1/2", "13.012", int64(-4096)},
{"13/1/3", "13.013", int64(8192)},
{"13/1/4", "13.014", int64(-65536)},
{"13/1/5", "13.015", int64(2147483647)},
{"14/0/0", "14.000", -1.31},
{"14/0/1", "14.001", 0.44},
{"14/0/2", "14.002", 32.08},
// {"14/0/3", "14.003", 92.69},
// {"14/0/4", "14.004", 1.00794},
{"14/1/0", "14.010", 5963.78},
{"14/1/1", "14.011", 150.95},
var testcases = []struct {
address string
dpt string
asstring bool
value interface{}
expected interface{}
}{
{"1/0/1", "1.001", false, true, true},
{"1/0/2", "1.002", false, false, false},
{"1/0/3", "1.003", false, true, true},
{"1/0/9", "1.009", false, false, false},
{"1/1/0", "1.010", false, true, true},
{"1/1/1", "1.001", true, true, "On"},
{"1/1/2", "1.001", true, false, "Off"},
{"1/1/3", "1.002", true, true, "True"},
{"1/1/4", "1.002", true, false, "False"},
{"1/1/5", "1.003", true, true, "Enable"},
{"1/1/6", "1.003", true, false, "Disable"},
{"1/1/7", "1.009", true, true, "Close"},
{"1/1/8", "1.009", true, false, "Open"},
{"1/2/0", "1.010", true, true, "Start"},
{"1/2/1", "1.010", true, false, "Stop"},
{"5/0/1", "5.001", false, 12.157, 12.157},
{"5/0/3", "5.003", false, 121.412, 121.412},
{"5/0/4", "5.004", false, uint64(25), uint64(25)},
{"9/0/1", "9.001", false, 18.56, 18.56},
{"9/0/4", "9.004", false, 243.84, 243.84},
{"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{}

// Setup the unit-under-test
measurements := make([]Measurement, 0, len(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{
ServiceType: "dummy",
Expand Down Expand Up @@ -129,8 +150,8 @@ func TestRegularReceives_DPT(t *testing.T) {
require.Equal(t, "test", m.Measurement)
require.Equal(t, testcases[i].address, m.Tags["groupaddress"])
require.Len(t, m.Fields, 1)
switch v := testcases[i].value.(type) {
case bool, int64, uint64:
switch v := testcases[i].expected.(type) {
case string, bool, int64, uint64:
require.Equal(t, v, m.Fields["value"])
case float64:
require.InDelta(t, v, m.Fields["value"], epsilon)
Expand All @@ -144,7 +165,7 @@ func TestRegularReceives_MultipleMessages(t *testing.T) {
listener := KNXListener{
ServiceType: "dummy",
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"},
}
Expand Down Expand Up @@ -197,7 +218,7 @@ func TestReconnect(t *testing.T) {
listener := KNXListener{
ServiceType: "dummy",
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"},
}
Expand Down
3 changes: 3 additions & 0 deletions plugins/inputs/knx_listener/sample.conf
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
# name = "temperature"
# ## Datapoint-Type (DPT) of the KNX messages
# 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
# addresses = ["5/5/1"]

Expand Down

0 comments on commit 212822e

Please sign in to comment.