Subversion Repositories Python_UH50_Script

Rev

Blame | Last modification | View Log | RSS feed

#
# Landi&Gyr UH50 IR Datalogger
# $Revision: 9 $
# $Author: raymond $
# $Date: 2015-09-06 13:21:04 +0200 (zo, 06 sep 2015) $
# Copyright (c) 2013 J. van der Linde
#
# Although there is a explicit copyright on this sourcecode, anyone may use it
# freely under a  "Creative Commons
# Naamsvermelding-NietCommercieel-GeenAfgeleideWerken 3.0 Nederland" licentie.
# Please check http://creativecommons.org/licenses/by-nc-nd/3.0/nl/ for details
#
# This software is provided as is and comes with absolutely no warranty.
# The author is not responsible or liable (direct or indirect) to anyone for
# the use or misuse of this software. Any person using this software does so
# entirely at his/her own risk.  That person bears sole responsibility and
# liability for any claims or actions, legal or civil, arising from such use.
# If you believe this software is in breach of anyone's copyright you will
# inform the author immediately so the offending material can be removed upon
# receipt of proof of copyright for that material.
#
# Dependend on Python 3.2+ and Python 3.2+ packages: PySerial 2.5
#

version = "UH50 v0.10 RVS"
import sys
import glob
import serial
import datetime
import csv
import os
import locale
from time import sleep

MySQL_loaded=True
try:
    import mysql.connector
except ImportError:
    MySQL_loaded=False

def scan_serial():
# scan for available ports. return a list of tuples (num, name)
    """ Lists serial port names

        :raises EnvironmentError:
            On unsupported or unknown platforms
        :returns:
            A list of the serial ports available on the system
    """
    if sys.platform.startswith('win'):
        ports = ['COM%s' % (i + 1) for i in range(256)]
    elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
        # this excludes your current terminal "/dev/tty"
        ports = glob.glob('/dev/tty[A-Za-z]*')
    elif sys.platform.startswith('darwin'):
        ports = glob.glob('/dev/tty.*')
    else:
        raise EnvironmentError('Unsupported platform')
    
    port_exceptions = ['/dev/ttyprintk','dev/ttyprintk']
    for port in port_exceptions:
        if port in ports:
            ports.remove(port)

    available = []
    for port in ports:
        try:
            s = serial.Serial(port)
            s.close()
            available.append(port)
        except (OSError, serial.SerialException):
            pass
    if not available:
            available.append('Helaas geen seriele poorten gevonden')
    return available
    
################
#Error display #
################
def show_error():
    ft = sys.exc_info()[0]
    fv = sys.exc_info()[1]
    print("Fout type: %s" % ft )
    print("Fout waarde: %s" % fv )
    return

################
#Scherm output #
################
def print_heat_telegram():
    print ("---------------------------------------------------------------------------------------")
    print ("Landis & Gyr UH50 telegram ontvangen op: %s" % heat_timestamp)
    print ("Meter fabrikant/type: Landis & Gyr Ultraheat 50")
    print (" 0. 0 - Meter identificatie: %s" % heat_equipment_id )
    print (" 6. 8 - Meterstand Energie: %0.3f %s" % (heat_meterreading_energy, heat_unitmeterreading_energy) )
    print (" 6.26 - Meterstand Volume: %0.3f %s" % (heat_meterreading_volume, heat_unitmeterreading_volume) )
    print (" 6.31 - Meterstand Gebruiksduur: %0.3f %s" % (heat_meterreading_hours, heat_unitmeterreading_hours) )    
    print ("Einde UH50 telegram" )
    return        

################
#Csv output #
################
def csv_heat_telegram():
#New filename every day
    csv_filename=datetime.datetime.strftime(datetime.datetime.today(), "UH50_"+"%Y-%m-%d"+".csv" )
    try:
#If csv_file exists: open it
        csv_file=open(csv_filename, 'rt')
        csv_file.close()
        csv_file=open(csv_filename, 'at', newline='', encoding="utf-8")
        writer = csv.writer(csv_file, dialect='excel', delimiter=';', quoting=csv.QUOTE_NONNUMERIC)
    except IOError:
#Otherwise: create it
        csv_file=open(csv_filename, 'wt', newline='', encoding="utf-8")
        writer = csv.writer(csv_file, dialect='excel', delimiter=';', quoting=csv.QUOTE_NONNUMERIC)
#Write csv-header
        writer.writerow([
         'heat_timestamp', 
         'heat_equipment_id',
         'heat_meterreading_energy', 
         'heat_unitmeterreading_energy', 
         'heat_meterreading_volume', 
         'heat_unitmeterreading_volume', 
         'heat_meterreading_hours', 
         'heat_unitmeterreading_hours']) 
    print ("UH50 telegram in %s gelogd op: %s" % (csv_filename, heat_timestamp) )
    writer.writerow([
         heat_timestamp, 
         heat_equipment_id,
         heat_meterreading_energy, 
         heat_unitmeterreading_energy, 
         heat_meterreading_volume, 
         heat_unitmeterreading_volume, 
         heat_meterreading_hours, 
         heat_unitmeterreading_hours ])
    csv_file.close()

    return        

################
#DB output     #
################
def db_heat_telegram():
    query = "insert into heat_log values (\'" + \
         heat_timestamp  + "\',\'" + \
         heat_equipment_id + "\',\'" + \
         str(heat_meterreading_energy) + "\',\'" + \
         heat_unitmeterreading_energy + "\',\'" + \
         str(heat_meterreading_volume) + "\',\'" + \
         heat_unitmeterreading_volume + "\',\'" + \
         str(heat_meterreading_hours) + "\',\'" + \
         heat_unitmeterreading_hours + "\')"
   
#   print(query)

    try:
        db = mysql.connector.connect(user=p1_mysql_user, password=p1_mysql_passwd, host=p1_mysql_host, database=p1_mysql_db)
        c = db.cursor()
        c.execute (query)
        db.commit()
        print ("UH50 telegram in database %s / %s gelogd op: %s" % (p1_mysql_host, p1_mysql_db, heat_timestamp) )
        db.close()
    except:
        show_error()
        print ("Fout bij het openen van / schrijven naar database %s / %s. UH50 Telegram wordt gelogd in csv-bestand."  % (p1_mysql_host, p1_mysql_db))       
        csv_heat_telegram()
    return    

    
################################################################################################################################################
#Main program
################################################################################################################################################
print ("Landis & Gyr IR Datalogger %s" % version)
equipment_prefix = "UH50"
comport=0
output_mode="scherm"
win_os = (os.name == 'nt')
if win_os:
    print("Windows Mode")
else:
    print("Non-Windows Mode")
print("Python versie %s.%s.%s" % sys.version_info[:3]) 
#if not MySQL_Loaded==False:
#    print("MySQL Connector/Python niet gevonden. Database uitvoer niet mogelijk")
print ("Control-C om af te breken")


#comport parameters
try:
    comport=int(sys.argv[1])
except:
    print ("Opstart syntaxis: 'heat.py {COM poort-nummer} {uitvoer-modus} {db_host} {db_user} {db_password} {db_database}'")
    print ("Ontbrekende of verkeerde parameter: COM poort-nummer.")
    print ("Toegestane waarden:")
#scanserial returns win_os serial ports and non win_os USB serial ports
    print (scan_serial())
    print ("Programma afgebroken.")
    sys.exit()

#output_mode parameters
try:
    output_mode=sys.argv[2]
except:
    print ("Opstart syntaxis: 'heat.py {COM poort-nummer} {uitvoer-modus} {db_host} {db_user} {db_password} {db_database}'")
    print ("Ontbrekende of verkeerde parameters: ")
    print ("- Uitvoer-modus. Geldige waarden: 'scherm', 'csv', 'db'. 'scherm' gebruikt")
    output_mode="scherm"
if output_mode not in ["scherm", "csv", "db"]:
    print ("Opstart syntaxis: 'heat.py {COM poort-nummer} {uitvoer-modus} {db_host} {db_user} {db_password} {db_database}'")
    print ("Ontbrekende of verkeerde parameters: ")
    print ("- Uitvoer-modus. Geldige waarden: 'scherm', 'csv', 'db'. 'scherm' gebruikt")
    output_mode="scherm"

#database parameters    
if output_mode == "db" and MySQL_loaded:     
    try:
        p1_mysql_host=sys.argv[3]
        p1_mysql_user=sys.argv[4]
        p1_mysql_passwd=sys.argv[5]
        p1_mysql_db=sys.argv[6]
    except:
        print ("Opstart syntaxis: 'heat.py {COM poort-nummer} {uitvoer-modus} {db_host} {db_user} {db_password} {db_database}'")
        print ("Ontbrekende of verkeerde parameters: ")
        print ("- db_host. 'localhost' gebruikt")
        print ("- db_user. 'root' gebruikt")
        print ("- db_password. 'password' gebruikt")
        print ("- db_database. 'p1' gebruikt")
        p1_mysql_host='localhost'
        p1_mysql_user='root'
        p1_mysql_passwd='password'
        p1_mysql_db='p1'        

if output_mode == "db" and not MySQL_loaded:
    print ("Opstart syntaxis: 'heat.py {COM poort-nummer} {uitvoer-modus} {db_host} {db_user} {db_password} {db_database}'")
    print ("Ontbrekende of verkeerde parameters: ")
    print ("- Uitvoer-modus. MySQL Connector/Python niet gevonden. Uitvoer-modus 'db' niet toegestaan. Uitvoer-modus 'csv' gebruikt")
    output_mode = "csv"        

        
#Set COM port config
#if comport != 0:
#    ser = serial.Serial(
#    baudrate = 300,
#    bytesize=serial.SEVENBITS,
#    parity=serial.PARITY_EVEN,
#    stopbits=1,
#    xonxoff=0,
#    rtscts=0,
#    timeout=2,
#    port="/dev/ttyAMA0" 
#   )
ser = serial.Serial("/dev/ttyAMA0", baudrate=300, bytesize=7, parity="E", stopbits=1, timeout=2, xonxoff=0, rtscts=0)
#Show startup arguments 
print ("Opstart parameters:")   
if comport != 0: 
        if win_os:
            print ("COM poort-nummer: %d (%s)" % (comport, ser.name) )        
        else:
# ser.name property is not available in Linux.        
            port="/dev/ttyAMA"+str(comport-1)  # Linux Style for /dev/ttyAMA0, /dev/ttyUSB1, etc...
            print ("COM poort-nummer: %d (%s)" % (comport, port) )
else:
    print ("COM poort-nummer: NVT, Interne testdata wordt gebruikt")
print ("Uitvoer-modus: %s" % output_mode )
if output_mode == "db": 
    print ("MySQL-verbinding: %s / %s" % (p1_mysql_host, p1_mysql_db) )

if comport == 0:
#################################################################
# Use test values instead of COM port reading                   #
#################################################################  
    ir_buffer = "/LUGC2WR5\r\n"
    ir_lines = ir_buffer.strip().split('\r\n')
    ir_buffer = "6.8(0347.292*GJ)6.26(02647.89*m3)9.21(65298392)\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "6.26*01(02378.83*m3)6.8*01(0311.399*GJ)\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "F(0)9.20(65298392)6.35(60*m)\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "6.6(0023.8*kW)6.6*01(0023.8*kW)6.33(000.636*m3ph)9.4(099*C&090*C)\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "6.31(0069294*h)6.32(0000343*h)9.22(R)9.6(000&65298392&0)9.7(20000)\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "6.32*01(0000343*h)6.36(01-01)6.33*01(000.636*m3ph)\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "6.8.1()6.8.2()6.8.3()6.8.4()6.8.5()\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "6.8.1*01()6.8.2*01()6.8.3*01()\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "6.8.4*01()6.8.5*01()\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "9.4*01(099*C&090*C)\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "6.36.1(2006-02-17)6.36.1*01(2006-02-17)\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "6.36.2(2011-12-21)6.36.2*01(2011-12-21)\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "6.36.3(2006-03-23)6.36.3*01(2006-03-23)\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "6.36.4(2006-02-21)6.36.4*01(2006-02-21)\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "6.36.5(2000-00-00)6.36*02(01)9.36(2013-10-04&12:56:50)9.24(1.5*m3ph)\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "9.17(0)9.18()9.19()9.25()\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "9.1(0&1&0&-&CV&3&2.20)9.2(&&)0.0(65298392)!\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
    ir_buffer = "h0\r\n"
    ir_lines.extend(ir_buffer.strip().split('\r\n'))  
else:  
#################################################################
# COM port reading                                              #
#################################################################    
    #Open COM port
    try:
        ser = serial.Serial("/dev/ttyAMA0", baudrate=300, bytesize=7, parity="E", stopbits=1, timeout=2, xonxoff=0, rtscts=0)
#        ser.open()
    except:
        if win_os:
            sys.exit ("Fout bij het openen van %s. Programma afgebroken."  % ser.name)
        else:
            sys.exit ("Fout bij het openen van %s. Programma afgebroken."  %  port) 
    print ("Activatie poort.")
    # Wake up
#    ser.setRTS(False)
#    ser.setDTR(False)
    sleep(5)
#    ser.setDTR(True)
#    ser.setRTS(True)
    ir_command=("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2F\x3F\x21\x0D\x0A")
    ser.write(ir_command.encode('utf-8')) 
    sleep(1.5)
    #Initialize
    print ("Initialisatie op 300 baud")
    ir_command='/?!\x0D\x0A'
    ser.write(ir_command.encode('utf-8'))
    ser.flush()
    #Wait for initialize confirmation
    ir_buffer = ''
    while '/LUGCUH50\r\n' not in ir_buffer:
        ir_buffer = str(ser.readline(), "utf-8")
        if '/?!\x0D\x0A' in ir_buffer:
            ir_buffer = str(ser.readline(), "utf-8")
    ir_lines = ir_buffer.strip().split('\r\n')

    print ("Gegevensuitwisseling op 2400 baud")
    #Set to 2400baud
    ser.baudrate = 2400

    #Wait for data
    ir_buffer = ''
    ETX = False
    while not ETX:
        ir_buffer = str(ser.readline(), "utf-8")
        if '\x03' in ir_buffer:
            ETX = True
    #Strip the STX character
        ir_buffer = ir_buffer.replace('\x02','')
    #Strip the ! character
        ir_buffer = ir_buffer.replace('!','')
    #Strip the ETX character
        ir_buffer = ir_buffer.replace('\x03','')
        ir_lines.extend(ir_buffer.strip().split('\r\n'))
    print ("Gegevensuitwisseling voltooid")
    #Close port and show status
    try:
        ser.close()
    except:
        if win_os:
            sys.exit ("Fout bij het sluiten van %s. Programma afgebroken."  % ser.name)
        else:
            sys.exit ("Fout bij het sluiten van %s. Programma afgebroken."  %  port)  

#################################################################
# Process data                                                  #
#################################################################           
#print ("Number of received elements: %d" % len(ir_lines))
#print ("Array of received elements: %s" % ir_lines)

heat_timestamp=datetime.datetime.strftime(datetime.datetime.today(), "%Y-%m-%d %H:%M:%S" )
heat_data = ir_lines
num_elements = len(ir_lines)
#print("Number of elements: %d"% num_elements)
#parse all heat_data elements
i=0
while i<num_elements:
#    print("Elements index: %d"% i)
    heat_element = heat_data[i]
#    print(heat_element)
    
    if heat_element.find("0.0(")!=-1:
    #heat_equipment_id 
    #0.0(11 digits C/N)
        heat_num_start=heat_element.find("0.0(")+4
        heat_num_end=heat_element.find(")",heat_num_start)
        heat_equipment_id = equipment_prefix + "_" + heat_element[heat_num_start:heat_num_end]

    if heat_element.find("6.8(")!=-1:
    #heat_meterreading_energy, heat_unitmeterreading_energy
    #6.8(Energy * unit)
        heat_num_start = heat_element.find("6.8(") +4
        heat_num_end=heat_element.find("*",heat_num_start)
        heat_meterreading_energy = float(heat_element[heat_num_start:heat_num_end])
        heat_num_start = heat_num_end+1
        heat_num_end=heat_element.find(")",heat_num_start)
        heat_unitmeterreading_energy = heat_element[heat_num_start:heat_num_end]

    if heat_element.find("6.26(")!=-1:
    #heat_meterreading_volume, heat_unitmeterreading_volume
    #6.26(Volume * m3)
        heat_num_start = heat_element.find("6.26(") +5
        heat_num_end=heat_element.find("*",heat_num_start)
        heat_meterreading_volume = float(heat_element[heat_num_start:heat_num_end])
        heat_num_start = heat_num_end+1
        heat_num_end=heat_element.find(")",heat_num_start)
        heat_unitmeterreading_volume = heat_element[heat_num_start:heat_num_end]

    if heat_element.find("6.31(")!=-1:
    #heat_meterreading_hours, heat_unitmeterreading_hours
    #6.31(Hours * h)
        heat_num_start = heat_element.find("6.31(") +5
        heat_num_end=heat_element.find("*",heat_num_start)
        heat_meterreading_hours = float(heat_element[heat_num_start:heat_num_end])
        heat_num_start = heat_num_end+1
        heat_num_end=heat_element.find(")",heat_num_start)
        heat_unitmeterreading_hours = heat_element[heat_num_start:heat_num_end]
     
    i+=1
#################################################################
# Output based on startup parameter 'output_mode'               #
#################################################################   
#Output to scherm
if output_mode=="scherm": print_heat_telegram()
#Output to csv_file
if output_mode=="csv": csv_heat_telegram()
#Output to database
if output_mode=="db": db_heat_telegram()