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


bus = smbus.SMBus(1)
pi = pigpio.pi()



def count_pulses():
        pi.set_pull_up_down(24, pigpio.PUD_DOWN)
        cb = pi.callback(24,pigpio.RISING_EDGE) # default callback counts rising edges
        last_count = cb.tally() # rising edge count
        time.sleep(1) # sleep 1.0 seconds
        now_count = cb.tally() # rising edge count
        val = (((now_count - last_count)*2.4)*0.6213)/1
        cb.cancel() # cancel callback
        last_count=0
	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



def test_BMP180():
	p = os.popen('sudo i2cdetect -y 1 |grep 77')
	s = p.readline()
	p.close()
	#print s
	b = s.find("77",2,len(s))
	if b<>-1:
		return True
	else:
		return False	

def test_SI1145():

        p = os.popen('sudo i2cdetect -y 1 |grep 60')
        s = p.readline()
        p.close()
        #print s
        b = s.find("60",2,len(s))
	if b<>-1:
		return True
	else:
		return False

def test_HTU21D():

        p = os.popen('sudo i2cdetect -y 1 |grep 40')
        s = p.readline()
        p.close()
        #print s
        b = s.find("40",2,len(s))
	if b<>-1:
		return True
	else:
		return False

def test_HMC5883L():

        p = os.popen('sudo i2cdetect -y 1 |grep 1E')
        s = p.readline()
        p.close()
        #print s
        b = s.find("1E",2,len(s))
	if b<>-1:
		return True
	else:
		return False






if test_HMC5883L()==True:
	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
else:
	print "HMC5883L() Offline"
	


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


print('Setting up buses')
sensor = BMP085.BMP085()
print('Now is '+time.asctime(time.gmtime(time.time())))
time_start = time.time()
if test_HTU21D()==True:
	htu_reset()
	humidity = read_humidity()
else:
	print "HTU21D Offline"
print('HTU sensor needs to reset. Resetted...')
if test_BMP180()==True:
	temp = sensor.read_temperature()
	pressure = sensor.read_pressure()
else:
	print "BMP180 Offline"
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)
dir = 0
if test_HMC5883L()==True:

	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)
else:
	print"HCM5883L Offline"
	direction = 0
print('Done !')
print('Wind dir is ',direction)
max = 0
totalwind = 0
print('Reading wind speed for 30S - 1st pass')
for n in range (1, 30):
	current = count_pulses()
	totalwind = totalwind + current
	if (current > max):
		max = current
	else:
		max = max
print('Round ',n,' - ',current,' - ',max)
totalwind = totalwind / 29
windspeedmph = totalwind
windgustmph = max
if windspeedmph >= 70:
	windspeedmph = 0
else:
	windspeedmph = windspeedmph

if windgustmph >= 90:
	windgustmph = 0

else:
	windgustmph = windgustmph
	
if windgustmph < windspeedmph:
	windgustmph = windspeedmph
else:
	windgustmph = windgustmph

print(' Windspeed in Km/h is ',windspeedmph/0.6213, ' with gusts in Km/h of ',windgustmph/0.6213)
if test_SI1145()==True:
	reset()
	calibration()
	irr = round(readU16LE(0x60,0x24)*0.0079,2)
	uv = readU16LE(0x60,0x2C)/100
       	uv = int(uv*0.65)
else:
	print "SI1145 Offline"	
	uv = 0
	irr = 0
print(' UV ',uv)
print(' Irr ',irr) 

cmd = "curl "+"'http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?ID=IWICKLOW13&PASSWORD=williams&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"+"'"
print('Uploading data...')
print(cmd)
os.system(cmd)
print('Measuring sequence done in ',round(time.time()-time_start,2),' seconds')

