Here is script I made based on above idea. This script is very resilient and should never miss pulses as long as it running (e.g. even if Domoticz stalls/stops it will keep accumulating counts and will send update to Domoticz when it can). Also it minimizes amount of code running inside interrupt handler, avoiding swamping Domoticz with update requests, high CPU usage or even missed updates if many pulses happen quickly.
You can adjust delay inside main loop to whatever *maximum* frequency you want Domoticz to be updated (script won't even bother trying to update if counter does not change). It will never miss pulses so can be whatever you want, but 30 secs is reasonable considering 1 minute is generally lowest precision you can get from Domoticz reports anyway.
This script requires that you make "Virtual Incremental Counter" in "Dummy" device on Domoticz and set their IDs as GAS_IDX & ELEC_IDX inside script
Set GAS_GPIO and ELEC_GPIO to your input GPIOs
Code: Select all
#!/usr/bin/env python
#imports
import time
import RPi.GPIO as GPIO
import json
import urllib2
import threading
#vars
GET_URL = 'http://localhost:8080/json.htm?type=devices&rid=%d'
SET_URL = 'http://localhost:8080/json.htm?type=command¶m=udevice&idx=%d&svalue=%d'
GAS_DELTA = 0
GAS_IDX = 3
GAS_GPIO = 26
GAS_COUNTER_LOCK = threading.Lock()
ELEC_DELTA = 0
ELEC_IDX = 4
ELEC_GPIO = 16
ELEC_COUNTER_LOCK = threading.Lock()
def gpio_intr(pin):
if pin == GAS_GPIO:
global GAS_DELTA
with GAS_COUNTER_LOCK:
GAS_DELTA += 1
print 'Gas counter tick: %d' % GAS_DELTA
if pin == ELEC_GPIO:
global ELEC_DELTA
with ELEC_COUNTER_LOCK:
ELEC_DELTA += 1
print 'Electricity counter tick: %d' % ELEC_DELTA
def main():
global GAS_DELTA
global ELEC_DELTA
GPIO.setmode(GPIO.BCM)
GPIO.setup(GAS_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(GAS_GPIO, GPIO.RISING, callback=gpio_intr, bouncetime=100)
GPIO.setup(ELEC_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(ELEC_GPIO, GPIO.RISING, callback=gpio_intr, bouncetime=100)
while True:
time.sleep(5)
GAS_DELTA_POST = GAS_DELTA
if GAS_DELTA_POST != 0:
try:
res = json.load(urllib2.urlopen(SET_URL % (GAS_IDX, GAS_DELTA_POST)))
if res['status'] != 'OK':
raise Exception('Domoticz json error')
with GAS_COUNTER_LOCK:
GAS_DELTA -= GAS_DELTA_POST
except Exception as e:
print e
ELEC_DELTA_POST = ELEC_DELTA
if ELEC_DELTA_POST != 0:
try:
res = json.load(urllib2.urlopen(SET_URL % (ELEC_IDX, ELEC_DELTA_POST)))
if res['status'] != 'OK':
raise Exception('Domoticz json error')
with ELEC_COUNTER_LOCK:
ELEC_DELTA -= ELEC_DELTA_POST
except Exception as e:
print e
print 'Gas delta %d; Elec delta %d' % (GAS_DELTA_POST, ELEC_DELTA_POST)
if __name__=="__main__":
main()
To set your "actual" meter values, issue "fake update" to meter via JSON, or run script with initial xxx_DELTA set to appropriate values -
but only do this *once*, normally script must start with deltas set to zero, or it will increase meter every time it restarts.
Startup of script & output logging is up to you.
E.g. you can start it up on boot with cron & disable unnecessary print statements (or configure Python logging to log to file).
Update: tabs fixed.