Skip to content

Commit

Permalink
#31 #42 #44 $45
Browse files Browse the repository at this point in the history
  • Loading branch information
jimboca committed Apr 21, 2019
1 parent c6cf45e commit c33a4bc
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 38 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ If you already have it installed and want the update before it's in the store.

## Release Notes

- 2.1.5: JimBo
- [Crash due to bad json returned from Ecobee](https://github.com/Einstein42/udi-ecobee-poly/issues/45)
- [Not properly recognizing expired token response?](https://github.com/Einstein42/udi-ecobee-poly/issues/44)
- [Track Vacation along with Smart Home/Away](https://github.com/Einstein42/udi-ecobee-poly/issues/31)
- Properly support Vacation, SmartAway, SmartHome and DemandResponse Events in 'Climate Type'
- [Support changing backlightOnIntensity](https://github.com/Einstein42/udi-ecobee-poly/issues/42)
- 2.1.4: JimBo
- [Crash due to bad json returned from Ecobee](https://github.com/Einstein42/udi-ecobee-poly/issues/45)
- 2.1.3: JimBo
Expand Down
21 changes: 10 additions & 11 deletions ecobee-poly.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,6 @@ def _getTokens(self, pinData):
res_data = res['data']
res_code = res['code']
if 'error' in res_data:
if res_data['error'] == 'authorization_expired':
LOGGER.error('_getTokens: Exiting because: {} -> {}'.format(res_data['error'], res_data['error_description']))
sys.exit(1)
LOGGER.error('_getTokens: {} :: {}'.format(res_data['error'], res_data['error_description']))
self.set_auth_st(False)
return False
Expand Down Expand Up @@ -213,7 +210,7 @@ def heartbeat(self):
self.reportCmd("DOF",2)
self.hb = 0

def updateThermostats(self):
def updateThermostats(self,force=False):
LOGGER.debug("{}:updateThermostats:".format(self.address))
thermostats = self.getThermostats()
if not isinstance(thermostats, dict):
Expand Down Expand Up @@ -387,8 +384,10 @@ def write_profile(self,climates):
for line in in_h:
line = re.sub(r'tstatid',r'{0}'.format(id),line)
line = re.sub(r'tstatcnta',r'{0}'.format(len(climateList)-1),line)
# This is minus 2 because we don't allow selecting vacation.
line = re.sub(r'tstatcnt',r'{0}'.format(len(climateList)-2),line)
# This is minus 3 because we don't allow selecting vacation or smartAway, ...
# But not currently using this because we don't have different list for
# status and programs?
line = re.sub(r'tstatcnt',r'{0}'.format(len(climateList)-5),line)
editor_h.write(line)
in_h.close()
# Then the NLS lines.
Expand Down Expand Up @@ -446,11 +445,11 @@ def getThermostats(self):
thermostats = {}
res_data = res['data']
res_code = res['code']
if res_data is False:
self.l_error('getThermostats','Ecobee returned code {} but no data? ({})'.format(res_code,res_data))
if 'revisionList' in res_data:
if res_data['revisionList'] is False:
self.l_error('getThermostats','revisionList is False.')
self.set_ecobee_st(False)
return False
self.l_error('getThermostats','Ecobee returned code {} but no revisionList? ({})'.format(res_code,res_data['revisionList']))
for thermostat in res_data['revisionList']:
revisionArray = thermostat.split(':')
thermostats['{}'.format(revisionArray[0])] = {
Expand Down Expand Up @@ -542,7 +541,7 @@ def ecobeePost(self, thermostatId, postData = {}):

def cmd_poll(self, *args, **kwargs):
LOGGER.debug("{}:cmd_poll".format(self.address))
self.updateThermostats()
self.updateThermostats(force=True)
self.query()

def cmd_query(self, *args, **kwargs):
Expand All @@ -568,7 +567,7 @@ def set_debug_mode(self,level=None):
except:
self.l_error('set_debug_mode','getDriver(GV2) failed',True)
if level is None:
level = 30
level = 10
level = int(level)
self.debug_mode = level
try:
Expand Down
5 changes: 4 additions & 1 deletion node_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ def ltom(list):
'smart5',
'smart6',
'smart7',
'vacation'
'vacation',
'smartAway',
'smartHome',
'demandResponse',
]
climateMap = ltom(climateList)

Expand Down
108 changes: 86 additions & 22 deletions node_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@
{ 'driver': 'GV6', 'value': 0, 'uom': '25' },
{ 'driver': 'GV7', 'value': 0, 'uom': '25' },
{ 'driver': 'GV8', 'value': 0, 'uom': '2' },
{ 'driver': 'GV9', 'value': 1, 'uom': '25' }
{ 'driver': 'GV9', 'value': 1, 'uom': '25' },
{ 'driver': 'GV10', 'value': 10, 'uom': '56' }
],
'EcobeeC': [
{ 'driver': 'ST', 'value': 0, 'uom': '4' },
Expand All @@ -97,7 +98,8 @@
{ 'driver': 'GV6', 'value': 0, 'uom': '25' },
{ 'driver': 'GV7', 'value': 0, 'uom': '25' },
{ 'driver': 'GV8', 'value': 0, 'uom': '2' },
{ 'driver': 'GV9', 'value': 1, 'uom': '25' }
{ 'driver': 'GV9', 'value': 1, 'uom': '25' },
{ 'driver': 'GV10', 'value': 10, 'uom': '56' }
],
'EcobeeSensorF': [
{ 'driver': 'ST', 'value': 0, 'uom': '17' },
Expand Down Expand Up @@ -283,7 +285,7 @@ def _update(self):
equipmentStatus = self.tstat['equipmentStatus'].split(',')
#LOGGER.debug("settings={}".format(json.dumps(self.settings, sort_keys=True, indent=2)))
self.runtime = self.tstat['runtime']
LOGGER.debug("{}:_update: runtime={}".format(self.address,json.dumps(self.runtime, sort_keys=True, indent=2)))
self.l_debug('_update:',' runtime={}'.format(json.dumps(self.runtime, sort_keys=True, indent=2)))
clihcs = 0
for status in equipmentStatus:
if status in equipmentStatusMap:
Expand All @@ -294,27 +296,51 @@ def _update(self):
# And the default mode, unless there is an event
self.clismd = 0
# Is there an active event?
LOGGER.debug("events={}".format(json.dumps(self.events, sort_keys=True, indent=2)))
# Why did this have and self.events[0]['running']
if len(self.events) > 0:
if self.events[0]['type'] == 'hold':
self.l_debug('_update','events={}'.format(json.dumps(self.events, sort_keys=True, indent=2)))
# Find the first running event
event_running = False
for event in self.events:
if event['running'] and event_running is False:
event_running = event
self.l_debug('_update','running event: {}'.format(json.dumps(event, sort_keys=True, indent=2)))
if event_running is not False:
if event_running['type'] == 'hold':
#LOGGER.debug("Checking: events={}".format(json.dumps(self.events, sort_keys=True, indent=2)))
LOGGER.debug("{}:_update: #events={} type={} holdClimateRef={}".
format(self.address,len(self.events),
self.events[0]['type'],
self.events[0]['holdClimateRef']))
self.l_debug('_update'," #events={} type={} holdClimateRef={}".
format(len(self.events),
event_running['type'],
event_running['holdClimateRef']))
# This seems to mean an indefinite hold
# "endDate": "2035-01-01", "endTime": "00:00:00",
if self.events[0]['endTime'] == '00:00:00':
if event_running['endTime'] == '00:00:00':
self.clismd = transitionMap['indefinite']
else:
self.clismd = transitionMap['nextTransition']
if self.events[0]['holdClimateRef'] != '':
climateType = self.events[0]['holdClimateRef']
elif self.events[0]['type'] == 'vacation':
climateType = 'vacation'
if event_running['holdClimateRef'] != '':
climateType = event_running['holdClimateRef']
elif event_running['type'] == 'vacation':
climateType = 'vacation'
elif event_running['type'] == 'autoAway':
# name will alwys smartAway or smartAway?
climateType = event_running['name']
if climateType != 'smartAway':
self.l_error('_update','autoAway event name is "{}" which is not supported, using smartAway. Please notify developer.'.format(climateType))
climateType = 'smartAway'
elif event_running['type'] == 'autoHome':
# name will alwys smartAway or smartHome?
climateType = event_running['name']
if climateType != 'smartHome':
self.l_error('_update','autoHome event name is "{}" which is not supported, using smartHome. Please notify developer.'.format(climateType))
climateType = 'smartHome'
elif event_running['type'] == 'demandResponse':
# What are thse names?
climateType = event_running['name']
self.l_error('_update','demandResponse event name is "{}" which is not supported, using demandResponse. Please notify developer.'.format(climateType))
climateType = 'demandResponse'
else:
self.l_error('_update','Unknown event type "{}" name "{}" for event: {}'.format(event_running['type'],event_running['name'],event))

LOGGER.debug("{}:_update: climateType={}".format(self.address,climateType))
self.l_debug('_update','climateType={}'.format(climateType))
#LOGGER.debug("program['climates']={}".format(self.program['climates']))
#LOGGER.debug("settings={}".format(json.dumps(self.settings, sort_keys=True, indent=2)))
#LOGGER.debug("program={}".format(json.dumps(self.program, sort_keys=True, indent=2)))
Expand All @@ -324,9 +350,10 @@ def _update(self):
clifrs = 1
else:
clifrs = 0
LOGGER.debug("{}:_update: clifrs={} (equipmentStatus={} or clihcs={}, fanControlRequired={}"
.format(self.address,clifrs,equipmentStatus,clihcs,self.settings['fanControlRequired'])
self.l_debug('_update','clifrs={} (equipmentStatus={} or clihcs={}, fanControlRequired={}'
.format(clifrs,equipmentStatus,clihcs,self.settings['fanControlRequired'])
)
self.l_debug('_update','backlightOnIntensity={}'.format(self.settings['backlightOnIntensity']))
updates = {
'ST': self.tempToDriver(self.runtime['actualTemperature'],True,False),
'CLISPH': self.tempToDriver(self.runtime['desiredHeat'],True),
Expand All @@ -343,10 +370,12 @@ def _update(self):
'GV5': self.runtime['desiredDehumidity'],
'GV6': 1 if self.settings['autoAway'] else 0,
'GV7': 1 if self.settings['followMeComfort'] else 0,
'GV8': 1 if self.runtime['connected'] else 0
'GV8': 1 if self.runtime['connected'] else 0,
'GV10': self.settings['backlightOnIntensity']
}
for key, value in updates.items():
self.setDriver(key, value)
self.l_debug('_update','setDriver({},{})'.format(key,value))
self.setDriver(key, value)

# Update my remote sensors.
for sensor in self.tstat['remoteSensors']:
Expand Down Expand Up @@ -473,6 +502,25 @@ def pushScheduleMode(self,clismd=None,coolTemp=None,heatTemp=None,fanMode=None):
self.setFanState(1)
else:
self.setFanState(0)

def pushBacklight(self,val):
self.l_debug('pushBacklight','{}'.format(val))
#
# Push settings test
#
params = {
"thermostat": {
"settings": {
"backlightOnIntensity":val
}
}
}
if self.ecobeePost(params):
self.setBacklight(val)

def setBacklight(self,val):
self.setDriver('GV10', val)

#
# Set Methods for drivers so they are set the same way
#
Expand Down Expand Up @@ -668,6 +716,9 @@ def cmdSetDoWeather(self, cmd):
self.do_weather = True if value == 1 else False
self.check_weather()

def cmdSetBacklight(self,cmd):
self.pushBacklight(cmd['value'])

# TODO: This should set the drivers and call pushHold...
def setPoint(self, cmd):
LOGGER.debug(cmd)
Expand Down Expand Up @@ -708,6 +759,18 @@ def setPoint(self, cmd):
self.setDriver(driver, newTemp)
self.setDriver('CLISMD',transitionMap[self.getHoldType()])

def l_info(self, name, string):
LOGGER.info("%s:%s:%s: %s" % (self.id,self.name,name,string))

def l_error(self, name, string):
LOGGER.error("%s:%s:%s: %s" % (self.id,self.name,name,string))

def l_warning(self, name, string):
LOGGER.warning("%s:%s:%s: %s" % (self.id,self.name,name,string))

def l_debug(self, name, string):
LOGGER.debug("%s:%s:%s:%s: %s" % (self.id,self.address,self.name,name,string))

hint = '0x010c0100'
commands = { 'QUERY': query,
'CLISPH': cmdSetPF,
Expand All @@ -721,7 +784,8 @@ def setPoint(self, cmd):
'GV7': cmdFollowMe,
'BRT': setPoint,
'DIM': setPoint,
'GV9': cmdSetDoWeather
'GV9': cmdSetDoWeather,
'GV10': cmdSetBacklight,
}

class Sensor(polyinterface.Node):
Expand Down
2 changes: 2 additions & 0 deletions pgSession.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ def response(self,response,name):
elif response.status_code == 401:
# Authentication error
self.l_error(fname,"Unauthorized: %s: text: %s" % (response.url,response.text) )
elif response.status_code == 500:
self.l_error(fname,"Server Error: %s: text: %s" % (response.url,response.text) )
else:
self.l_error(fname,"Unknown response %s: %s %s" % (response.status_code, response.url, response.text) )
self.l_error(fname,"Check system status: https://status.ecobee.com/")
Expand Down
3 changes: 3 additions & 0 deletions profile/editor/editors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
<editor id="I_DEBUG">
<range uom="25" subset="8,9,10,20,30,40,50" nls="CDM"/>
</editor>
<editor id="I_BACKLIGHT">
<range uom="56" subset="0-10"/>
</editor>

<!-- io_guy Ecobee models -->
<!-- Temperature -->
Expand Down
2 changes: 1 addition & 1 deletion profile/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.1.2
2.1.4
2 changes: 1 addition & 1 deletion server.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
{
"title": "ecobee: Polyglot NodeServer for Ecobee",
"author": "James Milne (Einstein.42)",
"version": "2.1.4",
"version": "2.1.5",
"date": "July 25, 2018",
"source": "https://github.com/Einstein42/udi-ecobee-poly",
"license": "https://github.com/Einstein42/udi-ecobee-poly/master/LICENSE"
Expand Down
5 changes: 3 additions & 2 deletions template/editors.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<editor id="CTA_tstatid">
<range uom="25" subset="0-10" nls="CT_tstatid" />
<range uom="25" subset="0-tstatcnta" nls="CT_tstatid" />
</editor>
<editor id="CT_tstatid">
<range uom="25" subset="0-tstatcnt" nls="CT_tstatid" />
<!-- Would like to use tstatcnt isntead of tstatcnta so only available selections are shown in status, but need all in programs for checking status -->
<range uom="25" subset="0-tstatcnta" nls="CT_tstatid" />
</editor>
2 changes: 2 additions & 0 deletions template/en_us.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@ ST-140E-GV6-NAME = Smart Home-Away
ST-140E-GV7-NAME = Follow Me
ST-140E-GV8-NAME = Connected
ST-140E-GV9-NAME = Weather
ST-140E-GV10-NAME = Backlight On Intensity
CMD-140E-GV3-NAME = Climate Type
CMD-140E-GV4-NAME = Fan On Time
CMD-140E-GV6-NAME = Smart Home-Away
CMD-140E-GV7-NAME = Follow Me
CMD-140E-GV9-NAME = Weather
CMD-140E-BRT-NAME = Setpoint Up
CMD-140E-DIM-NAME = Setpoint Down
CMD-140E-GV10-NAME = Backlight On Intensity
PGM-CMD-140E-GV3-FMT = //${c}/to ${v}/ /HoldType//, Hold Type ${v}/
CMDP-I_TSTAT_ECO_SCHED_OPT-HoldType-NAME = Hold Type

Expand Down
8 changes: 8 additions & 0 deletions template/thermostat.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<st id="GV7" editor="I_ENABLED" />
<st id="GV8" editor="BOOL" />
<st id="GV9" editor="I_ENABLED" />
<st id="GV10" editor="I_BACKLIGHT" />
</sts>
<cmds>
<accepts>
Expand Down Expand Up @@ -58,6 +59,9 @@
<cmd id="GV9">
<p id="" editor="I_ENABLED" init="GV9" />
</cmd>
<cmd id="GV10">
<p id="" editor="I_BACKLIGHT" init="GV10" />
</cmd>
<cmd id="QUERY" />
</accepts>
</cmds>
Expand All @@ -82,6 +86,7 @@
<st id="GV7" editor="I_ENABLED" />
<st id="GV8" editor="BOOL" />
<st id="GV9" editor="I_ENABLED" />
<st id="GV10" editor="I_BACKLIGHT" />
</sts>
<cmds>
<accepts>
Expand Down Expand Up @@ -123,6 +128,9 @@
<cmd id="GV9">
<p id="" editor="I_ENABLED" init="GV9" />
</cmd>
<cmd id="GV10">
<p id="" editor="I_BACKLIGHT" init="GV10" />
</cmd>
<cmd id="QUERY" />
</accepts>
</cmds>
Expand Down

0 comments on commit c33a4bc

Please sign in to comment.