Package: pyecobee
Pyecobee: A Python implementation of theecobee APIIntroductionPyecobee 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 anissueor even better
create apull requestif you encounter an issue with any of
them.control_plug: I don’t own an ecobee smart plug, so couldn’t test this functionreset_preferences: I didn’t want to wipe my thermostat’s settingsset_occupied: Can only be used by an EMS thermostatunlink_voice_engine: Requires a thermostat with voice controlupdate_sensor: Requires an ecobee3 or ecobee4 thermostatAll Hierarchy requests: Accessible to EMS and Utility accounts onlylist_setslist_usersadd_setremove_setrename_setmove_setadd_userremove_userunregister_userupdate_userregister_thermostatunregister_thermostatmove_thermostatassign_thermostatAll Utility requests: Accessible to Utility accounts onlylist_demand_responseissue_demand_responsecancel_demand_responseissue_demand_managementAll Runtime Report Job requests: Accessible to Utility accounts onlycreate_runtime_report_joblist_runtime_report_job_statuscancel_runtime_report_jobWarning:ecobee’s documentation for the following object definitions is unavailable and as such any request returning
any of these objects will throw an ExceptionECPDemandResponse (https://www.ecobee.com/home/developer/api/documentation/v1/objects/ECPDemandResponse.shtml)Energy (https://www.ecobee.com/home/developer/api/documentation/v1/objects/Energy.shtml)TimeOfUse (https://www.ecobee.com/home/developer/api/documentation/v1/objects/TimeOfUse.shtml)Disclaimer:Any ecobee API Keys, Authorization/Access/Refresh Tokens used in the following examples are fake.JSON Vs ObjectsWhereas 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 requestauthorize_response=ecobee_service.authorize()pin=authorize_response.ecobee_pincode=authorize_response.codescope=authorize_response.scopeexpires_in=authorize_response.expires_ininterval=authorize_response.intervalInstallationTo install Pyecobee:$pipinstallpyecobeeEnjoy.DocumentationPyecobee comes with extensive documentation. Use dir and help to explore all the details.
.. code-block:: python>>> from pyecobee import *
>>> dir(EcobeeService)
>>> help(EcobeeService)General usageTheEcobeeServiceclass provides the ecobee API implementation.EcobeeService Class DiagramTo use Pyecobee follow these stepsImport the modulesInstantiate an EcobeeService objectComplete the authorization sequence if required (authorize + request_tokens)Refresh tokens if required (refresh_tokens)Invoke the needed ecobee API requests/functionsAll 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 modulesfrompyecobeeimport*Instantiate an EcobeeService objectecobee_service=EcobeeService(thermostat_name='My Thermostat',application_key='jiNXJ2Q6dyeAPXxy4HsFGUp1nK94C9VF')Authorization & Token RequestsAuthorizeauthorize_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 instanceEcobeeAuthorizeResponse Class DiagramRequest Tokenstoken_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 instanceEcobeeTokenResponse Class DiagramRefresh Tokenstoken_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 instanceEcobeeTokenResponse Class DiagramThermostat RequestsRequest Thermostat Summarythermostat_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 instanceEcobeeThermostatsSummaryResponse Class DiagramRequest 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())assertthermostat_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 instanceEcobeeThermostatResponse Class DiagramUpdate Thermostatupdate_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())assertupdate_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 instanceEcobeeStatusResponse Class DiagramReport RequestsMeter Reporteastern=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())assertmeter_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 instanceEcobeeMeterReportsResponse Class DiagramRuntime Reporteastern=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())assertruntime_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 instanceEcobeeRuntimeReportsResponse Class DiagramGroup RequestsRequest Groupsgroup_response=ecobee_service.request_groups(selection=Selection(selection_type=SelectionType.REGISTERED.value))logger.info(group_response.pretty_format())assertgroup_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 instanceEcobeeGroupsResponse Class DiagramUpdate Groups# Create Groupsgroup_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())assertgroup_response.status.code==0,'Failure while executing update_groups:\n{0}'.format(group_response.pretty_format())# Update a Groupgroup_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())assertgroup_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())assertgroup_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 instanceEcobeeGroupsResponse Class DiagramHierarchy Set RequestsList Hierarchy Setslist_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())assertlist_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 instanceEcobeeListHierarchySetsResponse Class DiagramAdd Hierarchy Setadd_hierarchy_set_response=ecobee_service.add_hierarchy_set(set_name='NewSet',parent_path='/')logger.info(add_hierarchy_set_response.pretty_format())assertadd_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 instanceEcobeeStatusResponse Class DiagramRemove Hierarchy Setremove_hierarchy_set_response=ecobee_service.remove_hierarchy_set(set_path='/NewSet')logger.info(remove_hierarchy_set_response.pretty_format())assertremove_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 instanceEcobeeStatusResponse Class DiagramRename Hierarchy Setrename_hierarchy_set_response=ecobee_service.rename_hierarchy_set(set_path='/NewSet',new_name='ToRename')logger.info(rename_hierarchy_set_response.pretty_format())assertrename_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 instanceEcobeeStatusResponse Class DiagramMove Hierarchy Setmove_hierarchy_set_response=ecobee_service.move_hierarchy_set(set_path='/ToMove',to_path='MainNode')logger.info(move_hierarchy_set_response.pretty_format())assertmove_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 instanceEcobeeStatusResponse Class DiagramHierarchy User RequestsList Hierarchy Userslist_hierarchy_users_response=ecobee_service.list_hierarchy_users(set_path='/',recursive=True,include_privileges=True)logger.info(list_hierarchy_users_response.pretty_format())assertlist_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 instanceEcobeeListHierarchyUsersResponse Class DiagramAdd Hierarchy Usersadd_hierarchy_users_response=ecobee_service.add_hierarchy_users(users=[HierarchyUser(user_name='new@user1.com',first_name='User',last_name='1'),HierarchyUser(user_name='new@user2.com',first_name='User',last_name='2')],privileges=[HierarchyPrivilege(set_path='/MainNode',user_name='new@user1.com',allow_view=True),HierarchyPrivilege(set_path='/OtherNode',user_name='new@user1.com',allow_view=True)])logger.info(add_hierarchy_users_response.pretty_format())assertadd_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 instanceEcobeeStatusResponse Class DiagramRemove Hierarchy Usersremove_hierarchy_users_response=ecobee_service.remove_hierarchy_users(set_path='/',users=[HierarchyUser(user_name='todelete@hierarchy.com'),HierarchyUser(user_name='todelete2@hierarchy.com')])logger.info(remove_hierarchy_users_response.pretty_format())assertremove_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 instanceEcobeeStatusResponse Class DiagramUnregister Hierarchy Usersunregister_hierarchy_users_response=ecobee_service.unregister_hierarchy_users(users=[HierarchyUser(user_name='todelete@hierarchy.com'),HierarchyUser(user_name='todelete2@hierarchy.com')])logger.info(unregister_hierarchy_users_response.pretty_format())assertunregister_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 instanceEcobeeStatusResponse Class DiagramUpdate Hierarchy Usersupdate_hierarchy_users_response=update_hierarchy_users_response=ecobee_service.update_hierarchy_users(users=[HierarchyUser(user_name='user1@update.com',first_name='Updated',last_name='User',phone='222-333-4444',email_alerts=False)],privileges=[HierarchyPrivilege(set_path='/MainNode',user_name='user1@update.com',allow_view=True),HierarchyPrivilege(set_path='/MainNode',user_name='user2@update.com',allow_view=True),HierarchyPrivilege(set_path='/OtherNode',user_name='user2@update.com',allow_view=True)])logger.info(update_hierarchy_users_response.pretty_format())assertupdate_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 instanceEcobeeStatusResponse Class DiagramHierarchy Thermostat RequestsRegister Thermostatregister_hierarchy_thermostats_response=ecobee_service.register_hierarchy_thermostats(set_path='/OtherNode',thermostats=('123456789012,''123456789013'))logger.info(register_hierarchy_thermostats_response.pretty_format())assertregister_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 instanceEcobeeStatusResponse Class DiagramUnregister Thermostatunregister_hierarchy_thermostats_response=ecobee_service.unregister_hierarchy_thermostats(thermostats='123456789012,123456789013')logger.info(unregister_hierarchy_thermostats_response.pretty_format())assertunregister_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 instanceEcobeeStatusResponse Class DiagramMove Thermostatmove_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())assertmove_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 instanceEcobeeStatusResponse Class DiagramAssign Thermostatassign_hierarchy_thermostats_response=ecobee_service.assign_hierarchy_thermostats(set_path='/MainNode',thermostats=('123456789012,''123456789013'))logger.info(assign_hierarchy_thermostats_response.pretty_format())assertassign_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 instanceEcobeeStatusResponse Class DiagramUtility RequestsList Demand Responseslist_demand_responses_response=ecobee_service.list_demand_responses()logger.info(list_demand_responses_response.pretty_format())assertlist_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 instanceEcobeeListDemandResponsesResponse Class DiagramIssue Demand Responseissue_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())assertissue_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 instanceEcobeeIssueDemandResponsesResponse Class DiagramCancel Demand Responsecancel_demand_response_response=ecobee_service.cancel_demand_response(demand_response_ref='c253a12e0b3c3c93800095')logger.info(cancel_demand_response_response.pretty_format())assertcancel_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 instanceEcobeeStatusResponse Class DiagramIssue Demand Managementissue_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())assertissue_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 RequestsCreate Runtime Report Jobcreate_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())assertcreate_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 instanceEcobeeCreateRuntimeReportJobResponse Class DiagramList Runtime Report Job Statuslist_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())assertlist_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 instanceEcobeeListRuntimeReportJobStatusResponse Class DiagramCancel Runtime Report Jobcancel_runtime_report_response=ecobee_service.cancel_runtime_report_job(job_id='123')logger.info(cancel_runtime_report_response.pretty_format())assertcancel_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 instanceEcobeeStatusResponse Class DiagramThermostat FunctionsA successful invocation of any function returns an EcobeeStatusResponse instanceEcobeeStatusResponse Class DiagramSend Messageupdate_thermostat_response=ecobee_service.send_message('Hello World')logger.info(update_thermostat_response.pretty_format())assertthermostat_response.status.code==0,'Failure while executing request_thermostats:\n{0}'.format(thermostat_response.pretty_format())Acknowledgeselection=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=[alertforalertinthermostat.alertsifalert.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())assertupdate_thermostat_response.status.code==0,'Failure while executing acknowledge:\n{0}'.format(update_thermostat_response.pretty_format())Set Hold# Simplest formupdate_thermostat_response=ecobee_service.set_hold(hold_climate_ref='away',hold_type=HoldType.NEXT_TRANSITION)logger.info(update_thermostat_response.pretty_format())assertupdate_thermostat_response.status.code==0,'Failure while executing set_hold:\n{0}'.format(update_thermostat_response.pretty_format())# Using specific start/end date and timeeastern=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())assertupdate_thermostat_response.status.code==0,'Failure while executing set_hold:\n{0}'.format(update_thermostat_response.pretty_format())# Using durationeastern=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())assertupdate_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 indefinitelyupdate_thermostat_response=ecobee_service.set_hold(cool_hold_temp=65,hold_type=HoldType.INDEFINITE)logger.info(update_thermostat_response.pretty_format())assertupdate_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 indefinitelyupdate_thermostat_response=ecobee_service.set_hold(heat_hold_temp=72,hold_type=HoldType.INDEFINITE)logger.info(update_thermostat_response.pretty_format())assertupdate_thermostat_response.status.code==0,'Failure while executing set_hold:\n{0}'.format(update_thermostat_response.pretty_format())Resume Programupdate_thermostat_response=ecobee_service.resume_program(resume_all=False)logger.info(update_thermostat_response.pretty_format())assertupdate_thermostat_response.status.code==0,'Failure while executing resume_program:\n{0}'.format(update_thermostat_response.pretty_format())Create Vacationeastern=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())assertupdate_thermostat_response.status.code==0,'Failure while executing create_vacation:\n{0}'.format(update_thermostat_response.pretty_format())Delete Vacationupdate_thermostat_response=ecobee_service.delete_vacation(name='Christmas Vacation!')logger.info(update_thermostat_response.pretty_format())assertupdate_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())assertupdate_thermostat_response.status.code==0,'Failure while executing reset_preferences:\n{0}'.format(update_thermostat_response.pretty_format())PersistenceThe 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 followsimportshelvefromdatetimeimportdatetimeimportpytzfromsix.movesimportinputfrompyecobeeimport*logger=logging.getLogger(__name__)defpersist_to_shelf(file_name,ecobee_service):pyecobee_db=shelve.open(file_name,protocol=2)pyecobee_db[ecobee_service.thermostat_name]=ecobee_servicepyecobee_db.close()defrefresh_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)defrequest_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)defauthorize(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]exceptKeyError: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()ifecobee_service.authorization_tokenisNone:authorize(ecobee_service)ifecobee_service.access_tokenisNone:request_tokens(ecobee_service)now_utc=datetime.now(pytz.utc)ifnow_utc>ecobee_service.refresh_token_expires_on:authorize(ecobee_service)request_tokens(ecobee_service)elifnow_utc>ecobee_service.access_token_expires_on:token_response=refresh_tokens(ecobee_service)# Now make your requests :)Tokens RefreshAll 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-activeGet the current date/time in UTCCompare the current date/time to the date/time on which the access and refresh token are due to expireRe-authorize app if the current date/time is later than the refresh token expiry date/timeRefresh tokens if the current date/time is later than the access token expiry date/timenow_utc=datetime.now(pytz.utc)ifnow_utc>ecobee_service.refresh_token_expires_on:authorize(ecobee_service)request_tokens(ecobee_service)elifnow_utc>ecobee_service.access_token_expires_on:token_response=refresh_tokens(ecobee_service)ReactiveThe 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 tokentry:thermostat_summary_response=ecobee_service.request_thermostats_summary(selection=Selection(selection_type=SelectionType.REGISTERED.value,selection_match='',include_equipment_status=True))exceptEcobeeApiExceptionase:ife.status_code==14:token_response=ecobee_service.refresh_tokens()Date & Time HandlingSome 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 passedmust be a timezone awareobject.importpytzfromdatetimeimportdatetimefrompytzimporttimezoneeastern=timezone('US/Eastern')start_date_time=eastern.localize(datetime(2017,5,1,10,0,0),is_dst=True)# 2017/05/01 10:00:00 -0400The 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 HandlingYour code should be prepared to handle the following ExceptionsEcobeeApiException: Raised if a request results in an ecobee API error responseEcobeeAuthorizationException: Raised if a request results in a standard or extended OAuth error responseEcobeeRequestsException: Raised if a request results in an exception being raised by the underlying requests moduleEcobeeHttpException: Raised if a request results in any other HTTP errorEcobee Exceptions Class DiagramRelease History1.3.11 (2021-05-27)Add actual_voc actual_co2, actual_aq_accuracy, and actual_aq_score to Runtime objectFix bug in case of missing/unrecognized attribute1.3.10 (2020-08-08)Reformat code using Black instead of Autopep81.3.9 (2020-08-04)Migrate from PyCharm to VSCodeCode refactoring and cleanup using Autopep8 and PylintAdd undocumented ecobee objects (Energy & TimeOfUse)1.3.8 (2020-08-01)Add fan_speed to Event object1.3.7 (2020-07-31)Handle KeyError exception in case of new property added by ecobee1.3.6 (2020-07-31)Add fan_speed to Settings object1.3.5 (2020-04-03)Code refactoring and cleanup1.3.0 (2020-04-02)Uplift the implementation to include all update to the ecobee API since mid 20171.2.1 (2017-06-01)Internal __slots__ improvements1.2.0 (2017-05-31)Internal refactoring of EcobeeObject and EcobeeResponse1.1.1 (2017-05-31)Miscellaneous minor internal changes to facilitate the automatic generation of PlantUML Class Diagrams1.1.0 (2017-05-24)Added ecobee API operations that are only accessible by EMS and Utility accounts1.0.0 (2017-05-12)First public release supporting all ecobee API operations except those that are only accessible by EMS and Utility accounts