Giter VIP home page Giter VIP logo

mqtt2prometheus's Introduction

MQTT2Prometheus

This exporter translates from MQTT topics to prometheus metrics. The core design is that clients send arbitrary JSON messages on the topics. The translation between the MQTT representation and prometheus metrics is configured in the mqtt2prometheus exporter since we often can not change the IoT devices sending the messages. Clients can push metrics via MQTT to an MQTT Broker. This exporter subscribes to the broker and expose the received messages as prometheus metrics. Currently, the exporter supports only MQTT 3.1.

Overview Diagram

I wrote this exporter to expose metrics from small embedded sensors based on the NodeMCU to prometheus. The used arduino sketch can be found in the dht22tomqtt repository. A local hacking environment with mqtt2prometheus, a MQTT broker and a prometheus server is in the hack directory.

Assumptions about Messages and Topics

This exporter makes some assumptions about the MQTT topics. This exporter assumes that each client publish the metrics into a dedicated topic. The regular expression in the configuration field mqtt.device_id_regex defines how to extract the device ID from the MQTT topic. This allows an arbitrary place of the device ID in the mqtt topic. For example the tasmota firmware pushes the telemetry data to the topics tele/<deviceid>/SENSOR.

Let us assume the default configuration from configuration file. A sensor publishes the following message

{"temperature":23.20,"humidity":51.60, "computed": {"heat_index":22.92} }

to the MQTT topic devices/home/livingroom. This message becomes the following prometheus metrics:

temperature{sensor="livingroom",topic="devices/home/livingroom"} 23.2
heat_index{sensor="livingroom",topic="devices/home/livingroom"} 22.92
humidity{sensor="livingroom",topic="devices/home/livingroom"} 51.6

The label sensor is extracted with the default device_id_regex (.*/)?(?P<deviceid>.*) from the MQTT topic devices/home/livingroom. The device_id_regex is able to extract exactly one label from the topic path. It extracts only the deviceid regex capture group into the sensor prometheus label. To extract more labels from the topic path, have a look at this FAQ answer.

The topic path can contain multiple wildcards. MQTT has two wildcards:

  • +: Single level of hierarchy in the topic path
  • #: Many levels of hierarchy in the topic path

This page explains the wildcard in depth.

For example the topic_path: devices/+/sensors/# will match:

  • devices/home/sensors/foo/bar
  • devices/workshop/sensors/temperature

JSON Separator

The exporter interprets mqtt_name as gojsonq paths. Those paths will be used to find the value in the JSON message. For example mqtt_name: computed.heat_index addresses

{
  "computed": {
    "heat_index":22.92
  }
}

Some sensors might use a . in the JSON keys. Therefore, there the configuration option json_parsing.seperator in the exporter config. This allows us to use any other string to separate hierarchies in the gojsonq path. E.g let's assume the following MQTT JSON message:

{
  "computed": {
    "heat.index":22.92
  }
}

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.

Build

To build the exporter run:

make build

Only the latest two Go major versions are tested and supported.

Docker

Use Public Image

To start the public available image run:

docker run -it -v "$(pwd)/config.yaml:/config.yaml"  -p  9641:9641 ghcr.io/hikhvar/mqtt2prometheus:latest 

Please have a look at the latest relase to get a stable image tag. The latest tag may break at any moment in time since latest is pushed into the registries on every git commit in the master branch.

Build The Image locally

To build a docker container with the mqtt2prometheus exporter included run:

make container

To run the container with a given config file:

docker run -it -v "$(pwd)/config.yaml:/config.yaml"  -p 9641:9641 mqtt2prometheus:latest 

Configuration

The exporter can be configured via command line and config file.

Commandline

Available command line flags:

Usage of ./mqtt2prometheus:
  -config string
        config file (default "config.yaml")
  -listen-address string
        listen address for HTTP server used to expose metrics (default "0.0.0.0")
  -listen-port string
        HTTP port used to expose metrics (default "9641")
  -log-format string
        set the desired log output format. Valid values are 'console' and 'json' (default "console")
  -log-level value
        sets the default loglevel (default: "info")
  -version
        show the builds version, date and commit
  -web-config-file string
        [EXPERIMENTAL] Path to configuration file that can enable TLS or authentication for metric scraping.
  -treat-mqtt-password-as-file-name bool (default: false)
        treat MQTT2PROM_MQTT_PASSWORD environment variable as a secret file path e.g. /var/run/secrets/mqtt-credential. Useful when docker secret or external credential management agents handle the secret file. 

The logging is implemented via zap. The logs are printed to stderr and valid log levels are those supported by zap.

Config file

The config file can look like this:

mqtt:
 # The MQTT broker to connect to
 server: tcp://127.0.0.1:1883
 # Optional: Username and Password for authenticating with the MQTT Server
 user: bob
 password: happylittleclouds
 # Optional: for TLS client certificates
 ca_cert: certs/AmazonRootCA1.pem
 client_cert: certs/xxxxx-certificate.pem.crt
 client_key: certs/xxxxx-private.pem.key
 # Optional: Used to specify ClientID. The default is <hostname>-<pid>
 client_id: somedevice
 # The Topic path to subscribe to. Be aware that you have to specify the wildcard, if you want to follow topics for multiple sensors.
 topic_path: v1/devices/me/+
 # Optional: Regular expression to extract the device ID from the topic path. The default regular expression, assumes
 # that the last "element" of the topic_path is the device id.
 # The regular expression must contain a named capture group with the name deviceid
 # For example the expression for tasamota based sensors is "tele/(?P<deviceid>.*)/.*"
 device_id_regex: "(.*/)?(?P<deviceid>.*)"
 # The MQTT QoS level
 qos: 0
 # NOTE: Only one of metric_per_topic_config or object_per_topic_config should be specified in the configuration
 # Optional: Configures mqtt2prometheus to expect a single metric to be published as the value on an mqtt topic.
 metric_per_topic_config:
  # A regex used for extracting the metric name from the topic. Must contain a named group for `metricname`.
  metric_name_regex: "(.*/)?(?P<metricname>.*)"
 # Optional: Configures mqtt2prometheus to expect an object containing multiple metrics to be published as the value on an mqtt topic.
 # This is the default. 
 object_per_topic_config:
  # The encoding of the object, currently only json is supported
  encoding: JSON
cache:
 # Timeout. Each received metric will be presented for this time if no update is send via MQTT.
 # Set the timeout to -1 to disable the deletion of metrics from the cache. The exporter presents the ingest timestamp
 # to prometheus.
 timeout: 24h
 # Path to the directory to keep the state for monotonic metrics.
 state_directory: "/var/lib/mqtt2prometheus"
json_parsing:
 # Separator. Used to split path to elements when accessing json fields.
 # You can access json fields with dots in it. F.E. {"key.name": {"nested": "value"}}
 # Just set separator to -> and use key.name->nested as mqtt_name
 separator: .
# This is a list of valid metrics. Only metrics listed here will be exported
metrics:
 # The name of the metric in prometheus
 - prom_name: temperature
  # The name of the metric in a MQTT JSON message
   mqtt_name: temperature
  # The prometheus help text for this metric
   help: DHT22 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: dht22
  # The name of the metric in prometheus
 - prom_name: humidity
  # The name of the metric in a MQTT JSON message
   mqtt_name: humidity
  # The scale of the metric in a MQTT JSON message (prom_value = mqtt_value * scale)
   mqtt_value_scale: 100
  # The prometheus help text for this metric
   help: DHT22 humidity 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: dht22
  # The name of the metric in prometheus
 - prom_name: heat_index
  # The path of the metric in a MQTT JSON message
   mqtt_name: computed.heat_index
  # The prometheus help text for this metric
   help: DHT22 heatIndex calculation
  # 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: dht22
  # The name of the metric in prometheus
 - prom_name: state
  # The name of the metric in a MQTT JSON message
   mqtt_name: state
  # Regular expression to only match sensors with the given name pattern
   sensor_name_filter: "^.*-light$"
  # The prometheus help text for this metric
   help: Light state
  # The prometheus type for this metric. Valid values are: "gauge" and "counter"
   type: gauge
  # according to prometheus exposition format timestamp is not mandatory, we can omit it if the reporting from the sensor is sporadic
   omit_timestamp: true
  # A map of string to string for constant labels. This labels will be attached to every prometheus metric
   const_labels:
    sensor_type: ikea
  # When specified, enables mapping between string values to metric values.
   string_value_mapping:
    # A map of string to metric value.
    map:
     off: 0
     low: 0
    # Metric value to use if a match cannot be found in the map above.
    # If not specified, parsing error will occur.
    error_value: 1
  # The name of the metric in prometheus
 - prom_name: total_light_usage_seconds
  # The name of the metric in a MQTT JSON message
   mqtt_name: state
  # Regular expression to only match sensors with the given name pattern
   sensor_name_filter: "^.*-light$"
  # The prometheus help text for this metric
   help: Total time the light was on, in seconds
  # The prometheus type for this metric. Valid values are: "gauge" and "counter"
   type: counter
  # according to prometheus exposition format timestamp is not mandatory, we can omit it if the reporting from the sensor is sporadic
   omit_timestamp: true
  # A map of string to string for constant labels. This labels will be attached to every prometheus metric
   const_labels:
    sensor_type: ikea
  # When specified, enables mapping between string values to metric values.
   string_value_mapping:
    # A map of string to metric value.
    map:
     off: 0
     low: 0
    # Metric value to use if a match cannot be found in the map above.
    # If not specified, parsing error will occur.
    error_value: 1
  # Sum up the time the light is on, see the section "Expressions" below.
  expression: "value > 0 ? last_result + elapsed.Seconds() : last_result"
  # The name of the metric in prometheus
 - prom_name: total_energy
  # The name of the metric in a MQTT JSON message
   mqtt_name: aenergy.total
  # Regular expression to only match sensors with the given name pattern
   sensor_name_filter: "^shellyplus1pm-.*$"
  # The prometheus help text for this metric
   help: Total energy used
  # The prometheus type for this metric. Valid values are: "gauge" and "counter"
   type: counter
  # This setting requires an almost monotonic counter as the source. When monotonicy is enforced, the metric value is regularly written to disk. Thus, resets in the source counter can be detected and corrected by adding an offset as if the reset did not happen. The result is a true monotonic increasing time series, like an ever growing counter.
   force_monotonicy: true

Environment Variables

Having the MQTT login details in the config file runs the risk of publishing them to a version control system. To avoid this, you can supply these parameters via environment variables. MQTT2Prometheus will look for MQTT2PROM_MQTT_USER and MQTT2PROM_MQTT_PASSWORD in the local environment and load them on startup.

Example use with Docker

Create a file to store your login details, for example at ~/secrets/mqtt2prom:

#!/bin/bash
export MQTT2PROM_MQTT_USER="myUser" 
export MQTT2PROM_MQTT_PASSWORD="superpassword"

Then load that file into the environment before starting the container:

 source ~/secrets/mqtt2prom && \
  docker run -it \
  -e MQTT2PROM_MQTT_USER \
  -e MQTT2PROM_MQTT_PASSWORD \
  -v "$(pwd)/examples/config.yaml:/config.yaml" \
  -p 9641:9641 \
  ghcr.io/hikhvar/mqtt2prometheus:latest

Example use with Docker secret (in swarm)

Create a docker secret to store the password(mqtt-credential in the example below), and pass the optional treat-mqtt-password-as-file-name command line argument.

  mqtt_exporter_tasmota:
    image: ghcr.io/hikhvar/mqtt2prometheus:latest 
    secrets:
      - mqtt-credential 
    environment:
      - MQTT2PROM_MQTT_USER=mqtt
      - MQTT2PROM_MQTT_PASSWORD=/var/run/secrets/mqtt-credential
    entrypoint:
      - /mqtt2prometheus
      - -log-level=debug
      - -treat-mqtt-password-as-file-name=true
    volumes:
        - config-tasmota.yml:/config.yaml:ro

Expressions

Metric values can be derived from sensor inputs using complex expressions. Set the metric config option expression to the desired formular to calculate the result from the input. Here's an example which integrates all positive values over time:

expression: "value > 0 ? last_result + value * elapsed.Seconds() : last_result"

During the evaluation, the following variables are available to the expression:

  • value - the current sensor value (after string-value mapping, if configured)
  • last_value - the value during the previous expression evaluation
  • last_result - the result from the previous expression evaluation
  • elapsed - the time that passed since the previous evaluation, as a Duration value

The language definition describes the expression syntax. In addition, the following functions are available:

  • now() - the current time as a Time value
  • int(x) - convert x to an integer value
  • float(x) - convert x to a floating point value
  • round(x) - rounds value x to the nearest integer
  • ceil(x) - rounds value x up to the next higher integer
  • floor(x) - rounds value x down to the next lower integer
  • abs(x) - returns the x as a positive number
  • min(x, y) - returns the minimum of x and y
  • max(x, y) - returns the maximum of x and y

Time and Duration values come with their own methods which can be used in expressions. For example, elapsed.Milliseconds() yields the number of milliseconds that passed since the last evaluation, while now().Sub(elapsed).Weekday() returns the day of the week during the previous evaluation.

The last_value, last_result, and the timestamp of the last evaluation are regularly stored on disk. When mqtt2prometheus is restarted, the data is read back for the next evaluation. This means that you can calculate stable, long-running time serious which depend on the previous result.

Evaluation Order

It is important to understand the sequence of transformations from a sensor input to the final output which is exported to Prometheus. The steps are as follows:

  1. The sensor input is converted to a number. If a string_value_mapping is configured, it is consulted for the conversion.
  2. If an expression is configured, it is evaluated using the converted number. The result of the evaluation replaces the converted sensor value.
  3. If force_monotonicy is set to true, any new value that is smaller than the previous one is considered to be a counter reset. When a reset is detected, the previous value becomes the value offset which is automatically added to each consecutive value. The offset is persistet between restarts of mqtt2prometheus.
  4. If mqtt_value_scale is set to a non-zero value, it is applied to the the value to yield the final metric value.

Frequently Asked Questions

Listen to multiple Topic Pathes

The exporter can only listen to one topic_path per instance. If you have to listen to two different topic_paths it is recommended to run two instances of the mqtt2prometheus exporter. You can run both on the same host or if you run in Kubernetes, even in the same pod.

Extract more Labels from the Topic Path

A regular use case is, that user want to extract more labels from the topic path. E.g. they have sensors not only in their home but also in their workshop and they encode the location in the topic path. E.g. a sensor pushes the message

{"temperature":3.0,"humidity":34.60, "computed": {"heat_index":15.92} }

to the topic devices/workshop/storage, this will produce the prometheus metrics with the default configuration.

temperature{sensor="storage",topic="devices/workshop/storage"} 3.0
heat_index{sensor="storage",topic="devices/workshop/storage"} 15.92
humidity{sensor="storage",topic="devices/workshop/storage"} 34.60

The following prometheus relabel_config will extract the location from the topic path as well and attaches the location label.

relabel_config:
  - source_labels: [ "topic" ]
    target_label: location
    regex: '/devices/(.*)/.*'
    action: replace
    replacement: "$1"

With this config added to your prometheus scrape config you will get the following metrics in prometheus storage:

temperature{sensor="storage", location="workshop", topic="devices/workshop/storage"} 3.0
heat_index{sensor="storage", location="workshop", topic="devices/workshop/storage"} 15.92
humidity{sensor="storage", location="workshop", topic="devices/workshop/storage"} 34.60

mqtt2prometheus's People

Contributors

achmenz avatar alexbakker avatar anegrin avatar chr4 avatar chrschn avatar dependabot[bot] avatar dmolle avatar eyjhb avatar genkobar avatar hikhvar avatar m-rtijn avatar michael-robbins avatar mrtazz avatar mvadu avatar oxplot avatar pdostal avatar podorozhny avatar pulsar256 avatar renovate-bot avatar timbuchwaldt avatar vikramsubramanian avatar weboo avatar y-martin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mqtt2prometheus's Issues

ghcr.io/hikhvar/mqtt2prometheus:v0.1.6-RC8 doesn't work in a docker swarm

Not sure what is wrong with the image, but when I attempt to run in a docker swarm (docker service create ...) i get
no suitable node (unsupported platform on 1 node)

However, running with docker run seems to work without issue on the same host.

I had no issues testing with v0.1.5 so I'm not sure what changed.

Some info about my node

 Kernel Version: 5.10.7-0-virt
 Operating System: Alpine Linux v3.13
 OSType: linux
 Architecture: x86_64

Docker version info

Client:
 Version:           20.10.2
 API version:       1.41
 Go version:        go1.15.6
 Git commit:        2291f610ae73533e6e0749d4ef1e360149b1e46b
 Built:             Tue Jan  5 22:06:36 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server:
 Engine:
  Version:          20.10.2
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.15.6
  Git commit:       8891c58a433a823ce0a65b57efff45f32ee9cb45
  Built:            Tue Jan  5 21:59:41 2021
  OS/Arch:          linux/amd64
  Experimental:     true
 containerd:
  Version:          v1.4.3
  GitCommit:        269548fa27e0089a8b8278fc4fc781d7f65a939b
 runc:
  Version:          1.0.0-rc92
  GitCommit:        ff819c7e9184c13b7c2607fe6c30ae19403a7aff
 docker-init:
  Version:          0.19.0
  GitCommit:

is a scraper needed?

(again) i'm newbie of prometheus & mqtt & mqtt2prometheus

I was wondering how the mqtt2prometheus can send the data to prometheus, and found out that it's prometheus that need to scrape it.

so i've added

- job_name: mqtt2prometheus
  scrape_interval: 10s
  scrape_timeout: 10s
  static_configs:
  - targets:
    - localhost:9641
    labels:
      alias: mqtt2prometheus

and guessing... where is documented that i need to add a scraper?
the closest sentence i've found is:

This exporter subscribes to the broker and publish the received messages as prometheus metrics. 

But this seems to be the other way round.

Thanks,

Support for non-JSON format messages

I'm trying to parse data from a sensor that sends "raw values", like:
sensors/temperature/28E66D1B000000D4 23.4375

It does not look like that format is supported, or am I missing something? Is JSON the only supported payload format?

Regards,
Flemming

Ability for standard web.config.file

Hi @hikhvar

One last bit is missing for my setup in terms of security: is to be able to use TLS and basic auth.
Both node-exporter (https://github.com/prometheus/node_exporter) and blackbox-exporter (https://github.com/prometheus/blackbox_exporter) supports a flag called --web.config.file which is making it possible for end user.

In their source code I see they use

webConfig     = webflag.AddFlags(kingpin.CommandLine)

to parse up the input here.

Unfortunately I'm technically not capable to submit a PR to rewrite your code to use this parsing method hence be able to use webconfig.
Do you think you can implement this kind of flag parsing so standard flags would be available with mqtt2prometheus?

Thank you

How to import an array

I am a newbie of both prometheus & mqtt & mqtt2prometheus.

Anyhow, i'm having trouble parsing the following json:

whatever/boiler {"temperature":23.34,"temperature_unit":"ยฐC","pressure":0,"pressure_unit":"bar","uptime":5116907,"mqttRawData":["00000011","11001011","01011101","11100000"]}

I've added the following section to mqtt2prometheus:

  -
    # The name of the metric in prometheus
    prom_name: whatever_boiler_rawdata
    # The name of the metric in a MQTT JSON message
    mqtt_name: mqttRawData
    # The prometheus help text for this metric
    help: rawdata arduino boiler
    # 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: arduino_boiler

Logs say:

2022-02-01T03:18:32+01:00        error        cmd/mqtt2prometheus.go:116        Error while processing message        {"error": "could not store metrics '{\"temperature\":23.24,\"temperature_unit\":\"ยฐC\",\"pressure\":-0.01,\"pressure_unit\":\"bar\",\"uptime\":5229573,\"mqttRawData\":[\"00000011\",\"11001001\",\"01011101\",\"11000000\"]}' on topic whatever/boiler: failed to parse valid metric value: got data with unexpectd type: []interface {} ('[00000011 11001001 01011101 11000000]')"}

So is possible to import the 4 raw data into prometheus as array index?

Thanks,

allow topic format to add more segments

hey @hikhvar,

first of all, great work! this tool is the missing piece of the golden puzzle.

i have a question regarding the topic format

# The Topic path to subscripe to. Actually this will become `$topic_path/+`
topic_path: v1/devices/me

does it make sense to you to allow multiple levels

the way it is now

# The Topic path to subscripe to. Actually this will become `$topic_path/#`
topic_path: v1/devices/me/

i'm asking this in the scenario where there is a location nesting like

myhome/groundflood/livingroom
myhome/groundfloor/kitchen
myhome/attic/kitchen
myhome/attic/bathroom

hmm

Publish images to docker hub

The images published to the dockerhub are outdated. This causes headaches for the user (#19). The CI pipeline should publish the images to the dockerhub, too.

make container fails due to not used time package

Hi,

at the moment make container is not working due to the imported time package in mqtt2prometheus.go:

# github.com/hikhvar/mqtt2prometheus/cmd
cmd/mqtt2prometheus.go:7:2: imported and not used: "time"
Makefile:52: recipe for target 'static_build' failed
make: *** [static_build] Error 2

As I'm no developer, I cannot say if it's needed there, but without it, the container build is working again.

container doesn't seem to start in k8s using tasmota topics

Maybe I'm dense, but I haven't been able to get this to work for an hour now. Can someone EILI5?

logs from the container (in kubernetes)

kubectl logs -f mqtt-55c8754dd6-kbls6 mqtt-exporter
2020/10/12 05:05:41 Connected to MQTT Broker.
2020/10/12 05:05:41 Will subscribe to topic tele/+/SENSOR/+

MQTT Lens showing topics:
image

config.yaml:

mqtt:
  server: tcp://localhost:1883
  topic_path: tele/+/SENSOR
  device_id_regex: "tele/(?P<deviceid>.*)/.*"
  qos: 0
cache:
  timeout: 24h
metrics:
  - prom_name: power
    mqtt_name: Power
    help: Power reading
    type: gauge
  - prom_name: voltage
    mqtt_name: Voltage
    help: Voltage Reading
    type: gauge
  - prom_name: current
    mqtt_name: Current
    help: Current Reading
    type: gauge
  - prom_name: pf
    mqtt_name: Factor
    help: Power Factor reading
    type: gauge
  - prom_name: today
    mqtt_name: Today
    help: Todays kWH usage
    type: counter
  - prom_name: yesterday
    mqtt_name: Yesterday
    help: Yesterday's kWh usage
    type: counter
  - prom_name: total
    mqtt_name: Total
    help: Total kWh usage
    type: counter

I'm probably doing something really stupid here, but the container just won't successfully run.

Edit 1. Ok after looking at the examples folder, I basically copied and pasted the example doc, but still doesn't start:

mqtt:
  server: tcp://localhost:1883
  topic_path: tele/+/SENSOR
  device_id_regex: "tele/(?P<deviceid>.*)/SENSOR"
  qos: 0
cache:
  timeout: 24h
metrics:
  # The name of the metric in prometheus
  - prom_name: consumed_energy_kilowatthours_total
    mqtt_name: "ENERGY.Total"
    help: "total measured kilowatthours since flash"
    type: counter
  - prom_name: voltage_volts
    mqtt_name: "ENERGY.Voltage"
    help: "Currently measured voltage"
    type: gauge
  - prom_name: current_amperes
    mqtt_name: "ENERGY.Current"
    help: "Currently measured current"
    type: gauge
  - prom_name: power_watts
    mqtt_name: "ENERGY.Power"
    help: "Currently measured power"
    type: gauge
  - prom_name: apparent_power_watt
    mqtt_name: "ENERGY.ApparentPower"
    help: "Currently apparent power"
    type: gauge
  - prom_name: reactive_power_watt
    mqtt_name: "ENERGY.ReactivePower"
    help: "Currently reactive power"
    type: gauge

Edit 2: it seems it might be related to forcing the "+" at the end? when I use MQTT lens to look at that topic, nothing comes up:
image

CA Certs still not 'comprehensive'

So this might not be an issue, and feel free to just close if you think what's currently there is good enough and my workaround is something the user can easily do (maybe a doco update to help future users).

This still can't connect directly to my mosquitto mqtt broker with TLS enabled through Letsencrypt.

I've had to mount in my local servers cacerts file and overwrite the one in the image to get it to connect successfully.

--volume "/etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro"

This just allowed it to connect automatically using Ubuntu 20.04's default ca certs (I'm not doing anything special here, just default everything afaik).

I'm not totally sure of the solution here thought that could easily fix this without me having to mount in Ubuntu's certs to trust letsencrypt?

Map json prop as labels

Hi,

It would be nice to be able to map some properties as labels to help identify devices which publish to a single topic.

I have a use case with rtl_433 which is collecting weather station data into a single topic at rtl_433/{hostname}/events

Here is an example json:

{
   "time":"2021-11-11 14:18:45",
   "model":"Fineoffset-WHx080",
   "subtype":0,
   "id":196,
   "battery_ok":1,
   "temperature_C":13.1,
   "humidity":90,
   "wind_dir_deg":135,
   "wind_avg_km_h":1.224,
   "wind_max_km_h":3.672,
   "rain_mm":58.5,
   "mic":"CRC"
}

It would be useful to be able to map id or model to labels to help identify the device event.

- prom_name: temperature
  mqtt_name: temperature_C
  type: gauge
  labels:
  - model
  - id
  - subtype

Add configuration example for Shelly 3em Energy Meter

Hi,

I've spent some time to figure out how to configure mqtt2prometheus for my Shelly 3em Energy Meter.
Guess this might be usefull to others as well and could be inlcuded in the configuration examples.

Shelly 3em metrics example

$ mosquitto_sub -t "shellies/shellyem3-123456789/emeter/+/+" -v

shellies/shellyem3-123456789/emeter/0/power 41.25
shellies/shellyem3-123456789/emeter/0/pf 0.18
shellies/shellyem3-123456789/emeter/0/current 0.99
shellies/shellyem3-123456789/emeter/0/voltage 232.25
shellies/shellyem3-123456789/emeter/0/total 13372.4
shellies/shellyem3-123456789/emeter/0/total_returned 0.0
shellies/shellyem3-123456789/emeter/1/power 275.04
shellies/shellyem3-123456789/emeter/1/pf 0.72
shellies/shellyem3-123456789/emeter/1/current 1.65
shellies/shellyem3-123456789/emeter/1/voltage 232.83
shellies/shellyem3-123456789/emeter/1/total 27948.4
shellies/shellyem3-123456789/emeter/1/total_returned 0.0
shellies/shellyem3-123456789/emeter/2/power -2.23
shellies/shellyem3-123456789/emeter/2/pf -0.02
shellies/shellyem3-123456789/emeter/2/current 0.39
shellies/shellyem3-123456789/emeter/2/voltage 233.14
shellies/shellyem3-123456789/emeter/2/total 4107.8
shellies/shellyem3-123456789/emeter/2/total_returned 186.9

shelly_3em.yaml configuration

# Settings for the MQTT Client. Currently only these three are supported
mqtt:
  # The MQTT broker to connect to
  server: tcp://127.0.0.1:1883
  # Optional: Username and Password for authenticating with the MQTT Server
  # user: bob
  # password: happylittleclouds
  
  # The Topic path to subscribe to. Be aware that you have to specify the wildcard.
  topic_path: shellies/shellyem3-123456789/emeter/+/+

  # Use the phase number as device_id in order to see all three phases in /metrics
  device_id_regex: "shellies/(.*)/emeter/(?P<deviceid>.*)/.*"

  # Metrics are being published on a per-topic basis.
  metric_per_topic_config:
    metric_name_regex: "shellies/(?P<deviceid>.*)/emeter/(.*)/(?P<metricname>.*)"
  # The MQTT QoS level
  qos: 0
cache:
  timeout: 60m

metrics:
  - prom_name: power
    mqtt_name: power
    type: gauge
    const_labels:
      sensor_type: shelly

  - prom_name: voltage
    mqtt_name: voltage
    type: gauge
    const_labels:
      sensor_type: shelly

Result in /metrics. Label "sensor" = energy meter phase

# HELP power 
# TYPE power gauge
power{sensor="0",sensor_type="shelly",topic="shellies/shellyem3-123456789/emeter/0/power"} 35.4 1661984533463
power{sensor="1",sensor_type="shelly",topic="shellies/shellyem3-123456789/emeter/1/power"} 401.45 1661984533465
power{sensor="2",sensor_type="shelly",topic="shellies/shellyem3-123456789/emeter/2/power"} -2.31 1661984533467
# TYPE received_messages counter
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/0/current"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/0/pf"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/0/power"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/0/total"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/0/total_returned"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/0/voltage"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/1/current"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/1/pf"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/1/power"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/1/total"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/1/total_returned"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/1/voltage"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/2/current"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/2/pf"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/2/power"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/2/total"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/2/total_returned"} 4
received_messages{status="success",topic="shellies/shellyem3-123456789/emeter/2/voltage"} 4
# HELP voltage 
# TYPE voltage gauge
voltage{sensor="0",sensor_type="shelly",topic="shellies/shellyem3-123456789/emeter/0/voltage"} 231.78 1661984533464
voltage{sensor="1",sensor_type="shelly",topic="shellies/shellyem3-123456789/emeter/1/voltage"} 232.46 1661984533466
voltage{sensor="2",sensor_type="shelly",topic="shellies/shellyem3-123456789/emeter/2/voltage"} 232.71 1661984533468

Suggestion for Dockerfile

Hello everyone,

first of all, I have to thank everybody who is working on this project.

I love to read that code, even I am pretty new in this mqtt and prometheus universe and I am struggling with this project for a while.

But I have a suggestion.

Issue:

My first issue was to run this project as a docker container in debug-mode.
Command
docker run -it -v "$(pwd)/config.yaml:/config.yaml" -p 9641:9641 ghcr.io/hikhvar/mqtt2prometheus:latest -log-level debug

But all my parameters are ignored.
I figured out that the way how the current docker image is build, it will not execute my parameters correctly.

During my try and errors, I found the issue.
Dockerfile
line 10: CMD ["/mqtt2prometheus"]

Suggestion:

Dockerfile
line 10: ENTRYPOINT ["/mqtt2prometheus"]
I read the Docker reference file as far I understand, does the start of a container use the execution as entrypoint and read all following parameters.

Command:

docker run -it -v "$(pwd)/config.yaml:/config.yaml" -p 9641:9641 ghcr.io/hikhvar/mqtt2prometheus:latest -log-level debug

Result:

The container starts with the expected log-level debug like the CLI-Version.

Thank you for your attention and maybe it helps.
Forgive me, for my terrible english.

Relabel not working

Hi,

I'm trying to use relabel_configs, similar to explained in README.md. The message delivery to mqtt2prometheus (/metrics):
temperature{sensor="storage",topic="devices/workshop/storage"} 1 1655098848611.

Follow a snippet of my prometheus.yml:

  - job_name: mqtt2prometheus
    static_configs:
    - targets: ['mqtt2prometheus:9641']
      labels:
        service: 'mqtt2prometheus'

    relabel_configs:
    - source_labels: ["topic"]
      target_label: location
      regex: 'devices/(.*)/.*'
      action: replace
      replacement: "$1"

And my config.yml:

mqtt:
  # The MQTT broker to connect to
  server: tcp://mosquitto:1883
  # Optional: Username and Password for authenticating with the MQTT Server
  # user: bob
  # password: happylittleclouds
  # Optional: for TLS client certificates
  # ca_cert: certs/AmazonRootCA1.pem
  # client_cert: certs/xxxxx-certificate.pem.crt
  # client_key: certs/xxxxx-private.pem.key
  # Optional: Used to specify ClientID. The default is <hostname>-<pid>
  # client_id: somedevice
  # The Topic path to subscribe to. Be aware that you have to specify the wildcard.
  topic_path: devices/+/#
  # Optional: Regular expression to extract the device ID from the topic path. The default regular expression, assumes
  # that the last "element" of the topic_path is the device id.
  # The regular expression must contain a named capture group with the name deviceid
  # For example the expression for tasamota based sensors is "tele/(?P<deviceid>.*)/.*"
  # device_id_regex: "(.*/)?(?P<deviceid>.*)"
  # The MQTT QoS level
  qos: 0
cache:
  # Timeout. Each received metric will be presented for this time if no update is send via MQTT.
  # Set the timeout to -1 to disable the deletion of metrics from the cache. The exporter presents the ingest timestamp
  # to prometheus.
  timeout: 24h
json_parsing:
  # Separator. Used to split path to elements when accessing json fields.
  # You can access json fields with dots in it. F.E. {"key.name": {"nested": "value"}}
  # Just set separator to -> and use key.name->nested as mqtt_name
  separator: .
# This is a list of valid metrics. Only metrics listed here will be exported
metrics:
  - prom_name: temperature
    mqtt_name: temperature
    help: Device temperature
    type: gauge

I'm using latest stable version for prometheus and mqtt2prometheus.

MQTT Events to Loki and Prometheus Remote-write

Sometimes the data returned via MQTT could be events rather than a regular stream of metrics.
See the following pull request for the MQTT Sparkplug exporter which implements amongst other things:
Pull request for IHI-Energy-Storage/sparkpluggw

  • go decision tree for selecting events versus metrics (This is staticaly done in mqtt2prometheus, which is fine)
  • remote-write metrics to prometheus (for added scalability with high volume event streams)
  • remote-writing events to loki (in logfmt format for easy auto-parsing in loki)
  • relabelling metrics natively in the exporter (for scalability concerns)
  • relabelling events natively in the exporter (for scalability concerns)
  • adding static labels to metrics or events (already supported by mqtt2prometheus)

You can let yourself be inspired to a more complete feature set in mqtt2prometheus.

Exporter does not support MQTT metrics with dots in the name

The exporter doesn't support metrics in a JSON payload with dots in the key, since it uses gojsonq's Find() method which valuates a dot as a delimiter in a JSON path.

This means an MQTT message payload like the following will not work since the JSON parser expects a nested JSON structure:

{"particles_2.5um": 5}

The examples don't imply that the metric names are intended to be json paths, so this seems like something that should be called out in the docs. A quick fix is to enable the ability to use a different json path delimiter in the json parser, ex.

parsed := gojsonq.New(gojsonq.WithSeparator(";")).FromString(string(payload))

However that's not the most intuitive solution.

Add Kubernetes config example

Thanks for this package, nice job! Would be nice to have a kubernetes setup example. I'll submit a PR if you think it would be of interest to others.

Document how to configure Prometheus

I just installed and set up mqtt2prometheus, but there's no info on what needs to be changed in Prometheus to make it grab data. Would it be possible to provide an example? I'm guessing I have to make Prometheus connect to your daemon on port 8002 somehow.

Publish to a publicly available image registry

Hey! Just trying this out and noticed you've only published to Github's container registry, what are the chances of also publishing to Docker Hub or similar registry that doesn't require authentication before pulling?

It's really hard to automate the deployment of this image when I need to pass my github creds everywhere across my network!

Thanks!!

Publish multi-arch Docker images supporting ARM

Currently only x86-64 compatible docker images are pushed into the public registries. Since MQTT is often used in embedded contexts, or home automation setups with a raspberry PI as main hub, ARM docker images should be published.

Option a) Wait For /Push this efffort in goreleaser: goreleaser. goreleaser/goreleaser#530
Option b) Build the docker images with another tool.

deviceid regex idea expanded on

Hiya!

I really like the device_id named regex group idea, I'm wondering what's the appetite to expand that and have other named groups to extra metadata from the topic name and include them as attributes in the metric?

For example:

MQTT Message:

{"temperature":23.20,"humidity":51.60, "computed": {"heat_index":22.92} }

MQTT Topic:

site/melbourne/north/weather-01/metrics

Device ID Regex:

"site/(?P<site>[^\\/]+)/(?P<category>[^\\/]+)/(?P<deviceid>[^\\/]+)/metrics"

Would result in:

temperature{site="melbourne",category="north",deviceid="weather-01",topic="site/melbourne/north/weather-01/metrics"} 23.2
heat_index{site="melbourne",category="north",deviceid="weather-01",topic="site/melbourne/north/weather-01/metrics"} 22.92
humidity{site="melbourne",category="north",deviceid="weather-01",topic="site/melbourne/north/weather-01/metrics"} 51.6

I'm not actually sure what the deviceid regex actually does, as your example in the README doesn't actually include the 'output' of the named group in any examples? Or maybe deviceid is a prometheus concept I haven't discovered yet!

But what are your thoughts about the above?

how to use the exporter

Hello.
I have used docker run to start it.
and got:
2021-07-22T08:28:02Z info mqttclient/mqttClient.go:20 Connected to MQTT Broker
2021-07-22T08:28:02Z info mqttclient/mqttClient.go:21 Will subscribe to topic {"topic": "mdata/400101000b000c06/upAll/"}
2021-07-22T08:28:02Z info web/tls_config.go:191 {"level": "info", "msg": "TLS is disabled.", "http2": false}
it seems it works
But I got 404 on http://localhost:9164
so it works or not.

Wrong port - Keep port usage consistent

Hi,
I build the docker image on a RPI 4 and tried to run it with -p 8002:8002 which didn't work.
It must be -p 8002:9641 which isn't mentioned in the Readme.md.

I suggest to either change the port during building to 8002 or keep it as it is at 9641 and mention this in the Readme.md

Additionally it would be nice if ARM images are provided on Dockerhub.

Feature request: Support for boolean / non-string datatype mappings

I saw the string_value_mapping so something similar or a solution for generic data types should be possible.

This would support more sensors like motion, contact, water etc.

example config:

metrics:
  - prom_name: contact
    mqtt_name: contact
    sensor_name_filter: "^Contact[0-]+$"
    help: Door/Window Contact Sensor
    type: gauge
    bool_value_mapping:
      # A map of bool to metric value.
      map:
        false: 0
        true: 1
      # Metric value to use if a match cannot be found in the map above.
      # If not specified, parsing error will occur.
      error_value: 2
    const_labels:
      sensor_type: aqara

The metrics endpoint

Hello, I would like to thank you for the great effort you are doing for that project.

I used this project in my setup and I was able to connect to the MQTT successfully, also I can see the metrics printed out in the logs when I enabled the debug level logging. But when I tried to access the /metrics endpoint what I get are some internal metrics ( i.e. go_gc_duration_seconds{quantile="0"} 4.5e-05 ) .. the only part I found which can be relevant to the MQTT is below 3 lines and the number at the end of the third line (13) increased whenever new metric added to the Topic. Is that expected or I have missed something in my configuration?

# HELP received_messages received messages per topic and status
# TYPE received_messages counter
received_messages{status="success",topic="mydev/3/test_metrics"} 13

Below is the config file used:

mqtt:
 server: tcp://10.51.209.100:1883
 client_id: testmqqt
 topic_path: mydev/3/test_metrics
 device_id_regex: "mydev/?(?P<deviceid>.*)/.*"
 qos: 0
cache:
 timeout: 24h
json_parsing:
 separator: .
metrics:
 - prom_name: cpu_load
   mqtt_name: cpu_load
   help: test CPU load
   type: gauge
 - prom_name: memory_usage
   mqtt_name: memory_usage
   help: test memory usage
   type: gauge

And below is the mqtt2prometheus logs :

2022-03-11T15:16:30Z info mqttclient/mqttClient.go:21 Will subscribe to topic {"topic": "mydev/3/test_metrics"}
2022-03-11T15:16:31Z debug metrics/ingest.go:42 Got message {"topic": "mydev/3/test_metrics", "payload": "{"cpu_load":95.80 ,"memory_usage":123456789678.60 }\u0000"}

Thanks ..

Beginner Issues

Hi

First, I'm seeing a lot of go-related metrics in the output

go_gc_duration_seconds{quantile="0"} 3.2688e-05

I'm new to prometheus, but doesn't spamming it with 100s of extra metrics cause
some memory use - or should I configure prom to ignore anything starting with 'go'

Am I missing something?

Second, I'm sending messages like this:

topic: watchdog/esp-garage:
Payload: {"message": "Alive"}

I get this on the output:

received_messages{status="storeError",topic="watchdog/esp-garage"} 34

previously I sent non-JSON messages and it was happier, but I didn't see
a direct metric for my line.

My configuration is below - any thoughts?

 topic_path: watchdog/#
 device_id_regex: "(.*/)?(?P<deviceid>.*)"
 qos: 0
cache:
   timeout: 24h
json_parsing:
 - prom_name: watchdog
   mqtt_name: message
   help: Watchdog message
   type: gauge

Thanks

Martin Green

MQTT listener goes 'stale'

So I'm running mqtt2prometheus and it seems to generally work, but after some time, no more messages are received from mqtt.

The prometheus exporter side is still working (as prometheus reports the target as 'up').

I've enabled debug messaging, but nothing really comes up.

What kinda extra stuff can I enable? Happy to hack away and built it myself with extra debug logging enabled or something.

My guess is probably the component that listens to the mqtt topic has gone stale/timed out/needs to reconnect, but it never does and it just sits there doing nothing.

Thoughts? Might stare at the code later, just raising this as a first step :)

Multiple Istance, containers

Hi, I added a second istance today, I had to expose to a different localhost port (9642), and to configure another prometheus Job, is it the right way of proceding?
<
docker run -d -it -v "$(pwd)/config_04851E.yaml:/config.yaml" -p 9642:9641 ghcr.io/hikhvar/mqtt2prometheus:latest
>
in prometheus.yml

  • job_name: '04851E'
    static_configs:
    • targets: ['localhost:9642']

Caching doesn't work?

I've set the following:

mqtt:
  cache:
    timeout: 24h

I understood the docs, that this means a queried value will be cached for 24h if no other value is received.
However, that doesn't seem the case. When curling the exporter, the metric shows up only for a minute or so, afterwards disappears.

Skimming the source, I couldn't find anything with c.Get(), only c.Set() - but I might be overlooking something here.

Is this a bug? Glad to help out with more details or implemenation!

Incorrect port used

mqtt2prometheus is built from source in hack/docker-compose.yml. Shouldn't the port then be 9641:9641 instead of 8002:8002 for the mqtt2prometheus service?

I'd be happy to submit a pull request for the issue.

Thanks,
Vikram

Cannot connect to a TLS enabled MQTT broker? CA certs missing in container?

Heya, just trying out this tool and struggling to get connected to my MQTT broker (eclipse-mosquitto) with TLS enabled (and working with a few different programs already, paho.mqtt.python library to name a good example).

I'm got the below setup:

mqtt:
  server: ssl://mqtt.my.proper.domain.name:8883
michael@server:~$ openssl s_client -connect mqtt.my.proper.domain.name:8883
CONNECTED(00000003)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = mqtt.my.proper.domain.name
verify return:1
---
Certificate chain
 0 s:CN = mqtt.my.proper.domain.name
   i:C = US, O = Let's Encrypt, CN = R3
 1 s:C = US, O = Let's Encrypt, CN = R3
   i:O = Digital Signature Trust Co., CN = DST Root CA X3
---

And I'm seeing this error repeating:

2021-02-28T12:19:49Z	warn	cmd/mqtt2prometheus.go:99	could not connect to mqtt broker %s, sleep 10 second	{"error": "Network Error : x509: certificate signed by unknown authority"}

Now I know the certificate is signed by letsencrypt and that's all dandy, so I'm going to go out on a limb and say the CA certs in the image are either missing/out of date/etc? Not 100% sure?

I'm poking around on the internet to see if there's other Go libraries that have similar issues!

Data extraction issue

Hey there,

I freshly set up mqtt2prometheus with all the proper configs, and everything seems to work just fine. Somehow I'm not able to find the metrics I try to extract inside prometheus.

Extract of config.yaml

topic_path: home/ruuvi/+/sensor/+
device_id_regex: "home/ruuvi/(?P<deviceid>.*)/sensor/(?P<metricname>.*)"
metrics:
  - prom_name: temperature
    mqtt_name: temperature
    type: gauge
    const_labels:
      sensor_type: ruuvitag

Debug message of mqtt2prometheus:

2021-08-04T20:35:29Z	debug	metrics/ingest.go:42	Got message	{"topic": "home/ruuvi/FD-A6-86-79-13-C0/sensor/temperature", "payload": "21.34"}

Message visible in /metrics of prometheus

received_messages{status="success",topic="home/ruuvi/FD-A6-86-79-13-C0/sensor/temperature"} 99

And yet I'm not able to find any mqtt2prometheus-metrics on prometheus. The only metric available is mqtt2prometheus_connected

Any hints where I did a mistake?

Can't export Shelly HT, bug or configuration?

Hi!

First of all, thanks for releasing your mqtt2prometheus exporter under a OSS licence, it is much appreciated.

I'm failing to export the metrics of a Shelly HT thermometer and can't figure out, what is going wrong. Maybe you have an idea and can help?

Best regards
Calli

mqtt:
   server: tcp://mosquitto:1883
   topic_path: shellies/shellyht-livingroom/sensor/+
   device_id_regex: "shellies/(?P<deviceid>.*)/sensor"
   qos: 0
 cache:
   timeout: 24h
 metrics:
   - prom_name: temperature
     mqtt_name: temperature
     help: DHT22 temperature reading
     type: gauge
Starting mqtt2prometheus ... done
Attaching to mqtt2prometheus
mqtt2prometheus    | 2020-11-06T11:31:15Z	info	mqttclient/mqttClient.go:18	Connected to MQTT Broker
mqtt2prometheus    | 2020-11-06T11:31:15Z	info	mqttclient/mqttClient.go:19	Will subscribe to topic	{"topic": "shellies/shellyht-livingroom/sensor/+"}

The metrics:

/ # mosquitto_sub -t "shellies/shellyht-livingroom/sensor/+" -v
shellies/shellyht-livingroom/sensor/temperature 29.12
shellies/shellyht-livingroom/sensor/humidity 41.5
shellies/shellyht-livingroom/sensor/battery 99
shellies/shellyht-livingroom/sensor/error 0
shellies/shellyht-livingroom/sensor/act_reasons ["button"]

The curl output:

mg@raspberrypi:~ $ curl raspberrypi:9641/metrics | grep shelly
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  6629    0  6629    0     0   462k      0 --:--:-- --:--:-- --:--:--  462k
received_messages{status="success",topic="shellies/shellyht-livingroom/sensor/act_reasons"} 1
received_messages{status="success",topic="shellies/shellyht-livingroom/sensor/battery"} 1
received_messages{status="success",topic="shellies/shellyht-livingroom/sensor/error"} 1
received_messages{status="success",topic="shellies/shellyht-livingroom/sensor/humidity"} 1
received_messages{status="success",topic="shellies/shellyht-livingroom/sensor/temperature"} 1

Help wanted related to shelly1 with temperature module

Hi,

I've been looking at your project, and it's looking great!

I'm currently pulling temperature values from Shelly1 hardware with temperature module. The hardware module can have up to three temp sensors attached.

I've implemented it as three separate metrics, because i have yet to figure out how to put it all in the same one. (Is this possible?)

The documentation for this hardware and module can be found here: https://shelly-api-docs.shelly.cloud/gen1/#shelly1-1pm-mqtt

here's some JSON example data on the topic "shellies/shelly1-C45BBE77777B/ext_temperatures" is this:

{
  "0": {
    "hwID": "28f7f676e0000000",
    "tC": 25.9
  },
  "1": {
    "hwID": "28f7f676e0011111",
    "tC": 15.9
  },
  "2": {
    "hwID": "28f7f676e0022222",
    "tC": 6.9
  }
}

The config i'm using is roughly this:

mqtt:
  topic_path: shellies/+/ext_temperatures
  device_id_regex: "shellies/(?P<deviceid>.*)/ext_temperatures"

metrics:
  - prom_name: shelly_temperature_0
    mqtt_name: 0.tC
    help: shelly temperature reading
    type: gauge
    const_labels:
      sensor_type: shelly

Metrics are repeated prom_names "shelly_temperature_1 and 2, as well as mqtt_names: 1.tC and 2.tC

I'm greatful for any assistance.

Metrics not matching `sensor_name_filter` treated as errors

Perhaps this is feature and not a bug, so please help me understand if I misunderstanding.

I'm trying to use sensor_name_filter to filter out sensors (e.g. mqtt topics) that produce a specific mqtt metric (e.g key in the json value published on the topic). It works (e.g. doesn't parse and generate metrics for topics that don't match), however, it treats it as an error state, producing and error metric for Prometheus and also logging the error.

From reading the code, it seems to me like the problem is that the check for SensorNameFilter.Match should not happen in parse.validMetric, since not finding the config is a error case (albeit a pathological one, since it just checked to see that there was something in the config in the extractor configured in NewJSONObjectExtractor) but it not matching the filter is not. parseMetric is currently required to return something so there's not really way to filter from in there at all, so a bit of a code refactor would be required to make this work.

I'm happy to put together a pull request if you agree the behavior I'm describing is, in fact, correct.

ghcr.io/hikhvar/mqtt2prometheus:v0.1.7-rc1 config file loading error

Looks like ghcr.io/hikhvar/mqtt2prometheus:v0.1.7-rc1 triggers the following error:

2022-08-24T12:06:46Z	fatal	cmd/mqtt2prometheus.go:80	Could not load config	{"error": "open config.yaml: no such file or directory"}
main.main
	/home/runner/work/mqtt2prometheus/mqtt2prometheus/cmd/mqtt2prometheus.go:80
runtime.main
	/opt/hostedtoolcache/go/1.19.0/x64/src/runtime/proc.go:250

Moving from latest to v0.1.6 image tag solved the problem.

I can help with further debug but the config file should be there as the helm chart didn't change.

Thank you,
Radu

how to config it so that I can get this item

Dear
I really need this exporter for my further work. but I did not config it correctly for what I want.

Here is the data in my mqtt broker.

{
"app": {
"moteeui": "32010124131300ed",
"Class": 0,
"type": "payload",
"confirmed": true,
"userdata": {
"seqno": 1617,
"port": 2,
"payload": "qmcBAO0LAwBEAAAAAAAAAP4=",
"motetx": {
"freq": 472,
"modu": "LORA",
"datr": "SF7BW125",
"codr": "4/5",
"adr": false
}
},
"gwrx": [
{
"eui": "34010a44124e0025",
"time": "",
"timefromgateway": false,
"chan": 3,
"rfch": 1,
"rssi": -67,
"lsnr": 10
},
{
"eui": "34010a44124e0068",
"time": "",
"timefromgateway": false,
"chan": 3,
"rfch": 1,
"rssi": -34,
"lsnr": 8.8
}
]
}
}
in which, the app/userdata/payload is the mandatory item I need.
and my topic is mdata/400101000b000c06/upALL .
the device id is 400101000b000c06
May I ask you to give an example of the configuration file to get the item as prometheus metric?

Thank you so much !!!

trouble finding the right yaml

HI there,

please apologize, I seem to be unable to find thr right settings for the exporter .. But .. the documentation could be a bit clearer IMO, some more examples would helped me maybe.

Can anybody guide me in the right direction ? I am having

hoymiles/111817603175/pf 0.999   
hoymiles/111816703175/frequency 49.97   
hoymiles/111816703175/temperature 57.8    
hoymiles/111816703175/total 275.775   
hoymiles/111816703175/emeter/0/power 636.8   
hoymiles/111816703175/emeter/0/voltage 237.6   
hoymiles/111816703175/emeter/0/current 2.68   
hoymiles/111816703175/emeter-dc/0/total 70.852   
hoymiles/111816703175/emeter-dc/0/power 253.6
hoymiles/111816703175/emeter-dc/0/voltage 38.8
hoymiles/111816703175/emeter-dc/0/current 6.54
hoymiles/111816703175/emeter-dc/1/total 72.247
hoymiles/111816703175/emeter-dc/1/power 262.1
hoymiles/111816703175/emeter-dc/1/voltage 38.8
hoymiles/111816703175/emeter-dc/1/current 6.76
hoymiles/111816703175/emeter-dc/2/total 69.769
hoymiles/111816703175/emeter-dc/2/power 109.2
hoymiles/111816703175/emeter-dc/2/voltage 43.5
hoymiles/111816703175/emeter-dc/2/current 2.51
hoymiles/111816703175/emeter-dc/3/total 62.91
hoymiles/111816703175/emeter-dc/3/power 45.4
hoymiles/111816703175/emeter-dc/3/voltage 43.5
hoymiles/111816703175/emeter-dc/3/current 1.04

in mosquitto, and would like to get that into prometheus .. What does my config.yaml need to look like ? The best I was able to achieve was a

2022-10-16T16:39:43Z error cmd/mqtt2prometheus.go:158 Error while processing message {"error": "could not store metrics '275.798' on topic hoymiles/111816703175/total: failed to extract metric values from topic: failed to find valid metric in topic path"}

and some more of this kind of messages..

any help would really be appreciated, best regards

How to get around the one topic limit in k8s

Not an issue, just thought I'd share this if anyone is running this in K8s like I am (at home). Since it has an assumption of a single topic, you need to spin up multiple containers in a pod for each topic. I did this by defining 2 seperate config files, then running on different ports (using a service monitor to have prometheus autmatically grab them. Here's the pod definition relevant to the 2 containers, if it helps anyone:

- name: mqtt-exporter
        image: docker.pkg.github.com/hikhvar/mqtt2prometheus/mqtt2prometheus:v0.1.2
        volumeMounts:
        - name: dockerdata
          subPath: mqttexporter/config.yaml
          mountPath: /config.yaml
        ports:
          - name: mqtt-exporter
            containerPort: 9641
      - name: mqtt-exporter2
        image: docker.pkg.github.com/hikhvar/mqtt2prometheus/mqtt2prometheus:v0.1.2
        volumeMounts:
        - name: dockerdata
          subPath: mqttexporter/config2.yaml
          mountPath: /config.yaml
        command: ["./mqtt2prometheus"]
        args: ["-listen-port", "9642"]
        ports:
          - name: mqtt-exporter
            containerPort: 9642

Feature request: Extract custom labels from topic

Hello,

It would be nice to be able to extract labels (other than deviceid) from the mqtt topic. A new config dict with labelname: regex pairs could be very useful for adding labels with data encoded in mqtt topics.

Thanks! :)

Refactor Documentation

The documentation is rather dated and confusing. It needs a big refactoring.
For example the confusion shown in #45
Or the missing documentation on the shelly devices.

How to detect when MQTT is unreachable

Hello,

I'm might be off here a bit, but would like to get a bit of help, how would we detect by this exporter if the connection between the exported and MQTT is down?
I read the cache timeout option which is keeping data there for a defined amount of time.

What I would like to get help with: how would I see if mqtt2prometheus exporter is UP but my MQTT bridge is down (or connectivity between mqtt2prometheus and MQTT bridge is down)

Let's say I monitoring temperature (gauge) and losing my MQTT and cache is there forever (-1), showing "old" values forever. I would like to see somehow that my MQTT is having issues so I can fix it.

Any idea?

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.