#!/usr/bin/env python3
#-*- coding: utf-8 -*-

#--------------------------------------------------------------------------------------------------
import time
import sys
import struct
import smbus2

import globals
import CRC8

#--------------------------------------------------------------------------------------------------
# variables et constantes globales
#--------------------------------------------------------------------------------------------------
I2C_SCD41 = 0x62
Count_data_ready_maxi = 20

#--------------------------------------------------------------------------------------------------
SCD41_INTERVALLE = 5

SCD41_COMMANDS = [																\
[0x21, 0xb1, 0, 0,  0.001, True ],#  0: start_periodic_measurement				\
[0xec, 0x05, 0, 9,  0.001, False],#  1: read_measurement						\
[0x3f, 0x86, 0, 0,  0.500, False],#  2: stop_periodic_measurement				\
[0x24, 0x1d, 3, 0,  0.001, True ],#  3: set_temperature_offset					\
[0x23, 0x18, 0, 3,  0.001, True ],#  4: get_temperature_offset					\
[0x24, 0x27, 3, 0,  0.001, True ],#  5: set_sensor_altitude						\
[0x23, 0x22, 0, 3,  0.001, True ],#  6: get_sensor_altitude						\
[0xe0, 0x00, 3, 0,  0.001, False],#  7: set_ambient_pressure					\
[0x36, 0x2f, 3, 3,  0.400, True ],#  8: perform_forced_recalibration			\
[0x24, 0x16, 3, 0,  0.001, True ],#  9: set_automatic_self_calibration_enabled	\
[0x23, 0x13, 0, 3,  0.001, True ],# 10: get_automatic_self_calibration_enabled	\  
[0x21, 0xac, 0, 0,  0.000, True ],# 11: start_low_power_periodic_measurement	\
[0xe4, 0xb8, 0, 3,  0.001, False],# 12: get_data_ready_status					\
[0x36, 0x15, 0, 0,  0.800, True ],# 13: persist_settings						\
[0x36, 0x82, 0, 9,  0.001, True ],# 14: get_serial_number						\
[0x36, 0x39, 0, 3, 10.000, True ],# 15: perform_self_test						\
[0x36, 0x32, 0, 0,  1.200, True ],# 16: perform_factory_reset					\
[0x36, 0x46, 0, 0,  0.020, True ],# 17: reinit									\
]

#--------------------------------------------------------------------------------------------------
# SCD41 open
#--------------------------------------------------------------------------------------------------
def SCD41_open() :

	global SCD41_open_flag

	try :
		if ( globals.BUS_5_OK_flag ) :
		
			if globals.DEBUG_SCD41:
				print("SCD41_open : starting...")
				print(" ")
				
			raw_message = [SCD41_COMMANDS[12][0], SCD41_COMMANDS[12][1]]
			write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
			globals.bus_5.i2c_rdwr(write_txn)
			time.sleep(SCD41_COMMANDS[12][4])
			
			read_txn = smbus2.i2c_msg.read(I2C_SCD41, SCD41_COMMANDS[12][3])
			globals.bus_5.i2c_rdwr(read_txn)
			
			if globals.DEBUG_SCD41:
				print("SCD41_open : succès...")
				print(" ")
			SCD41_open_flag = True
			return True
		else :
			if globals.DEBUG_SCD41:
				print("SCD41_open : échec !")
				print(" ")
			SCD41_open_flag = False
			return False

	except Exception as e:

		exception_type, exception_object, exception_traceback = sys.exc_info()
		line_number = exception_traceback.tb_lineno
		exception_string = "type : " + str(exception_type) + " ; ligne = " + str(line_number)
		if globals.DEBUG_SCD41:
			print("SCD41_open : exception&nbsp;&nbsp;►►&nbsp;&nbsp;" + exception_string)
			print(" ")

		SCD41_open_flag = False
		return False


#--------------------------------------------------------------------------------------------------
# SCD41 intialisation
#--------------------------------------------------------------------------------------------------
def SCD41_init() :

	global SCD41_RUNNING_STATUS
	
	try:
		#------------------------------------------------------------------------------------------
		SCD41_RUNNING_STATUS = True		# on suppose qu'il est déjà en mode mesures
		
		#------------------------------------------------------------------------------------------
		if globals.DEBUG_SCD41 :
			print("SCD41_init : starting...")
			print(" ")
			
		#------------------------------------------------------------------------------------------
		if not SCD41_stop_periodic_measurement() :
			if globals.DEBUG_SCD41 :
				print("  SCD41_init : SCD41_stop_periodic_measurement&nbsp;&nbsp;►►&nbsp;&nbsp;échec !")
				print(" ")
			return False
		
		#------------------------------------------------------------------------------------------
		'''
		if (  not SCD41_reinit() ) :
			if globals.DEBUG_SCD41 :
				print("  SCD41_init : SCD41_reinit&nbsp;&nbsp;►►&nbsp;&nbsp;échec !")
				print(" ")
			return False
		'''
			
		#------------------------------------------------------------------------------------------
		if not SCD41_start_periodic_measurement() :
			if globals.DEBUG_SCD41:
				print("  SCD41_init : SCD41_start_periodic_measurement&nbsp;&nbsp;►►&nbsp;&nbsp;échec !")
				print(" ")
			return False
			
		else :
			if globals.DEBUG_SCD41:
				print("  SCD41_init : SCD41_start_periodic_measurement&nbsp;&nbsp;►►&nbsp;&nbsp;succès...")
				print(" ")
			return True
			
		#------------------------------------------------------------------------------------------
			
	except: 
		if globals.DEBUG_SCD41:
			print("  SCD41_init : exception !")
			print(" ")
		return False

#--------------------------------------------------------------------------------------------------
# stop_continuous_measurement :	0x3f, 0x86, 0,  0
#--------------------------------------------------------------------------------------------------
def SCD41_stop_periodic_measurement() :
	try :
		return_STATUS = False

		raw_message = [SCD41_COMMANDS[2][0], SCD41_COMMANDS[2][1]]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[2][4])

		console_string = "  SCD41_stop_periodic_measurement&nbsp;&nbsp;►►&nbsp;&nbsp;OK"
		return_STATUS = True
		
	except :
		console_string = "  SCD41_stop_periodic_measurement&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;exception"
		return_STATUS = False

	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS
		
#--------------------------------------------------------------------------------------------------
# start_continuous_measurement : 0x21, 0xb1, 0,  0
#--------------------------------------------------------------------------------------------------
def SCD41_start_periodic_measurement() :
	try:
		return_STATUS = False
		
		raw_message = [SCD41_COMMANDS[0][0], SCD41_COMMANDS[0][1]]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[0][4])

		console_string = "  SCD41_start_periodic_measurement&nbsp;&nbsp;►►&nbsp;&nbsp;OK"
		return_STATUS = True

	except:
		console_string = "  SCD41_start_periodic_measurement&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;exception"
		return_STATUS = False

	finally :
		SCD41_RUNNING_STATUS = return_STATUS
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# get_data_ready_status : 0xe4, 0xb8, 0,  3, 0.001, no stop
#--------------------------------------------------------------------------------------------------
def SCD41_get_data_ready_status() :
	try:
		console_string = "  SCD41_get_data_ready_status&nbsp;&nbsp;►►&nbsp;&nbsp;?"
		return_STATUS = False
		Count_data_ready = Count_data_ready_maxi
		
		while ( ( Count_data_ready > 0 ) and ( not return_STATUS ) ) :
		
			raw_message = [SCD41_COMMANDS[12][0], SCD41_COMMANDS[12][1]]
			write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
			globals.bus_5.i2c_rdwr(write_txn)
			time.sleep(SCD41_COMMANDS[12][4])
			
			read_txn = smbus2.i2c_msg.read(I2C_SCD41, SCD41_COMMANDS[12][3])
			globals.bus_5.i2c_rdwr(read_txn)
			data = list(read_txn)

			if ( len(data) == SCD41_COMMANDS[12][3] ):

				data_crc8 = CRC8.crc8_scd30(data[0],data[1])
				
				'''
				if globals.DEBUG_SCD41:
					print("  SCD41_get_data_ready_status : " + str(data[0]) + "_" +  str(data[1]) + "_" +  str(data[2]) + " ; CRC = " +  str(data_crc8) )
				'''
				
				if data[2] == data_crc8:
				
					if not ( ( ( data[0] and 0x7f ) == 0x00 ) and ( data[1] == 0x00 ) ) :
						console_string = "  SCD41_get_data_ready_status&nbsp;&nbsp;►►&nbsp;&nbsp;OK&nbsp;&nbsp;►►&nbsp;&nbsp;ready"
						return_STATUS = True
						
					else:
						console_string = "  SCD41_get_data_ready_status&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;not ready"

				else:
					console_string = "  SCD41_get_data_ready_status&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur CRC"
					
			else:
				console_string = "  SCD41_get_data_ready_status&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur Nb bytes"
			
			Count_data_ready = Count_data_ready - 1
			if ( Count_data_ready <= 0 ) :
				console_string = "  SCD41_get_data_ready_status : échec après " + str(Count_data_ready_maxi) + " tentatives !"
			
	except:
		console_string = "  SCD41_get_data_ready_status&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;exception"
		return_STATUS = False
		
	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# read_measurement : 0xec, 0x05, 0,  9, 0.001, no stop
#--------------------------------------------------------------------------------------------------
def SCD41_read() :

	try:
	
		console_string = "  read_measurement&nbsp;&nbsp;►►&nbsp;&nbsp;?"
		SCD41_read_measurement_retour = [ "???", "???", "???" ]
		
		if SCD41_get_data_ready_status() :
		
			raw_message = [SCD41_COMMANDS[1][0], SCD41_COMMANDS[1][1]]
			write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
			globals.bus_5.i2c_rdwr(write_txn)
			time.sleep(SCD41_COMMANDS[1][4])
			
			read_txn = smbus2.i2c_msg.read(I2C_SCD41, SCD41_COMMANDS[1][3])
			globals.bus_5.i2c_rdwr(read_txn)
			data = list(read_txn)

			if ( len(data) == SCD41_COMMANDS[1][3] ):
			
				#----------------------------------------------------------------------------------
				# calcul des CRC
				#----------------------------------------------------------------------------------
				data_crc8 = [0,0,0]
				for i in range(3) :
					data_crc8[i] = CRC8.crc8_scd30(data[3*i],data[3*i+1])
					
				'''
				if globals.DEBUG_SCD41:
					print("  SCD41_read_CO2 : " + str(data[0]) + "_" +  str(data[1]) + "_" +  str(data[2])  + "_CRC=" +  str(data_crc8[0]) )
					print("  SCD41_read_T   : " + str(data[3]) + "_" +  str(data[4]) + "_" +  str(data[5])  + "_CRC=" +  str(data_crc8[1]) )
					print("  SCD41_read_HR  : " + str(data[6]) + "_" +  str(data[7]) + "_" +  str(data[8])  + "_CRC=" +  str(data_crc8[2]) )
				'''

				#----------------------------------------------------------------------------------
				# test des CRC  (175/2^16) = 0.002670288 ; ( 100 / 65536 ) = 0.0015258789
				#----------------------------------------------------------------------------------
				if ( ( data[2]  == data_crc8[0] )  and ( data[5]  == data_crc8[1] ) and ( data[8]  == data_crc8[2] ) ) :
					 
					SCD41_CO2 =     data[0] * 256 + data[1]
					SCD41_T   = ( ( data[3] * 256 + data[4] ) * ( 0.00267029   ) ) - 45.0
					SCD41_HR  =   ( data[3] * 256 + data[4] ) * ( 0.0015258789 )

					chaine_SCD41_CO2 = "%d"    % SCD41_CO2
					chaine_SCD41_T   = "%2.2f" % SCD41_T
					chaine_SCD41_HR  = "%2.1f" % SCD41_HR

					console_string = "  SCD41_raw = " + chaine_SCD41_CO2 + " ppm ; " +  chaine_SCD41_T + " °C ; " + chaine_SCD41_HR + " %"
					SCD41_read_measurement_retour = [ chaine_SCD41_T, chaine_SCD41_HR, chaine_SCD41_CO2 ]
					
				else:
					console_string = "  read_measurement&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur CRC"
					globals.Flag_mesures_OK = ( globals.Flag_mesures_OK & 0xFFFFFFFFFF0F )  | 0x000000000010
					SCD41_read_measurement_retour = [ "CRC", "CRC", "CRC" ]
					
			else:
				console_string = "  read_measurement&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur_nb_bytes"
				globals.Flag_mesures_OK = ( globals.Flag_mesures_OK & 0xFFFFFFFFFF0F )  | 0x000000000020
				SCD41_read_measurement_retour = [ "NBB", "NBB", "NBB" ]
				
		else:
			console_string = "  read_measurement&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;data not ready"
			globals.Flag_mesures_OK = ( globals.Flag_mesures_OK & 0xFFFFFFFFFF0F )  | 0x000000000030
			SCD41_read_measurement_retour = [ "NRD", "NRD", "NRD" ]
			
	except Exception as e:

		console_string = "  read_measurement&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;exception"
		globals.Flag_mesures_OK = ( globals.Flag_mesures_OK & 0xFFFFFFFFFF0F )  | 0x000000000040
		SCD41_read_measurement_retour = [ "EXC", "EXC", "EXC" ]

		exception_type, exception_object, exception_traceback = sys.exc_info()
		line_number = exception_traceback.tb_lineno
		exception_string = "type : " + str(exception_type) + " ; ligne = " + str(line_number)
		if globals.DEBUG_SCD41:
			print("SCD41_read : exception&nbsp;&nbsp;►►&nbsp;&nbsp;" + exception_string)
			print(" ")
		
	finally:
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return SCD41_read_measurement_retour
		
#--------------------------------------------------------------------------------------------------
# reinit : 0x36, 0x46, 0,  0, 0.020, stop
#--------------------------------------------------------------------------------------------------
def SCD41_reinit() :
	try:
		return_STATUS = False
		
		raw_message = [SCD41_COMMANDS[17][0], SCD41_COMMANDS[17][1]]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[17][4])

		return_STATUS = True
		console_string = "  SCD41_reinit&nbsp;&nbsp;►►&nbsp;&nbsp;OK"
				
	except:
		return_STATUS = False
		console_string = "  SCD41_reinit&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;exception"

	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS
		
def SCD41_RE_INIT() :

	try :
		return_STATUS  = False
		
		SCD41_STOP_FLAG    = SCD41_stop_periodic_measurement()
		SCD41_RE_INIT_FLAG = SCD41_reinit()
		SCD41_START_FLAG   = SCD41_start_periodic_measurement()
		
		if ( SCD41_STOP_FLAG and SCD41_RE_INIT_FLAG and SCD41_START_FLAG ) :
			return_STATUS = True
	
	except :
		return_STATUS = False
	
	finally :
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# factory_reset : 0x36, 0x32, 0,  0
#--------------------------------------------------------------------------------------------------
def SCD41_factory_reset() :
	try:
		return_STATUS = False
		
		raw_message = [SCD41_COMMANDS[16][0], SCD41_COMMANDS[16][1]]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[16][4])
		
		return_STATUS = True
		console_string = "  SCD41_factory_reset&nbsp;&nbsp;►►&nbsp;&nbsp;OK"

	except:
		return_STATUS = False
		console_string = "  SCD41_factory_reset&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;exception"

	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS

def SCD41_FACTORY() :

	try :
		return_STATUS  = False
		
		SCD41_STOP_FLAG    = SCD41_stop_periodic_measurement()
		SCD41_FACTORY_FLAG = SCD41_factory_reset()
		SCD41_START_FLAG   = SCD41_start_periodic_measurement()
		
		if ( SCD41_STOP_FLAG and SCD41_FACTORY_FLAG and SCD41_START_FLAG ) :
			return_STATUS = True
	
	except :
		return_STATUS = False
	
	finally :
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# persist_settings (13) : 0x36, 0x15, 0,  0
#--------------------------------------------------------------------------------------------------
def SCD41_persist_settings() :
	try:
		return_STATUS = False
		
		raw_message = [SCD41_COMMANDS[13][0], SCD41_COMMANDS[13][1]]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[13][4])
		
		console_string = "  SCD41_persist_settings&nbsp;&nbsp;►►&nbsp;&nbsp;OK"
		return_STATUS = True

	except:
		console_string = "  SCD41_persist_settings&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;exception"
		return_STATUS = False

	finally :
		SCD41_RUNNING_STATUS = return_STATUS
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS

def SCD41_PERSIST() :

	try :
		return_STATUS  = False
		
		SCD41_STOP_FLAG    = SCD41_stop_periodic_measurement()
		SCD41_PERSIST_FLAG = SCD41_persist_settings()
		SCD41_START_FLAG   = SCD41_start_periodic_measurement()
		
		if ( SCD41_STOP_FLAG and SCD41_PERSIST_FLAG and SCD41_START_FLAG ) :
			return_STATUS = True
	
	except :
		return_STATUS = False
	
	finally :
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# TEMPERATURE To
#--------------------------------------------------------------------------------------------------

#--------------------------------------------------------------------------------------------------
# get_temperature_offset : 0x23, 0x18, 3,  0  ;  To_value(°C) = valeur_offset_To * ( 175 / 65536 )
#--------------------------------------------------------------------------------------------------
def SCD41_get_temperature_offset() :
	try:
		console_string = "  SCD41_get_temperature_offset&nbsp;&nbsp;►►&nbsp;&nbsp;?"
		return_STATUS = [False, 0.00, "???"]
		
		raw_message = [SCD41_COMMANDS[4][0], SCD41_COMMANDS[4][1]]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[4][4])
		
		read_txn = smbus2.i2c_msg.read(I2C_SCD41, SCD41_COMMANDS[4][3])
		globals.bus_5.i2c_rdwr(read_txn)
		data = list(read_txn)

		if ( len(data) == SCD41_COMMANDS[4][3] ):

			data_crc8  =  CRC8.crc8_scd30(data[0], data[1])
			
			if data[2] == data_crc8:
			
				valeur_offset_To = data[0] * 256 + data[1]
				To_value         = valeur_offset_To * 0.002670288086
				To_value_str     = "%.2f" % To_value
				
				return_STATUS = [True, To_value, To_value_str]
				
				console_string = "  SCD41_get_temperature_offset : " + To_value_str + " °C ; " + str(data[0]) + "_" +  str(data[1]) + "_" +  str(data[2]) + " ; CRC = " +  str(data_crc8)

			else:
				return_STATUS = [False, 0.00, "CRC"]
				console_string = "  SCD41_get_temperature_offset&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur CRC"

		else:
			return_STATUS = [False, 0.00, "NBB"]
			console_string = "  SCD41_get_temperature_offset&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur Nb bytes"
				
	except: 
		return_STATUS = [False, 0.00, "EXC"]
		console_string = "  SCD41_get_temperature_offset&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;exception"

	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS
		
#--------------------------------------------------------------------------------------------------
# set_temperature_offset : 0x24, 0x1d, 3,  0  ;  OFFSET_To_WORD = To(°C) * ( 65536 / 175 ) ( 374.491429 )
#--------------------------------------------------------------------------------------------------
def SCD41_set_temperature_offset(To_string) :
	try:
		return_STATUS = False
		console_string = "  SCD41_set_temperature_offset&nbsp;&nbsp;►►&nbsp;&nbsp;?"
		
		OFFSET_To_WORD = int( float(To_string) * 374.491429 )
		LSB = 0xFF &  OFFSET_To_WORD
		MSB = 0xFF & (OFFSET_To_WORD >> 8)
		valeur_offset_To = [MSB,LSB]
		
		data_crc8 = CRC8.crc8_scd30(valeur_offset_To[0],valeur_offset_To[1])

		raw_message = [ SCD41_COMMANDS[3][0], SCD41_COMMANDS[3][1], valeur_offset_To[0], valeur_offset_To[1], data_crc8 ]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[3][4])
		
		console_string = "  SCD41_set_temperature_offset&nbsp;&nbsp;►►&nbsp;&nbsp;OK : " + str(valeur_offset_To[0]) + "_" +  str(valeur_offset_To[1]) + " ; CRC = " +  str(data_crc8)
		return_STATUS = True
		
	except: 
		console_string = "  SCD41_set_temperature_offset&nbsp;&nbsp;►►&nbsp;&nbsp;NOK ►►EXC"
		return_STATUS = False

	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS
		
def SCD41_SET_To(To_string) :

	try :
		return_STATUS  = False
		
		SCD41_STOP_FLAG   = SCD41_stop_periodic_measurement()
		SCD41_SET_To_FLAG = SCD41_set_temperature_offset(To_string)
		SCD41_START_FLAG  = SCD41_start_periodic_measurement()
		
		if ( SCD41_STOP_FLAG and SCD41_SET_To_FLAG and SCD41_START_FLAG ) :
			return_STATUS = True
	
	except :
		return_STATUS = False
	
	finally :
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# ALTITUDE
#--------------------------------------------------------------------------------------------------

#--------------------------------------------------------------------------------------------------
# SCD41_get_sensor_altitude : 0x23, 0x22, 0, 3
#--------------------------------------------------------------------------------------------------
def SCD41_get_sensor_altitude() :
	try:
		console_string = "  SCD41_get_sensor_altitude&nbsp;&nbsp;►►&nbsp;&nbsp;?"
		return_STATUS = [False, 0.00, "???"]
		
		raw_message = [SCD41_COMMANDS[6][0], SCD41_COMMANDS[6][1]]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[6][4])

		read_txn = smbus2.i2c_msg.read(I2C_SCD41, SCD41_COMMANDS[6][3])
		globals.bus_5.i2c_rdwr(read_txn)
		data = list(read_txn)

		if ( len(data) == SCD41_COMMANDS[6][3] ):
			
			data_crc8  =  CRC8.crc8_scd30(data[0], data[1])
			
			if data[2] == data_crc8:
			
				QNH_value         = data[0] * 256 + data[1]
				QNH_value_str     = "%.0f" % QNH_value
				
				return_STATUS = [True, QNH_value, QNH_value_str]
				
				console_string = "  SCD41_get_sensor_altitude : " + return_STATUS[2] + " m ; " + str(data[0]) + "_" +  str(data[1]) + "_" +  str(data[2]) + " ; CRC = " +  str(data_crc8)

			else:
				return_STATUS = [False, 0.00, "CRC"]
				console_string = "  SCD41_get_sensor_altitude&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur CRC"

		else:
			return_STATUS = [False, 0.00, "NBB"]
			console_string = "  SCD41_get_sensor_altitude&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur Nb bytes"
				
	except: 
		return_STATUS = [False, 0.00, "EXC"]
		console_string = "  SCD41_get_sensor_altitude&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;exception"

	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# SCD41_set_sensor_altitude (5) : 0x24, 0x27, 3,  0
#--------------------------------------------------------------------------------------------------
def SCD41_set_sensor_altitude(QNH_string) :
	try:
		return_STATUS = False
		console_string = "  SCD41_set_sensor_altitude&nbsp;&nbsp;►►&nbsp;&nbsp;?"
		
		QNH_int_value = int(QNH_string)
		LSB = 0xFF &  QNH_int_value
		MSB = 0xFF & (QNH_int_value >> 8)
		valeur_altitude = [MSB,LSB]
		
		data_crc8 = CRC8.crc8_scd30(valeur_altitude[0],valeur_altitude[1])

		raw_message = [ SCD41_COMMANDS[5][0], SCD41_COMMANDS[5][1], valeur_altitude[0], valeur_altitude[1], data_crc8 ]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[5][4])

		console_string = "  SCD41_set_sensor_altitude&nbsp;&nbsp;►►&nbsp;&nbsp;OK : " + str(valeur_altitude[0]) + "_" +  str(valeur_altitude[1]) + " ; CRC = " +  str(data_crc8)
		return_STATUS = True
		
	except: 
		console_string = "  SCD41_set_sensor_altitude&nbsp;&nbsp;►►&nbsp;&nbsp;NOK ►►EXC"
		return_STATUS = False

	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS

def SCD41_SET_QNH(QNH_string) :

	try :
		return_STATUS  = False
		
		SCD41_STOP_FLAG    = SCD41_stop_periodic_measurement()
		SCD41_SET_QNH_FLAG = SCD41_set_sensor_altitude(QNH_string)
		SCD41_START_FLAG   = SCD41_start_periodic_measurement()
		
		if ( SCD41_STOP_FLAG and SCD41_SET_QNH_FLAG and SCD41_START_FLAG ) :
			return_STATUS = True
	
	except :
		return_STATUS = False
	
	finally :
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# ASC mode
#--------------------------------------------------------------------------------------------------

#--------------------------------------------------------------------------------------------------
# get ASC : 0x23, 0x13, 0,  3
#--------------------------------------------------------------------------------------------------
def SCD41_get_automatic_self_calibration_enabled() :
	try:
		console_string = "  SCD41_get_automatic_self_calibration_enabled&nbsp;&nbsp;►►&nbsp;&nbsp;?"
		return_STATUS  = [False, "???"]
		
		raw_message = [SCD41_COMMANDS[10][0], SCD41_COMMANDS[10][1]]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[10][4])
		
		read_txn = smbus2.i2c_msg.read(I2C_SCD41, SCD41_COMMANDS[10][3])
		globals.bus_5.i2c_rdwr(read_txn)
		data = list(read_txn)

		if ( len(data) == SCD41_COMMANDS[10][3] ):
			
			data_crc8  =  CRC8.crc8_scd30(data[0], data[1])
			
			if data[2] == data_crc8:
			
				ASC_value = data[0] * 256 + data[1]
				
				if ( ASC_value == 1 ) :
					ASC_value_str = "ON"
				else :
					ASC_value_str = "OFF"
					
				return_STATUS = [True, ASC_value_str]

				console_string = "  SCD41_get_automatic_self_calibration_enabled : " + return_STATUS[1] + " ; " + str(data[0]) + "_" +  str(data[1]) + "_" +  str(data[2]) + " ; CRC = " +  str(data_crc8)

			else:
				return_STATUS = [False, "CRC"]
				console_string = "  SCD41_get_automatic_self_calibration_enabled&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur CRC"

		else:
			return_STATUS = [False, "NBB"]
			console_string = "  SCD41_get_automatic_self_calibration_enabled&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur Nb bytes"
				
	except: 
		return_STATUS = [False, "EXC"]
		console_string = "  SCD41_get_automatic_self_calibration_enabled&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;exception"

	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# set_automatic_self_calibration_enabled (9) : 0x24, 0x16, 3,  0    ( enable&nbsp;&nbsp;►►&nbsp;&nbsp;1 ; disable&nbsp;&nbsp;►►&nbsp;&nbsp;0 )
#--------------------------------------------------------------------------------------------------
def SCD41_set_automatic_self_calibration_enabled(ASC_value) :
	try:
		return_STATUS = False
		console_string = "  SCD41_set_automatic_self_calibration_enabled&nbsp;&nbsp;►►&nbsp;&nbsp;?"

		ASC_value_int_value = int(ASC_value)
		LSB = 0xFF &  ASC_value_int_value
		MSB = 0xFF & (ASC_value_int_value >> 8)
		valeur_ASC_MODE = [MSB,LSB]
		
		data_crc8 = CRC8.crc8_scd30(valeur_ASC_MODE[0],valeur_ASC_MODE[1])

		raw_message = [ SCD41_COMMANDS[9][0], SCD41_COMMANDS[9][1], valeur_ASC_MODE[0], valeur_ASC_MODE[1], data_crc8 ]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[9][4])
		
		console_string = "  SCD41_set_automatic_self_calibration_enabled&nbsp;&nbsp;►►&nbsp;&nbsp;OK : " + str(valeur_ASC_MODE[0]) + "_" +  str(valeur_ASC_MODE[1]) + " ; CRC = " +  str(data_crc8)
		return_STATUS = True
		
	except: 
		console_string = "  SCD41_set_automatic_self_calibration_enabled&nbsp;&nbsp;►►&nbsp;&nbsp;NOK ►►EXC"
		return_STATUS = False

	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS
		
def SCD41_SET_ASC(ASC_string) :

	try :
		return_STATUS  = False
		
		if ( ASC_string == "ONH" ) :
			ASC_value = 1
		else :
			ASC_value = 0
		
		SCD41_STOP_FLAG    = SCD41_stop_periodic_measurement()
		SCD41_SET_ASC_FLAG = SCD41_set_automatic_self_calibration_enabled(ASC_value)
		SCD41_START_FLAG   = SCD41_start_periodic_measurement()
		
		if ( SCD41_STOP_FLAG and SCD41_SET_ASC_FLAG and SCD41_START_FLAG ) :
			return_STATUS = True
	
	except :
		return_STATUS = False
	
	finally :
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# DIVERS
#--------------------------------------------------------------------------------------------------

#--------------------------------------------------------------------------------------------------
# get_serial_number : 0x36, 0x82, 0,  9
#--------------------------------------------------------------------------------------------------
def SCD41_get_serial_number() :
	try:
		console_string = "  SCD41_get_serial_number&nbsp;&nbsp;►►&nbsp;&nbsp;?"
		return_STATUS  = [False, "???"]
		
		raw_message = [SCD41_COMMANDS[14][0], SCD41_COMMANDS[14][1]]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[14][4])
		
		read_txn = smbus2.i2c_msg.read(I2C_SCD41, SCD41_COMMANDS[14][3])
		globals.bus_5.i2c_rdwr(read_txn)
		data = list(read_txn)

		if ( len(data) == SCD41_COMMANDS[14][3] ):

			#----------------------------------------------------------------------------------
			# calcul des CRC
			#----------------------------------------------------------------------------------
			data_crc8 = [0,0,0]
			for i in range(3) :
				data_crc8[i] = CRC8.crc8_scd30(data[3*i],data[3*i+1])
				
			'''
			if globals.DEBUG_SCD41:
				print("  SCD41_read_word_0 : " + str(data[0]) + "_" +  str(data[1]) + "_" +  str(data[2])  + "_CRC=" +  str(data_crc8[0]) )
				print("  SCD41_read_word_1 : " + str(data[3]) + "_" +  str(data[4]) + "_" +  str(data[5])  + "_CRC=" +  str(data_crc8[1]) )
				print("  SCD41_read_word_2 : " + str(data[6]) + "_" +  str(data[7]) + "_" +  str(data[8])  + "_CRC=" +  str(data_crc8[2]) )
			'''

			#----------------------------------------------------------------------------------
			# test des CRC
			#----------------------------------------------------------------------------------
			if ( ( data[2]  == data_crc8[0] )  and ( data[5]  == data_crc8[1] ) and ( data[8]  == data_crc8[2] ) ) :
				 
				SCD41_SERIAL = (f"{data[0]:02x}") + (f"{data[1]:02x}") + (f"{data[3]:02x}") + (f"{data[4]:02x}") + (f"{data[6]:02x}") + (f"{data[7]:02x}")
				
				return_STATUS  = [True, SCD41_SERIAL]
				console_string = "  SCD41_get_serial_number&nbsp;&nbsp;►►&nbsp;&nbsp;OK : " + hex(data[0]) + " " + hex(data[1]) + " " + hex(data[3]) + " " + hex(data[4]) + " " + hex(data[6]) + " " + hex(data[7])

			else:
				return_STATUS  = [False, "erreur CRC !"]
				console_string = "  SCD41_get_serial_number&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur CRC"
				
		else:
			return_STATUS  = [False, "erreur Nb bytes !"]
			console_string = "  SCD41_get_serial_number&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur Nb bytes"
		
	except: 
		return_STATUS  = [False, "exception !"]
		console_string = "  SCD41_get_serial_number&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;exception"

	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# set_ambient_pressure (7) : 0xe0, 0x00, 3,  0		PRESSION en hPa
#--------------------------------------------------------------------------------------------------
def SCD41_set_ambient_pressure(PRESSION_string) :
	try:
		return_STATUS = False
		console_string = "  SCD41_set_ambient_pressure&nbsp;&nbsp;►►&nbsp;&nbsp;?"
		
		pression_int_value = int(PRESSION_string)
		LSB = 0xFF &  pression_int_value
		MSB = 0xFF & (pression_int_value >> 8)
		valeur_pression = [MSB,LSB]
		
		data_crc8 = CRC8.crc8_scd30(valeur_pression[0],valeur_pression[1])

		raw_message = [ SCD41_COMMANDS[7][0], SCD41_COMMANDS[7][1], valeur_pression[0], valeur_pression[1], data_crc8 ]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[7][4])
		
		console_string = "  SCD41_set_ambient_pressure&nbsp;&nbsp;►►&nbsp;&nbsp;OK : " + str(valeur_pression[0]) + "_" +  str(valeur_pression[1]) + " ; CRC = " +  str(data_crc8)
		return_STATUS = True
		
	except: 
		console_string = "  SCD41_set_ambient_pressure&nbsp;&nbsp;►►&nbsp;&nbsp;NOK ►►EXC"
		return_STATUS = False

	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# perform_forced_recalibration (8) : 0x36, 0x2f, 3,  3
#--------------------------------------------------------------------------------------------------
def SCD41_perform_forced_recalibration(REF_CO2_string) :
	try:
		return_STATUS = [ False, False, 0, "???" ]
		
		console_string_W = "  SCD41_perform_forced_recalibration WRITE&nbsp;&nbsp;►►&nbsp;&nbsp;?"
		console_string_R = "  SCD41_perform_forced_recalibration READ &nbsp;&nbsp;►►&nbsp;&nbsp;?"
		
		ref_co2_int_value = int(REF_CO2_string)
		LSB = 0xFF &  ref_co2_int_value
		MSB = 0xFF & (ref_co2_int_value >> 8)
		valeur_ref_co2 = [MSB,LSB]
		
		data_crc8 = CRC8.crc8_scd30(valeur_ref_co2[0],valeur_ref_co2[1])

		raw_message = [ SCD41_COMMANDS[8][0], SCD41_COMMANDS[8][1], valeur_ref_co2[0], valeur_ref_co2[1], data_crc8 ]
		write_txn = smbus2.i2c_msg.write(I2C_SCD41, raw_message)
		globals.bus_5.i2c_rdwr(write_txn)
		time.sleep(SCD41_COMMANDS[8][4])
		
		return_STATUS[0] = True
		
		console_string_W = "  SCD41_perform_forced_recalibration WRITE&nbsp;&nbsp;►►&nbsp;&nbsp;OK : " + str(valeur_ref_co2[0]) + "_" +  str(valeur_ref_co2[1]) + " ; CRC = " +  str(data_crc8)

		try :
			(count, data) = globals.RPi.i2c_read_device(handle_i2c_SCD41, SCD41_COMMANDS[8][3])
			
			if ( count == SCD41_COMMANDS[8][3] ) :
				
				data_crc8  =  CRC8.crc8_scd30(data[0], data[1])
				
				if data[2] == data_crc8:
				
					valeur_offset_CO2 = data[0] * 256 + data[1]
					if ( valeur_offset_CO2 == 65535 ) :
						valeur_offset_CO2 = 9999
						valeur_offset_CO2_value_str = "!!!"
					else :
						valeur_offset_CO2 = valeur_offset_CO2 - 32768
						valeur_offset_CO2_value_str = "%.0f" % valeur_offset_CO2
					
					return_STATUS = [True, True, valeur_offset_CO2, valeur_offset_CO2_value_str]
					
					console_string_R = "  SCD41_perform_forced_recalibration : " + valeur_offset_CO2_value_str + " ppm ; " + str(data[0]) + "_" +  str(data[1]) + "_" +  str(data[2]) + " ; CRC = " +  str(data_crc8)

				else:
					return_STATUS = [True, False, 0.00, "CRC"]
					console_string_R = "  SCD41_perform_forced_recalibration READ&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur CRC"

			else:
				return_STATUS = [True, False, 0.00, "NBB"]
				console_string_R = "  SCD41_perform_forced_recalibration READ&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur Nb bytes"
					
		except :
			return_STATUS = [True, False, 0.00, "EXC"]
			console_string_R = "  SCD41_perform_forced_recalibration READ&nbsp;&nbsp;►►&nbsp;&nbsp;NOK ►►EXC"
		
	except: 
		console_string_W = "  SCD41_perform_forced_recalibration WRITE&nbsp;&nbsp;►►&nbsp;&nbsp;NOK ►►EXC"
		return_STATUS = [False, False, 0.00, "EXC"]

	finally :
		if globals.DEBUG_SCD41:
			print(console_string_W)
			print(console_string_R)
			print(" ")
		return return_STATUS
		
def SCD41_FRC(REF_CO2_string) :

	try :
		return_STATUS  = False
		
		SCD41_STOP_FLAG   = SCD41_stop_periodic_measurement()
		SCD41_FRC_FLAG    = SCD41_perform_forced_recalibration(REF_CO2_string)
		SCD41_START_FLAG  = SCD41_start_periodic_measurement()
		
		if ( SCD41_STOP_FLAG and SCD41_FRC_FLAG and SCD41_START_FLAG ) :
			return_STATUS = True
	
	except :
		return_STATUS = False
	
	finally :
		return return_STATUS

#--------------------------------------------------------------------------------------------------
# read To, QNH, ASC, FW
#--------------------------------------------------------------------------------------------------
def SCD41_READ_To_QNH_ASC_FW() :

	try :
		console_string = "  SCD41_READ_To_QNH_ASC&nbsp;&nbsp;►►&nbsp;&nbsp;?"
		return_STATUS  = [ False, "?", "?", "?", "?" ]
		
		SCD41_STOP_FLAG  = SCD41_stop_periodic_measurement()
		SCD41_READ_To    = SCD41_get_temperature_offset()
		SCD41_READ_QNH   = SCD41_get_sensor_altitude()
		SCD41_READ_ASC   = SCD41_get_automatic_self_calibration_enabled()
		SCD41_READ_FW    = SCD41_get_serial_number()	
		SCD41_START_FLAG = SCD41_start_periodic_measurement()
		
		if ( SCD41_STOP_FLAG and SCD41_READ_To[0] and SCD41_READ_QNH[0] and SCD41_READ_ASC[0] and SCD41_READ_FW[0] and SCD41_START_FLAG ) :

			return_STATUS = [ True, SCD41_READ_To[2], SCD41_READ_QNH[2], SCD41_READ_ASC[1], SCD41_READ_FW[1] ]
			
			console_string = "  SCD41_READ_To_QNH_ASC&nbsp;&nbsp;►►&nbsp;&nbsp;OK : To = " + SCD41_READ_To[2] + " °C ; QNH = " + SCD41_READ_QNH[2] + " m ; ASC = " + SCD41_READ_ASC[1] + " ; FW = " + SCD41_READ_FW[1]
				
		else :
			console_string = "  SCD41_READ_To_QNH_ASC&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;erreur"
	
	except :
		console_string = "  SCD41_READ_To_QNH_ASC&nbsp;&nbsp;►►&nbsp;&nbsp;NOK&nbsp;&nbsp;►►&nbsp;&nbsp;exception"
	
	finally :
		if globals.DEBUG_SCD41:
			print(console_string)
			print(" ")
		return return_STATUS

#--------------------------------------------------------------------------------------------------
