forked from ragingcomputer/amridm2mqtt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
amridm2mqtt
executable file
·113 lines (87 loc) · 3.82 KB
/
amridm2mqtt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/usr/bin/env python3
'''
Runs rtlamr to watch for IDM broadcasts from power meter. If meter id
is in the list, usage is sent to 'readings/{meter id}/meter_reading'
topic on the MQTT broker specified in settings.
WATCHED_METERS = A Python list indicating those meter IDs to record and post.
MQTT_HOST = String containing the MQTT server address.
MQTT_PORT = An int containing the port the MQTT server is active on.
'''
import os
import subprocess
import signal
import sys
import time
import paho.mqtt.publish as publish
import settings
# uses signal to shutdown and hard kill opened processes and self
def shutdown(signum, frame):
rtltcp.send_signal(15)
rtlamr.send_signal(15)
time.sleep(1)
rtltcp.send_signal(9)
rtlamr.send_signal(9)
sys.exit(0)
signal.signal(signal.SIGTERM, shutdown)
signal.signal(signal.SIGINT, shutdown)
# stores last interval id to avoid duplication, includes getter and setter
last_reading = {}
auth = None
if len(settings.MQTT_USER) and len(settings.MQTT_PASSWORD):
auth = {'username':settings.MQTT_USER, 'password':settings.MQTT_PASSWORD}
DEBUG=os.environ.get('DEBUG', '').lower() in ['1', 'true', 't']
def debug_print(*args, **kwargs):
if DEBUG:
print(*args, **kwargs)
def get_last_interval(meter_id):
return last_reading.get(meter_id, (None))
def set_last_interval(meter_id, interval_ID):
last_reading[meter_id] = (interval_ID)
# send data to MQTT broker defined in settings
def send_mqtt(topic, payload,):
try:
publish.single(topic, payload=payload, qos=1, hostname=settings.MQTT_HOST, port=settings.MQTT_PORT, auth=auth)
except Exception as ex:
print("MQTT Publish Failed: " + str(ex))
# start the rtl_tcp program
rtltcp = subprocess.Popen([settings.RTL_TCP + " > /dev/null 2>&1 &"], shell=True,
stdin=None, stdout=None, stderr=None, close_fds=True)
time.sleep(5)
# start the rtlamr program.
rtlamr_cmd = [settings.RTLAMR, '-msgtype=idm', '-format=csv']
rtlamr = subprocess.Popen(rtlamr_cmd, stdout=subprocess.PIPE, universal_newlines=True)
while True:
try:
amrline = rtlamr.stdout.readline().strip()
flds = amrline.split(',')
if len(flds) != 66:
# proper IDM results have 66 fields
continue
# make sure the meter id is one we want
meter_id = int(flds[9])
if settings.WATCHED_METERS and meter_id not in settings.WATCHED_METERS:
continue
# get some required info: current meter reading, current interval id, most recent interval usage
read_cur = int(flds[15])
interval_cur = int(flds[10])
idm_read_cur = int(flds[16])
# retreive the interval id of the last time we sent to MQTT
interval_last = get_last_interval(meter_id)
if interval_cur != interval_last:
# as observed on on my meter...
# using values set in settings...
# each idm interval is 5 minutes (12x per hour),
# measured in hundredths of a kilowatt hour
# take the last interval usage times 10 to get watt-hours,
# then times 12 to get average usage in watts
rate = idm_read_cur * settings.WH_MULTIPLIER * settings.READINGS_PER_HOUR
current_reading_in_kwh = (read_cur * settings.WH_MULTIPLIER) / 1000
debug_print('Sending meter {} reading: {}'.format(meter_id, current_reading_in_kwh))
send_mqtt('readings/{}/meter_reading'.format(meter_id), str(current_reading_in_kwh))
debug_print('Sending meter {} rate: {}'.format(meter_id, rate))
send_mqtt('readings/{}/meter_rate'.format(meter_id), str(rate))
# store interval ID to avoid duplicating data
set_last_interval(meter_id, interval_cur)
except Exception as e:
debug_print('Exception squashed! {}: {}', e.__class__.__name__, e)
time.sleep(2)