#!/bin/python

import dht
from machine import Pin, Timer, RTC
from micropyserver import MicroPyServer
from micropyserver_utils import send_response, get_request_post_params
import ntptime
import os

DHT_PIN = 26
RELAY_PIN = 4
UPDATE_INTERVAL_S = 60
MAX_LOG_SIZE = 3 * 1024 * 1024 # MegaByte

name = "Test Sensor"
humidity_limit_path = 'humidity_limit'
sensor_log_path = 'sensors.log'
sensor_log_path = 'sensors.log'
log_file = None 
log_cursor_file = None

server = MicroPyServer()
dht = dht.DHT22(Pin(DHT_PIN))
relay = Pin(RELAY_PIN, Pin.OUT)
update_timer = Timer(0)
index_template = ""

humidity_limit = 80

temp = 0
humidity = 0

def redirect_root():
    send_response(server, ' ', http_code=303, content_type="text/plain", extend_headers=["Location: /"])
    
def handle_update(_):
    update("")

    redirect_root()

def write_log():
    global log_file
    pos = log_file.tell()
    if pos > MAX_LOG_SIZE:
        log_file.seek(0, 0)
    
    log_values(log_file)

    log_cursor_file.seek(0,0)
    log_cursor_file.write(str(log_file.tell()))

def log_values(file):
    global temp, humidity
    time = ntptime.time()
    log_string = f'{time:014d},{str(temp)},{str(humidity)};'
    file.write(log_string)
    file.flush()

def get_logs(_):
    log = ''
    try:
        with open(sensor_log_path) as log_file:
            log = log_file.readline()
    except OSError:
        None

    send_response(server, log, http_code=200, content_type="text/plain", extend_headers=['Content-Disposition: attachment; filename="logs.csv"',"Location: /"])

def update(_):
    read_sensors()

    update_relay()

    write_log()
    
def update_relay():
    if humidity > humidity_limit:
        relay_on()
        return

    relay_off()

def high_humidity() -> bool:
    return humidity >= humidity_limit

def read_sensors():
    global temp, humidity
    try:
        dht.measure()
    except:
        return

    temp = dht.temperature()
    humidity = dht.humidity()

def serve_root(_):
    global server, temp, humidity, index_template, relay, humidity_limit

    relay_status = "On" if relay.value() else "Off"
    index = index_template \
        .replace('{name}', name) \
        .replace('{temp}', str(temp)) \
        .replace('{humidity}', str(humidity)) \
        .replace('{relay_status}', relay_status) \
        .replace('{humidity_limit}', str(humidity_limit)) 

    send_response(server, index)

def toggle_relay(_):
    global relay
    val = relay.value()
    relay.value(not val)

    redirect_root()

def handle_relay_off(_):
    relay_off()
    redirect_root()

def relay_off():
    global relay
    relay.value(0)


def handle_relay_on(_):
    relay_on()
    redirect_root()

def relay_on():
    global relay
    relay.value(1)

def set_humidity_limit(request):
    global humidity_limit

    params = get_request_post_params(request)
    print(params)

    if not params or not params["limit"]:
        redirect_root()
        return

    new_value = int(params["limit"])
    if new_value < 0 or new_value > 100:
        redirect_root()
        return

    humidity_limit = new_value
    write_limit(new_value)

    redirect_root()
    
def write_limit(limit: int):
    with open(humidity_limit_path, 'w') as file:
        file.write(str(humidity_limit))

def read_limit() -> int:
    with open(humidity_limit_path) as file:
        return int(file.readline())

def init():
    init_clock()
    init_log()
    init_settings()
    init_timer()
    init_webserver()

def init_log():
    global log_file, log_cursor_file
    try:
        log_file = open(sensor_log_path, 'r+')
    except OSError:
        log_file = open(sensor_log_path, 'w+')
    try:
        log_cursor_file = open(f'{sensor_log_path}.cursor', 'r+')
    except OSError:
        log_cursor_file = open(f'{sensor_log_path}.cursor', 'w+')

    cursor = 0
    cursor_content = log_cursor_file.readline()
    print(cursor_content)
    try:
        cursor = int(cursor_content)
    except:
        cursor = 0

    print(cursor)
    log_file.seek(cursor, 0)

def init_clock():
    ntptime.settime()

def init_settings():
    global humidity_limit
    
    try:
        os.stat(humidity_limit_path)
    except OSError:
        write_limit(humidity_limit)

    humidity_limit = read_limit()

def init_timer():
    global update_timer
    update_timer = update_timer.init(period=UPDATE_INTERVAL_S * 1000, callback=update)

def init_webserver():
    load_index_template()
    server.add_route('/', serve_root)
    server.add_route('/toggle', toggle_relay)
    server.add_route('/off', handle_relay_off)
    server.add_route('/on', handle_relay_on)
    server.add_route('/set_limit', set_humidity_limit, method="POST")
    server.add_route('/update', handle_update)
    server.add_route('/get_logs', get_logs)
    
def load_index_template():
    global index_template
    with open('index.html') as index_html:
        index_template = ''.join(index_html.readlines())

def main():
    global server
    init()
    server.start()


if __name__ == "__main__":
    main()

