13 Commits
0.3 ... master

Author SHA1 Message Date
Ben Roberts
a9461e20e6 Bump version to 0.5 2022-05-25 22:09:35 +01:00
Ben Roberts
b4c5ceb90e Merge pull request #4 from optiz0r/single_fuel
Support data for only a single meter
2022-05-25 22:07:55 +01:00
Ben Roberts
9e5ebeb744 Drop invalid noop keyword parameter 2022-05-25 21:52:31 +01:00
Ben Roberts
20502f14ff Handle messages which contain only electricity or gas data 2022-05-25 20:34:34 +01:00
Ben Roberts
596288161a Add noop change to kick travis 2022-05-25 20:32:45 +01:00
Ben Roberts
b7b57fb05e Add noop change to kick travis 2021-06-13 21:10:29 +01:00
Ben Roberts
3edebcf6f8 Add travis config 2021-06-13 20:51:44 +01:00
Ben Roberts
120a717efc Bump version and changelog to 0.4 2021-06-13 20:47:23 +01:00
Ben Roberts
829f7cbe58 Include dependencies in setup.py 2021-06-13 20:44:06 +01:00
Ben Roberts
e14fb13bcd Update grafana dashboard 2020-10-04 17:45:30 +01:00
Ben Roberts
bfaef6ef76 Update gitignore to omit build artifacts 2020-10-04 17:45:14 +01:00
Ben Roberts
b4c756bc40 Add grafana info to Readme 2020-09-13 13:01:09 +01:00
Ben Roberts
688f9d1088 Add grafana dashboard and screenshot 2020-09-13 12:55:15 +01:00
10 changed files with 1750 additions and 35 deletions

5
.gitignore vendored
View File

@@ -1 +1,6 @@
/build/ /build/
dist/
*.egg-info/
__pycache__
config.yaml
env/

8
.travis.yml Normal file
View File

@@ -0,0 +1,8 @@
language: python
python:
- "3.6" # current default Python on Travis CI
- "3.7"
# command to install dependencies
install:
- pip install -r requirements.txt
# noop change

View File

@@ -1,5 +1,26 @@
# Changelog # Changelog
## v0.5 (2022-05-25)
Improvements:
* Support messages containing data for a single meter
(electricity or gas only)
## v0.4 (2021-06-13)
Improvements:
* Added grafana dashboard
* Added dependencies to setup.py
* Published to pypi
## v0.3 (2020-09-13)
Misc:
* Add documentation
## v0.2 (2020-09-06) ## v0.2 (2020-09-06)
Bug fixes: Bug fixes:

View File

@@ -40,6 +40,14 @@ docker build -t energy-usage:latest .
docker run -v config.yaml:/etc/energy-usage/config.yaml energy-usage:latest docker run -v config.yaml:/etc/energy-usage/config.yaml energy-usage:latest
``` ```
## Grafana
`grafana.energy-usage.json` contains an example Grafana dashboard which consumes this data (using the prometheus query interface of VictoriaMetrics).
![Grafana dashboard screenshot](energy-usage-dashboard.png)
Upon import of the dashboard, you will be prompted to select your datasource, and enter your unit and standing charges. These are used to plot the costs of realtime usage data, and the daily/weekly/monthly consumption using accumulated usage statistics by the meters. The dashboard does not currently use live tarrif data, as this is not provided in the Bright MQTT feed.
## Tested with: ## Tested with:
* Python 3 * Python 3

BIN
energy-usage-dashboard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

View File

@@ -1 +1 @@
VERSION = "0.1" VERSION = "0.5"

View File

@@ -99,6 +99,7 @@ def main():
usage = parse_sep(msg.topic, msg.payload) usage = parse_sep(msg.topic, msg.payload)
if usage: if usage:
usage_datapoints = usage_to_datapoints(usage) usage_datapoints = usage_to_datapoints(usage)
logger.debug('Writing metrics to influx: %s', usage_datapoints)
if not config["noop"].get(bool): if not config["noop"].get(bool):
influx_client.write_points(usage_datapoints) influx_client.write_points(usage_datapoints)
except KeyboardInterrupt: except KeyboardInterrupt:

View File

@@ -31,30 +31,7 @@ def parse_sep(topic, payload_str):
payload = json.loads(payload_str) payload = json.loads(payload_str)
try:
assert(_get_metric(["elecMtr", "0702", "03", "00"]) == 0) # kWh
assert(_get_metric(["gasMtr", "0702", "03", "01"]) == 1) # m3
assert(_get_metric(["gasMtr", "0702", "03", "12"]) == 0) # kWh
except AssertionError:
logger.warning("Received a payload without expected data")
return None
timestamp = datetime.datetime.fromtimestamp(payload["gmtime"], tz=datetime.timezone.utc) timestamp = datetime.datetime.fromtimestamp(payload["gmtime"], tz=datetime.timezone.utc)
electricity_consumption = _get_metric(["elecMtr", "0702", "04", "00"])
electricity_daily_consumption = _get_metric(["elecMtr", "0702", "04", "01"])
electricity_weekly_consumption = _get_metric(["elecMtr", "0702", "04", "30"])
electricity_monthly_consumption = _get_metric(["elecMtr", "0702", "04", "40"])
electricity_multiplier = _get_metric(["elecMtr", "0702", "03", "01"])
electricity_divisor = _get_metric(["elecMtr", "0702", "03", "02"])
electricity_meter = _get_metric(["elecMtr", "0702", "00", "00"])
electricity_mpan = _get_metric(["elecMtr", "0702", "03", "07"], str)
gas_daily_consumption = _get_metric(["gasMtr", "0702", "0C", "01"])
gas_weekly_consumption = _get_metric(["gasMtr", "0702", "0C", "30"])
gas_monthly_consumption = _get_metric(["gasMtr", "0702", "0C", "40"])
gas_multiplier = _get_metric(["gasMtr", "0702", "03", "01"])
gas_divisor = _get_metric(["gasMtr", "0702", "03", "02"])
gas_meter = _get_metric(["gasMtr", "0702", "00", "00"])
gas_mpan = _get_metric(["gasMtr", "0702", "03", "07"], str)
device_gid = _get_metric(["gid"], str) device_gid = _get_metric(["gid"], str)
data = { data = {
@@ -63,7 +40,21 @@ def parse_sep(topic, payload_str):
'topic': topic, 'topic': topic,
'gid': device_gid, 'gid': device_gid,
}, },
'electricity': { }
try:
assert(_get_metric(["elecMtr", "0702", "03", "00"]) == 0) # kWh
electricity_consumption = _get_metric(["elecMtr", "0702", "04", "00"])
electricity_daily_consumption = _get_metric(["elecMtr", "0702", "04", "01"])
electricity_weekly_consumption = _get_metric(["elecMtr", "0702", "04", "30"])
electricity_monthly_consumption = _get_metric(["elecMtr", "0702", "04", "40"])
electricity_multiplier = _get_metric(["elecMtr", "0702", "03", "01"])
electricity_divisor = _get_metric(["elecMtr", "0702", "03", "02"])
electricity_meter = _get_metric(["elecMtr", "0702", "00", "00"])
electricity_mpan = _get_metric(["elecMtr", "0702", "03", "07"], str)
data.update({'electricity': {
'tags': { 'tags': {
'mpan': electricity_mpan, 'mpan': electricity_mpan,
}, },
@@ -74,8 +65,23 @@ def parse_sep(topic, payload_str):
'consumption_monthly': electricity_monthly_consumption * electricity_multiplier / electricity_divisor, 'consumption_monthly': electricity_monthly_consumption * electricity_multiplier / electricity_divisor,
'meter_reading': electricity_meter * electricity_multiplier / electricity_divisor, 'meter_reading': electricity_meter * electricity_multiplier / electricity_divisor,
}, },
}, }})
'gas': { except AssertionError:
pass
try:
assert(_get_metric(["gasMtr", "0702", "03", "01"]) == 1) # m3
assert(_get_metric(["gasMtr", "0702", "03", "12"]) == 0) # kWh
gas_daily_consumption = _get_metric(["gasMtr", "0702", "0C", "01"])
gas_weekly_consumption = _get_metric(["gasMtr", "0702", "0C", "30"])
gas_monthly_consumption = _get_metric(["gasMtr", "0702", "0C", "40"])
gas_multiplier = _get_metric(["gasMtr", "0702", "03", "01"])
gas_divisor = _get_metric(["gasMtr", "0702", "03", "02"])
gas_meter = _get_metric(["gasMtr", "0702", "00", "00"])
gas_mpan = _get_metric(["gasMtr", "0702", "03", "07"], str)
data.update({'gas': {
'tags': { 'tags': {
'mpan': gas_mpan, 'mpan': gas_mpan,
}, },
@@ -85,8 +91,13 @@ def parse_sep(topic, payload_str):
'consumption_monthly': gas_monthly_consumption * gas_multiplier / gas_divisor, 'consumption_monthly': gas_monthly_consumption * gas_multiplier / gas_divisor,
'meter_reading': gas_meter * gas_multiplier / gas_divisor, 'meter_reading': gas_meter * gas_multiplier / gas_divisor,
}, },
}, }})
} except AssertionError:
pass
if 'electricity' not in data and 'gas' not in data:
logger.warning("Received a payload without either electricity or gas data")
return None
return data return data
@@ -95,6 +106,7 @@ def usage_to_datapoints(usage):
datapoints = [] datapoints = []
for utility in ['electricity', 'gas']: for utility in ['electricity', 'gas']:
if utility in usage:
datapoints.append({ datapoints.append({
"measurement": utility, "measurement": utility,
"tags": {**usage['tags'], **usage[utility]['tags']}, "tags": {**usage['tags'], **usage[utility]['tags']},

1654
grafana.energy-usage.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -38,4 +38,10 @@ setup(
data_files=[ data_files=[
('/etc/energy-usage/config.yaml.example', ['config.yaml.example']), ('/etc/energy-usage/config.yaml.example', ['config.yaml.example']),
], ],
install_requires=[
'confuse~=1.3',
'influxdb~=5.3',
'paho-mqtt~=1.5',
]
) )