GithubHelp home page GithubHelp logo

pyecobee's Introduction

Pyecobee: A Python implementation of the ecobee API

Introduction

Pyecobee is a simple, elegant, and object oriented implementation of the ecobee API in Python. It is compatible with Python 2.6/2.7/3.3+

Warning: Pyecobee has been tested with an ecobee Smart Si. Though the following methods have not been tested I believe they should work find. Please create an issue or even better create a pull request if you encounter an issue with any of them.

  • control_plug: I don't own an ecobee smart plug, so couldn't test this function
  • reset_preferences: I didn't want to wipe my thermostat's settings
  • set_occupied: Can only be used by an EMS thermostat
  • unlink_voice_engine: Requires a thermostat with voice control
  • update_sensor: Requires an ecobee3 or ecobee4 thermostat
  • All Hierarchy requests: Accessible to EMS and Utility accounts only
    • list_sets
    • list_users
    • add_set
    • remove_set
    • rename_set
    • move_set
    • add_user
    • remove_user
    • unregister_user
    • update_user
    • register_thermostat
    • unregister_thermostat
    • move_thermostat
    • assign_thermostat
  • All Utility requests: Accessible to Utility accounts only
    • list_demand_response
    • issue_demand_response
    • cancel_demand_response
    • issue_demand_management
  • All Runtime Report Job requests: Accessible to Utility accounts only
    • create_runtime_report_job
    • list_runtime_report_job_status
    • cancel_runtime_report_job

Warning: ecobee's documentation for the following object definitions is unavailable and as such any request returning any of these objects will throw an Exception

Disclaimer: Any ecobee API Keys, Authorization/Access/Refresh Tokens used in the following examples are fake.

JSON Vs Objects

Whereas JSON notation is used for the serialization/deserialization of request/response objects sent to and from the ecobee API, Pyecobee's interface is based on core Python data types and user defined objects instead. Pyecobee handles the serialization of Python objects into JSON request objects and deserialization of JSON response objects into Python objects thus completely alleviating the developer's need to create/parse JSON objects.

Pyecobee response from an authorize request

authorize_response = ecobee_service.authorize()
pin = authorize_response.ecobee_pin
code = authorize_response.code
scope = authorize_response.scope
expires_in = authorize_response.expires_in
interval = authorize_response.interval

Installation

To install Pyecobee:

$ pip install pyecobee

Enjoy.

Documentation

Pyecobee comes with extensive documentation. Use dir and help to explore all the details. .. code-block:: python

>>> from pyecobee import *
>>> dir(EcobeeService)
>>> help(EcobeeService)

General usage

The EcobeeService class provides the ecobee API implementation.

EcobeeService Class Diagram

To use Pyecobee follow these steps

  • Import the modules
  • Instantiate an EcobeeService object
  • Complete the authorization sequence if required (authorize + request_tokens)
  • Refresh tokens if required (refresh_tokens)
  • Invoke the needed ecobee API requests/functions

All Pyecobee user defined objects overload __repr__, __str__, and implement a pretty_format method.

>>> repr(authorize_response)
AuthorizeResponse(ecobee_pin='bv29', code='uiNQok9Uhy5iScG4gncCAilcFUMK0zWT', scope='smartWrite', expires_in=9, interval=30)

>>> str(authorize_response)
AuthorizeResponse(ecobeePin=bv29, code=uiNQok9Uhy5iScG4gncCAilcFUMK0zWT, scope=smartWrite, expires_in=9, interval=30)

>>> authorize_response.pretty_format()
AuthorizeResponse(
  ecobeePin=bv29,
  code=uiNQok9Uhy5iScG4gncCAilcFUMK0zWT,
  scope=smartWrite,
  expires_in=9,
  interval=30
)

Import the modules

from pyecobee import *

Instantiate an EcobeeService object

ecobee_service = EcobeeService(thermostat_name='My Thermostat',
                               application_key='jiNXJ2Q6dyeAPXxy4HsFGUp1nK94C9VF')

Authorization & Token Requests

Authorize

authorize_response = ecobee_service.authorize()
logger.info(authorize_response.pretty_format())
logger.info('Authorization Token => {0}'.format(ecobee_service.authorization_token))

A successful invocation of authorize() returns an EcobeeAuthorizeResponse instance

EcobeeAuthorizeResponse Class Diagram

Request Tokens

token_response = ecobee_service.request_tokens()
logger.info(token_response.pretty_format())
logger.info(
        'Access Token => {0}\n'
        'Access Token Expires On => {1}\n'
        'Refresh Token => {2}\n'
        'Refresh Token Expires On => {3}'.format(ecobee_service.access_token,
                                                 ecobee_service.access_token_expires_on,
                                                 ecobee_service.refresh_token,
                                                 ecobee_service.refresh_token_expires_on))

A successful invocation of request_tokens() returns an EcobeeTokenResponse instance

EcobeeTokenResponse Class Diagram

Refresh Tokens

token_response = ecobee_service.refresh_tokens()
logger.info(token_response.pretty_format())
logger.info(
        'Access Token => {0}\n'
        'Access Token Expires On => {1}\n'
        'Refresh Token => {2}\n'
        'Refresh Token Expires On => {3}'.format(ecobee_service.access_token,
                                                 ecobee_service.access_token_expires_on,
                                                 ecobee_service.refresh_token,
                                                 ecobee_service.refresh_token_expires_on))

A successful invocation of refresh_tokens() returns an EcobeeTokenResponse instance

EcobeeTokenResponse Class Diagram

Thermostat Requests

Request Thermostat Summary

thermostat_summary_response = ecobee_service.request_thermostats_summary(selection=Selection(
        selection_type=SelectionType.REGISTERED.value,
        selection_match='',
        include_equipment_status=True))
logger.info(thermostat_summary_response.pretty_format())

A successful invocation of request_thermostats_summary() returns an EcobeeThermostatsSummaryResponse instance

EcobeeThermostatsSummaryResponse Class Diagram

Request Thermostats

# Only set the include options you need to True. I've set most of them to True for illustrative purposes only.
selection = Selection(selection_type=SelectionType.REGISTERED.value, selection_match='', include_alerts=True,
                      include_device=True, include_electricity=True, include_equipment_status=True,
                      include_events=True, include_extended_runtime=True, include_house_details=True,
                      include_location=True, include_management=True, include_notification_settings=True,
                      include_oem_cfg=False, include_privacy=False, include_program=True, include_reminders=True,
                      include_runtime=True, include_security_settings=False, include_sensors=True,
                      include_settings=True, include_technician=True, include_utility=True, include_version=True,
                      include_weather=True)
thermostat_response = ecobee_service.request_thermostats(selection)
logger.info(thermostat_response.pretty_format())
assert thermostat_response.status.code == 0, 'Failure while executing request_thermostats:\n{0}'.format(
    thermostat_response.pretty_format())

A successful invocation of request_thermostats() returns an EcobeeThermostatResponse instance

EcobeeThermostatResponse Class Diagram

Update Thermostat

update_thermostat_response = ecobee_service.update_thermostats(
        selection=Selection(
            selection_type=SelectionType.REGISTERED.value,
            selection_match=''),
        thermostat=Thermostat(
            settings=Settings(
                hvac_mode='off')),
        functions=[
            Function(
                type='deleteVacation',
                params={'name': 'My vacation'})])
logger.info(update_thermostat_response.pretty_format())
assert update_thermostat_response.status.code == 0, 'Failure while executing update_thermostats:\n{0}'.format(
    update_thermostat_response.pretty_format())

A successful invocation of update_thermostats() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Report Requests

Meter Report

eastern = timezone('US/Eastern')
meter_reports_response = ecobee_service.request_meter_reports(
        selection=Selection(
            selection_type=SelectionType.THERMOSTATS.value,
            selection_match='123456789012'),
        start_date_time=eastern.localize(datetime(2013, 4, 4, 0, 0, 0), is_dst=True),
        end_date_time=eastern.localize(datetime(2013, 4, 4, 23, 59, 0), is_dst=True))
logger.info(meter_report_response.pretty_format())
assert meter_report_response.status.code == 0, 'Failure while executing request_meter_reports:\n{0}'.format(
    meter_report_response.pretty_format())

A successful invocation of request_meter_reports() returns an EcobeeMeterReportsResponse instance

EcobeeMeterReportsResponse Class Diagram

Runtime Report

eastern = timezone('US/Eastern')
runtime_report_response = ecobee_service.request_runtime_reports(
        selection=Selection(
            selection_type=SelectionType.THERMOSTATS.value,
            selection_match='123456789012'),
        start_date_time=eastern.localize(datetime(2010, 1, 1, 0, 0, 0), is_dst=False),
        end_date_time=eastern.localize(datetime(2010, 1, 2, 0, 0, 0), is_dst=False),
        columns='auxHeat1,auxHeat2,auxHeat3,compCool1,compCool2,compHeat1,compHeat2,dehumidifier,dmOffset,'
                'economizer,fan,humidifier,hvacMode,outdoorHumidity,outdoorTemp,sky,ventilator,wind,zoneAveTemp,'
                'zoneCalendarEvent,zoneClimate,zoneCoolTemp,zoneHeatTemp,zoneHumidity,zoneHumidityHigh,'
                'zoneHumidityLow,zoneHvacMode,zoneOccupancy')
logger.info(runtime_report_response.pretty_format())
assert runtime_report_response.status.code == 0, 'Failure while executing request_runtime_reports:\n{0}'.format(
    runtime_report_response.pretty_format())

A successful invocation of request_runtime_reports() returns an EcobeeRuntimeReportsResponse instance

EcobeeRuntimeReportsResponse Class Diagram

Group Requests

Request Groups

group_response = ecobee_service.request_groups(
        selection=Selection(
            selection_type=SelectionType.REGISTERED.value))
logger.info(group_response.pretty_format())
assert group_response.status.code == 0, 'Failure while executing request_groups:\n{0}'.format(
    group_response.pretty_format())

A successful invocation of request_groups() returns an EcobeeGroupsResponse instance

EcobeeGroupsResponse Class Diagram

Update Groups

# Create Groups
group_response = ecobee_service.update_groups(
        selection=Selection(
            selection_type=SelectionType.REGISTERED.value),
        groups=[
            Group(
                group_ref='3d03a26fd80001',
                group_name='ground_floor',
                synchronize_alerts=True,
                synchronize_vacation=True,
                thermostats=[
                    '123456789101']),
            Group(
                group_ref='3bb5a91b180001',
                group_name='first_floor',
                synchronize_reset=True,
                synchronize_vacation=True,
                thermostats=[
                    '123456789102'])])
logger.info(group_response.pretty_format())
assert group_response.status.code == 0, 'Failure while executing update_groups:\n{0}'.format(
    group_response.pretty_format())

# Update a Group
group_response = ecobee_service.update_groups(
        selection=Selection(
            selection_type=SelectionType.REGISTERED.value),
        groups=[
            Group(
                group_ref='3d03a26fd80001',
                synchronize_system_mode=True)])
logger.info(group_response.pretty_format())
assert group_response.status.code == 0, 'Failure while executing update_groups:\n{0}'.format(
    group_response.pretty_format())

# Delete a group (Set the thermostats parameter of the group to an empty list)
group_response = ecobee_service.update_groups(
        selection=Selection(
            selection_type=SelectionType.REGISTERED.value),
        groups=[
            Group(
                group_ref='3d03a26fd80001',
                thermostats=[])])
logger.info(group_response.pretty_format())
assert group_response.status.code == 0, 'Failure while executing update_groups:\n{0}'.format(
    group_response.pretty_format())

A successful invocation of request_groups() returns an EcobeeGroupsResponse instance

EcobeeGroupsResponse Class Diagram

Hierarchy Set Requests

List Hierarchy Sets

list_hierarchy_sets_response = ecobee_service.list_hierarchy_sets(set_path='/',
                                                                  recursive=True,
                                                                  include_privileges=True,
                                                                  include_thermostats=True)
logger.info(list_hierarchy_sets_response.pretty_format())
assert list_hierarchy_sets_response.status.code == 0, 'Failure while executing list_hierarchy_sets:\n{0}'.format(
    list_hierarchy_sets_response.pretty_format())

A successful invocation of list_hierarchy_sets() returns an EcobeeListHierarchySetsResponse instance

EcobeeListHierarchySetsResponse Class Diagram

Add Hierarchy Set

add_hierarchy_set_response = ecobee_service.add_hierarchy_set(set_name='NewSet',
                                                              parent_path='/')
logger.info(add_hierarchy_set_response.pretty_format())
assert add_hierarchy_set_response.status.code == 0, 'Failure while executing add_hierarchy_set:\n{0}'.format(
    add_hierarchy_set_response.pretty_format())

A successful invocation of add_hierarchy_set() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Remove Hierarchy Set

remove_hierarchy_set_response = ecobee_service.remove_hierarchy_set(set_path='/NewSet')
logger.info(remove_hierarchy_set_response.pretty_format())
assert remove_hierarchy_set_response.status.code == 0, 'Failure while executing remove_hierarchy_set:\n{0}'.format(
    remove_hierarchy_set_response.pretty_format())

A successful invocation of remove_hierarchy_set() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Rename Hierarchy Set

rename_hierarchy_set_response = ecobee_service.rename_hierarchy_set(set_path='/NewSet',
                                                                    new_name='ToRename')
logger.info(rename_hierarchy_set_response.pretty_format())
assert rename_hierarchy_set_response.status.code == 0, 'Failure while executing rename_hierarchy_set:\n{0}'.format(
    rename_hierarchy_set_response.pretty_format())

A successful invocation of rename_hierarchy_set() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Move Hierarchy Set

move_hierarchy_set_response = ecobee_service.move_hierarchy_set(set_path='/ToMove',
                                                                to_path='MainNode')
logger.info(move_hierarchy_set_response.pretty_format())
assert move_hierarchy_set_response.status.code == 0, 'Failure while executing move_hierarchy_set:\n{0}'.format(
    move_hierarchy_set_response.pretty_format())

A successful invocation of move_hierarchy_set() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Hierarchy User Requests

List Hierarchy Users

list_hierarchy_users_response = ecobee_service.list_hierarchy_users(set_path='/',
                                                                    recursive=True,
                                                                    include_privileges=True)
logger.info(list_hierarchy_users_response.pretty_format())
assert list_hierarchy_users_response.status.code == 0, 'Failure while executing list_hierarchy_users:\n{0}'.format(
    list_hierarchy_users_response.pretty_format())

A successful invocation of list_hierarchy_users() returns an EcobeeListHierarchyUsersResponse instance

EcobeeListHierarchyUsersResponse Class Diagram

Add Hierarchy Users

add_hierarchy_users_response = ecobee_service.add_hierarchy_users(
    users=[
        HierarchyUser(
            user_name='[email protected]',
            first_name='User',
            last_name='1'),
        HierarchyUser(
            user_name='[email protected]',
            first_name='User',
            last_name='2')],
    privileges=[
        HierarchyPrivilege(
            set_path='/MainNode',
            user_name='[email protected]',
            allow_view=True),
        HierarchyPrivilege(
            set_path='/OtherNode',
            user_name='[email protected]',
            allow_view=True)])
    logger.info(add_hierarchy_users_response.pretty_format())
    assert add_hierarchy_users_response.status.code == 0, (
        'Failure while executing add_hierarchy_users:\n{0}'.format(
         add_hierarchy_users_response.pretty_format()))

A successful invocation of add_hierarchy_users() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Remove Hierarchy Users

remove_hierarchy_users_response = ecobee_service.remove_hierarchy_users(
    set_path='/',
    users=[
        HierarchyUser(
            user_name='[email protected]'),
        HierarchyUser(
            user_name='[email protected]')])
logger.info(remove_hierarchy_users_response.pretty_format())
assert remove_hierarchy_users_response.status.code == 0, (
    'Failure while executing remove_hierarchy_users:\n{0}'.format(
        remove_hierarchy_users_response.pretty_format()))

A successful invocation of remove_hierarchy_users() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Unregister Hierarchy Users

unregister_hierarchy_users_response = ecobee_service.unregister_hierarchy_users(
    users=[
        HierarchyUser(
            user_name='[email protected]'),
        HierarchyUser(
            user_name='[email protected]')])
logger.info(unregister_hierarchy_users_response.pretty_format())
assert unregister_hierarchy_users_response.status.code == 0, (
    'Failure while executing unregister_hierarchy_users_response:\n{0}'.format(
        unregister_hierarchy_users_response.pretty_format()))

A successful invocation of unregister_hierarchy_users() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Update Hierarchy Users

update_hierarchy_users_response = update_hierarchy_users_response = ecobee_service.update_hierarchy_users(
    users=[
        HierarchyUser(
            user_name='[email protected]',
            first_name='Updated',
            last_name='User',
            phone='222-333-4444',
            email_alerts=False)],
    privileges=[
        HierarchyPrivilege(
            set_path='/MainNode',
            user_name='[email protected]',
            allow_view=True),
        HierarchyPrivilege(
            set_path='/MainNode',
            user_name='[email protected]',
            allow_view=True),
        HierarchyPrivilege(
            set_path='/OtherNode',
            user_name='[email protected]',
            allow_view=True)])
logger.info(update_hierarchy_users_response.pretty_format())
assert update_hierarchy_users_response.status.code == 0, (
    'Failure while executing update_hierarchy_users_response:\n{0}'.format(
        update_hierarchy_users_response.pretty_format()))

A successful invocation of update_hierarchy_users() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Hierarchy Thermostat Requests

Register Thermostat

register_hierarchy_thermostats_response = ecobee_service.register_hierarchy_thermostats(set_path='/OtherNode',
                                                                                        thermostats=(
                                                                                            '123456789012,'
                                                                                            '123456789013'))
logger.info(register_hierarchy_thermostats_response.pretty_format())
assert register_hierarchy_thermostats_response.status.code == 0, (
    'Failure while executing register_hierarchy_thermostats_response:\n{0}'.format(
        register_hierarchy_thermostats_response.pretty_format()))

A successful invocation of register_hierarchy_thermostats() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Unregister Thermostat

unregister_hierarchy_thermostats_response = ecobee_service.unregister_hierarchy_thermostats(
    thermostats='123456789012,123456789013')
logger.info(unregister_hierarchy_thermostats_response.pretty_format())
assert unregister_hierarchy_thermostats_response.status.code == 0, (
    'Failure while executing unregister_hierarchy_thermostats_response:\n{0}'.format(
        unregister_hierarchy_thermostats_response.pretty_format()))

A successful invocation of unregister_hierarchy_thermostats() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Move Thermostat

move_hierarchy_thermostats_response = ecobee_service.move_hierarchy_thermostats(set_path='/MainNode',
                                                                                to_path='/OtherNode',
                                                                                thermostats=('123456789012,'
                                                                                             '123456789013'))
logger.info(move_hierarchy_thermostats_response.pretty_format())
assert move_hierarchy_thermostats_response.status.code == 0, (
    'Failure while executing move_hierarchy_thermostats_response:\n{0}'.format(
        move_hierarchy_thermostats_response.pretty_format()))

A successful invocation of move_hierarchy_thermostats() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Assign Thermostat

assign_hierarchy_thermostats_response = ecobee_service.assign_hierarchy_thermostats(set_path='/MainNode',
                                                                                    thermostats=('123456789012,'
                                                                                                 '123456789013'))
logger.info(assign_hierarchy_thermostats_response.pretty_format())
assert assign_hierarchy_thermostats_response.status.code == 0, (
    'Failure while executing assign_hierarchy_thermostats_response:\n{0}'.format(
        assign_hierarchy_thermostats_response.pretty_format()))

A successful invocation of assign_hierarchy_thermostats() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Utility Requests

List Demand Responses

list_demand_responses_response = ecobee_service.list_demand_responses()
logger.info(list_demand_responses_response.pretty_format())
assert list_demand_responses_response.status.code == 0, (
    'Failure while executing list_demand_responses_response:\n{0}'.format(
        list_demand_responses_response.pretty_format()))

A successful invocation of list_demand_responses() returns an EcobeeListDemandResponsesResponse instance

EcobeeListDemandResponsesResponse Class Diagram

Issue Demand Response

issue_demand_response_response = ecobee_service.issue_demand_response(
    selection=Selection(
        selection_type=SelectionType.MANAGEMENT_SET.value,
        selection_match='/'),
    demand_response=DemandResponse(
        name='myDR',
        message='This is a DR!',
        event=Event(
            heat_hold_temp=790,
            end_time='11:37:18',
            end_date='2011-01-10',
            name='apiDR',
            type='useEndTime',
            cool_hold_temp=790,
            start_date='2011-01-09',
            start_time='11:37:18',
            is_temperature_absolute=True)))
logger.info(issue_demand_response_response.pretty_format())
assert issue_demand_response_response.status.code == 0, (
    'Failure while executing issue_demand_response_response:\n{0}'.format(
        issue_demand_response_response.pretty_format()))

A successful invocation of issue_demand_response() returns an EcobeeIssueDemandResponsesResponse instance

EcobeeIssueDemandResponsesResponse Class Diagram

Cancel Demand Response

cancel_demand_response_response = ecobee_service.cancel_demand_response(
    demand_response_ref='c253a12e0b3c3c93800095')
logger.info(cancel_demand_response_response.pretty_format())
assert cancel_demand_response_response.status.code == 0, (
    'Failure while executing cancel_demand_response_response:\n{0}'.format(
        cancel_demand_response_response.pretty_format()))

A successful invocation of cancel_demand_response() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Issue Demand Management

issue_demand_management_response = ecobee_service.issue_demand_managements(
    selection=Selection(
        selection_type=SelectionType.MANAGEMENT_SET.value,
        selection_match='/'),
    demand_managements=[
        DemandManagement(
            date='2012-01-01',
            hour=5,
            temp_offsets=[20, 20, 20, 0, 0, 0, 0, -20, -20, -20, 0, 0]),
        DemandManagement(
            date='2012-01-01',
            hour=6,
            temp_offsets=[0, 0, 20, 20, 0, 0, 0, 0, 0, -20, -20, -20])])
logger.info(issue_demand_management_response.pretty_format())
assert issue_demand_management_response.status.code == 0, (
    'Failure while executing issue_demand_management_response:\n{0}'.format(
        issue_demand_management_response.pretty_format()))

Runtime Report Job Requests

Create Runtime Report Job

create_runtime_report_job_response = ecobee_service.create_runtime_report_job(
    selection=Selection(
        selection_type=SelectionType.THERMOSTATS.value,
        selection_match='123456789012'),
    start_date=date(2016, 7, 1),
    end_date=date(2016, 10, 1),
    columns='zoneCalendarEvent,zoneHvacMode,zoneHeatTemp,zoneCoolTemp,zoneAveTemp,dmOffset')
logger.info(create_runtime_report_job_response.pretty_format())
assert create_runtime_report_job_response.status.code == 0, (
    'Failure while executing create_runtime_report_job_response:\n{0}'.format(
        create_runtime_report_job_response.pretty_format()))

A successful invocation of create_runtime_report_job() returns an EcobeeCreateRuntimeReportJobResponse instance

EcobeeCreateRuntimeReportJobResponse Class Diagram

List Runtime Report Job Status

list_runtime_report_job_status_response = ecobee_service.list_runtime_report_job_status(job_id='123')
logger.info(list_runtime_report_job_status_response.pretty_format())
assert list_runtime_report_job_status_response.status.code == 0, (
    'Failure while executing list_runtime_report_job_status_response:\n{0}'.format(
        list_runtime_report_job_status_response.pretty_format()))

A successful invocation of list_runtime_report_job_status() returns an EcobeeListRuntimeReportJobStatusResponse instance

EcobeeListRuntimeReportJobStatusResponse Class Diagram

Cancel Runtime Report Job

cancel_runtime_report_response = ecobee_service.cancel_runtime_report_job(job_id='123')
logger.info(cancel_runtime_report_response.pretty_format())
assert cancel_runtime_report_response.status.code == 0, (
    'Failure while executing cancel_runtime_report_response:\n{0}'.format(
        cancel_runtime_report_response.pretty_format()))

A successful invocation of cancel_runtime_report_job() returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Thermostat Functions

A successful invocation of any function returns an EcobeeStatusResponse instance

EcobeeStatusResponse Class Diagram

Send Message

update_thermostat_response = ecobee_service.send_message('Hello World')
logger.info(update_thermostat_response.pretty_format())
assert thermostat_response.status.code == 0, 'Failure while executing request_thermostats:\n{0}'.format(
    thermostat_response.pretty_format())

Acknowledge

selection = Selection(selection_type=SelectionType.REGISTERED.value, selection_match='', include_alerts=True)
thermostat_response = ecobee_service.request_thermostats(selection)
thermostat = thermostat_response.thermostat_list[0]
alerts = [alert for alert in thermostat.alerts if alert.text == message]

update_thermostat_response = ecobee_service.acknowledge(thermostat_identifier=thermostat.identifier,
                                                        ack_ref=alerts[0].acknowledge_ref,
                                                        ack_type=AckType.ACCEPT)
logger.info(update_thermostat_response.pretty_format())
assert update_thermostat_response.status.code == 0, 'Failure while executing acknowledge:\n{0}'.format(
    update_thermostat_response.pretty_format())

Set Hold

# Simplest form
update_thermostat_response = ecobee_service.set_hold(hold_climate_ref='away', hold_type=HoldType.NEXT_TRANSITION)
logger.info(update_thermostat_response.pretty_format())
assert update_thermostat_response.status.code == 0, 'Failure while executing set_hold:\n{0}'.format(
    update_thermostat_response.pretty_format())

# Using specific start/end date and time
eastern = timezone('US/Eastern')
update_thermostat_response = ecobee_service.set_hold(hold_climate_ref='away',
                                                     start_date_time=eastern.localize(datetime(
                                                         2017, 5, 10, 13, 0, 0),
                                                         is_dst=True),
                                                     end_date_time=eastern.localize(datetime(
                                                         2017, 5, 10, 14, 0, 0),
                                                         is_dst=True),
                                                     hold_type=HoldType.DATE_TIME)
logger.info(update_thermostat_response.pretty_format())
assert update_thermostat_response.status.code == 0, 'Failure while executing set_hold:\n{0}'.format(
    update_thermostat_response.pretty_format())

# Using duration
eastern = timezone('US/Eastern')
update_thermostat_response = ecobee_service.set_hold(hold_climate_ref='away',
                                                     start_date_time=eastern.localize(datetime(
                                                         2017, 5, 10, 13, 0, 0),
                                                         is_dst=True),
                                                     hold_type=HoldType.HOLD_HOURS,
                                                     hold_hours=1)
logger.info(update_thermostat_response.pretty_format())
assert update_thermostat_response.status.code == 0, 'Failure while executing set_hold:\n{0}'.format(
    update_thermostat_response.pretty_format())

# Specifically the cooling temperature to use and hold indefinitely
update_thermostat_response = ecobee_service.set_hold(cool_hold_temp=65,  hold_type=HoldType.INDEFINITE)
logger.info(update_thermostat_response.pretty_format())
assert update_thermostat_response.status.code == 0, 'Failure while executing set_hold:\n{0}'.format(
    update_thermostat_response.pretty_format())

# Specifically the heating temperature to use and hold indefinitely
update_thermostat_response = ecobee_service.set_hold(heat_hold_temp=72,  hold_type=HoldType.INDEFINITE)
logger.info(update_thermostat_response.pretty_format())
assert update_thermostat_response.status.code == 0, 'Failure while executing set_hold:\n{0}'.format(
    update_thermostat_response.pretty_format())

Resume Program

update_thermostat_response = ecobee_service.resume_program(resume_all=False)
logger.info(update_thermostat_response.pretty_format())
assert update_thermostat_response.status.code == 0, 'Failure while executing resume_program:\n{0}'.format(
    update_thermostat_response.pretty_format())

Create Vacation

eastern = timezone('US/Eastern')
update_thermostat_response = ecobee_service.create_vacation(name='Christmas Vacation!',
                                                            cool_hold_temp=104,
                                                            heat_hold_temp=59,
                                                            start_date_time=eastern.localize(datetime(
                                                                2017, 12, 23, 10, 0, 0),
                                                                is_dst=True),
                                                            end_date_time=eastern.localize(datetime(
                                                                2017, 12, 28, 17, 0, 0),
                                                                is_dst=True),
                                                            fan_mode=FanMode.AUTO,
                                                            fan_min_on_time=0)
logger.info(update_thermostat_response.pretty_format())
assert update_thermostat_response.status.code == 0, 'Failure while executing create_vacation:\n{0}'.format(
    update_thermostat_response.pretty_format())

Delete Vacation

update_thermostat_response = ecobee_service.delete_vacation(name='Christmas Vacation!')
logger.info(update_thermostat_response.pretty_format())
assert update_thermostat_response.status.code == 0, 'Failure while executing delete_vacation:\n{0}'.format(
    update_thermostat_response.pretty_format())

Reset Preferences

# Danger zone!!!
update_thermostat_response = ecobee_service.reset_preferences()
logger.info(update_thermostat_response.pretty_format())
assert update_thermostat_response.status.code == 0, 'Failure while executing reset_preferences:\n{0}'.format(
    update_thermostat_response.pretty_format())

Persistence

The ecobee API specifies that all tokens issued must be stored by the application. These tokens represent the credentials of the user and must be kept secure. A simple way is to use the Python shelve module as follows

import shelve
from datetime import datetime

import pytz
from six.moves import input

from pyecobee import *

logger = logging.getLogger(__name__)


def persist_to_shelf(file_name, ecobee_service):
    pyecobee_db = shelve.open(file_name, protocol=2)
    pyecobee_db[ecobee_service.thermostat_name] = ecobee_service
    pyecobee_db.close()


def refresh_tokens(ecobee_service):
    token_response = ecobee_service.refresh_tokens()
    logger.debug('TokenResponse returned from ecobee_service.refresh_tokens():\n{0}'.format(
        token_response.pretty_format()))

    persist_to_shelf('pyecobee_db', ecobee_service)


def request_tokens(ecobee_service):
    token_response = ecobee_service.request_tokens()
    logger.debug('TokenResponse returned from ecobee_service.request_tokens():\n{0}'.format(
        token_response.pretty_format()))

    persist_to_shelf('pyecobee_db', ecobee_service)


def authorize(ecobee_service):
    authorize_response = ecobee_service.authorize()
    logger.debug('AutorizeResponse returned from ecobee_service.authorize():\n{0}'.format(
        authorize_response.pretty_format()))

    persist_to_shelf('pyecobee_db', ecobee_service)

    logger.info('Please goto ecobee.com, login to the web portal and click on the settings tab. Ensure the My '
                'Apps widget is enabled. If it is not click on the My Apps option in the menu on the left. In the '
                'My Apps widget paste "{0}" and in the textbox labelled "Enter your 4 digit pin to '
                'install your third party app" and then click "Install App". The next screen will display any '
                'permissions the app requires and will ask you to click "Authorize" to add the application.\n\n'
                'After completing this step please hit "Enter" to continue.'.format(
        authorize_response.ecobee_pin))
    input()


if __name__ == '__main__':
    formatter = logging.Formatter('%(asctime)s %(name)-18s %(levelname)-8s %(message)s')

    stream_handler = logging.StreamHandler()
    stream_handler.setFormatter(formatter)

    logger.addHandler(stream_handler)
    logger.setLevel(logging.DEBUG)

    thermostat_name = 'My Thermostat'
    try:
        pyecobee_db = shelve.open('pyecobee_db', protocol=2)
        ecobee_service = pyecobee_db[thermostat_name]
    except KeyError:
        application_key = input('Please enter the API key of your ecobee App: ')
        ecobee_service = EcobeeService(thermostat_name=thermostat_name, application_key=application_key)
    finally:
        pyecobee_db.close()

    if ecobee_service.authorization_token is None:
        authorize(ecobee_service)

    if ecobee_service.access_token is None:
        request_tokens(ecobee_service)

    now_utc = datetime.now(pytz.utc)
    if now_utc > ecobee_service.refresh_token_expires_on:
        authorize(ecobee_service)
        request_tokens(ecobee_service)
    elif now_utc > ecobee_service.access_token_expires_on:
        token_response = refresh_tokens(ecobee_service)

    # Now make your requests :)

Tokens Refresh

All access tokens must be refreshed periodically. Access tokens expire 3600 seconds (1 hour) from the time they were refreshed. There are two patterns to refresh the access token.

Pro-active

  • Get the current date/time in UTC
  • Compare the current date/time to the date/time on which the access and refresh token are due to expire
  • Re-authorize app if the current date/time is later than the refresh token expiry date/time
  • Refresh tokens if the current date/time is later than the access token expiry date/time
now_utc = datetime.now(pytz.utc)
if now_utc > ecobee_service.refresh_token_expires_on:
    authorize(ecobee_service)
    request_tokens(ecobee_service)
elif now_utc > ecobee_service.access_token_expires_on:
    token_response = refresh_tokens(ecobee_service)

Reactive

The ecobee API returns status code 14 to indicate that a request was attempted using an expired access token. All non-successful ecobee API responses are wrapped into the EcobeeApiException. The following code snippet demonstrates how to refresh an expired access token

try:
    thermostat_summary_response = ecobee_service.request_thermostats_summary(selection=Selection(
    selection_type=SelectionType.REGISTERED.value,
    selection_match='',
    include_equipment_status=True))
except EcobeeApiException as e:
    if e.status_code == 14:
        token_response = ecobee_service.refresh_tokens()

Date & Time Handling

Some of the ecobee API requests expect the date and time to be in thermostat time, while others expect the date and time to be in UTC time.

Any EcobeeService method that accepts a datetime object as an argument expects the argument to be passed in thermostat time. The datetime object passed must be a timezone aware object.

import pytz
from datetime import datetime

from pytz import timezone

eastern = timezone('US/Eastern')
start_date_time=eastern.localize(datetime(2017, 5, 1, 10, 0, 0), is_dst=True) # 2017/05/01 10:00:00 -0400

The method will then either use the passed in datetime object as is, or convert it to its UTC time equivalent depending on the requirements of the ecobee API request being executed.

Exception Handling

Your code should be prepared to handle the following Exceptions

  • EcobeeApiException: Raised if a request results in an ecobee API error response
  • EcobeeAuthorizationException: Raised if a request results in a standard or extended OAuth error response
  • EcobeeRequestsException: Raised if a request results in an exception being raised by the underlying requests module
  • EcobeeHttpException: Raised if a request results in any other HTTP error

Ecobee Exceptions Class Diagram

pyecobee's People

Contributors

hudcap avatar sherif-fanous avatar sherif-virtasant avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

pyecobee's Issues

Increasingly frequent MaxRetryErrors from urllib3

I don't think that this is resulting from a bug or bugs in pyecobee or any of the imported software libraries, but I am seeing increasingly frequent (2-10X/day) crashes from my thermostat monitoring and control program reporting the above error. I had increased the timeout parameters on most of the service calls from the default (5) to 30 seconds. I have now increased it further to 60. Has anyone else seen this and/or does anyone have any other thoughts?

[Edit] Increasing the timeout does not seem to have changed/fixed the issue.[/Edit]

Fan control

Maybe I missed it, but is there a way to control the fan?

Connection error handling

Thanks a lot for the python interface. You saved me a lot of time for a small project that I am trying to do with my home automation.

I am able to successfully use this package but only thing I cannot figure out is how to prevent script from crashing when there is not internet connection.

When there is no internet connection, it throws an error. Instead, it should report to user that it is not able to reach ecobee server and they should try again later.

KeyError, when serving include_runtime=True in request_thermostats call

selection = Selection(selection_type=SelectionType.REGISTERED.value, selection_match='', include_runtime=True)
thermostat_response = ecobee_service.request_thermostats(selection)

File "/Users/jwu/PycharmProjects/ecobee/ecobee.py", line 133, in thermostats_summary
thermostat_response = self.ecobee_service.request_thermostats(selection)
File "/Users/jwu/ecobee/lib/python3.5/site-packages/pyecobee/service.py", line 367, in request_thermostats
return EcobeeService.__process_http_response(response, EcobeeThermostatResponse)
File "/Users/jwu/ecobee/lib/python3.5/site-packages/pyecobee/service.py", line 130, in __process_http_response
is_top_level=True)
File "/Users/jwu/ecobee/lib/python3.5/site-packages/pyecobee/utilities.py", line 89, in dictionary_to_object
dictionary_to_object(data[key], property_type, response_properties, parent_classes, indent + 4)
File "/Users/jwu/ecobee/lib/python3.5/site-packages/pyecobee/utilities.py", line 138, in dictionary_to_object
indent + 8)
File "/Users/jwu/ecobee/lib/python3.5/site-packages/pyecobee/utilities.py", line 89, in dictionary_to_object
dictionary_to_object(data[key], property_type, response_properties, parent_classes, indent + 4)
File "/Users/jwu/ecobee/lib/python3.5/site-packages/pyecobee/utilities.py", line 159, in dictionary_to_object
generated_code = '{0}={1!r}'.format(parent_classes[-1].attribute_name_map[key], data[key])
KeyError: 'showIconMode'

set_occupied

Hi, thanks a lot for this awesome package.

What I'm trying to build is

  • get occupancy data from the thermostat and its remote sensors every 5 minutes
  • If occupancy becomes true, then use either set_hold or set_occupied to change setpoints (let's say heating setpoint during heating hvacMode)
  • if occupancy becomes false, then get rid of the event from the thermostat.
  • Before turning off the app, save occupancy, setpoints data as a csv file.

This seems doable with your package, and I succeeded to do a simple request (the thermostat_summary_response) once. But the issue is my programming skill. I do programming but I am more of a level that I gotta google many things to build something.
I don't even know whether writing this here is appropriate haha.

Is there any tips or guides that you can give me? It would be very helpful.

Thanks a lot.

Best,
Wooyoung

Readme Typo in Persistence Section

In your persistence example you execute
token_response = ecobee_service.refresh_tokens()

This calls the wrong refresh_tokens() resulting in the refreshed token not being written to shelve and thus an eventual 400 error once your access token expires.

It should be:
token_response = refresh_tokens(ecobee_service)

Logger

When working with your example code I get some issues that "logger is not defined". I'm not sure If I'm missing something.

tokens keep expiring, generates fine.

I can generate a token and it works for an hour, but shortly after expires. I call the refresh, still no dice. Simply trying to toggle the status of my thermostat with this script. I have noticed that pyecobee_db is not taking any changes, even after calling the refresh. The only way to fix is wipe away the db and provide the 4 digit code to ecobee...trying to integrate this into my own automation. Thanks!

thermostat_name = 'Home'
try:
    pyecobee_db = shelve.open('/var/www/scripts/notify/ecobee/pyecobee_db', protocol=2)
    ecobee_service = pyecobee_db[thermostat_name]
except KeyError:
    application_key = input('Please enter the API key of your ecobee App: ')
    ecobee_service = EcobeeService(thermostat_name=thermostat_name, application_key=application_key)
finally:
    pyecobee_db.close()

if not ecobee_service.authorization_token:
    authorize(ecobee_service)

if not ecobee_service.access_token:
    request_tokens(ecobee_service)

now_utc = datetime.now(pytz.utc)
if now_utc > ecobee_service.refresh_token_expires_on:
    authorize(ecobee_service)
    request_tokens(ecobee_service)
elif now_utc > ecobee_service.access_token_expires_on:
    token_response = ecobee_service.refresh_tokens()

try:
    thermostat_summary_response = ecobee_service.request_thermostats_summary(selection=Selection(
    selection_type=SelectionType.REGISTERED.value,
    selection_match='',
    include_equipment_status=True))
except EcobeeApiException as e:
    if e.status_code == 14:
        token_response = ecobee_service.refresh_tokens()

selection = Selection(selection_type=SelectionType.REGISTERED.value, selection_match='',include_equipment_status=True)

thermostat_response = ecobee_service.request_thermostats(selection)    
print thermostat_response

returns the following once expired

Traceback (most recent call last):
  File "status2.py", line 69, in <module>
    token_response = ecobee_service.refresh_tokens()
  File "/usr/local/lib/python2.7/dist-packages/pyecobee/service.py", line 218, in refresh_tokens
    tokens_response = Utilities.process_http_response(response, EcobeeTokensResponse)
  File "/usr/local/lib/python2.7/dist-packages/pyecobee/utilities.py", line 349, in process_http_response
    error_response.error_uri)
pyecobee.exceptions.EcobeeAuthorizationException: ecobee authorization error encountered for URL => https://api.ecobee.com/token?code=&client_id=&grant_type=refresh_token
HTTP error code => 400
Error type => invalid_grant
Error description => The authorization grant, token or credentials are invalid, expired, revoked, do not match the redirection URI used in the authorization request, or was issued to another client.
Error URI => https://tools.ietf.org/html/rfc6749#section-5.2

Missing Attribute displayAirQuality

When using the API, I'm getting the following error message.

Missing attribute in class Settings
Attribute name  => displayAirQuality
Attribute value => True
Please open a new issue here (https://github.com/sfanous/Pyecobee/issues/new)

Read timeout when refreshing token

Every so often, I get a read timeout exception while refreshing the token:

HTTPSConnectionPool(host='api.ecobee.com', port=443): Read timed out. (read timeout=5)

If I attempt to refresh again, I get an invalid_grant error, which means I have to start auth all over again:

ecobee authorization error encountered for URL => https://api.ecobee.com/token?client_id=REDACTEDSDFSF&code=REDACTEDDFGDFG&grant_type=refresh_token
HTTP error code => 400
Error type => invalid_grant
Error description => The authorization grant, token or credentials are invalid, expired, revoked, do not match the redirection URI used in the authorization request, or was issued to another client.
Error URI => https://tools.ietf.org/html/rfc6749#section-5.2

Are there any workarounds here?

Undefined object - Thermostat --> Reminders

If the Selection parameter 'include reminders = True' is specified for the call to request_thermostats, and reminders are returned in the response contents, a key error occurs. This is apparently because of an undefined object for Reminders, which include the following attributes: type, title, description, reminderDate, and remindMe. (All are six.text_type except the last, which is bool.)

The Ecobee website documentation mentions an object ThermostatReminder2[] as an attribute of the Thermostat object, but I have not found a definition for this object. The Pyecobee library includes references for this object, including in the attribute_type_map in thermostat.py. However, it appears the object name should be Reminder (as this is the key returned in the response) and a new definition created for it (reminder.py).

Readme Typo in Tokens Refresh Section

Found another one. Looks like you're using the same code as the persistence section for a non-persistence example.

if now_utc > ecobee_service.refresh_token_expires_on:
    authorize(ecobee_service)
    request_tokens(ecobee_service)
elif now_utc > ecobee_service.access_token_expires_on:
    token_response = ecobee_service.refresh_tokens()

I believe it should be:

if now_utc > ecobee_service.refresh_token_expires_on:
    ecobee_service.authorize()
    ecobee_service.request_tokens()
elif now_utc > ecobee_service.access_token_expires_on:
    token_response = ecobee_service.refresh_tokens()

Class diagrams in README.md & pypi broken

As the subject says, the class diagrams intended to be shown as part of README.md (and thus on pypi) are broken, with the github CDN simply responding Error Fetching Resource. These would be useful, so it would begreat if they were able to be returned to their former glory. <3

invalid syntax following upgrade to 1.3.7

ERROR:pyecobee.utilities:Missing attribute in class Event
Attribute name => fanSpeed
Attribute value => low

Please open a new issue here (https://github.com/sfanous/Pyecobee/issues/new)
ERROR:pyecobee.utilities:Missing attribute in class Event
Attribute name => fanSpeed
Attribute value => optimized

Please open a new issue here (https://github.com/sfanous/Pyecobee/issues/new)
ERROR:pyecobee.utilities:Missing attribute in class Event
Attribute name => fanSpeed
Attribute value => low

Please open a new issue here (https://github.com/sfanous/Pyecobee/issues/new)
Traceback (most recent call last):
File "./ecobee.py", line 274, in
thermostat_response = ecobee_service.request_thermostats(selection)
File "/usr/local/lib/python3.5/dist-packages/pyecobee/service.py", line 292, in request_thermostats
return Utilities.process_http_response(response, EcobeeThermostatResponse)
File "/usr/local/lib/python3.5/dist-packages/pyecobee/utilities.py", line 325, in process_http_response
is_top_level=True)
File "/usr/local/lib/python3.5/dist-packages/pyecobee/utilities.py", line 243, in dictionary_to_object
return eval(''.join(response_properties[parent_classes[0]]))
File "", line 646
,
^
SyntaxError: invalid syntax

KeyError, when serving include_events=True in request_thermostats call

Was working fine yesterday, but today the KeyError comes up similar to issue #5 . Is there a better workaround for these KeyErrors?

Traceback (most recent call last):
  File "/home/user/myecobeelib.py", line 67, in _request_data
    thermostat_response = self.ecobee_service.request_thermostats(selection)
  File "/usr/local/lib/python3.7/dist-packages/pyecobee/service.py", line 292, in request_thermostats
    return Utilities.process_http_response(response, EcobeeThermostatResponse)
  File "/usr/local/lib/python3.7/dist-packages/pyecobee/utilities.py", line 317, in process_http_response
    is_top_level=True)
  File "/usr/local/lib/python3.7/dist-packages/pyecobee/utilities.py", line 118, in dictionary_to_object
    cls.dictionary_to_object(data[key], property_type, response_properties, parent_classes, indent + 4)
  File "/usr/local/lib/python3.7/dist-packages/pyecobee/utilities.py", line 176, in dictionary_to_object
    indent + 8)
  File "/usr/local/lib/python3.7/dist-packages/pyecobee/utilities.py", line 176, in dictionary_to_object
    indent + 8)
  File "/usr/local/lib/python3.7/dist-packages/pyecobee/utilities.py", line 203, in dictionary_to_object
    generated_code = '{0}={1!r}'.format(parent_classes[-1].attribute_name_map[key], data[key])
KeyError: 'fanSpeed'

ecobee api changes, effective dec 1 2020

just got this e-mail, figured i would share here since the client will obviously need some changes to work with the new token format...

Upcoming API Changes Effective December 1, 2020
The following changes will go into effect on December 1, 2020. If you are unsure whether these changes will have an impact on your solution today, we encourage you to discuss it with your technology team, program manager, other stakeholders and ecobee partners.
Access/Refresh Token Format Changes
Starting from December 1, 2020, ecobee access tokens will no longer be returned as opaque 32-character strings. Access tokens will now be JWTs, which are considerably longer and uses a wider character set. Our JWTs follow the RFC7575 standard for JSON Web Signature tokens.
To ensure your application will continue to work, you will need to ensure that your application supports the following changes: Access tokens will be up to 7KB in length, and includes upper/lower case alphanumeric characters, hyphens, underscores, and periods.

Refresh tokens can be of varying lengths and can contain non-alphanumeric characters.
Authorization Code Changes
The Redirect URI associated with your registered application should be a semi-colon separated list of absolute URLs that start with https://. We do not accept http:// protocol links.
PIN Authorization Changes
PINs will become 10 character alphanumeric strings.

This flow is only recommended in situations where a user is interacting with a device that cannot easily use a web-based login form; we recommend migrating to the Authorization Code strategy for a better user experience.

Working App suddenly started crashing with apparent error in pyecobee code

This afternoon, a service which uses pyecobee to monitor my Ecobee Thermostat and has been running without problems for months suddenly crashed. This does occasionally happen when the ecobee server or the network glitches, but when I attempted to restart the service it crashed immediately, Running it (with appropriate privileges) from the command line produced the following chain of exceptions:

Traceback (most recent call last):
File "ThermostatService.py", line 164, in
t_response = e_service.request_thermostats(selection, timeout=30)
File "/usr/local/lib/python3.7/dist-packages/pyecobee/service.py", line 292, in request_thermostats
return Utilities.process_http_response(response, EcobeeThermostatResponse)
File "/usr/local/lib/python3.7/dist-packages/pyecobee/utilities.py", line 325, in process_http_response
is_top_level=True)
File "/usr/local/lib/python3.7/dist-packages/pyecobee/utilities.py", line 243, in dictionary_to_object
return eval(''.join(response_properties[parent_classes[0]]))
File "", line 155
, ^

SyntaxError: invalid syntax

When the error occurs, pyecobee has already been successfully initialized. I have looked at the indicated pyecobee source file and cannot see an obvious problem, and I don't understand the apparent reference to 'File "string>"'. Any suggestions?

Credentials expire randomly after 1-4 weeks

Hi,

I am running calls frequently, at least 10 times per hour. They work consistently but after 1-4 weeks, the credentials expire and I have to reconfigure it with a new 4 digit app code on the ecobee website. Does anyone else experience this? The credentials have expired after 3 weeks and just 1 week, so it seems inconsistent.

Thanks

[30/Sep/2020 09:20:04] ERROR - EcobeeAuthorizationException raised:
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/pyecobee/utilities.py", line 349, in process_http_response
    error_response.error_uri)
EcobeeAuthorizationException: ecobee authorization error encountered for URL => https://api.ecobee.com/token?code=XXX&client_id=XXX&grant_type=refresh_token
HTTP error code => 400
Error type => invalid_grant
Error description => The authorization grant, token or credentials are invalid, expired, revoked, do not match the redirection URI used in the authorization request, or was issued to another client.
Error URI => https://tools.ietf.org/html/rfc6749#section-5.2

New crash in previously working code

I have been updating the program which monitors and controls my thermostat for summer conditions. In doing so, I exercised some code which was certainly working a couple of months ago, but which is not normally called when it is not significantly colder than it has been since March or April. I am having problems pasting the code, because neither 'Insert code' nor quoting it are retaining comprehensible formatting, so I have attached the function source as a file.
The exception report is as follows:

Traceback (most recent call last):
  File "ThermostatService0a.py", line 226, in <module>
    set_hold(set_temp_cool,set_temp_heat,'on') # Turn fan on 
  File "ThermostatService0a.py", line 101, in set_hold
    params={'heatHoldTemp':heat_set,'coolHoldTemp':cold_set,'fan':fan_setting,'holdType':'nextTransition'})])
TypeError: __init__() got an unexpected keyword argument 'type'

It appears that the Function initializer is not recognizing the documented 'type' argument. but this does not make sense. The parameters passed to my function are valid and reasonable, and the function used to work. What am I missing?
Code.txt

pyecobee for MicroPython on the Raspberry Pi PICO W

I would really like to see a subset of pyecobee that would work with MicroPython on the Raspberry Pi PICO W. I am trying to control various devices in the house and requires only the basic info from my Ecobee Thermostat like the running state of the furnace and the temperatures from the various sensors. Current, the size of the pyecobee library is so large that it will not even fit into the available file space on the PICO W without compilation first.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.