#!/usr/bin/python
# Code to control the HTU21D temperature and humidity sensor. Write observations to disk
# and to web in intervals determined by input.txt
# Paul A. Kucera, Ph.D. and Joseph E. Rener
# UCAR
# Boulder, CO USA
# Email: pkucera@ucar.edu and jrener@ucar.edu
# Copyright (c) 2018 UCAR
# Developed at COMET at University Corporation for Atmospheric Research and the Research Applications Laboratory at the National Center for Atmospheric Research (NCAR)
# Updated: 28 September 2018

import sys, struct, array, time, io, os, fcntl, datetime, helper_functions # pylint: disable=import-error
from helper_functions import root

I2C_SLAVE=0x0703
HTU21D_ADDR = 0x40
CMD_READ_TEMP_HOLD = "\xE3"
CMD_READ_HUM_HOLD = "\xE5"
CMD_READ_TEMP_NOHOLD = "\xF3"
CMD_READ_HUM_NOHOLD = "\xF5"
CMD_WRITE_USER_REG = "\xE6"
CMD_READ_USER_REG = "\xE7"
CMD_SOFT_RESET= "\xFE"

class i2c(object):
  	def __init__(self, device, bus):
		self.fr = io.open("/dev/i2c-"+str(bus), "rb", buffering=0)
		self.fw = io.open("/dev/i2c-"+str(bus), "wb", buffering=0)
		# set device address
		fcntl.ioctl(self.fr, I2C_SLAVE, device)
		fcntl.ioctl(self.fw, I2C_SLAVE, device)

	def write(self, bytes):
		self.fw.write(bytes)

  	def read(self, bytes):
		return self.fr.read(bytes)

  	def close(self):
		self.fw.close()
		self.fr.close()

class HTU21D(object):
  	def __init__(self):
		self.dev = i2c(HTU21D_ADDR, 1) #HTU21D 0x40, bus 1
		self.dev.write(CMD_SOFT_RESET) #soft reset
		time.sleep(.1)

	def ctemp(self, sensorTemp):
		tSensorTemp = sensorTemp / 65536.0
		return -46.85 + (175.72 * tSensorTemp)

	def chumid(self, sensorHumid):
		tSensorHumid = sensorHumid / 65536.0
		return -6.0 + (125.0 * tSensorHumid)

	def crc8check(self, value):
		# Ported from Sparkfun Arduino HTU21D Library: https://github.com/sparkfun/HTU21D_Breakout
		remainder = ( ( value[0] << 8 ) + value[1] ) << 8
		remainder |= value[2]
		# POLYNOMIAL = 0x0131 = x^8 + x^5 + x^4 + 1
		divsor = 0x988000 # this is the 0x0131 polynomial shifted to farthest left of three bytes
		for i in range(0, 16):
			if( remainder & 1 << (23 - i) ):
				remainder ^= divsor
			divsor = divsor >> 1
		if remainder == 0:
			return True
		else:
			return False
	
	def read_temperature(self):
		self.dev.write(CMD_READ_TEMP_NOHOLD) #measure temp
		time.sleep(.1)
		data = self.dev.read(3)
		buf = array.array('B', data)
		if self.crc8check(buf):
			temp = (buf[0] << 8 | buf [1]) & 0xFFFC
			return self.ctemp(temp)
		else:
			return -255
				
	def read_humidity(self):
		self.dev.write(CMD_READ_HUM_NOHOLD) #measure humidity
		time.sleep(.1)
		data = self.dev.read(3)
		buf = array.array('B', data)
		if self.crc8check(buf):
			humid = (buf[0] << 8 | buf [1]) & 0xFFFC
			return self.chumid(humid)
		else:
			return -255

         
if __name__ == "__main__":
	# Get script arguments
	arguments = helper_functions.getArguments()
	interval = arguments[0]
	chords_toggle = arguments[1]
	chords_id = arguments[2]
	try:
		obj = HTU21D()
		tempC = obj.read_temperature()
		tempF = obj.read_temperature()*1.8+32
		rh = obj.read_humidity()

		# Print to screen
		print "HTU21D Sensor"
		print "Temperature:  %.2f degC" % tempC
		print "Temperature:  %.2f degF" % tempF
		print "Humidity:     %.0f%%" % rh

		# Get current time
		now = datetime.datetime.now()

		# Handle script output
		line = '%02d %02d %4d %02d %02d %6.1f %5.1f %5.1f' % (now.month, now.day, now.year, now.hour, now.minute, tempC, tempF, rh)
		filename = '/home/pi/3d_paws/data/htu21d/htu21d_%4d%02d%02d.dat' % (now.year, now.month, now.day)
		helper_functions.output(False, line, filename)

		# Function to send data to CHORDS (if applicable)
		url = "http://3d.chordsrt.com/measurements/url_create?instrument_id=%d&t1=%05.1f&rh1=%04.1f&key=21DE6A8A" % (chords_id, tempC, rh)
		helper_functions.reportCHORDS(chords_toggle, now.minute, interval, url)	

	except Exception, e:
		helper_functions.handleError(e)
