#!/usr/bin/python3
#
# Name:         subsmartmeters.py
# Purpose:      Client to get MQTT data from Mosquitto
# Author:       weigu.lu
# Date:         4/17 rev 19/7/17
#
#-----------------------------------------------------------------------------

import sys
import os
import shutil
import shlex
from time import gmtime, strftime, localtime, sleep
from datetime import datetime, timedelta, time
import paho.mqtt.client as mqtt
import json
import subprocess

ftime = strftime("%Y_%m_%d", localtime())
rftime = (datetime.today() - timedelta(days=1)).strftime("%Y_%m_%d")
ftime2 = strftime("%d.%m.%y", localtime())
ftime3 = strftime("%d.%m.%y %H:%M:%S", localtime())
ftime4 = strftime("%H:%M", localtime())

wpath = "/var/www/png/"
fpath = "/home/weigu/teensylogger/"
gp_dir = fpath+"gp/"
png_dir = fpath+"png/"
png_a_dir = fpath+"png_archive/"
data_dir = fpath+"data/"
data_a_dir = fpath+"data_archive/"
sm_datafile1 = data_dir+"sm_led_data.min"
sm_datafile2 = data_dir+"sm_led_data_"
sm_gnupfile1 = gp_dir+"sm_led_gp_template.gp"
sm_gnupfile2 = gp_dir+"sm_led.gp"
mailfile = fpath+'mail.txt'
pngfile = png_a_dir+'sm_led_'+rftime+'.png'

imp1 = 0.06  #Wh/imp Z2-5
imp2 = 2  #Wh/imp Z1 lansis and gear
clientID = "getsmartmeters"
brokerIP = "192.168.1.69"
brokerPort = 1883
topic  = "smartmeters_LED"
DEBUG = 0

# Callback that is executed when the client receives a CONNACK response from the server.
def onConnect(client, userdata, flags, rc):
   print("Connected with result code " + str(rc))
   mqttc.subscribe(topic, 0)  # Subscribe to the topic (topic name, QoS)


# Callback that is executed when we disconnect from the broker.
def onDisconnect(client, userdata, message):
   print("Disconnected from the broker.")

# Callback that is executed when subscribing to a topic
def onSubscribe(client, userdata, mid, granted_qos):
   print('Subscribed on topic.')

# Callback that is executed when unsubscribing to a topic
def onUnsubscribe(client, userdata, mid, granted_qos):
   print('Unsubscribed on topic.')

# Callback that is executed when a message is received.
def onMessage(client, userdata, message):
    #print('message received')
    ftime = strftime("%Y_%m_%d", localtime())
    ftime3 = strftime("%d.%m.%y %H:%M:%S", localtime())
    io=message.payload.decode("utf-8");
    print(io)
    try:
        ioj=json.loads(io)
    except:
        ioj={"time":"error"}
    consum_e = 0
    solar10_e = 0
    solar8_e = 0
    solar3_e = 0
    electris_kWh = 0
    elecrtis_kvar = 0
    solarall_e = 0
    try: 
        temp = ioj["time"]
    except:
        temp = ioj["wemos"]
    print(temp)
    if (temp[0]!='e') and (temp[0]!='c'):
        iodate = '.'.join((temp[0:2],temp[2:4],temp[4:6]))
        iotime = ':'.join((temp[6:8],temp[8:10],temp[10:12]))    
        sm1 = str(round(float(ioj["s1"])*imp1*60,2)) # Z2
        sm2 = str(round(float(ioj["s4"])*imp1*60,2)) # Z3 10kW
        sm3 = str(round(float(ioj["s5"])*imp1*60,2)) # Z4 8kW
        sm4 = str(round(float(ioj["s6"])*imp1*60,2)) # Z5 3kW
        sm5 = str(round(float(ioj["s2"])*imp2*60,2)) # Z1 landis and gear kWh
        sm6 = str(round(float(ioj["s3"])*imp2*60,2)) # Z1 landis amd gear kvar
        solarall = str(round((float(sm2)+float(sm3)+float(sm4)),2))
        try:    
            f = open (sm_datafile1, 'r')
        except IOError:
            print("error reading file "+sm_datafile1)
            return
        lineList = f.readlines()            #read all lines        
        f.close()
        try:    
            f = open (sm_datafile1, 'a')
        except IOError:
            print ("Cannot create or find file: " + sm_datafile1)
        try:    
            f2 = open (sm_datafile2+ftime+'.min', 'a')
        except IOError:
            print ("Cannot create or find file: " + sm_datafile2)
        if (len(lineList)) == 1:
            sm_data = ' '.join((ftime3,sm1,sm2,sm3,sm4,sm5,sm6,solarall,'0','0','0','0','0','0','0',iodate,iotime))
            sm_data = sm_data + '\n'                                
        else:                        
            line = lineList[len(lineList)-1]    #get the last line
            lline =shlex.split(line)            #convert string (space seperated items) to list            
            consum_e = str(round(float(sm1)/60+float(lline[9]),2)) #Wh
            solar10_e = str(round(float(sm2)/60+float(lline[10]),2))
            solar8_e = str(round(float(sm3)/60+float(lline[11]),2))
            solar3_e = str(round(float(sm4)/60+float(lline[12]),2))
            electris_kWh = str(round(float(sm5)/60+float(lline[13]),2))
            electris_kvar = str(round(float(sm6)/60+float(lline[14]),2))
            solarall_e = str(round(float(solarall)/60+float(lline[15]),2))
            sm_data = ' '.join((ftime3,sm1,sm2,sm3,sm4,sm5,sm6,solarall,consum_e,solar10_e,solar8_e,solar3_e,electris_kWh,electris_kvar,solarall_e,iodate,iotime))
            sm_data = sm_data + '\n'
        print (sm_data,end='')
        f.write(sm_data)
        f2.write(sm_data)
        f.close()
        f2.close()
    else:
        print("loop not executed: ",end='')
        print(ioj)

def sm_create_gp_file():
    """ The function prepares the gp file for plotting with gnuplot. First the
    old gp file is deleted. Then it uses the xx_gp_template.gp file in
    ~/../gp and replaces the keywords between the % sign by creating
    a new gp (xx.gp) file."""
    ftime2 = strftime("%d.%m.%y", localtime())
    Title = ftime2
    XFormat = '"%H:%M"'
    XTics = "60*60" #seconds
    Begin = ftime2 +" 00:00:01"
    End = ftime2 +" 23:59:59"
    Output = png_dir + "sm_led_" + ftime + ".png"
    Input = sm_datafile1
    try:
        os.remove(sm_gnupfile2)
    except OSError:
        pass
    try:
        gf1 = open (sm_gnupfile1,'r')
    except IOError:
        print ("Cannot find file: " + sm_gnupfile1)
    try:
        gf2 = open (sm_gnupfile2,'a')
    except IOError:
        print ("Cannot find file: " + sm_gnupfile2)    
    gline1 = gf1.readline()
    while gline1 != "":
        if "%TITLE%" in gline1:
            gline1 = gline1.replace("%TITLE%",Title)
        if "%XFORMAT%" in gline1:
            gline1 = gline1.replace("%XFORMAT%",XFormat)
        if "%XTICS%" in gline1:
            gline1 = gline1.replace("%XTICS%",XTics)
        if "%BEGIN%" in gline1:
            gline1 = gline1.replace("%BEGIN%",Begin)
        if "%END%" in gline1:
            gline1 = gline1.replace("%END%",End)
        if "%OUTPUT%" in gline1:
            gline1 = gline1.replace("%OUTPUT%",Output)
        if "%INPUT%" in gline1:
            gline1 = gline1.replace("%INPUT%",Input)
        gf2.write(gline1)
        gline1 = gf1.readline()
    gf1.close()
    gf2.close()
    
    
    
def move_files(dir_src,dir_dst):
    for file in os.listdir(dir_src):
        if "sm_led_" in file:
            src_file = os.path.join(dir_src, file)
            dst_file = os.path.join(dir_dst, file)
            shutil.move(src_file, dst_file)
   
#-----------------------------------------------------------------------------
# Main
#-----------------------------------------------------------------------------

try:    
    f = open (sm_datafile1, 'r')
except IOError:
    try:    
        f = open (sm_datafile1, 'w')
        sm_data = ' '.join(("date","time","consumption [W]","solar_10kW [W]",
                            "solar_8kW [W]","solar_2.7kW [W]","electris [W]",
                            "electris [var]","consumtion [Wh]","solar_10kW [Wh]",
                            "solar_8kW [Wh]","solar_2.7kW [Wh]","electris [Wh]",
                            "electris [varh]","solar_all [Wh]","PC_date","PC_time\n"))
        f.write(sm_data)
        f.close()
    except IOError:
        print ("Cannot create or find file for smartmeter data")        
f.close()

mqttc = mqtt.Client(client_id=clientID, clean_session=True) # create client

mqttc.on_connect      = onConnect   # define the callback functions
mqttc.on_disconnect   = onDisconnect
mqttc.on_subscribe    = onSubscribe
mqttc.on_unsubscribe  = onUnsubscribe
mqttc.on_message      = onMessage

#mqttc.username_pw_set(config['MQTT']['userMQTT'], password=config['MQTT']['passwdMQTT'])
mqttc.connect(brokerIP, brokerPort, keepalive=60, bind_address="") # connect to the broker
mqttc.loop_start() # start loop to process callbacks! (new thread!) 

flag_files=0
flag_new_header=0
flag_mail=0

try:
    while True:                   # looping, asking every 2 seconds.
        now = datetime.now()
        now_time = now.time()
        rftime = (datetime.today() - timedelta(days=1)).strftime("%Y_%m_%d")
        sec=now.second
        if now_time >= time(23,59,58) and now_time < time(23,59,59):
            flag_files=1
        if now_time >= time(0,0,0) and now_time < time(0,0,4):
            flag_new_header=1
        if now_time >= time(1,10,10) and now_time < time(1,10,12):
            flag_mail=1
        if sec==0:
            ftime4 = strftime("%H:%M", localtime())
            ftime = strftime("%Y_%m_%d", localtime())
            try:
                sm_create_gp_file()
            except:
                print ("cannot create sm_gp file")               
            try:
                p = subprocess.Popen(["/usr/bin/gnuplot", sm_gnupfile2], stdin= subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                stdout, stderr = p.communicate('\r\n\r\n'.encode(), timeout=10)
                print ("gnuplot used for sm  ",end='')
            except:
                print ("Error plotting file sm (gnuplot)")
            try:
                shutil.copy(png_dir+'sm_led_'+ftime+'.png', wpath+'sm_led_daily.png')
            except:
                print ("Cannot copy sm file")
            sleep(2.2)
        if flag_files==1:
            print (now_time)
            try:
                os.remove(data_dir+'sm_led_data.min')
            except OSError:
                print ("Error while trying to delete sm_led_data.min")
            dir_src = data_dir
            dir_dst = data_a_dir
            move_files(dir_src,dir_dst)
            dir_src = png_dir
            dir_dst = png_a_dir
            move_files(dir_src,dir_dst)
            sleep(3)
            flag_files=0
        if flag_new_header==1:
            print (now_time)
            try:    
                f = open (sm_datafile1, 'r')
            except IOError:
                try:    
                    f = open (sm_datafile1, 'w')
                    sm_data = ' '.join(("date","time","consumption [W]","solar_10kW [W]",
                                        "solar_8kW [W]","solar_2.7kW [W]","electris [W]",
                                        "electris [var]","consumtion [Wh]","solar_10kW [Wh]",
                                        "solar_8kW [Wh]","solar_2.7kW [Wh]","electris [Wh]",
                                        "electris [varh]","solar_all [Wh]","PC_date","PC_time\n"))
                    f.write(sm_data)
                    f.close()
                except IOError:
                    print ("Cannot create or find file for smartmeter data")        
            f.close()
            sleep(5)
            flag_new_header=0
        if flag_mail==1:
            print (now_time)
            print(rftime)
            try:
                os.system('mpack -s "Mail from my beaglebone sm" -d '+ mailfile \
                          + ' ' + png_a_dir+'sm_led_'+rftime+'.png' + ' weigu@weigu.lu')
                print ("sending sm mail")
            except:
                print ("Error mailing sm png file")
            sleep(5)
            flag_mail=0
           
except KeyboardInterrupt:
    print("Keyboard interrupt by user")
    mqttc.loop_stop() # clean up
    mqttc.disconnect()

# End
