11"""Update coordinator for TAURON sensors."""
22import datetime
33import logging
4- import re
54import ssl
5+ import re
66from typing import Optional , Tuple
77
88import requests
9- from requests import adapters
9+ from requests import adapters , Response , Session
1010from urllib3 import poolmanager
1111
12- from .const import (CONST_DATE_FORMAT , CONST_MAX_LOOKUP_RANGE , CONST_REQUEST_HEADERS , CONST_URL_ENERGY , CONST_URL_LOGIN ,
13- CONST_URL_READINGS , CONST_URL_SELECT_METER , CONST_URL_SERVICE )
12+ from .const import (CONST_DATE_FORMAT , CONST_MAX_LOOKUP_RANGE , CONST_REQUEST_HEADERS , CONST_URL_ENERGY ,
13+ CONST_URL_ENERGY_BUSINESS , CONST_URL_LOGIN , CONST_URL_LOGIN_MOJ_TAURON , CONST_URL_READINGS ,
14+ CONST_URL_SELECT_METER , CONST_URL_SERVICE , CONST_URL_SERVICE_MOJ_TAURON )
1415
1516_LOGGER = logging .getLogger (__name__ )
1617
@@ -36,6 +37,8 @@ def __init__(self):
3637 self .tariff = None
3738 self .consumption : Optional [TauronAmiplusDataSet ] = None
3839 self .generation : Optional [TauronAmiplusDataSet ] = None
40+ self .amount_value : Optional [float ] = None
41+ self .amount_status : Optional [str ] = None
3942
4043 def data_unavailable (self ):
4144 return self .consumption is None or self .generation is None
@@ -98,6 +101,7 @@ def __init__(self, username, password, meter_id, show_generation=False, show_12_
98101 self .username = username
99102 self .password = password
100103 self .meter_id = meter_id
104+ self .is_business = False
101105 self .meters = []
102106 self .show_generation = show_generation
103107 self .show_12_months = show_12_months
@@ -110,15 +114,16 @@ def __init__(self, username, password, meter_id, show_generation=False, show_12_
110114
111115 def get_raw_data (self ) -> TauronAmiplusRawData :
112116 data = TauronAmiplusRawData ()
113- self .login ()
117+ # amount_value, amount_status = self.get_moj_tauron()
118+ # data.amount_value = amount_value
119+ # data.amount_status = amount_status
120+ data .tariff = self .login ()
114121 generation_max_cache = datetime .datetime .now ()
115122 data .consumption , consumption_max_cache = self .get_data_set (generation = False )
116123 if self .show_generation or self .show_balanced :
117124 data .generation , generation_max_cache = self .get_data_set (generation = True )
118125 else :
119126 data .generation = TauronAmiplusDataSet ()
120- if data .consumption .json_yearly is not None :
121- data .tariff = data .consumption .json_yearly ["data" ]["tariff" ]
122127 self ._cache .delete_older_than (min (consumption_max_cache , generation_max_cache ))
123128 return data
124129
@@ -149,68 +154,77 @@ def get_data_set(self, generation) -> Tuple[TauronAmiplusDataSet, datetime.datet
149154 cache_max = potential_max
150155 return dataset , cache_max
151156
152- def login (self ) :
157+ def login_service (self , login_url : str , service : str ) -> tuple [ Session , Response ] :
153158 payload_login = {
154159 "username" : self .username ,
155160 "password" : self .password ,
156- "service" : CONST_URL_SERVICE ,
161+ "service" : service ,
157162 }
158163 session = requests .session ()
159164 session .mount ("https://" , TLSAdapter ())
160- self .log ("Logging in..." )
161- session .request (
165+ self .log (f "Logging in... ( { service } ) " )
166+ r1 = session .request (
162167 "POST" ,
163- CONST_URL_LOGIN ,
168+ login_url ,
164169 data = payload_login ,
165170 headers = CONST_REQUEST_HEADERS ,
166171 )
172+ if "Przekroczono maksymalną liczbę logowań." in r1 .text :
173+ self .log ("Too many login attempts" )
174+ raise Exception ("Too many login attempts" )
167175 r2 = session .request (
168176 "POST" ,
169- CONST_URL_LOGIN ,
177+ login_url ,
170178 data = payload_login ,
171179 headers = CONST_REQUEST_HEADERS ,
172180 )
181+ if "Przekroczono maksymalną liczbę logowań." in r2 .text :
182+ self .log ("Too many login attempts" )
183+ raise Exception ("Too many login attempts" )
173184 if "Login lub hasło są nieprawidłowe." in r2 .text :
174185 self .log ("Invalid credentials" )
175186 raise Exception ("Invalid credentials" )
176- if self .username not in r2 .text :
187+ if ( self .username not in r2 .text ) and ( self . username . upper () not in r2 . text ) :
177188 self .log ("Failed to login" )
178189 raise Exception ("Failed to login" )
190+ return session , r2
191+
192+ def login (self ):
193+ session , login_response = self .login_service (CONST_URL_LOGIN , CONST_URL_SERVICE )
194+ self .session = session
179195 self .log ("Logged in." )
180- self .meters = self ._get_meters (r2 .text )
196+ self .meters = self ._get_meters (login_response .text )
181197 payload_select_meter = {"site[client]" : self .meter_id }
198+ selected_meter_info = list (filter (lambda m : m ["meter_id" ] == self .meter_id , self .meters ))
199+ if len (selected_meter_info ) > 0 :
200+ self .is_business = selected_meter_info [0 ]["meter_type" ] == "WO"
201+ else :
202+ self .is_business = False
182203 self .log (f"Selecting meter: { self .meter_id } " )
183- session .request ("POST" , CONST_URL_SELECT_METER , data = payload_select_meter , headers = CONST_REQUEST_HEADERS )
184- self .session = session
204+ select_response = self .session .request ("POST" , CONST_URL_SELECT_METER , data = payload_select_meter , headers = CONST_REQUEST_HEADERS )
205+ tariff_search = re .findall (r"'Tariff' : '(.*)'," , select_response .text )
206+ if len (tariff_search ) > 0 :
207+ tariff = tariff_search [0 ]
208+ return tariff
209+ return "unknown"
185210
186211 @staticmethod
187- def _get_meters (text ) :
212+ def _get_meters (text : str ) -> list :
188213 regex = r".*data-data='{\"type\": \".*\"}'>.*"
189214 matches = list (re .finditer (regex , text ))
190215 meters = []
191216 for match in matches :
192217 m1 = re .match (r".*value=\"([\d\_]+)\".*" , match .group ())
193218 m2 = re .match (r".*\"}'>(.*)</option>" , match .group ())
194- if m1 is None or m2 is None :
219+ m3 = re .match (r".*data-data='{\"type\": \"(.*)\"}'>.*" , match .group ())
220+ if m1 is None or m2 is None or m3 is None :
195221 continue
196222 meter_id = m1 .groups ()[0 ]
197223 display_name = m2 .groups ()[0 ]
198- meters .append ({"meter_id" : meter_id , "meter_name" : display_name })
224+ meter_type = m3 .groups ()[0 ]
225+ meters .append ({"meter_id" : meter_id , "meter_name" : display_name , "meter_type" : meter_type })
199226 return meters
200227
201- def calculate_configuration (self , days_before = 2 , throw_on_empty = True ):
202- self .log ("Calculating configuration..." )
203- json_data , _ = self .get_raw_values_daily (days_before , generation = False )
204- if json_data is None :
205- self .log ("Failed to calculate configuration" )
206- if throw_on_empty :
207- raise Exception ("Failed to login" )
208- else :
209- return None
210- tariff = json_data ["data" ]["tariff" ]
211- self .log (f"Calculated configuration: { tariff } " )
212- return tariff
213-
214228 def get_values_yearly (self , generation ):
215229 now = datetime .datetime .now ()
216230 first_day_of_year = now .replace (day = 1 , month = 1 )
@@ -220,6 +234,7 @@ def get_values_yearly(self, generation):
220234 "to" : TauronAmiplusConnector .format_date (last_day_of_year ),
221235 "profile" : "year" ,
222236 "type" : "oze" if generation else "consum" ,
237+ "energy" : 2 if generation else 1 ,
223238 }
224239 self .log (f"Downloading yearly data for year: { now .year } , generation: { generation } " )
225240 values = self .get_chart_values (payload )
@@ -240,6 +255,7 @@ def get_values_monthly(self, generation):
240255 "to" : TauronAmiplusConnector .format_date (last_day_of_month ),
241256 "profile" : "month" ,
242257 "type" : "oze" if generation else "consum" ,
258+ "energy" : 2 if generation else 1 ,
243259 }
244260 values = self .get_chart_values (payload )
245261 if values is not None :
@@ -293,7 +309,8 @@ def get_raw_values_daily_for_range(self, day_from: datetime.date, day_to: dateti
293309 data ["data" ]["allData" ].extend (day_data ["data" ]["allData" ])
294310 data ["data" ]["sum" ] += day_data ["data" ]["sum" ]
295311 data ["data" ]["zonesName" ] = day_data ["data" ]["zonesName" ]
296- data ["data" ]["tariff" ] = day_data ["data" ]["tariff" ]
312+ if "tariff" in day_data ["data" ]:
313+ data ["data" ]["tariff" ] = day_data ["data" ]["tariff" ]
297314 for z , v in day_data ["data" ]["zones" ].items ():
298315 if z in data ["data" ]["zones" ]:
299316 data ["data" ]["zones" ][z ] += v
@@ -316,6 +333,7 @@ def get_raw_values_daily_for_day(self, day, generation):
316333 "to" : day_str ,
317334 "profile" : "full time" ,
318335 "type" : "oze" if generation else "consum" ,
336+ "energy" : 2 if generation else 1 ,
319337 }
320338 self .log (f"Downloading daily data for day: { day_str } , generation: { generation } " )
321339 values = self .get_chart_values (payload )
@@ -346,15 +364,20 @@ def get_reading(self, generation):
346364 return post
347365
348366 def get_chart_values (self , payload ):
349- return self .execute_post (CONST_URL_ENERGY , payload )
367+ return self .execute_post (CONST_URL_ENERGY_BUSINESS if self . is_business else CONST_URL_ENERGY , payload )
350368
351369 def execute_post (self , url , payload ):
370+ self .log (f"EXECUTING: { url } with payload: { payload } " )
352371 response = self .session .request (
353372 "POST" ,
354373 url ,
355374 data = payload ,
356375 headers = CONST_REQUEST_HEADERS ,
357376 )
377+ self .log (f"RESPONSE: { response .text } " )
378+ if "Przekroczono maksymalną liczbę logowań." in response .text :
379+ self .log ("Too many login attempts" )
380+ raise Exception ("Too many login attempts" )
358381 if response .status_code == 200 and response .text .startswith ('{"success":true' ):
359382 json_data = response .json ()
360383 return json_data
@@ -363,6 +386,41 @@ def execute_post(self, url, payload):
363386 def log (self , msg ):
364387 _LOGGER .debug (f"[{ self .meter_id } ]: { msg } " )
365388
389+ def get_moj_tauron (self ):
390+ session , response = self .login_service (CONST_URL_LOGIN_MOJ_TAURON , CONST_URL_SERVICE_MOJ_TAURON )
391+
392+ if response is None :
393+ return None , "unknown"
394+ find_1_1 = re .findall (r".*class=\"amount-value\".*" , response .text )
395+ find_2_1 = re .findall (r".*class=\"amount-status\".*" , response .text )
396+ if len (find_1_1 ) > 0 and len (find_2_1 ) > 0 :
397+ amount_value = float (
398+ find_1_1 [0 ].strip ()
399+ .replace ("<span class=\" amount-value\" >" , "" )
400+ .replace ("zł" , "" )
401+ .replace ("</span>" , "" )
402+ .replace ("," , "." ).strip ())
403+ amount_status = (find_2_1 [0 ].strip ()
404+ .replace ("<span class=\" amount-status\" >" , "" )
405+ .replace ("</span>" , "" ).strip ())
406+ return amount_value , amount_status
407+
408+ find_1_2 = re .findall (r".*class=\"amount\".*\s*.*\s*</div>" , response .text )
409+ find_2_2 = re .findall (r".*class=\"date\".*" , response .text )
410+ if len (find_1_2 ) > 0 and len (find_2_2 ) > 0 :
411+ amount_value = float (
412+ find_1_2 [0 ].strip ()
413+ .replace ("<div class=\" amount\" >" , "" )
414+ .replace ("zł" , "" )
415+ .replace ("</div>" , "" )
416+ .replace ("," , "." ).strip ())
417+ amount_status = (find_2_2 [0 ].strip ()
418+ .replace ("<div class=\" date\" >" , "" )
419+ .replace ("</div>" , "" ).strip ())
420+ return amount_value , amount_status
421+
422+ return None , "unknown"
423+
366424 @staticmethod
367425 def format_date (date ):
368426 return date .strftime (CONST_DATE_FORMAT )
@@ -373,16 +431,15 @@ def get_available_meters(username, password):
373431 connector .login ()
374432 if connector .meters is not None and len (connector .meters ) > 0 :
375433 return connector .meters
376- raise Exception ("Failed to login " )
434+ raise Exception ("Failed to retrieve energy meters " )
377435
378436 @staticmethod
379437 def calculate_tariff (username , password , meter_id ):
380438 connector = TauronAmiplusConnector (username , password , meter_id )
381- connector .login ()
382- config = connector .calculate_configuration ()
383- if config is not None :
384- return config
385- raise Exception ("Failed to login" )
439+ tariff = connector .login ()
440+ if tariff is not None :
441+ return tariff
442+ raise Exception ("Failed to calculate configuration" )
386443
387444 @staticmethod
388445 def add_all_data (data : dict , date ):
0 commit comments