Skip to content

Commit 7d30068

Browse files
authored
Fix typos (#71)
Fix some Typos Fix undefined variable correction spaces Correcting Homedata execution when there are no smokesensors, camera's, persons or events in home data. keeping [Fix] Don't crash MinMaxTH() on empty body #67 adjusting class "thermostat" correcting function 'getThermostat'
1 parent 121c68c commit 7d30068

File tree

1 file changed

+111
-75
lines changed

1 file changed

+111
-75
lines changed

lnetatmo.py

Lines changed: 111 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"""
1313

1414
import warnings
15-
if __name__ == "__main__": warnings.filterwarnings("ignore") # For installation test only
15+
if __name__ == "__main__": warnings.filterwarnings("ignore") # For installation test only
1616

1717
from sys import version_info
1818
from os import getenv
@@ -87,20 +87,20 @@ def getParameter(key, default):
8787
_GETHOMEDATA_REQ = _BASE_URL + "api/gethomedata"
8888
_GETCAMERAPICTURE_REQ = _BASE_URL + "api/getcamerapicture"
8989
_GETEVENTSUNTIL_REQ = _BASE_URL + "api/geteventsuntil"
90-
_HOME_STATUS = _BASE_URL + "api/homestatus" # Used for Home+ Control Devices
91-
_GETHOMES_DATA = _BASE_URL + "api/homesdata" # New API
92-
_GETHOMECOACH = _BASE_URL + "api/gethomecoachsdata" #
90+
_HOME_STATUS = _BASE_URL + "api/homestatus" # Used for Home+ Control Devices
91+
_GETHOMES_DATA = _BASE_URL + "api/homesdata" # New API
92+
_GETHOMECOACH = _BASE_URL + "api/gethomecoachsdata" #
9393

9494
#TODO# Undocumented (but would be very usefull) API : Access currently forbidden (403)
9595

9696
_POST_UPDATE_HOME_REQ = _BASE_URL + "/api/updatehome"
9797

9898
# For presence setting (POST BODY):
99-
# _PRES_BODY_REC_SET = "home_id=%s&presence_settings[presence_record_%s]=%s" # (HomeId, DetectionKind, DetectionSetup.index)
99+
# _PRES_BODY_REC_SET = "home_id=%s&presence_settings[presence_record_%s]=%s" # (HomeId, DetectionKind, DetectionSetup.index)
100100
_PRES_DETECTION_KIND = ("humans", "animals", "vehicles", "movements")
101101
_PRES_DETECTION_SETUP = ("ignore", "record", "record & notify")
102102

103-
# _PRES_BODY_ALERT_TIME = "home_id=%s&presence_settings[presence_notify_%s]=%s" # (HomeID, "from"|"to", "hh:mm")
103+
# _PRES_BODY_ALERT_TIME = "home_id=%s&presence_settings[presence_notify_%s]=%s" # (HomeID, "from"|"to", "hh:mm")
104104

105105
# Regular (documented) commands (both cameras)
106106

@@ -113,14 +113,14 @@ def getParameter(key, default):
113113

114114
_PRES_CDE_GET_LIGHT = "/command/floodlight_get_config"
115115
# Not working yet, probably due to scope restriction
116-
#_PRES_CDE_SET_LIGHT = "/command/floodlight_set_config?config=mode:%s" # "auto"|"on"|"off"
116+
#_PRES_CDE_SET_LIGHT = "/command/floodlight_set_config?config=mode:%s" # "auto"|"on"|"off"
117117

118118

119119
# For all cameras
120120

121-
_CAM_CHANGE_STATUS = "/command/changestatus?status=%s" # "on"|"off"
121+
_CAM_CHANGE_STATUS = "/command/changestatus?status=%s" # "on"|"off"
122122
# Not working yet
123-
#_CAM_FTP_ACTIVE = "/command/ftp_set_config?config=on_off:%s" # "on"|"off"
123+
#_CAM_FTP_ACTIVE = "/command/ftp_set_config?config=on_off:%s" # "on"|"off"
124124

125125
#Known TYPE used by Netatmo services + API, there can be more types possible
126126
TYPES = {
@@ -135,30 +135,30 @@ def getParameter(key, default):
135135
'BNDL' : ["Bticino Doorlock", 'Home + Security'],
136136
'BNEU' : ["Bticino external unit", 'Home + Security'],
137137
'BNFC' : ["Bticino Thermostat", 'Home+Control'],
138-
'BNMH' : ["Bticino My Home Server 1", 'Home + Security'], # also API Home+Control GATEWAY
138+
'BNMH' : ["Bticino My Home Server 1", 'Home + Security'], # also API Home+Control GATEWAY
139139
'BNSE' : ["Bticino Alarm Sensor", 'Home + Security'],
140140
'BNSL' : ["Bticino Staircase Light", 'Home + Security'],
141141
'BNTH' : ["Bticino Thermostat", 'Home+Control'],
142142
'BNTR' : ["Bticino module towel rail", 'Home+Control'],
143143
'BNXM' : ["Bticino X meter", 'Home+Control'],
144144

145-
'NACamera' : ["indoor camera", 'Home + Security'],
145+
'NACamera' : ["indoor camera", 'Home + Security'],
146146
'NACamDoorTag' : ["door tag", 'Home + Security'],
147147
'NAMain' : ["weather station", 'Weather'],
148148
'NAModule1' : ["outdoor unit", 'Weather'],
149149
'NAModule2' : ["wind unit", 'Weather'],
150150
'NAModule3' : ["rain unit", 'Weather'],
151151
'NAModule4' : ["indoor unit", 'Weather'],
152-
'NAPlug' : ["thermostat relais station", 'Energy'], # A smart thermostat exist of a thermostat$
153-
# The relais module is also the bridge bet$
152+
'NAPlug' : ["thermostat relais station", 'Energy'], # A smart thermostat exist of a thermostat and a Relais module
153+
# The relais module is also the bridge for thermostat and Valves
154154
'NATherm1' : ["thermostat", 'Energy'],
155-
'NCO' : ["co2 sensor", 'Home + Security'], # The same API as smoke sensor
155+
'NCO' : ["co2 sensor", 'Home + Security'], # The same API as smoke sensor
156156
'NDB' : ["doorbell", 'Home + Security'],
157157
'NOC' : ["outdoor camera", 'Home + Security'],
158-
'NRV' : ["thermostat valves", 'Energy'], # also API Home+Control
158+
'NRV' : ["thermostat valves", 'Energy'], # also API Home+Control
159159
'NSD' : ["smoke sensor", 'Home + Security'],
160160
'NHC' : ["home coach", 'Aircare'],
161-
'NIS' : ["indoor sirene", 'Home + Security'],
161+
'NIS' : ["indoor sirene", 'Home + Security'],
162162

163163
'NLC' : ["Cable Outlet", 'Home+Control'],
164164
'NLE' : ["Ecometer", 'Home+Control'],
@@ -193,14 +193,14 @@ def getParameter(key, default):
193193
1: "inHg",
194194
2: "mmHg"
195195
},
196-
"Health index" : { # Homecoach
196+
"Health index" : { # Homecoach
197197
0: "Healthy",
198198
1: "Fine",
199199
2: "Fair",
200200
3: "Poor",
201201
4: "Unhealthy"
202202
},
203-
"Wifi status" : { # Wifi Signal quality
203+
"Wifi status" : { # Wifi Signal quality
204204
86: "Bad",
205205
71: "Average",
206206
56: "Good"
@@ -226,6 +226,7 @@ class AuthFailure( Exception ):
226226
class outOfScope( Exception ):
227227
pass
228228

229+
229230
class ClientAuth:
230231
"""
231232
Request authentication and keep access token available through token method. Renew it automatically if necessary
@@ -369,25 +370,42 @@ def __init__(self, authData, home=None):
369370
resp = postRequest("Thermostat", _GETTHERMOSTATDATA_REQ, postParams)
370371
self.rawData = resp['body']['devices']
371372
if not self.rawData : raise NoDevice("No thermostat available")
372-
self.thermostatData = filter_home_data(self.rawData, home)
373-
if not self.thermostatData : raise NoHome("No home %s found" % home)
374-
self.thermostatData['name'] = self.thermostatData['home_name']
375-
for m in self.thermostatData['modules']:
376-
m['name'] = m['module_name']
377-
self.defaultThermostat = self.thermostatData['home_name']
378-
self.defaultThermostatId = self.thermostatData['_id']
379-
self.defaultModule = self.thermostatData['modules'][0]
380-
381-
def getThermostat(self, name=None):
382-
if ['name'] != name: return None
373+
#
374+
# keeping OLD code for Reference
375+
# self.thermostatData = filter_home_data(self.rawData, home)
376+
# if not self.thermostatData : raise NoHome("No home %s found" % home)
377+
# self.thermostatData['name'] = self.thermostatData['home_name'] # New key = 'station_name'
378+
# for m in self.thermostatData['modules']:
379+
# m['name'] = m['module_name']
380+
# self.defaultThermostat = self.thermostatData['home_name'] # New key = 'station_name'
381+
# self.defaultThermostatId = self.thermostatData['_id']
382+
# self.defaultModule = self.thermostatData['modules'][0]
383+
# Standard the first Relaystation and Thermostat is returned
384+
# self.rawData is list all stations
385+
386+
def Relay_Plug(self, _id=None):
387+
for Relay in self.rawData:
388+
if _id in Relay:
389+
return Relay
390+
else:
391+
#print (Relay['_id'])
392+
return Relay
393+
394+
def Thermostat_Data(self):
395+
for thermostat in self.Relay_Plug()['modules']:
396+
#
397+
return thermostat
398+
399+
def getThermostat(self, name=None, tid=None):
400+
if self.rawData[0]['station_name'] != name: return None # OLD ['name']
383401
else: return
384402
return self.thermostat[self.defaultThermostatId]
385403

386-
def moduleNamesList(self, name=None, tid=None): # ERROR getThermostat() got an unexpected keyword argument 'tid'
404+
def moduleNamesList(self, name=None, tid=None):
387405
thermostat = self.getThermostat(name=name, tid=tid)
388406
return [m['name'] for m in thermostat['modules']] if thermostat else None
389407

390-
def getModuleByName(self, name, thermostatId=None): # ERROR 'NoneType' object is not subscriptable
408+
def getModuleByName(self, name, thermostatId=None): # ERROR 'NoneType' object is not subscriptable
391409
thermostat = self.getThermostat(tid=thermostatId)
392410
for m in thermostat['modules']:
393411
if m['name'] == name: return m
@@ -562,6 +580,7 @@ def MinMaxTH(self, module=None, frame="last24"):
562580
else:
563581
return None
564582

583+
565584
class DeviceList(WeatherStationData):
566585
"""
567586
This class is now deprecated. Use WeatherStationData directly instead
@@ -570,6 +589,7 @@ class DeviceList(WeatherStationData):
570589
DeprecationWarning )
571590
pass
572591

592+
573593
class HomeData:
574594
"""
575595
List the Netatmo home informations (Homes, cameras, events, persons)
@@ -586,35 +606,56 @@ def __init__(self, authData, home=None):
586606
self.rawData = resp['body']
587607
# Collect homes
588608
self.homes = { d['id'] : d for d in self.rawData['homes'] }
589-
if not self.homes : raise NoDevice("No home available")
590-
self.default_home = home or list(self.homes.values())[0]['name']
591-
# Split homes data by category
592-
self.persons = dict()
593-
self.events = dict()
594-
self.cameras = dict()
595-
self.lastEvent = dict()
596-
for i in range(len(self.rawData['homes'])):
597-
curHome = self.rawData['homes'][i]
598-
nameHome = curHome['name']
599-
if nameHome not in self.cameras:
600-
self.cameras[nameHome] = dict()
601-
if 'persons' in curHome:
602-
for p in curHome['persons']:
603-
self.persons[ p['id'] ] = p
604-
if 'events' in curHome:
609+
for k, v in self.homes.items():
610+
self.homeid = k
611+
C = v.get('cameras')
612+
P = v.get('persons')
613+
S = v.get('smokedetectors')
614+
E = v.get('events')
615+
if not S:
616+
logger.warning('No Smokedetectors found')
617+
# raise NoDevice("No Devices available")
618+
if not C:
619+
logger.warning('No Cameras found')
620+
# raise NoDevice("No Cameras available")
621+
if not P:
622+
logger.warning('No Persons found')
623+
# raise NoDevice("No Persons available")
624+
if not E:
625+
logger.warning('No events found')
626+
# raise NoDevice("No Events available")
627+
if S or C or P or E:
628+
self.default_home = home or list(self.homes.values())[0]['name']
629+
# Split homes data by category
630+
self.persons = dict()
631+
self.events = dict()
632+
self.cameras = dict()
633+
self.lastEvent = dict()
634+
for i in range(len(self.rawData['homes'])):
635+
curHome = self.rawData['homes'][i]
636+
nameHome = curHome['name']
637+
if nameHome not in self.cameras:
638+
self.cameras[nameHome] = dict()
639+
if 'persons' in curHome:
640+
for p in curHome['persons']:
641+
self.persons[ p['id'] ] = p
642+
if 'events' in curHome:
605643
for e in curHome['events']:
606644
if e['camera_id'] not in self.events:
607645
self.events[ e['camera_id'] ] = dict()
608646
self.events[ e['camera_id'] ][ e['time'] ] = e
609-
if 'cameras' in curHome:
610-
for c in curHome['cameras']:
611-
self.cameras[nameHome][ c['id'] ] = c
612-
c["home_id"] = curHome['id']
613-
for camera in self.events:
614-
self.lastEvent[camera] = self.events[camera][sorted(self.events[camera])[-1]]
615-
if not self.cameras[self.default_home] : raise NoDevice("No camera available in default home")
616-
self.default_camera = list(self.cameras[self.default_home].values())[0]
617-
647+
if 'cameras' in curHome:
648+
for c in curHome['cameras']:
649+
self.cameras[nameHome][ c['id'] ] = c
650+
c["home_id"] = curHome['id']
651+
for camera in self.events:
652+
self.lastEvent[camera] = self.events[camera][sorted(self.events[camera])[-1]]
653+
if not self.cameras[self.default_home] : raise NoDevice("No camera available in default home")
654+
self.default_camera = list(self.cameras[self.default_home].values())[0]
655+
else:
656+
pass
657+
# raise NoDevice("No Devices available")
658+
618659
def homeById(self, hid):
619660
return None if hid not in self.homes else self.homes[hid]
620661

@@ -859,6 +900,7 @@ class WelcomeData(HomeData):
859900
DeprecationWarning )
860901
pass
861902

903+
862904
class HomesData:
863905
"""
864906
List the Netatmo actual topology and static information of all devices present
@@ -890,6 +932,7 @@ def __init__(self, authData, home=None):
890932
# print (self.Homes_Data)
891933
if not self.Homes_Data : raise NoDevice("No Devices available")
892934

935+
893936
class HomeCoach:
894937
"""
895938
List the HomeCoach modules
@@ -902,7 +945,7 @@ def __init__(self, authData, home=None):
902945
# I don't own a HomeCoach thus I am not able to test the HomeCoach support
903946

904947
# warnings.warn("The HomeCoach code is not tested due to the lack of test environment.\n", RuntimeWarning )
905-
# "As Netatmo is continuously breaking API compatibility, risk that current bindings are wrong is h$
948+
# "As Netatmo is continuously breaking API compatibility, risk that current bindings are wrong is high.\n" \
906949
# "Please report found issues (https://github.com/philippelt/netatmo-api-python/issues)"
907950

908951
self.getAuthToken = authData.accessToken
@@ -929,16 +972,19 @@ def lastData(self, _id=None, exclude=0):
929972

930973
def checkNotUpdated(self, delay=3600):
931974
res = self.lastData()
975+
_id = res['_id']
932976
ret = []
933-
if time.time()-res['When'] > delay : ret.update({_id['_id']: 'Device Not Updated')
977+
if time.time()-res['When'] > delay : ret.append({_id['_id']: 'Device Not Updated'})
934978
return ret if ret else None
935979

936980
def checkUpdated(self, delay=3600):
937981
res = self.lastData()
982+
_id = res['_id']
938983
ret = []
939-
if time.time()-res['When'] < delay : rret.update({_id['_id']: 'Device up-to-date')
984+
if time.time()-res['When'] < delay : ret.append({_id['_id']: 'Device up-to-date'})
940985
return ret if ret else None
941986

987+
942988
# Utilities routines
943989

944990
def rawAPI(authData, url, parameters={}):
@@ -1050,35 +1096,25 @@ def getStationMinMaxTH(station=None, module=None, home=None):
10501096
stderr.write("Library source missing identification arguments to check lnetatmo.py (user/password/etc...)")
10511097
exit(1)
10521098

1053-
authorization = ClientAuth() # Test authentication method
1099+
authorization = ClientAuth() # Test authentication method
10541100

10551101
try:
1056-
weatherStation = WeatherStationData(authorization) # Test DEVICELIST
1102+
weatherStation = WeatherStationData(authorization) # Test DEVICELIST
10571103
except NoDevice:
10581104
logger.warning("No weather station available for testing")
10591105
else:
1060-
weatherStation.MinMaxTH() # Test GETMEASUR
1106+
weatherStation.MinMaxTH() # Test GETMEASUR
10611107

10621108
try:
10631109
homes = HomeData(authorization)
1064-
for k, v in homes.homes.items():
1065-
#print (v)
1066-
C = v.pop('cameras')
1067-
P = v.pop('persons')
1068-
S = v.pop('smokedetectors')
1069-
#
1070-
if C == [] and P == [] and S == []:
1071-
#print (v)
1072-
logger.info("No Cameras, Persons, Smokedetectors found")
1073-
#
1074-
else:
1075-
homeid = k
1076-
#
1110+
homeid = homes.homeid
10771111
except NoDevice :
10781112
logger.warning("No home available for testing")
10791113

10801114
try:
10811115
thermostat = ThermostatData(authorization)
1116+
Default_relay = thermostat.Relay_Plug()
1117+
Default_thermostat = thermostat.Thermostat_Data()
10821118
except NoDevice:
10831119
logger.warning("No thermostat avaible for testing")
10841120

0 commit comments

Comments
 (0)