Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Prometheus support #195

Closed
wants to merge 50 commits into from
Closed

Conversation

kereis
Copy link

@kereis kereis commented Feb 13, 2021

See #193

If you open this project in GoLand, it will create a .idea/ directory which could have been tracked by Git.
Some metrics are implemented in handler.go and scan.go.
Each metrics is accessible via global variable.
Helper method UpdateMeasurementMetric adds flexibility to updating specific measurement without hardcoding Prometheus Metric in certain places.
When using newGaugeOpts/newCounterOpts, all objects will share the same namespace "mbmd"
@kereis kereis marked this pull request as draft February 20, 2021 15:06
@kereis kereis changed the title WIP: Add Prometheus support Add Prometheus support Feb 20, 2021
…auges of measurements

Instead of creating a new counter/gauges for a measurement by hand, we simply just add a newly added measurement to the appropriate counterVeh/gaugesVeh map. This also means that everytime a new measurement in meters.Measurement is introduced, the maps in prometheus.go need to be updated as well.
Instead of actively managing and storing each measurement in gauges and counters map respectively, in measurements.go, each entry in `iec` is assigned a PrometheusMetricType.

When prometheus_metrics.Init is called, the appropriate prometheus.Metric will be initialized and will still be stored in gauges/counters map, but its content now dynamically changes based on meters.Measurements actually enum entries, making meters.Measurements the single instance of responsibility for handling metric types.
Instead of creating only one instance of each Prometheus metric measurement, each metric will now differ in each device's manufacturer
Each static metrics is now categorized by interface `collectable`. `collectable.Collect()` will be called when all static metrics are registered to the default Prometheus registry.
When using `prometheus.MustRegister(...)`, the app will panic if a slice entry is nil. Meanwhile fail fast isn't bad, the stack trace doesn't provide enough/precise information about the panic.

`prometheus.Register(prometheus.Collector)` however returns an error object which makes it much easier to troubleshoot metric registrations.
If no device description is available, we cannot distinguish between all device structs which it makes also difficult to distinguish between metrics.

Therefore I add the device name that the config specifies in order to make them "comparable"
As these metrics are SunSpec specific, we integrate them into Prometheus metrics name
Add conversion funcs in order to display measurement values in units specifically set for Prometheus.

Starting with this commit, Kilowatt-hours are converted to Joules.
This is purely a change of expressions
This can be quite useful in case the serial number of the smart meter is missing
meters/units.go Outdated Show resolved Hide resolved
meters/units.go Outdated Show resolved Hide resolved
meters/units.go Outdated Show resolved Hide resolved
prometheus_metrics/measurements.go Outdated Show resolved Hide resolved
@kereis kereis marked this pull request as ready for review March 21, 2021 18:15
…eus names

This also renames measurementOptions functions:
- withPrometheusDescription -> withPrometheusHelpText
- withGenericPrometheusDescription -> withGenericPrometheusHelpText
- generatePrometheusDescription -> generatePrometheusHelpText
Prometheus metrics are now automatically converted to a measurement's elementary unit.
…riptions

Unit stuff is now in a separate package called `units`.
units.go has been completely refactored to use the functional options pattern as well.
Comment on lines +186 to +191
Sum: newInternalMeasurement(withDescription("Total Energy Sum"), withPrometheusName("energy_sum"), withUnit(units.KiloWattHour), withMetricType(Counter)),
SumT1: newInternalMeasurement(withDescription("Tariff 1 Energy Sum"), withUnit(units.KiloWattHour), withMetricType(Counter)),
SumT2: newInternalMeasurement(withDescription("Tariff 2 Energy Sum"), withUnit(units.KiloWattHour), withMetricType(Counter)),
SumL1: newInternalMeasurement(withDescription("L1 Energy Sum"), withUnit(units.KiloWattHour), withMetricType(Counter)),
SumL2: newInternalMeasurement(withDescription("L2 Energy Sum"), withUnit(units.KiloWattHour), withMetricType(Counter)),
SumL3: newInternalMeasurement(withDescription("L3 Energy Sum"), withUnit(units.KiloWattHour), withMetricType(Counter)),
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andig What does Total [Energy] Sum exactly mean? Does it represent a kind of balance between imported/exported energy?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is just the Sum value that mbmd is reading from the meters. Whether this is actually a sum of import and export (probably import - export) is up to the meter manufacturer.

Bus scan metrics are pointless as they're used for diagnosis purposes.
As they're not registered and no REST is available, we can remove these metrics.
…metheus

Also removes debug message of printing all measurement names.
This allows us to pass a measurement's timestamp and using setters on gauges.
@andig andig added the enhancement New feature or request label May 26, 2021
@SchumacherFM
Copy link

any update on this?

@RichieB2B
Copy link
Contributor

While not the same as a native Prometheus exporter, I am now using a python script to get the mbmd data via mqtt into Prometheus: https://github.com/RichieB2B/simple-mqtt-exporter/blob/main/examples/config-mbmd.py

@kereis
Copy link
Author

kereis commented Jan 5, 2024

Hey, I'm sorry, but I'm afraid I cannot provide real support or updates on this one. This implementation has been part of a research project some years before, and I can't guarantee its functionality anymore as e.g. I have no way to test this in a local environment properly.

Feel free to pick up on this MR if you think that the current code base suits your needs.

@SchumacherFM
Copy link

SchumacherFM commented Jan 7, 2024

@kereis Thanks for the update! Once my SolarEdge inverters are running will continue with your PR/MR.

https://github.com/SchumacherFM/mbmd already started with some refactorings of your code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants