@@ -87,8 +87,9 @@ def getParameter(key, default):
87
87
_GETHOMEDATA_REQ = _BASE_URL + "api/gethomedata"
88
88
_GETCAMERAPICTURE_REQ = _BASE_URL + "api/getcamerapicture"
89
89
_GETEVENTSUNTIL_REQ = _BASE_URL + "api/geteventsuntil"
90
- _HOME_STATUS = _BASE_URL + "api/homestatus" # Used for Home+ Control Devices
91
-
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" #
92
93
93
94
#TODO# Undocumented (but would be very usefull) API : Access currently forbidden (403)
94
95
@@ -121,6 +122,59 @@ def getParameter(key, default):
121
122
# Not working yet
122
123
#_CAM_FTP_ACTIVE = "/command/ftp_set_config?config=on_off:%s" # "on"|"off"
123
124
125
+ #Known TYPE used by Netatmo services + API, there can be more types possible
126
+ TYPES = {
127
+ 'BFII' : ["Bticino IP Indoor unit" , 'Home + Security' ],
128
+ 'BFIC' : ["Bticino IP Guard station" , 'Home + Security' ],
129
+ 'BFIO' : ["Bticino IP Entrance panel" , 'Home + Security' ],
130
+ 'BFIS' : ["Bticino Server DES" , 'Home + Security' ],
131
+ 'BNS' : ["Smarther with Netatmo Thermostat" , 'Home+Control' ],
132
+ 'BNCU' : ["Bticino Bticino Alarm Central Unit" , 'Home + Security' ],
133
+ 'BNCS' : ["Bticino module Controlled Socket" , 'Home+Control' ],
134
+ 'BNCX' : ["Bticino Class 300 EOS" , 'Home + Security' ],
135
+ 'BNDL' : ["Bticino Doorlock" , 'Home + Security' ],
136
+ 'BNEU' : ["Bticino external unit" , 'Home + Security' ],
137
+ 'BNFC' : ["Bticino Thermostat" , 'Home+Control' ],
138
+ 'BNMH' : ["Bticino My Home Server 1" , 'Home + Security' ], # also API Home+Control GATEWAY
139
+ 'BNSE' : ["Bticino Alarm Sensor" , 'Home + Security' ],
140
+ 'BNSL' : ["Bticino Staircase Light" , 'Home + Security' ],
141
+ 'BNTH' : ["Bticino Thermostat" , 'Home+Control' ],
142
+ 'BNTR' : ["Bticino module towel rail" , 'Home+Control' ],
143
+ 'BNXM' : ["Bticino X meter" , 'Home+Control' ],
144
+
145
+ 'NACamera' : ["indoor camera" , 'Home + Security' ],
146
+ 'NACamDoorTag' : ["door tag" , 'Home + Security' ],
147
+ 'NAMain' : ["weather station" , 'Weather' ],
148
+ 'NAModule1' : ["outdoor unit" , 'Weather' ],
149
+ 'NAModule2' : ["wind unit" , 'Weather' ],
150
+ 'NAModule3' : ["rain unit" , 'Weather' ],
151
+ '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$
154
+ 'NATherm1' : ["thermostat" , 'Energy' ],
155
+ 'NCO' : ["co2 sensor" , 'Home + Security' ], # The same API as smoke sensor
156
+ 'NDB' : ["doorbell" , 'Home + Security' ],
157
+ 'NOC' : ["outdoor camera" , 'Home + Security' ],
158
+ 'NRV' : ["thermostat valves" , 'Energy' ], # also API Home+Control
159
+ 'NSD' : ["smoke sensor" , 'Home + Security' ],
160
+ 'NHC' : ["home coach" , 'Aircare' ],
161
+ 'NIS' : ["indoor sirene" , 'Home + Security' ],
162
+
163
+ 'NLC' : ["Cable Outlet" , 'Home+Control' ],
164
+ 'NLE' : ["Ecometer" , 'Home+Control' ],
165
+ 'NLG' : ["Gateway" , 'Home+Control' ],
166
+ 'NLGS' : ["Standard DIN Gateway" , 'Home+Control' ],
167
+ 'NLP' : ["Power Outlet" , 'Home+Control' ],
168
+ 'NLPC' : ["DIN Energy meter" , 'Home+Control' ],
169
+ 'NLPD' : ["Dry contact" , 'Home+Control' ],
170
+ 'NLPM' : ["Mobile Socket" , 'Home+Control' ],
171
+ 'NLPO' : ["Contactor" , 'Home+Control' ],
172
+ 'NLPT' : ["Teleruptor" , 'Home+Control' ],
173
+
174
+ 'OTH' : ["Opentherm Thermostat Relay" , 'Home+Control' ],
175
+ 'OTM' : ["Smart modulating Thermostat" , 'Home+Control' ]
176
+ }
177
+
124
178
# UNITS used by Netatmo services
125
179
UNITS = {
126
180
"unit" : {
@@ -138,6 +192,18 @@ def getParameter(key, default):
138
192
0 : "mbar" ,
139
193
1 : "inHg" ,
140
194
2 : "mmHg"
195
+ },
196
+ "Health index" : { # Homecoach
197
+ 0 : "Healthy" ,
198
+ 1 : "Fine" ,
199
+ 2 : "Fair" ,
200
+ 3 : "Poor" ,
201
+ 4 : "Unhealthy"
202
+ },
203
+ "Wifi status" : { # Wifi Signal quality
204
+ 86 : "Bad" ,
205
+ 71 : "Average" ,
206
+ 56 : "Good"
141
207
}
142
208
}
143
209
@@ -317,11 +383,11 @@ def getThermostat(self, name=None):
317
383
else : return
318
384
return self .thermostat [self .defaultThermostatId ]
319
385
320
- def moduleNamesList (self , name = None , tid = None ):
386
+ def moduleNamesList (self , name = None , tid = None ): # ERROR getThermostat() got an unexpected keyword argument 'tid'
321
387
thermostat = self .getThermostat (name = name , tid = tid )
322
388
return [m ['name' ] for m in thermostat ['modules' ]] if thermostat else None
323
389
324
- def getModuleByName (self , name , thermostatId = None ):
390
+ def getModuleByName (self , name , thermostatId = None ): # ERROR 'NoneType' object is not subscriptable
325
391
thermostat = self .getThermostat (tid = thermostatId )
326
392
for m in thermostat ['modules' ]:
327
393
if m ['name' ] == name : return m
@@ -792,6 +858,87 @@ class WelcomeData(HomeData):
792
858
warnings .warn ("The 'WelcomeData' class was renamed 'HomeData' to handle new Netatmo Home capabilities" ,
793
859
DeprecationWarning )
794
860
pass
861
+
862
+ class HomesData :
863
+ """
864
+ List the Netatmo actual topology and static information of all devices present
865
+ into a user account. It is also possible to specify a home_id to focus on one home.
866
+
867
+ Args:
868
+ authData (clientAuth): Authentication information with a working access Token
869
+ home : Home name or id of the home who's module belongs to
870
+ """
871
+ def __init__ (self , authData , home = None ):
872
+ #
873
+ self .getAuthToken = authData .accessToken
874
+ postParams = {
875
+ "access_token" : self .getAuthToken ,
876
+ "home_id" : home
877
+ }
878
+ #
879
+ resp = postRequest ("Module" , _GETHOMES_DATA , postParams )
880
+ # self.rawData = resp['body']['devices']
881
+ self .rawData = resp ['body' ]['homes' ]
882
+ if not self .rawData : raise NoHome ("No home %s found" % home )
883
+ #
884
+ if home :
885
+ # Find a home who's home id or name is the one requested
886
+ for h in self .rawData :
887
+ #print (h.keys())
888
+ if h ["name" ] == home or h ["id" ] == home :
889
+ self .Homes_Data = h
890
+ # print (self.Homes_Data)
891
+ if not self .Homes_Data : raise NoDevice ("No Devices available" )
892
+
893
+ class HomeCoach :
894
+ """
895
+ List the HomeCoach modules
896
+
897
+ Args:
898
+ authData (clientAuth): Authentication information with a working access Token
899
+ home : Home name or id of the home who's HomeCoach belongs to
900
+ """
901
+ def __init__ (self , authData , home = None ):
902
+ # I don't own a HomeCoach thus I am not able to test the HomeCoach support
903
+
904
+ # 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$
906
+ # "Please report found issues (https://github.com/philippelt/netatmo-api-python/issues)"
907
+
908
+ self .getAuthToken = authData .accessToken
909
+ postParams = {
910
+ "access_token" : self .getAuthToken
911
+ }
912
+ resp = postRequest ("HomeCoach" , _GETHOMECOACH , postParams )
913
+ self .rawData = resp ['body' ]['devices' ]
914
+ # homecoach data
915
+ if not self .rawData : raise NoDevice ("No HomeCoach available" )
916
+
917
+ for i in range (len (self .rawData )):
918
+ #
919
+ self .HomecoachDevice = self .rawData [i ]
920
+ # print ('Homecoach = ', self.HomecoachDevice)
921
+ # print (' ')
922
+ # print ('Homecoach_data = ', self.rawData[i]['dashboard_data'])
923
+ # print (' ')
924
+
925
+ def lastData (self , _id = None , exclude = 0 ):
926
+ s = self .HomecoachDevice ['dashboard_data' ]['time_utc' ]
927
+ _id = self .HomecoachDevice ['_id' ]
928
+ return {'When' :s }, {'_id' :_id }
929
+
930
+ def checkNotUpdated (self , delay = 3600 ):
931
+ res = self .lastData ()
932
+ ret = []
933
+ if time .time ()- res ['When' ] > delay : ret .update ({_id ['_id' ]: 'Device Not Updated' )
934
+ return ret if ret else None
935
+
936
+ def checkUpdated (self , delay = 3600 ):
937
+ res = self .lastData ()
938
+ ret = []
939
+ if time .time ()- res ['When' ] < delay : rret .update ({_id ['_id' ]: 'Device up-to-date' )
940
+ return ret if ret else None
941
+
795
942
# Utilities routines
796
943
797
944
def rawAPI (authData , url , parameters = {}):
@@ -902,17 +1049,30 @@ def getStationMinMaxTH(station=None, module=None, home=None):
902
1049
stderr .write ("Library source missing identification arguments to check lnetatmo.py (user/password/etc...)" )
903
1050
exit (1 )
904
1051
905
- authorization = ClientAuth () # Test authentication method
1052
+ authorization = ClientAuth () # Test authentication method
906
1053
907
1054
try :
908
1055
weatherStation = WeatherStationData (authorization ) # Test DEVICELIST
909
1056
except NoDevice :
910
1057
logger .warning ("No weather station available for testing" )
911
1058
else :
912
- weatherStation .MinMaxTH () # Test GETMEASUR
1059
+ weatherStation .MinMaxTH () # Test GETMEASUR
913
1060
914
1061
try :
915
1062
homes = HomeData (authorization )
1063
+ for k , v in homes .homes .items ():
1064
+ #print (v)
1065
+ C = v .pop ('cameras' )
1066
+ P = v .pop ('persons' )
1067
+ S = v .pop ('smokedetectors' )
1068
+ #
1069
+ if C == [] and P == [] and S == []:
1070
+ #print (v)
1071
+ logger .info ("No Cameras, Persons, Smokedetectors found" )
1072
+ #
1073
+ else :
1074
+ homeid = k
1075
+ #
916
1076
except NoDevice :
917
1077
logger .warning ("No home available for testing" )
918
1078
@@ -921,6 +1081,18 @@ def getStationMinMaxTH(station=None, module=None, home=None):
921
1081
except NoDevice :
922
1082
logger .warning ("No thermostat avaible for testing" )
923
1083
1084
+ try :
1085
+ # homesdata = lnetatmo.HomesData(authorization)
1086
+ # ERROR ; Your current token scope do not allow access to Module ? - No Home ID given !
1087
+ homesdata = HomesData (authorization , homeid )
1088
+ except NoDevice :
1089
+ logger .warning ("No HomesData avaible for testing" )
1090
+
1091
+ try :
1092
+ Homecoach = HomeCoach (authorization )
1093
+ except NoDevice :
1094
+ logger .warning ("No HomeCoach avaible for testing" )
1095
+
924
1096
# If we reach this line, all is OK
925
1097
logger .info ("OK" )
926
1098
0 commit comments