diff --git a/README.md b/README.md index df97c5d32898271e1d88a9e780896dc73e0432ee..e3c8b38b9cb0611d1434228c4beb491546e33dd2 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,16 @@ Query: curl localhost:3089 +## Systemd service + +See `opensprinkler_prometheus_exporter.service` for an example system service +unit file. + +## Grafana dashbord + +See `grafana/opensprinkler.json` for an example dashboard +and `grafana/opensprinkler.jsonnet` for it's +[grafonnet](https://grafana.github.io/grafonnet-lib/)/jsonnet code. ## References * [Opensprinkler](https://opensprinkler.com/) diff --git a/grafana/opensprinkler.json b/grafana/opensprinkler.json new file mode 100644 index 0000000000000000000000000000000000000000..f2b5bac9bce1d052a1e461aa485693b230f86e94 --- /dev/null +++ b/grafana/opensprinkler.json @@ -0,0 +1,843 @@ +{ + "__inputs": [ ], + "__requires": [ ], + "annotations": { + "list": [ ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ ], + "refresh": "", + "rows": [ + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 1, + "fill": 1, + "fillGradient": 0, + "gridPos": { }, + "id": 2, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "opensprinkler_wt_eto", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ type }}", + "refId": "A" + } + ], + "thresholds": [ ], + "timeFrom": null, + "timeShift": null, + "title": "Evapotranspiration (ETo)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ ] + }, + "yaxes": [ + { + "decimals": 1, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": 1, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 1, + "fill": 1, + "fillGradient": 0, + "gridPos": { }, + "id": 3, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "opensprinkler_wt_precip", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "precipation", + "refId": "A" + } + ], + "thresholds": [ ], + "timeFrom": null, + "timeShift": null, + "title": "Precipation", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ ] + }, + "yaxes": [ + { + "decimals": 1, + "format": "mm", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": 1, + "format": "mm", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 1, + "fill": 1, + "fillGradient": 0, + "gridPos": { }, + "id": 4, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "opensprinkler_wt_wind", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Wind velocity", + "refId": "A" + } + ], + "thresholds": [ ], + "timeFrom": null, + "timeShift": null, + "title": "Wind", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ ] + }, + "yaxes": [ + { + "decimals": 1, + "format": "velocitymph", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": 1, + "format": "velocitymph", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 1, + "fill": 1, + "fillGradient": 0, + "gridPos": { }, + "id": 5, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "opensprinkler_wt_radiation", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Solar radiation", + "refId": "A" + } + ], + "thresholds": [ ], + "timeFrom": null, + "timeShift": null, + "title": "Solar radiation", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ ] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Wm2", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": 1, + "format": "Wm2", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 1, + "fill": 1, + "fillGradient": 0, + "gridPos": { }, + "id": 6, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "opensprinkler_wt_temp_c", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ type }}", + "refId": "A" + } + ], + "thresholds": [ ], + "timeFrom": null, + "timeShift": null, + "title": "Temperature", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ ] + }, + "yaxes": [ + { + "decimals": 1, + "format": "celsius", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": 1, + "format": "celsius", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 1, + "fill": 1, + "fillGradient": 0, + "gridPos": { }, + "id": 7, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "opensprinkler_wt_hum", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ type }}", + "refId": "A" + } + ], + "thresholds": [ ], + "timeFrom": null, + "timeShift": null, + "title": "Humidity", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ ] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percent", + "label": null, + "logBase": 1, + "max": 100, + "min": null, + "show": true + }, + { + "decimals": 1, + "format": "percent", + "label": null, + "logBase": 1, + "max": 100, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 1, + "fill": 1, + "fillGradient": 0, + "gridPos": { }, + "id": 8, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "opensprinkler_water_level", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Calculated water level", + "refId": "A" + } + ], + "thresholds": [ ], + "timeFrom": null, + "timeShift": null, + "title": "Water level", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ ] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percent", + "label": null, + "logBase": 1, + "max": 250, + "min": null, + "show": true + }, + { + "decimals": 1, + "format": "percent", + "label": null, + "logBase": 1, + "max": 250, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { }, + "id": 9, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "opensprinkler_station_open", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ station }}", + "refId": "A" + } + ], + "thresholds": [ ], + "timeFrom": null, + "timeShift": null, + "title": "Station open", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": 1, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": 1, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "dateTimeAsLocal", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { }, + "id": 10, + "interval": null, + "links": [ ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "opensprinkler_last_weather_call{type=\"request\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ type }}", + "refId": "A" + } + ], + "thresholds": "", + "title": "Last weather provider request", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ ], + "templating": { + "list": [ ] + }, + "time": { + "from": "now-1d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Opensprinkler", + "version": 0 +} diff --git a/grafana/opensprinkler.jsonnet b/grafana/opensprinkler.jsonnet new file mode 100644 index 0000000000000000000000000000000000000000..626743e1d8f9b9e62d94f5b3575aeb51a137effb --- /dev/null +++ b/grafana/opensprinkler.jsonnet @@ -0,0 +1,139 @@ +# Todo: +# +# * Fix date singlestat for last weather API call which shows the wrong time +# The grafonnet-lib API doesn't provide a `fields` key for `singlestat`, but +# it does so for `stat` + +local grafana = import 'github.com/grafana/grafonnet-lib/grafonnet/grafana.libsonnet'; +local dashboard = grafana.dashboard; +local row = grafana.row; +local prometheus = grafana.prometheus; +local template = grafana.template; +local graphPanel = grafana.graphPanel; +local singlestat = grafana.singlestat; + +local precipation = + graphPanel.new( + 'Precipation', + datasource='Prometheus', + format='mm', + decimals=1, + ) + .addTarget(prometheus.target('opensprinkler_wt_precip', + legendFormat='precipation') + ); + +local evapotranspiration = + graphPanel.new( + 'Evapotranspiration (ETo)', + datasource='Prometheus', + # format='', + decimals=1, + ) + .addTarget(prometheus.target('opensprinkler_wt_eto', + legendFormat='{{ type }}') + ); + +local radiation = + graphPanel.new( + 'Solar radiation', + datasource='Prometheus', + format='Wm2', + decimals=1, + ) + .addTarget(prometheus.target('opensprinkler_wt_radiation', + legendFormat='Solar radiation') + ); + +local temperature = + graphPanel.new( + 'Temperature', + datasource='Prometheus', + format='celsius', + decimals=1, + ) + .addTarget(prometheus.target('opensprinkler_wt_temp_c', + legendFormat='{{ type }}') + ); + +local humidity = + graphPanel.new( + 'Humidity', + datasource='Prometheus', + format='percent', + decimals=1, + max=100 + ) + .addTarget(prometheus.target('opensprinkler_wt_hum', + legendFormat='{{ type }}') + ); + +local wind = + graphPanel.new( + 'Wind', + datasource='Prometheus', + format='velocitymph', + decimals=1, + ) + .addTarget(prometheus.target('opensprinkler_wt_wind', + legendFormat='Wind velocity') + ); + +local water_level = + graphPanel.new( + 'Water level', + datasource='Prometheus', + format='percent', + decimals=1, + max=250 + ) + .addTarget(prometheus.target('opensprinkler_water_level', + legendFormat='Calculated water level') + ); + +local station_open = + graphPanel.new( + 'Station open', + datasource='Prometheus', + max=1 + ) + .addTarget(prometheus.target('opensprinkler_station_open', + legendFormat='{{ station }}') + ); + +local last_request = + singlestat.new( + 'Last weather provider request', + datasource='Prometheus', + format='dateTimeAsLocal' + ) + .addTarget(prometheus.target('opensprinkler_last_weather_call{type="request"}', + legendFormat='{{ type }}') + ); + +dashboard.new( + 'Opensprinkler', + time_from='now-1d', + editable=true, +) +.addRow( + row.new() + .addPanel(evapotranspiration) + .addPanel(precipation) + .addPanel(wind) +) +.addRow( + row.new() + .addPanel(radiation) + .addPanel(temperature) + .addPanel(humidity) +) +.addRow( + row.new() + .addPanel(water_level) + .addPanel(station_open) +) +.addRow( + row.new() + .addPanel(last_request) +)