# -*- coding: utf-8 -*-
"""
Created on Mon Jun 22 05:06:23 2020

@author: Alexander Dallinger
https://cloud.tugraz.at/index.php/s/xrskRH6Jmz7BkXw
ESPEC SH-222 climate chamber HTTP control

"""

import re
from time import sleep
import pyvisa
import time



class SH222:

    # define the temperature that should be after cool down
    COOL_DOWN_TEMPERATURE = 20
    COOL_DOWN_TARGET_ACCURACY = 1
    COOL_DOWN_SETTLING_TIME = 60
    
    


    def __init__(self, ip_address):
        """
        Implements the basic operation of the Espec SH222 climate chamber

        Arguments:
            ip_address: The IP address of the climate chamber

        Returns:
            A climate chamber object
        """

        #TODO: Try, catch
        
        # store the credentials so that methods can access them
        self.__ip_address = ip_address

        # we try to connect to the climate chamber just to see if there is an error
        self.rm = pyvisa.ResourceManager()

        self.chamber = self.rm.open_resource("TCPIP0::" +str(self.__ip_address) +"::57732::SOCKET")
        self.chamber.write_termination = '\r\n'
        self.chamber.read_termination = '\r\n'
        self.chamber.timeout = 5000

    def get_temperature(self):
        """get actual and target temperature
        data format: [current temp, set temp, upper limit, lower limit]
        """

        # send the request to the chamber
        response = self.chamber.query("TEMP?",delay=2)
        
        #convert into float numbers 
        temps = [float(i) for i in response.split(sep=',')]
        return temps
    
    def get_humidity(self):
        """get actual and target humidity
                output data format: [current hum, set hum, upper limit, lower limit]
"""

        # send the request to the chamber
        response = self.chamber.query("HUMI?",delay=2)
        
        #convert into float numbers 
        temps = [float(i) for i in response.split(sep=',')]
        return temps

    def get_mode(self):
        """ gets the mode of the chamber: 
        Panel power off "OFF" 
        All operation stop "STANDBY" 
        Constant operation "CONSTANT" 
        Program/remote operation "RUN"
        """
        response = self.chamber.query("MODE?",delay=2)
        return response

    def get_monitor(self):
        """ gets the chamber test area state
        output data format: [temp, humid, op-state, num. of alarms]
        """

        response = self.chamber.query("MON?",delay=2)
        return response
    
    def set_temp(self, temp):
        """
        sets the temp of the chamber, (float) temp
        """
        response = self.chamber.query("TEMP, S" + str(temp))
        #response = (OK: HUMI, S30\r\n)
        return response

    
    def set_humidity(self, humid):
        """
        sets the humidity of the chamber, (float) humid
        """
        response = self.chamber.query("HUMI, S" + str(humid))
        return response

    def set_temp_limit(self,upper_limit, lower_limit):
        """
        Sets the upper and lower temperature limits for the chamber

        Parameters
        ----------
        upper_limit : int
            Temperature upper limit.
        lower_limit : int
            Temperature lower limit.

        Returns
        -------
        None.

        """
        response = self.chamber.query("TEMP, H" + str(upper_limit))
        response = self.chamber.query("TEMP, L" + str(lower_limit))
        

    def set_mode(self, mode):
        """ sets the mode of the chamber: 
        Operation-mode is described as follows. 
        Panel power off     "OFF" 
        An  operation  stopped      "STANDBY"  
        Constant  operation  (No.1)     "CONSTANT"  
        Program operation       "RUN-pattern-number" 
        """
        response = self.chamber.query("MODE, " + mode ,delay=2)
        return response

    
    def close(self):
        self.rm.close()
 
    def _get_const(self, mode):
        response = self.chamber.query("CONSTANT SET?" + mode)
        return response
    
    def get_const(self):
        """ 
        combination of get_temperature() and get_humidity()
        """
        temp = self.get_temperature()
        hum = self.get_humidity()
        return [temp,hum]
    
    def set_const(self, setPoint):
        """
    
        Parameters
        ----------
        setPoint : tuple(float,float)
            A tuple of temperature and humidity as setpoint

        Returns
        -------
        None.

        """
        #setPoint = (temp,hum)
        self.set_temp(setPoint[0])
        self.set_humidity(setPoint[1])
        
    def goto_const(self, setPoint, target_accuracy = (0.2, 1), soaking_time = 60):
        """

        Parameters
        ----------
        setPoint :  tuple(float,float)
            A tuple of temperature and humidity as setpoint.
        target_accuracy : tuple(float,float), optional
            A tuple of temperature and humidity as accuracy. The default is (0.2, 1).
        soaking_time : int, optional
            Soaking time. The default is 60.

        Returns
        -------
        None.

        """
        
        current_milli_time = lambda: int(round(time.time() * 1000))

        #set temp and humidity
        self.set_const(setPoint)
        
        #set mode to Const 
        self.set_mode('CONSTANT')
        

        start_time = current_milli_time()
        #wait until setpoint is reached (+soaking time)
        while True:
            # get the actual temperature & humidity
            [temp, hum, mode, alarms] = self.get_monitor().split(',')
    
            # if we are not within the target range reset start time
            if not(setPoint[0] - target_accuracy[0] <= float(temp) <= setPoint[0] + target_accuracy[0]):
                start_time = current_milli_time()
            
            if not(setPoint[1] - target_accuracy[1] <= float(hum) <= setPoint[1] + target_accuracy[1]):
                start_time = current_milli_time()
                
    
            # if the value is stable long enough
            if ((current_milli_time()-start_time)/1000 > soaking_time) :
                print('SOAKING FINISHED!')
                break
    
    
            print('Temp: ' + temp + ' °c'
                  + '| Humid: ' + hum + '%'
                  + '|| time soaking:' + str((current_milli_time()-start_time)/1000) + 's')
    
            sleep(1)
        
    

