
#--------------------------------------------------------------------------------------------------
# Modules
import time
import math

import pigpio

import globals
import CRC8

#--------------------------------------------------------------------------------------------------
# variables et constantes globales
#--------------------------------------------------------------------------------------------------
I2C_SHT85 = 0x44


# SHT85 hex adress
SHT85_ADDR       = 0x44 # Device Adress
SHT85_SS         = 0x24 # Single Shot Data Acquisition Mode
SHT85_SS_2       = {'HIGH' : 0x00, 'MEDIUM' : 0x0B, 'LOW' : 0x16} # Repeatability: (HIGH, MEDIUM, LOW)
SHT85_ART        = 0x2B # ART Command (accelerated response time) frequency of 4Hz
SHT85_ART_2      = 0x32
SHT85_P          = {0.5 : 0x20, 1 : 0x21, 2 : 0x22, 4 : 0x23, 10 : 0x27} # Periodic Data Acquisition Mode mps
SHT85_P_2        = {0.5 : (0x32,0x24,0x2F), 1 : (0x30,0x26,0x2D), 2 : (0x36,0x20,0x2B), 4 : (0x34,0x22,0x29), 10 : (0x37,0x21,0x2A)} # Repeatability: (HIGH, MEDIUM, LOW)
SHT85_STOP       = 0x30 # Break command / Stop Periodic Data Acquisition Mode
SHT85_STOP_2     = 0x93
SHT85_RESET      = 0x30 # Soft Reset
SHT85_RESET_2    = 0xA2
SHT85_HEATER     = 0x30 # Heater for plausibility checking
SHT85_HEATER_ON  = 0x6D # enable
SHT85_HEATER_OFF = 0x66 # disable
SHT85_STATUS     = 0xF3 # Status Register
SHT85_STATUS_2   = 0x2D
SHT85_CLEAR      = 0x30 # Clear Status Register
SHT85_CLEAR_2    = 0x41
SHT85_SN         = 0x36 # Serial Number
SHT85_SN_2       = 0x82

SHT85_READ       = 0x00 # Read output

#--------------------------------------------------------------------------------------------------
# SHT85_open : ouverture du bus I2C pour SHT85
#--------------------------------------------------------------------------------------------------
def SHT85_open() :

	global handle_i2c_SHT85
	global SHT85_open_flag
	
	try:
		#------------------------------------------------------------------------------------------
		if globals.DEBUG_SHT85:
			print("SHT85_open : starting...")
			print(" ")

		#------------------------------------------------------------------------------------------
		SHT85_open_flag =  False
		
		#------------------------------------------------------------------------------------------
		handle_i2c_SHT85 = globals.RPi.i2c_open(globals.I2C_BUS_1, I2C_SHT85)
		
		if (handle_i2c_SHT85 < 0):
			if globals.DEBUG_SHT85:
				print("  SHT85_open : ouverture handle i2c = échec !")
				print(" ")
			return False
			
		else:
			if globals.DEBUG_SHT85:
				print("  SHT85_open : ouverture handle i2c = succès.")
				print(" ")
			SHT85_open_flag = True
			return True

	except: 
		if globals.DEBUG_SHT85:
			print("  SHT85_open : exception !")
			print(" ")
		return False

#--------------------------------------------------------------------------------------------------
# get serial number : 0x36, 0x82, 6,  0
#--------------------------------------------------------------------------------------------------
def SHT85_get_SN():
	try:
		retour = [False, "0x00000000"]
		data_crc8 = [0,0]
		Flag_crc8 = True

		
		globals.RPi.i2c_write_device(handle_i2c_SHT85, [0x36, 0x82])
		time.sleep(0.001)
		
		(count, data) = globals.RPi.i2c_read_device(handle_i2c_SHT85, 0x06)
		if ( count == 6 ):
			
			for i in range(2):
				data_crc8[i] = CRC8.crc8_scd30(data[3*i],data[3*i+1])
				Flag_crc8    = Flag_crc8 and ( data[3*i+2]  == data_crc8[i] )
				
			if Flag_crc8 :
				retour = [True, ( f"{data[0]:02x}" ) + ( f"{data[1]:02x}" ) + ( f"{data[3]:02x}" ) + ( f"{data[4]:02x}" ) ]
			else:
				if globals.DEBUG_SHT85 :
					print("  SHT85_get_SN : erreur CRC !")
				
		else:
			if globals.DEBUG_SHT85 :
				print("  SHT85_get_SN : erreur Nb bytes !")
		
	except: 
		if globals.DEBUG_SHT85:
			print("  SHT85_get_SN : exception !")

	finally :
		return retour

#--------------------------------------------------------------------------------------------------
# Measurement Commands for Periodic Data Acquisition Mode : 1 mps, HIGH
#--------------------------------------------------------------------------------------------------
def SHT85_periodic():
	try:
		globals.RPi.i2c_write_device(handle_i2c_SHT85, [0x21, 0x30] )

		return True
	
	except:
		print("  SHT85_periodic : exception !")
		print(" ")
		
		return False
		



def single_shot(rep='HIGH'):
    '''
    Single Shot Data Acquisition Mode
    In this mode one issued measurement command triggers the acquisition of one data pair.
    '''
    bus.write_i2c_block_data(SHT85_ADDR,SHT85_SS,[SHT85_SS_2[rep]])
    time.sleep(0.5)
    data   = bus.read_i2c_block_data(SHT85_ADDR,SHT85_READ,6)
    t_data = data[0] << 8 | data[1]
    h_data = data[3] << 8 | data[4]
    temp = -45. + 175. * t_data / (2**16-1.)
    relh = 100. * h_data / (2**16-1.)
    return round(temp,4), round(relh,4)

def periodic(mps=1,rep='HIGH'):
    ''' 
    Start Periodic Data Acquisition Mode
    In this mode one issued measurement command yields a stream of data pairs.
    In periodicmode different measurement commands can be selected.
    They differ with respect to data acquisition frequency (0.5, 1, 2, 4 & 10 measurements per second, mps) and repeatability (LOW, MEDIUM and HIGH, rep).
    '''
    rep_dict = {'HIGH' : 0, 'MEDIUM' : 1, 'LOW' : 2}
    rep = rep_dict[rep]
    bus.write_i2c_block_data(SHT85_ADDR,SHT85_P[mps],[SHT85_P_2[mps][rep]])
    time.sleep(0.5e-3)
    return 'Periodic Data Acquisition Mode started'


def art():
    '''
    Start the ART (accelerated response time) feature
    After issuing the ART command the sensor will start acquiring data with a frequency of 4Hz
    '''
    bus.write_i2c_block_data(SHT85_ADDR,SHT85_ART,[SHT85_ART_2])
    return 'ART Comannd started'

def read_data():
    '''
    Readout of Measurement Results for Periodic Mode or ART feature
    Transmission  of  the  measurement  data  can  be  initiated  through  the  fetch  data  command. After the read out command fetch data has been issued, the data memory is cleared
    '''
    data   = bus.read_i2c_block_data(SHT85_ADDR,SHT85_READ,6)
    t_data = data[0] << 8 | data[1]
    h_data = data[3] << 8 | data[4]
    temp = -45. + 175. * t_data / (2**16-1.)
    relh = 100. * h_data / (2**16-1.)
    return round(temp,4), round(relh,4)

def SHT85_read(): 
	try:
		#--------------------------------------------------------------
		retour_SHT85 = [ False, "0.00", "0.00" ]
		
		#--------------------------------------------------------------
		if True :
			globals.RPi.i2c_write_device(handle_i2c_SHT85, [0xE0, 0x00])
			time.sleep(0.010)
			
			(count, data) = globals.RPi.i2c_read_device(handle_i2c_SHT85, 6)

			if ( count == 6 ):
			
				data_crc8 = [0,0]
				Flag_crc8 = True
				for i in range(2):
					data_crc8[i] = CRC8.crc8_scd30(data[3*i],data[3*i+1])
					Flag_crc8 = Flag_crc8 and ( data[3*i+2]  == data_crc8[i] )
					
				if Flag_crc8:
					SHT85_T    = -45.0 + float( 256*data[0] + data[1] ) * ( 175/65535 )
					SHT85_HR   = 100.0 * float( 256*data[3] + data[4] ) / ( 65535 )
					
					retour_SHT85 = [ 
						True , 
						"{0:.2f}".format( SHT85_T ) , 
						"{0:.2f}".format( SHT85_HR ) 
					 ]
					 
				else:
					if globals.DEBUG_SHT85:
						print("SHT85_read : erreur CRC !")
			else:
				if globals.DEBUG_SHT85:
					print("SHT85_read : erreur nb bytes !")
		else:
			if globals.DEBUG_SHT85:
				print("SHT85_read : data not ready !")
			
	except:
		print("SHT85_read : exception !")
		
	finally:
		if globals.DEBUG_SHT85:
			print(" ")
			
		return retour_SHT85
		
#-----------------------------------------------------------------------------


def stop():
    '''
    Break command / Stop Periodic Data Acquisition Mode or ART feature
    It is recommended to stop  the  periodic  data  acquisition  prior  to  sending  another  command  (except  Fetch  Data  command)  using  the  break command Upon reception of the break command the sensor will abort the ongoing measurement and enter the single shot mode. This takes 1ms.
    '''
    bus.write_i2c_block_data(SHT85_ADDR,SHT85_STOP,[SHT85_STOP_2])
    return 'Break'

def reset():
    '''
    Soft Reset
    A system reset of the SHT85 can be generated externally by issuing a command (soft reset). Additionally, a system reset is generated internally during power-up. During the reset procedure the sensor will not process commands. 
    '''
    bus.write_i2c_block_data(SHT85_ADDR,SHT85_RESET,[SHT85_RESET_2])
    return 'Reset'

def heater(heat='on'):
    '''
    Switch heater on/off
    The SHT85is equipped with an internal heater, which is meant for plausibility checking only.
    '''
    if heat == 'on':
        heat = SHT85_HEATER_ON
    elif heat == 'off':
        heat = SHT85_HEATER_OFF
    bus.write_i2c_block_data(SHT85_ADDR,SHT85_HEATER,[heat])
    return 'heater is ', heat

def status():
    '''
    Status Register
    The status register contains information on the operational status of the heater, the alert mode and on the execution status of the last command and the last write sequence.
    '''
    bus.write_i2c_block_data(SHT85_ADDR,SHT85_STATUS,[SHT85_STATUS_2])
    time.sleep(0.5e-3)
    status_read = bus.read_i2c_block_data(SHT85_ADDR,SHT85_READ,3)
    status_to_bit = bin(status_read[0] << 8 | status_read[1])
    status_dict={'checksum status'      : status_to_bit[0],
                 'Command status'       : status_to_bit[1],
                 'System reset'         : status_to_bit[4],
                 'T tracking alert'     : status_to_bit[10],
                 'RH tracking alert'    : status_to_bit[11],
                 'Heater status'        : status_to_bit[13],
                 'Alert pending status' : status_to_bit[15]
                }
    return status_dict

def clear():
    '''
    Clear Status Register
    All flags (Bit 15, 11, 10, 4)in the status register can be cleared (set to zero)
    '''
    bus.write_i2c_block_data(SHT85_ADDR,SHT85_CLEAR,[SHT85_CLEAR_2])
    return 'Status Register cleared'

def sn():
    '''
    Output of the serial number
    '''
    bus.write_i2c_block_data(SHT85_ADDR,SHT85_SN,[SHT85_SN_2])
    time.sleep(0.5e-3)
    sn_read = bus.read_i2c_block_data(SHT85_ADDR,SHT85_READ,6)
    sn = sn_read[0] << 16 | sn_read[4]
    return sn


def dew_point(t,rh):
    '''
    Calculate dew point from temperature and rel. humidity.
    '''
    t_range = 'water' if t >= 0 else 'ice'
    tn = dict(water=243.12, ice=272.62)[t_range]
    m = dict(water=17.62, ice=22.46)[t_range]

    dew_p = tn * (math.log(rh / 100.0) + (m * t) / (tn + t))/ (m - math.log(rh / 100.0) - m * t / (tn + t))
    return round(dew_p,4)






