#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Adjusts my thermostat when my solar array is generating lots of power, and is
likely to continue.
"""

import csvkit
import os
import sys
import sqlite3
import urllib, json
import time
import datetime
import requests
import yaml
import decimal
from subprocess import call

# Load the config file.
CONFIG = yaml.safe_load(open('config.yml'))

def main():
    """The main program function."""
    if os.path.isfile(CONFIG['data_file']) is False:
        print CONFIG['data_file'] + " not found"
        sys.exit()

    # Make database connection variables available to all functions.
    global db
    global cursor

    # Make energy data available to all functions.
    global energy_data

    # Open up a SQLite connection.
    try:
        db = sqlite3.connect('energy.db')
    except sqlite3.error, e:
        print "Count not connect to SQLite, with error %s:" % e.args[0]
        sys.exit(1)
    db.row_factory = dict_factory

    # Create a SQLite cursor.
    cursor = db.cursor()

    # See if the database table exists. If not, create it.
    cursor.execute("SELECT 1 \
                    FROM sqlite_master \
                    WHERE type='table' AND name='energy'")
    exists = cursor.fetchone()
    if exists is None:
        cursor.execute("CREATE TABLE energy(time INTEGER PRIMARY KEY NOT NULL, " \
            + "used INTEGER, generated INTEGER, label TEXT NULL, change TEXT NULL, "\
            + " temp_int INT NULL, temp_ext INT NULL")
        db.commit()

    energy_data = dict()

    # Fetch Enphase data if the sun is shining.
    #if is_daylight():
    from datetime import datetime, time
    now = datetime.now()
    now_time = now.time()
    if time(7,00) <= now.time() <= time(20,00):
        enphase_url = 'https://api.enphaseenergy.com/api/v2/systems/' \
            + CONFIG['enphase_system'] + '/summary?key=' + CONFIG['enphase_key'] \
            + '&user_id=' + CONFIG['enphase_user']
        response = urllib.urlopen(enphase_url)
        # We make this a global as a lousy hack to access it in export_json()
        global solar_data
        solar_data = json.loads(response.read())
        
        energy_data['generated'] = int(solar_data['current_power'])
        energy_data['generated_time'] = int(float(solar_data['last_report_at']))

        # See when we last recorded power generation data, to avoid duplicates.
        cursor.execute("SELECT time \
                        FROM energy \
                        WHERE generated IS NOT NULL \
                        ORDER BY time DESC \
                        LIMIT 1")
        last = cursor.fetchone()
        if last['time'] < energy_data['generated_time']:

            cursor.execute("INSERT INTO energy (time, generated) " \
                            + "VALUES(?, ?)", \
                            (energy_data['generated_time'], energy_data['generated']))
            db.commit()
    # Otherwise, note that we're generating no power.
    else:
        energy_data['generated'] = 0

    # See when we last recorded power use data.
    cursor.execute("SELECT time \
                    FROM energy \
                    WHERE used IS NOT NULL \
                    ORDER BY time DESC \
                    LIMIT 1")
    last = cursor.fetchone()
    
    # Parse cron-retrieved records, providing the average amount of power used
    # in the prior two minutes. (The data file contains records with a
    # granularity that's much finer.)
    records = csvkit.CSVKitDictReader(open(CONFIG['data_file'], 'rb'))
    watts = []
    for record in records:
        if last['time'] >= int(round(float(record['src']))):
            continue
        energy_data['time'] = int(round(float(record['src'])))
        energy_data['used'] = abs(int(record['ch1watts']) + int(record['ch2watts']) \
            - energy_data['generated'])
        energy_data['temp_int'] = int(float(record['tmprF']))
        cursor.execute("INSERT INTO energy (time, used, temp_int) " \
                        + "VALUES(?, ?, ?)", \
                        (energy_data['time'], energy_data['used'], \
                        energy_data['temp_int']))
    db.commit()

    # Display the power use and generation data on the command line
    print energy_data

    # Save the last 12 hours of data as a JSON File.
    export_json()

    # Retrieve the most recent power data from the database.
    energy_data = get_current_status()

    # If we're generating >1kW of unused power.
    if (energy_data['generated'] - energy_data['used']) > 1000:

        # Provide a notification via Pushover.
        send_alert()

        # See if we've been generating >1kW for at least 20 minutes.
        cursor.execute("SELECT generated \
                        FROM energy \
                        WHERE time >= (strftime('%s','now') - (60*20) ) \
                        ORDER BY time DESC")
        records = cursor.fetchall()
        insufficient = False
        for record in records:
            if record['generated'] < 1000:
                insufficient = True
                break
        if insufficient == False:
            nest_set()

    db.close

def dict_factory(cursor, row):
    """Emit SQLite results as a dict."""
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

def get_current_status():
    """Retrieve the most recent generation and use data from the database."""
    status = {}
    cursor.execute("SELECT used \
                    FROM energy \
                    WHERE used IS NOT NULL \
                    ORDER BY time DESC \
                    LIMIT 1")
    record = cursor.fetchone()
    status['used'] = record['used']

    cursor.execute("SELECT generated \
                    FROM energy \
                    WHERE generated IS NOT NULL \
                    ORDER BY time DESC \
                    LIMIT 1")
    record = cursor.fetchone()
    status['generated'] = record['generated']

    return status

def export_json():
    """Store the past 12 hours of power use and generation data in a file."""
    cursor.execute("SELECT datetime(time, 'unixepoch', 'localtime') AS time, \
                    used, generated, label, change, temp_int \
                    FROM energy \
                    WHERE time >= (strftime('%s','now') - (60 * 60 * 12)) \
                    ORDER BY time DESC")
    records = cursor.fetchmany(10000)

    # Drop 90% of data points -- we have too many to chart reasonably. We
    # iterate through in reverse because going in order while deleting records
    # makes a mess.
    num_records = len(records)
    i=0
    for j in range(num_records):
        reverse_i = num_records - 1 - j
        if records[reverse_i]['generated'] > 0:
            continue
        if i%9 != 0:
            records.pop(reverse_i)
        i+=1

    output = {}
    output['history'] = records
    
    output['today'] = daily_cumulative()
    try:
        solar_data['energy_today']
    except NameError:
        pass