Page 1 of 1
My DIY smart meter
Posted: Thursday 11 July 2019 12:11
by MikeF
Not being a fan of (UK) smart meters (the first generation ones go 'dumb' if you switch energy supplier, and I don't like the idea of the meters 'phoning home' to the supplier all the time), I decided to build my own.
My electricity meter incorporates a LED which flashes once per kWh, and my gas meter has a small magnet in the least significant digit dial, which corresponds to 1/100 m3 per revolution. Using this post as inspiration:
https://www.domoticz.com/forum/viewtopi ... 32&t=11315, I am using an opto-sensor like this:
https://www.ebay.co.uk/itm/371350785169 ... EBIDX%3AIT and a reed switch sensor like this:
https://www.ebay.co.uk/itm/Reed-Sensor- ... Sw6CJbEYRS, connected to the GPIO of a RPi Zero WH, which runs a python script to send meter data to Domoticz.
Below are pictures of the 2 sensors mounted in small plastic cases, and fixed to the meters with Blu Tack (not fallen off yet!):
I have set up devices in the Utility tab in Domoticz to display electricity and gas usage, and I've also created a number of custom and text sensors to display calculated information: energy (in kWh), cost (using rates from my supplier), and meter readings (these last are incremented by the python script, and over the course of a month have remained very close to the actual meter readings which I read periodically to send to my supplier).
By clicking on the Log button on the cost devices, I can view cost history over the last month:
Finally, as the
pièce de resistance, I have set up a meter display in ImperiHome (via MyDomoAtHome), which I run on a Samsung Android tablet:

Re: My DIY smart meter
Posted: Thursday 11 July 2019 12:27
by MikeF
I'm attaching below the 2 scripts I use to drive the above setup.
1. Python script to read meter pulses and send to Domoticz
This is based on RidingTheFlow's script (see first post); I have modified it so that I can input actual meter readings when it is first run (and I rerun it periodically, to 'calibrate' it). It uses the RPi gpiozero library. I run it in the background using screen. Replace the Domoticz url / port and idx's with your own values. GPIO pins 17 and 24 are used here for the gas and electricity counters respectively.
- Spoiler: show
Code: Select all
#!/usr/bin/env python
'''
Based on https://www.domoticz.com/forum/viewtopic.php?f=32&t=11315
by RidingTheFlow
'''
import time, datetime
import json
import urllib2
import requests
import threading
import os
from gpiozero import DigitalInputDevice
import sys
init_elec = float(input("Elec meter reading: "))
init_gas = float(input("Gas meter reading: "))
get_url = 'http://<Domoticz url:port>/json.htm?type=devices&rid=%s'
set_url = 'http://<Domoticz url:port>/json.htm?type=command¶m=udevice&idx=%s&svalue=%s'
gas_delta = 0
gas_idx = <xxx>
gas_gpio = 17
gas_counter_lock = threading.Lock()
elec_delta = 0
elec_idx = <xxx>
elec_gpio = 24
elec_counter_lock = threading.Lock()
elec_last_time = 0
elec_post_time = 0
init = True
elec_meter_idx = <xxx>
gas_meter_idx = <xxx>
def gas_intr():
global gas_delta
with gas_counter_lock:
gas_delta += 10
def elec_intr():
tme = time.time()
global elec_delta
global elec_last_time
global elec_post_time
with elec_counter_lock:
elec_last_time = tme
if elec_post_time == 0:
elec_post_time = elec_last_time
else:
elec_delta += 1
def main():
global gas_delta
global gas_counter
global elec_delta
global elec_last_time
global elec_post_time
global elec_counter
global init
global init_elec
global init_gas
res = json.load(urllib2.urlopen(get_url % elec_idx))
elec_counter = int(float(res['result'][0]['Data'][:-4]) * 1000)
if init:
elec_counter = init_elec * 1000
print
print "Initial elec meter reading: ", datetime.datetime.now().strftime("%a %b %d %H:%M:%S"), init_elec
#init = False
res = json.load(urllib2.urlopen(get_url % gas_idx))
gas_counter = int(float(res['result'][0]['Data']) * 1000)
if init:
gas_counter = init_gas * 1000
print "Initial gas meter reading: ", datetime.datetime.now().strftime("%a %b %d %H:%M:%S"), init_gas
init = False
elecSensor = DigitalInputDevice(elec_gpio, pull_up=True)
elecSensor.when_deactivated = elec_intr
gasSensor = DigitalInputDevice(gas_gpio, pull_up=True)
gasSensor.when_activated = gas_intr
#os.nice(-20)
while True:
time.sleep(60)
gas_delta_post = gas_delta
if gas_delta_post >= 0:
gas_counter += gas_delta_post
with gas_counter_lock:
gas_delta -= gas_delta_post
meter = format(gas_counter / 1000.0, '.3f') + "%20m3" # text sensor
res = requests.get(set_url % (gas_idx, gas_counter))
res = requests.get(set_url % (gas_meter_idx, meter))
with elec_counter_lock:
if elec_last_time > elec_post_time:
elec_load = elec_delta * 3600 / ( elec_last_time - elec_post_time )
else:
elec_load = 0
elec_counter += elec_delta
meter = format(elec_counter / 1000.0, '.2f') + "%20kWh" # text sensor
elec_delta = 0
elec_post_time = elec_last_time
if elec_load != 0:
res = requests.get((set_url+';%s') % (elec_idx, int(elec_load), elec_counter))
res = requests.get((set_url) % (elec_meter_idx, meter))
if __name__=="__main__":
main()
2. dzVents script to calculate electricity and gas energy (in kWh) and costs. Change device names and cost rates to your own values.
- Spoiler: show
Code: Select all
-- dzVents script to calculate electricity and gas costs
return {
on = { timer = { "every minute" }},
execute = function(dz)
-- devices
local elecUsage = dz.devices("Electricity usage").counterToday
local elecCost = dz.devices("Electricity cost")
local elecEnergy = dz.devices("Electricity energy")
local gasUsage = dz.devices("Gas usage").counterToday
local gasCost = dz.devices("Gas cost")
local gasEnergy = dz.devices("Gas energy")
local totalCost = dz.devices("Total cost")
-- prices in pence
local elecStdChge = 20.44
local elecUnitPrice = 13.587
local m3_kWh = 1.02264 * 39.3 / 3.6 -- conversion factor x calorific value / kWh
local gasStdChge = 20.44
local gasUnitPrice = 3.371
-- calculate values
local elecCostVal = dz.utils.round((elecUsage * elecUnitPrice + elecStdChge),1) -- rounded to 1 dp
local elecUsageVal = dz.utils.round(elecUsage,3) -- rounded to 3 dp's
local gasCostVal = dz.utils.round((gasUsage * m3_kWh * gasUnitPrice + gasStdChge),1) -- rounded to 1 dp
local gasEnergyVal = dz.utils.round((gasUsage * m3_kWh),3) -- rounded to 3 dp's
local totalCostVal = elecCostVal + gasCostVal
--print(elecCostText, gasCostText, totalCostText)
-- update devices
elecCost.updateCustomSensor(elecCostVal)
elecEnergy.updateCustomSensor(elecUsageVal)
gasCost.updateCustomSensor(gasCostVal)
gasEnergy.updateCustomSensor(gasEnergyVal)
totalCost.updateCustomSensor(totalCostVal)
end
}
Re: My DIY smart meter
Posted: Saturday 23 November 2019 10:57
by mgerhard74
Cool! A friend of me designed a ESP8266 reader to get data via Wifi from our NETZ OÖ Siemens TD-3511 smartmeters:

- amis.jpg (67.74 KiB) Viewed 4763 times

- amisapi.jpg (22.95 KiB) Viewed 4763 times
Data can be read by a small LUA script or sent by MQTT.
Re: My DIY smart meter
Posted: Friday 21 February 2020 21:05
by Jinja1l
mgerhard74 wrote: ↑Saturday 23 November 2019 10:57
Cool! A friend of me designed a ESP8266 reader to get data via Wifi from our NETZ OÖ Siemens TD-3511 smartmeters:
amis.jpg
amisapi.jpg
Data can be read by a small LUA script or sent by MQTT.
Really professional looking board.
Any change you could share schematics of the reader?
Re: My DIY smart meter
Posted: Saturday 22 February 2020 8:07
by mgerhard74
Hi Jinja1l ,
this Amis-Reader project is "open source". So we share schematics, PCB (Eagle files) and sourcecode (soon) at my webpage:
http://www.mitterbaur.at/amis-leser.html (sorry only in german)
lg
Gerhard
Re: My DIY smart meter
Posted: Saturday 22 February 2020 8:19
by Jinja1l
Awesome, thank you!
Would it be possible to share also source code?
Re: My DIY smart meter
Posted: Saturday 22 February 2020 10:05
by mgerhard74
source code added to downloads.
Re: My DIY smart meter
Posted: Saturday 22 February 2020 20:18
by Jinja1l
mgerhard74 wrote: ↑Saturday 22 February 2020 10:05
source code added to downloads.
Sorry but I cannot find it. Link?
Re: My DIY smart meter
Posted: Sunday 23 February 2020 9:09
by Jinja1l
Maybe I just forgot to reload the page. Source code is there now. Thank you!