Skip to content
This repository has been archived by the owner on Dec 12, 2021. It is now read-only.

Commit

Permalink
Initial upload of Hydrogen. Still in development.
Browse files Browse the repository at this point in the history
  • Loading branch information
billykwooten committed Jul 15, 2017
1 parent d9c216e commit 79555a2
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,5 @@ ENV/

# mypy
.mypy_cache/

.idea
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Hydrogen

#### Description
Hydrogen is a python app that will control your ecobee thermostats to get around the CobbEMC peak hours. Thus saving you money!
Empty file added __init__.py
Empty file.
Empty file added ecobee/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions ecobee/data/ecobee_authentication.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"apikey": ""
}
Empty file added ecobee/data/ecobee_secret.json
Empty file.
Empty file added ecobee/data/ecobee_tokens.json
Empty file.
116 changes: 116 additions & 0 deletions ecobee/ecobee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import json
import requests
import logging

logging.basicConfig(filename='log/hydrogen.log', level=logging.DEBUG)

with open('ecobee/data/ecobee_secret.json') as data_file:
data = json.load(data_file)
apikey = data['apikey']

with open('ecobee/data/ecobee_authentication.json') as data_file:
data = json.load(data_file)
authcode = data['code']


# Only used to initialize the ecobee application on the developer console (myapp) console on ecobee.com
def get_ecobee_pin():
url = "https://api.ecobee.com/authorize"
params = {'response_type': 'ecobeePin', 'client_id': apikey, 'scope': 'smartWrite'}
request = requests.get(url, params=params)
with open('ecobee/data/ecobee_authentication.json', 'w') as outfile:
json.dump(request.json(), outfile)


# Get initial tokens
def get_tokens():
url = 'https://api.ecobee.com/token'
params = {'grant_type': 'ecobeePin', 'code': authcode, 'client_id': apikey}
request = requests.post(url, params=params)
if request.status_code == requests.codes.ok:
with open('ecobee/data/ecobee_tokens.json', 'w') as outfile:
json.dump(request.json(), outfile)
else:
print('Error while requesting tokens from ecobee.com.' + ' Status code: ' + str(request.status_code))


# Refresh bad tokens
def refresh_tokens(refresh_token):
url = 'https://api.ecobee.com/token'
params = {'grant_type': 'refresh_token',
'refresh_token': refresh_token,
'client_id': apikey}
request = requests.post(url, params=params)
if request.status_code == requests.codes.ok:
with open('ecobee/data/ecobee_tokens.json', 'w') as outfile:
json.dump(request.json(), outfile)
else:
sys.exit(4)


# Get all data for all thermostats
def get_thermostats():
with open('ecobee/data/ecobee_tokens.json') as data_file:
data = json.load(data_file)
accesstoken = data['access_token']
refresh_token = data['refresh_token']

url = 'https://api.ecobee.com/1/thermostat'
header = {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer ' + accesstoken}
params = {'json': ('{"selection":{"selectionType":"registered",'
'"includeRuntime":"true",'
'"includeSensors":"true",'
'"includeProgram":"true",'
'"includeEquipmentStatus":"true",'
'"includeEvents":"true",'
'"includeSettings":"true"}}')}
request = requests.get(url, headers=header, params=params)
if request.status_code == requests.codes.ok:
authenticated = True
thermostats = request.json()['thermostatList']
return thermostats
else:
authenticated = False
if refresh_tokens(refresh_token):
return get_thermostats()
else:
return None


# Set your HVAC Mode
def set_hvac_mode(index, hvac_mode):
""" possible hvac modes are auto, auxHeatOnly, cool, heat, off
indexes for thermostats are 0 (downstairs) and 1 (upstairs) """
with open('ecobee/data/ecobee_tokens.json') as data_file:
data = json.load(data_file)
accesstoken = data['access_token']
thermostats = get_thermostats()
url = 'https://api.ecobee.com/1/thermostat'
header = {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer ' + accesstoken}
params = {'format': 'json'}
body = ('{"selection":{"selectionType":"thermostats","selectionMatch":'
'"' + thermostats[index]['identifier'] +
'"},"thermostat":{"settings":{"hvacMode":"' + hvac_mode +
'"}}}')
request = requests.post(url, headers=header, params=params, data=body)
if request.status_code == requests.codes.ok:
logging.info("Setting Ecobee to " + hvac_mode + " hvac mode on Ecobee index " + str(index))
return request
else:
logger.warn("Error connecting to Ecobee while attempting to set HVAC mode. Refreshing tokens...")
refresh_tokens()


def get_weather(index):
with open('ecobee/data/ecobee_tokens.json') as data_file:
data = json.load(data_file)
accesstoken = data['access_token']
thermostats = get_thermostats()
url = 'https://api.ecobee.com/1/thermostat'
header = {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer ' + accesstoken}
params = {'format': 'json'}
body = ('{"selection":{"selectionType":"thermostats","selectionMatch":'
'"' + thermostats[index]['identifier'] +
'"},"thermostat":{"weatherforecast":{"temperature":"}}}')
request = requests.post(url, headers=header, params=params, data=body)
print request.json()
Empty file added hydrogen/__init__.py
Empty file.
Empty file added hydrogen/data/__init__.py
Empty file.
Empty file.
73 changes: 73 additions & 0 deletions hydrogen/hydrogen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from __future__ import print_function
import httplib2
import os
import logging
import datetime

from apiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage

try:
import argparse
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
flags = None

logging.basicConfig(filename='log/hydrogen.log', level=logging.DEBUG)

SCOPES = 'https://www.googleapis.com/auth/gmail.readonly'
CLIENT_SECRET_FILE = 'hydrogen/data/client_secret.json'
APPLICATION_NAME = 'Hydrogen'


def get_credentials():
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir, 'gmail-python-quickstart.json')

store = Storage(credential_path)
credentials = store.get()
if not credentials or credentials.invalid:
flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
flow.user_agent = APPLICATION_NAME
if flags:
credentials = tools.run_flow(flow, store, flags)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
logging.info('Storing credentials to ' + credential_path)
return credentials


def check_gmail():
valid=''
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('gmail', 'v1', http=http)
today = str(datetime.date.today())
yesterday = str(datetime.date.fromordinal(datetime.date.today().toordinal() - 1))
todayhours = int(datetime.datetime.now().strftime("%H")) #Hour of the day in 24 hour format

if todayhours not in range(14, 19): #Check if it is peak hours for CobbEMC
return 2

#Check Gmail messages with label 41(CobbEMC Peak Hours)
messages = service.users().messages().list(userId='me', labelIds='Label_41').execute().get('messages', [])
for message in messages:
tdata = service.users().messages().get(userId='me', id=message['id']).execute()
epochtime = str(tdata['internalDate'])
emaildate = str(datetime.datetime.fromtimestamp(float(epochtime.replace(' ', '')[:-3].upper())).strftime("%Y-%m-%d"))
if emaildate == yesterday:
valid = 1
break

if valid == 1:
logging.info("Ecobee's need to be turned off to avoid peak hours that CobbEMC has set for " + today + " from 2 P.M. EST to 7 P.M. EST")
return 1
else:
return 0


38 changes: 38 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import sys
import logging
import requests
import datetime


from ecobee import ecobee
from hydrogen import hydrogen

logging.basicConfig(filename='log/hydrogen.log', level=logging.DEBUG)
now = datetime.datetime.now()
logging.info("Hydrogen ran at " + str(now))

# Set your ecobee index list
thermostatlist = [0, 1]


def main():
""" Result of 1 means that the ecobees need to be turned off to avoid peak hours """
result = hydrogen.check_gmail()
if result == 1:
logging.info("Gmail check has come back with peak hours, setting ecobees to off hvac mode")
for i in thermostatlist:
requesthvacset = ecobee.set_hvac_mode(i, 'off')
if requesthvacset.status_code == requests.codes.ok:
logging.info("Successfully set thermostat index " + str(i) + " to off hvac mode")
elif result == 2:
logging.info("It's not peak hours right now, setting ecobees to cool")
for i in thermostatlist:
requesthvacset = ecobee.set_hvac_mode(i, 'cool')
if requesthvacset.status_code == requests.codes.ok:
logging.info("Successfully set thermostat index " + str(i) + " to cool hvac mode")
elif result == 0:
logging.info("No Peak Hours have been set by CobbEMC, we're good!")
sys.exit(0)

if __name__ == '__main__':
main()

0 comments on commit 79555a2

Please sign in to comment.