"""
Zapíná a kontroluje topení pro baterie LiFePo4 přes pomocné relé na PINu 21,
současné hlidani podpeti na LiFePo4 aby neohrozil vybitím. Teplotní čidlo je na PINu 4.

Příkazem sudo nano /boot/config.txt; na konec tohoto souboru dopište
dtoverlay=w1-gpio, potom reboot a
sudo modprobe w1-gpio - je uz v programu
sudo modprobe w1-therm - je uz v programu
Pull-up RPi HW/SW resistor stačí místo reálného odporu, ale měření nemusí být přesné
výslednou teplotu u baterií určuje až samostatný termostat, tj. pokud bude okolí trvale
pod minimální teplotou, relé je trvale zapnuto a topení reguluje jen termostat.
napětí odečítáno z BMV700"
"""
import RPi.GPIO as GPIO
import json
import os
import glob
import time
from pymodbus.constants import Defaults
from pymodbus.constants import Endian
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
from pymodbus.payload import BinaryPayloadDecoder

Defaults.Timeout = 25
Defaults.Retries = 5
client = ModbusClient('192.168.0.56', port='502')
result = client.read_input_registers(259,3,unit=239)
decoder = BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=Endian.Big)
voltage=decoder.decode_16bit_uint()
battery = voltage/100


bat_min = 49.6 #minimální napětí vypne topení
bat_norm = 51.0 #nominální napětí dovolí zpětné zapnutí
temp_min = 1.5 #0.5 minimální teplota °C pro zapnutí topení, termostat má hysterezi 2°C
min_dne = 0 #proměnná pro nejnižší teplotu v noci
min_vcera = 0 #nejnižší teplota včera

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_UP)
os.system('sudo modprobe w1-gpio')
os.system('sudo modprobe w1-therm')

time.sleep(10) #stabilizace čidla

base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'

def read_temp_raw():
    f = open(device_file, 'r')
    lines = f.readlines()
    f.close()
    return lines

def read_temp():
    lines = read_temp_raw()
    while lines[0].strip()[-3:] != 'YES':
        time.sleep(0.2)
        lines = read_temp_raw()
    equals_pos = lines[1].find('t=')
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_c = float(temp_string) / 1000.0
        cas = time.strftime("%d-%m-%Y %H:%M:%S")
        return temp_c, cas

#začátek vlastního programu
temp_c2, cas2 = read_temp() #z definice načte teplotu a čas měření
print (temp_c2) #jen kontrola při ladění

if (temp_c2 < temp_min):
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(21, GPIO.OUT) #spínání relé poklesem napětí na GND = kontakt NO
    #GPIO.output(21, GPIO.HIGH)
    if (battery > bat_norm):
        GPIO.output(21, GPIO.LOW) # Zapnout relé pouze při správném napětí baterií 
    elif (battery < bat_min): # Při poklesu napětí pod minimum vypne relé
        GPIO.output(21, GPIO.HIGH)
    else:
        pass    
else: #jestliže je teplota vyšší než minimální, vypne relé nebo jen potvrdí vypnutý stav
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(21, GPIO.OUT)
    GPIO.output(21, GPIO.HIGH)

# a v každém případě zapíše do souboru ulogpwr.json naměřené hodnoty Temp a Cas_t a minimum
print("Battery value: " + str(battery) + "\n") #kontrola
with open('/home/pi/FVE_ML/mstsd.json', "r") as ulog_PW:
    data = json.load(ulog_PW)
    min_dne = data ["data"]["MINTEMP"]
    min_vcera = data ["data"]["MINVCERA"]
    battery = data ["data"]["BATTERY"]
    print ("Původní obsah ulog_PW = " + str(data))
    ulog_PW.close()
if (temp_c2 < min_dne):
    min_dne = temp_c2
actual = int(format(time.localtime()[3]))
if actual < 1:
    min_vcera = min_dne #zápis pro evidenci
    min_dne = 30 #reset minimální teploty dne při prvním měření
with open('/home/pi/FVE_ML/mstsd.json', "w") as ulog_PW:
    temp_c2, cas2 = read_temp()
    data["data"]["Temp"] = temp_c2
    data["data"]["Cas_t"] = cas2
    data["data"]["MINTEMP"] = min_dne
    data["data"]["MINVCERA"] = min_vcera
    data["data"]["BATTERY"] = battery
    print ("\nNový obsah ulog_PW = " + str(data))
    json.dump(data, ulog_PW)
    ulog_PW.close()