Well, a solution turned out to be a lot easier than I initially thought.
Let me start by saying first that this is only an exercise in getting something from my meter to Domotics. My half-smart meter does not send out the current consumption, so there is little of value coming out of Domotics if you only send out the total delivered hi and low counters with no decimal information, but the proof of concept works.
In a nut-shell, I'm collecting the Telegram from my half-smart meter by asking for it. The interface that I use to ask the meter to send me the Telegram, and to receive it, is through an optical pick-up. I purchased the TTL version, because I wanted to hook it up directly to the P1-connector of my Raspberry Pi.
Here are the connections from the optical pick-up to the RPi:
white lead to P1-1 3V3
yellow lead to P1-6 GND
brown lead to P1-8 TXD
green lead to P1-10 RXD
The python script I use reads the data from the meter, manipulates it to produce a .csv file for further processing (by hand) with MS-Excel. It now also produces a Telegram in the style of a smart meter, such that Domoticz can accept it. This took some trying but turned out to be quite simple.
My initial script came from
http://www.SmartMeterDashboard.nl, and it is called "Iskra Datalogger V2.rar" I'm using the MT171 version, that I modified quite a bit.
I added the following function to that script:
Code: Select all
def write_iskra_telegram():
with open("/var/tmp/Telegram", "w") as fout: # file is send to a tmpfs created RAM disk location
fout.write ("/ISk5MT171-0133\n")
# power consumption
fout.write ("1-0:1.8.1(%0.3f*%s)\n" % (iskra_meterreading_1_1, iskra_unitmeterreading_1_1) )
fout.write ("1-0:1:8.2(%0.3f*%s)\n" % (iskra_meterreading_1_2, iskra_unitmeterreading_1_2) )
fout.write ("1-0:1.8.0(%0.3f %s)\n" % (iskra_meterreading_1_tot, iskra_unitmeterreading_1_tot) ) # not shown in report
# power generation - not used
# fout.write ("1-0:2.8.1(%0.3f*%s)\n" % (iskra_meterreading_2_1, iskra_unitmeterreading_2_1) )
# fout.write ("1-0:2.8.2(%0.3f*%s)\n" % (iskra_meterreading_2_2, iskra_unitmeterreading_2_2) )
# gas - not used
fout.write ("!\n")
return()
And in the main code, I simply call this function. Many of the changes I made were related to making sure the script does not hang. It always returns with an exit code, which is 0 (zero) for a successful execution, and non-zero otherwise. The comm port (/dev/ttyAMA0) that is used for this connection is always closed at the end of the script.
This script is executed every 5 minutes by cron. It makes no sense to do this more frequent because the half-smart meter only sends whole integer numbers as kWh.
I then created another script to read the Telegram, and send it over the the same serial port. Because the USB-serial port is connected in parallel to the Raspi P1 port, Domoticz can see the activity on the /dev/ttyUSB0 port and intercept it. I elected to execute this program right after the previous script, and such that it will not run when the previous script exited with an error. You can do that by using the double ampersand && between the execution of the two scripts. The command after the && will only get executed when the previous one ends with a clean exit.
This is what I have in cron :
Code: Select all
*/5 * * * * /usr/bin/python2.7 /home/pi/read_MT171.py && /usr/bin/python2.7 /home/pi/send_domo.py
My send_domo script looks as follows:
Code: Select all
#!/usr/bin/python2.7
#-------------------------------------------------------------------------------
# Name: send_domo.py
# Purpose: write to serial port /dev/ttyAMA0 & /dev/ttyUSB0
#
# Author: paulv
#
# Created: 04-12-2016
# Copyright: (c) paulv 2016
# Licence: <your licence>
#-------------------------------------------------------------------------------
from __future__ import print_function
from time import sleep
import serial
import sys
TEST = True # used for debugging, False normally
def main():
try:
ser = serial.Serial(
baudrate = 9600,
bytesize = serial.SEVENBITS,
parity = serial.PARITY_EVEN,
stopbits = serial.STOPBITS_ONE,
xonxoff = 0,
rtscts = 0,
timeout = 0.5,
port = '/dev/tty/AMA0' # Serial from Raspi P1: TXD and RXD, but /dev/ttyUSB0 sees it too!
)
except Exception as e:
print(str(e))
sys.exit("Error opening comm port, aborting")
try:
at_END = 0
i = 0
with open("/var/tmp/Telegram", "r") as fin: # file location is on a RAM disk
while not at_END:
f_data = fin.readline()
if TEST : print(f_data, end='') # end= this is a double ' , meaning no end of line
ser.write(f_data)
if f_data == "!":
at_END = True
i += 1
if i > 20 : break # don't get into a hung loop situation
if TEST : print("Done")
sys.exit(0)
except IOError:
sys.exit("Cannot open Telegram. Terminating")
except KeyboardInterrupt:
print("\nDone")
try:
if ser.isOpen():
if TEST : print("Port is still open, closing it")
ser.close()
except:
sys.exit("Error closing comm port. Terminating")
if __name__ == '__main__':
main()
The USB serial adapter is plugged into one the the USB ports, and the four wires go the to the same pins of the P1 connector of the RPi.
The USB leads go as follows:
red lead to P1-1 3V3
black lead to P1-6 GND
white lead to P1-8 TXD
green lead to P1-10 RXD
I created a tiny PCB with some header pins to connect it all together.
The trick of the whole contraption is that I use the RPi serial device (/dev/ttyAMA0) to communicate with the meter, and also to send the Telegram out to the /dev/ttyUSB0 that is connected in parallel. Because the USB serial device (/dev/tty/USB0) that is activated by Domoticz, hangs off the same wires, it receives the data and Domoticz intercepts it. Make sure you don't manipulate the /dev/ttyUSB0 port, or close it, because Domoticz will stop using it.
As soon as I get a real smart meter, it's now fairly simple to make the required changes with what I have now.
Enjoy!