From 51b627abce587364ab82cad32a4e8d30422e15b2 Mon Sep 17 00:00:00 2001 From: yan Date: Wed, 19 Apr 2023 01:06:13 +0200 Subject: [PATCH] Handle json payload in metric_per_topic mode --- Readme.md | 6 ++++++ hack/shellyplusht.yaml | 22 ++++++++++++++++++++++ pkg/config/config.go | 1 + pkg/metrics/extractor.go | 14 +++++++++++++- 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 hack/shellyplusht.yaml diff --git a/Readme.md b/Readme.md index 4e6da5c..c40e6c8 100644 --- a/Readme.md +++ b/Readme.md @@ -71,6 +71,12 @@ E.g let's assume the following MQTT JSON message: We can now set `json_parsing.seperator` to `/`. This allows us to specify `mqtt_name` as `computed/heat.index`. Keep in mind, `json_parsing.seperator` is a global setting. This affects all `mqtt_name` fields in your configuration. +Some devices like Shelly Plus H&T publish one metric per-topic in a JSON format: +``` +shellies/shellyplusht-xxx/status/humidity:0 {"id": 0,"rh":51.9} +``` +You can use PayloadField to extract the desired value. + ### Tasmota An example configuration for the tasmota based Gosund SP111 device is given in [examples/gosund_sp111.yaml](examples/gosund_sp111.yaml). diff --git a/hack/shellyplusht.yaml b/hack/shellyplusht.yaml new file mode 100644 index 0000000..0fbff98 --- /dev/null +++ b/hack/shellyplusht.yaml @@ -0,0 +1,22 @@ +mqtt: + server: tcp://mosquitto:1883 + topic_path: shellies/+/sensor/+ + device_id_regex: "shellies/(?P.*)/sensor" + metric_per_topic_config: + metric_name_regex: "shellies/(?P.*)/sensor/(?P.*)" + qos: 0 +cache: + timeout: 24h +metrics: + - prom_name: temperature + # The name of the metric in a MQTT JSON message + mqtt_name: status/temperature:0 + # The field to extract in JSON payload + PayloadField: rh + # The prometheus help text for this metric + help: shelly temperature reading + # The prometheus type for this metric. Valid values are: "gauge" and "counter" + type: gauge + # A map of string to string for constant labels. This labels will be attached to every prometheus metric + const_labels: + sensor_type: shellyplusht diff --git a/pkg/config/config.go b/pkg/config/config.go index c28a40e..376de29 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -130,6 +130,7 @@ type MetricPerTopicConfig struct { type MetricConfig struct { PrometheusName string `yaml:"prom_name"` MQTTName string `yaml:"mqtt_name"` + PayloadField string `yaml:"payload_field"` SensorNameFilter Regexp `yaml:"sensor_name_filter"` Help string `yaml:"help"` ValueType string `yaml:"type"` diff --git a/pkg/metrics/extractor.go b/pkg/metrics/extractor.go index 1f2ed47..0476cd1 100644 --- a/pkg/metrics/extractor.go +++ b/pkg/metrics/extractor.go @@ -51,7 +51,19 @@ func NewMetricPerTopicExtractor(p Parser, metricNameRegex *config.Regexp) Extrac return nil, nil } - m, err := p.parseMetric(config, string(payload)) + var rawValue interface{} + if config.PayloadField != "" { + parsed := gojsonq.New(gojsonq.SetSeparator(p.separator)).FromString(string(payload)) + rawValue = parsed.Find(config.PayloadField) + parsed.Reset() + if rawValue == nil { + return nil, fmt.Errorf("failed to extract field %s from payload %s", config.PayloadField, payload) + } + } else { + rawValue = string(payload) + } + + m, err := p.parseMetric(config, rawValue) if err != nil { return nil, fmt.Errorf("failed to parse metric: %w", err) }