'''
This sketch measures temperature and humidity and calculates (approximately) the dew point
For more information on how to calculate the dew point see Make Magazin 1/2022 S.22 (German only)

date: 02.10.2023
'''
from machine import Pin, SoftI2C
import time
import ssd1306
import dht
import math
from lcd_1602_2004_i2c import LCD


# constructor
scl = Pin(22)
sda = Pin(21)
#i2c = SoftI2C(scl=Pin(22), sda=Pin(21))
i2c = SoftI2C(scl, sda)
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
lcd = LCD(SoftI2C(scl, sda, freq=100000))
inside = dht.DHT22(Pin(13))
outside = dht.DHT22(Pin(12))
ledRed = Pin(2, Pin.OUT)
ledGreen = Pin(4, Pin.OUT)

# function to approximate the dew point
def call_dewPoint(temperature, humidity):
    _temperature = temperature
    _humidity = humidity

    if _temperature >= 0:
        a = 7.5
        b = 237.3
    else:
        a = 7.6
        b = 240.7

    saturationVaporPressure = 6.1078 * 10 ** ((a*_temperature)/(b+_temperature)) # hPa
    
    # vaporPressure
    vp = saturationVaporPressure * (_humidity / 100)

    # calculate vapor pressure
    vp = vp/6.1078

    dewPoint = (b * math.log(vp,10)) / (a - math.log(vp,10))
    
    return dewPoint

def call_oledDisplay2(temperature, humidity, dewPoint):

    oled.text('T [C]: ', 0,10)
    oled.text(str(temperature), 50, 10)
    oled.text('H [%]: ', 0, 21)
    oled.text(str(humidity), 50, 21)

    #dp = call_dewPoint(temperature, humidity)
    oled.text('DP: ', 0, 32)
    oled.text(str(dewPoint), 50, 32)
   
    oled.show()

def call_oledDisplay(temperature_inside, \
                        humidity_inside, \
                        dewPoint_inside, \
                        temperature_outside, \
                        humidity_outside, \
                        dewPoint_outside, \
                        fan):
    
    # clear display
    oled.fill(0)
    oled.show()
    
    # Update display
    oled.text('Inside',0,0)
    oled.text('T:', 0,10)
    oled.text(str(round(temperature_inside)), 15, 10)
    oled.text('H:', 45, 10)
    oled.text(str(round(humidity_inside)), 55, 10)
    oled.text('DP', 75, 10)
    oled.text(str(round(dewPoint_inside, 1)), 95, 10)
   
    oled.text('Outside',0,30)
    oled.text('T:', 0,40)
    oled.text(str(round(temperature_outside)), 15, 40)
    oled.text('H:', 45, 40)
    oled.text(str(round(humidity_outside)), 55, 40)
    oled.text('DP', 75, 40)
    oled.text(str(round(dewPoint_outside, 1)), 95, 40)

    oled.text('Fan: ', 0, 55)
    if fan == 1:
        oled.text('ON', 45, 55)
    else:
        oled.text('OFF', 45, 55)

    oled.show()

    #print to console
    print('T: ', round(temperature_inside, 2), ' H: ', round(humidity_inside,2), ' DP: ', round(dewPoint_inside, 4), \
            ' | T: ', round(temperature_outside, 2), ' H: ', round(humidity_outside, 2), ' DP: ', round(dewPoint_outside, 4))

def call_ventilation(_dp_i, _dp_o):
    
    # ventilate, if inside dew point > outside dew point
    if (_dp_i - 1) > _dp_o:
        return 1
    else:
        return 0

def call_switchRelay(fan):
    if fan == 1:
        # reley ON
        ledGreen.value(1)
        ledRed.value(0)
    else:
        # relay OFF
        ledGreen.value(0)
        ledRed.value(1)

def call_lcdDisplay(temperature_inside, \
                        humidity_inside, \
                        dewPoint_inside, \
                        temperature_outside, \
                        humidity_outside, \
                        dewPoint_outside, \
                        fan):
    _in = 'IN : ' + str(round(temperature_inside, 1)) + 'C | ' + str(round(humidity_inside)) + '%  '
    _out = 'OUT: ' + str(round(temperature_outside,1)) + 'C | ' + str(round(humidity_outside)) + '%  '
    _dpIn = 'DP in : ' + str(round(dewPoint_inside, 2)) + 'C  '
    _dpOut = 'DP out: ' + str(round(dewPoint_outside, 2)) + 'C  '
    
    lcd.puts(_in, 0, 0)
    lcd.puts(_out, 1, 0)
    lcd.puts(_dpIn, 2, 0)
    lcd.puts(_dpOut,3, 0)

    '''lcd.puts('Fan', 2, 16)
    if fan ==0:
        lcd.puts('OFF', 3, 16)
    else:
        lcd.puts('ON ', 3, 16)'''

while True:
    #
    # get and calculate room (inside) data
    inside.measure()
    t_i = inside.temperature()
    h_i = inside.humidity()

    # calculate dew point
    dp_i = call_dewPoint(t_i, h_i)

    #
    # get and calculate outside data
    outside.measure()
    t_o = outside.temperature()
    h_o = outside.humidity()

    # calculate dew point
    dp_o = call_dewPoint(t_o, h_o)

    # check ventilation
    relay = call_ventilation(dp_i, dp_o)

    # switch LED indicator
    call_switchRelay(relay)

    # update oled disply
    call_oledDisplay(t_i, h_i, dp_i, t_o, h_o, dp_o, relay)


    call_lcdDisplay(t_i, h_i, dp_i, t_o, h_o, dp_o, relay)

    time.sleep(5)
NOCOMNCVCCGNDINLED1PWRRelay Module