import Adafruit_BMP.BMP085 as BMP085
import smbus
import os
import sys
import getopt
import sqlite3
import math
import pigpio
import time
import RPi.GPIO as GPIO


bus = smbus.SMBus(1)
address = 0x1e


def count_pulses():
	pi.set_mode(23, pigpio.INPUT)
	pi.set_pull_up_down(23, pigpio.PUD_DOWN)
	cb = pi.callback(23, pigpio.FALLING_EDGE)
	start = time.time()
	old_count = 0
   	time.sleep(1.0)
   	count = cb.tally() # Get the number of pulses seen so far.
   	#print("counted {} pulses".format(count - old_count))
   	val = count - old_count
	old_count = count
	cb.cancel() # cancel callback
	return val


	

def read_byte(address,adr):
    return bus.read_byte_data(address, adr)



def read_word(address,adr):
    high = bus.read_byte_data(address, adr)
    low = bus.read_byte_data(address, adr+1)
    val = (high << 8) + low
    return val

def read_word_2c(address,adr):
    val = read_word(address,adr)
    if (val >= 0x8000):
        return -((65535 - val) + 1)
    else:
        return val




def write_byte(address,adr, value):
    bus.write_byte_data(address, adr, value)


def median(lst):
    lst = sorted(lst)
    if len(lst) < 1:
            return None
    if len(lst) %2 == 1:
            return lst[((len(lst)+1)/2)-1]
    else:
            return float(sum(lst[(len(lst)/2)-1:(len(lst)/2)+1]))/2.0


def write_param(address,p,v):
        write_byte(address,0x17,v)
        write_byte(address,0x18,p | 0xA0)
        value = read_byte(address,0x2E)
        return value


def readU16(address, register, little_endian=True):
        result = bus.read_word_data(address,register) & 0xFFFF
        if not little_endian:
                result = ((result << 8) & 0xFF00) + (result >> 8)
        return result


def readU16LE(address, register):
        return readU16(address,register, little_endian=True)


def reset():
        write_byte(0x60,0x08,0x00)
        write_byte(0x60,0x09,0x00)
        write_byte(0x60,0x04,0x00)
        write_byte(0x60,0x05,0x00)
        write_byte(0x60,0x06,0x00)
        write_byte(0x60,0x03,0x00)
        write_byte(0x60,0x21,0xFF)
        write_byte(0x60,0x18,0x01)
        time.sleep(0.01)
        write_byte(0x60,0x07,0x17)
        time.sleep(0.01)


def calibration():
        write_byte(0x60,0x13,0x29)
        write_byte(0x60,0x14,0x89)
        write_byte(0x60,0x15,0x02)
        write_byte(0x60,0x16,0x00)
        write_param(0x60,0x01,0x80 | 0x20 | 0x10 | 0x01)
        write_byte(0x60,0x03,0x01)
        write_byte(0x60,0x04,0x01)
        write_byte(0x60,0x0F,0x03)
        write_param(0x60,0x07,0x03)
        write_param(0x60,0x02,0x01)
        write_param(0x60,0x0B,0x00)
        write_param(0x60,0x0A,0x70)
        write_param(0x60,0x0C,0x20 | 0x04)
        write_param(0x60,0x1E,0x00)
        write_param(0x60,0x1D,0x70)
        write_param(0x60,0x1F,0x20)
        write_param(0x60,0x11,0x00)
        write_param(0x60,0x10,0x70)
        write_param(0x60,0x12,0x20)
        write_byte(0x60,0x08,0xFF)
        write_byte(0x60,0x18,0x0F)


def read_uv():
        uv = readU16LE(0x60,0x2C)/100
        uv = int((uv/10)*6)
        print("UV Index : ",uv)
        print("Vis + IR : ",readU16LE(0x60,0x22))
        print("IR       : ",readU16LE(0x60,0x24))
        print("Proximity: ",readU16LE(0x60,0x26))
        print("Irr W/m  : ",round(readU16LE(0x60,0x24)*0.0079,2))



def htu_reset():
   handle = pi.i2c_open(1, 0x40) # open i2c bus
   pi.i2c_write_byte(handle,0xFE) # send reset command
   pi.i2c_close(handle) # close i2c bus
   time.sleep(0.2) # reset takes 15ms so let's give it some time



def read_temperature():
	handle = pi.i2c_open(1, 0x40) # open i2c bus
	pi.i2c_write_byte(handle, 0xF3) # send read temp command
	time.sleep(0.055) # readings take up to 50ms, lets give it some time
	(count, byteArray) = pi.i2c_read_device(handle, 3) # vacuum up those bytes
	pi.i2c_close(handle) # close the i2c bus
	t1 = byteArray[0] # most significant byte msb
	t2 = byteArray[1] # least significant byte lsb
	temp_reading = (t1 * 256) + t2 # combine both bytes into one big integer
	temp_reading = math.fabs(temp_reading) # I'm an idiot and can't figure out any other way to make it a float 
	temperature = ((temp_reading / 65536) * 175.72 ) - 46.85 # formula from datasheet
	return temperature

def read_humidity():
	handle = pi.i2c_open(1, 0x40) # open i2c bus
	pi.i2c_write_byte(handle, 0xF5) # send read humi command
	time.sleep(0.055) # readings take up to 50ms, lets give it some time
	(count, byteArray) = pi.i2c_read_device(handle, 3) # vacuum up those bytes
	pi.i2c_close(handle) # close the i2c bus
	h1 = byteArray[0] # most significant byte msb
	h2 = byteArray[1] # least significant byte lsb
	humi_reading = (h1 * 256) + h2 # combine both bytes into one big integer
	humi_reading = math.fabs(humi_reading) # I'm an idiot and can't figure out any other way to make it a float
	uncomp_humidity = ((humi_reading / 65536) * 125 ) - 6 # formula from datasheet
	# to get the compensated humidity we need to read the temperature
	temperature = read_temperature()
	humidity = ((25 - temperature) * -0.15) + uncomp_humidity
	return humidity



write_byte(0x1E,0, 0b01110000) # Set to 8 samples @ 15Hz
write_byte(0x1E,1, 0b00100000) # 1.3 gain LSb / Gauss 1090 (default)
write_byte(0x1E,2, 0b00000000) # Continuous sampling
scale = 0.92
x_offset = 45
y_offset = -82



def get_heading():
	x_out = (read_word_2c(0x1E,3) - x_offset) * scale
	y_out = (read_word_2c(0x1E,7) - y_offset) * scale
	z_out = (read_word_2c(0x1E,5)) * scale
	bearing  = math.atan2(y_out, x_out) 
	if (bearing < 0):
		bearing += 2 * math.pi
	if ((math.degrees(bearing) + 90) < 360 and (math.degrees(bearing)+90) > 90):
		heading = math.degrees(bearing)+90
#		print round(heading,0)
	elif math.degrees(bearing)+90 == 360:
		heading = 0
#		print round(heading,0)
	else:
		heading = math.degrees(bearing)-270
#		print round(heading,0)
	return heading





var = 1
print('Setting up buses')
sensor = BMP085.BMP085()
pi = pigpio.pi()

while var == 1:
	print('Now is '+time.asctime(time.gmtime(time.time())))
	time_start = time.time()
	
	htu_reset()
	print('HTU sensor needs to reset. Resetted...')
	temp = sensor.read_temperature()
	pressure = sensor.read_pressure()
	humidity = read_humidity()
	if humidity > 100 : humidity = 100
	po1 = math.log(humidity/100) + ((17.62 * temp)/(243.12 + temp))
	po = (243.12 * po1) / (17.62 - po1)
	po = round(po,2)
	print('Temp is ',temp)
	print("Pressure is ",round(pressure/100,1))
	print("Humidity is ",humidity)
	print("Dew point is ",po)
	#print('Temp ',temp,' Pressure ',pressure,' Humidity ',humidity,' Dew ',po)
	dir = 0
	lista = range(500)
	print('Reading 500 times wind direction separated by 10mS each for smoothing final reading ...')
	for dd in range (0, 500):
		lista[dd] = get_heading()
		time.sleep(0.01)
	direction = median(lista)
	print('Done !')
	print('Wind dir is ',direction)
#	direction = 0


	max = 0
	totalwind = 0
	print('Reading wind speed for 30S')
	

	for n in range (1, 30):
		current = count_pulses()
		totalwind = totalwind + current
		if (current > max):
			max = current
		else:
			max = max
		#print(n,' - ',current,' - ',max)
	


	totalwind = totalwind / 29
	#windspeedmph = ((totalwind * 2.4) * 0.6213)
	#windgustmph = ((max * 2.4) * 0.6213)
	windspeedmph = ((totalwind * 1.342857) * 0.6213)
	windgustmph = ((max * 1.342857) * 0.6213)
	print(' Windspeed in Km/h is ',windspeedmph/0.6213, ' with gusts in Km/h of ',windgustmph/0.6213)
	reset()
	calibration()
	irr = round(readU16LE(0x60,0x24)*0.0079,2)
	uv = readU16LE(0x60,0x2C)/100
        uv = int(uv*0.65)	
	print(' UV ',uv)
	print(' Irr ',irr) 
	#conn=sqlite3.connect('/var/www/templog.db')
	#curs=conn.cursor()
	#curs.execute("INSERT INTO temps values(datetime('now'), (?),(?),(?))", (temp,pressure,humidity))
	#conn.commit()B
	#conn.close()
	#cmd = "curl -d "+"'temp="+str(temp)+"&humidity="+str(round(humidity,2))+"&pressure="+str(pressure/100)+"' --user 'extraman:williams' http://openweathermap.org/data/post"
	#print(cmd)
	#os.system(cmd)
	cmd = "curl "+"'http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?ID=<YOURID>&PASSWORD=<YOURPASS>&dateutc=now&tempf="+str((temp*1.8)+32)+"&dewptf="+str((po*1.8)+32)+"&humidity="+str(round(humidity,2))+"&baromin="+str((pressure/100)*0.0295299)+"&winddir="+str(direction)+"&UV="+str(uv)+"&solarradiation="+str(irr)+"&windspeedmph="+str(round(windspeedmph,2))+"&windgustmph="+str(round(windgustmph,2))+"&action=updateraw"+"'"
	#cmd = "curl -d "+"'dateutc=now&tempf="+str(temp)+"&humidity="+str(round(humidity,2))+"&baromin="+str(pressure/100)+"&action=updateraw"+"' --user 'IWICKLOW13:williams' http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php"
	print('Uploading data...')
	print(cmd)
	os.system(cmd)
	print('Measuring sequence done in ',round(time.time()-time_start,2),' seconds')
	print('Waiting 60s for next measuring sequence...')
	time.sleep(60)
#	var = 0

