Compare commits
13 Commits
0.2
...
optional_g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20502f14ff | ||
|
|
596288161a | ||
|
|
3edebcf6f8 | ||
|
|
120a717efc | ||
|
|
829f7cbe58 | ||
|
|
e14fb13bcd | ||
|
|
bfaef6ef76 | ||
|
|
b4c756bc40 | ||
|
|
688f9d1088 | ||
|
|
a67298263e | ||
|
|
d0a44b902c | ||
|
|
08f54e55ce | ||
|
|
0daa79454f |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1 +1,6 @@
|
||||
/build/
|
||||
dist/
|
||||
*.egg-info/
|
||||
__pycache__
|
||||
config.yaml
|
||||
env/
|
||||
8
.travis.yml
Normal file
8
.travis.yml
Normal 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
|
||||
25
CHANGELOG.md
Normal file
25
CHANGELOG.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Changelog
|
||||
|
||||
## 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)
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* Fixed packaging of `config_default.yaml`
|
||||
|
||||
## v0.1 (2020-09-06)
|
||||
|
||||
* Initial version
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Ben Roberts
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
56
README.md
Normal file
56
README.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# energy-usage
|
||||
|
||||
Realtime energy usage reporting from Bright MQTT feed (SEP) into InfluxDB/VictoriaMetrics. Can be installed and run via pip or docker.
|
||||
|
||||
## Configuration
|
||||
|
||||
Copy `config.yaml.example` to `config.yaml` and fill in your MQTT login details, and your influx/vm server details.
|
||||
The config file should be placed into one of the following locations:
|
||||
|
||||
* `/etc/energy-usage/config.yaml`
|
||||
* `~/.config/energy-usage/config.yaml`
|
||||
* Any dir pointed at by `ENERGY-USAGEDIR` env var
|
||||
|
||||
## Pip usage
|
||||
|
||||
### Installation
|
||||
|
||||
pip install energy-usage
|
||||
|
||||
### Run
|
||||
|
||||
```bash
|
||||
energy-usage [--debug] [--noop]
|
||||
```
|
||||
|
||||
* `--debug` enables verbose output about what the script is doing
|
||||
* `--noop` mode will retrieve stats from mqtt, and show you what would be published to influx but does not actually send anything
|
||||
|
||||
## Docker usage
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
docker build -t energy-usage:latest .
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
```bash
|
||||
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).
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||
* Python 3
|
||||
* VictoriaMetrics 1.40
|
||||
* Docker 19.03.05
|
||||
* Nomad 0.12.4
|
||||
BIN
energy-usage-dashboard.png
Normal file
BIN
energy-usage-dashboard.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 201 KiB |
@@ -1 +1 @@
|
||||
VERSION = "0.1"
|
||||
VERSION = "0.4"
|
||||
|
||||
@@ -99,8 +99,9 @@ def main():
|
||||
usage = parse_sep(msg.topic, msg.payload)
|
||||
if usage:
|
||||
usage_datapoints = usage_to_datapoints(usage)
|
||||
logger.debug('Writing metrics to influx: %s', usage_datapoints)
|
||||
if not config["noop"].get(bool):
|
||||
influx_client.write_points(usage_datapoints)
|
||||
influx_client.write_points(usage_datapoints, noop=config["noop"].get(bool))
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
|
||||
|
||||
@@ -31,30 +31,7 @@ def parse_sep(topic, 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)
|
||||
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)
|
||||
|
||||
data = {
|
||||
@@ -63,7 +40,21 @@ def parse_sep(topic, payload_str):
|
||||
'topic': topic,
|
||||
'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': {
|
||||
'mpan': electricity_mpan,
|
||||
},
|
||||
@@ -74,8 +65,23 @@ def parse_sep(topic, payload_str):
|
||||
'consumption_monthly': electricity_monthly_consumption * 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': {
|
||||
'mpan': gas_mpan,
|
||||
},
|
||||
@@ -85,8 +91,13 @@ def parse_sep(topic, payload_str):
|
||||
'consumption_monthly': gas_monthly_consumption * 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
|
||||
|
||||
@@ -95,11 +106,12 @@ def usage_to_datapoints(usage):
|
||||
datapoints = []
|
||||
|
||||
for utility in ['electricity', 'gas']:
|
||||
datapoints.append({
|
||||
"measurement": utility,
|
||||
"tags": {**usage['tags'], **usage[utility]['tags']},
|
||||
"time": usage['timestamp'].isoformat(),
|
||||
"fields": usage[utility]['metrics'],
|
||||
})
|
||||
if utility in usage:
|
||||
datapoints.append({
|
||||
"measurement": utility,
|
||||
"tags": {**usage['tags'], **usage[utility]['tags']},
|
||||
"time": usage['timestamp'].isoformat(),
|
||||
"fields": usage[utility]['metrics'],
|
||||
})
|
||||
|
||||
return datapoints
|
||||
|
||||
1654
grafana.energy-usage.json
Normal file
1654
grafana.energy-usage.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user