55import datetime as dt
66import logging
77
8+ import aiohttp
89import async_timeout
910from dateutil import tz
1011from dateutil .parser import parse
6869
6970
7071def device_state_updater (data , devs , d_id , d_dict ):
71- """Helper-function for _update_gw_devices ().
72+ """Helper-function for async_update ().
7273 Update the Device_State sensor state.
7374 """
7475 for idx , item in enumerate (d_dict ["sensors" ]):
@@ -114,7 +115,7 @@ def update_device_state(data, d_dict):
114115
115116
116117def pw_notification_updater (devs , d_id , d_dict , notifs ):
117- """Helper-function for _update_gw_devices ().
118+ """Helper-function for async_update ().
118119 Update the PW_Notification binary_sensor state.
119120 """
120121 for idx , item in enumerate (d_dict ["binary_sensors" ]):
@@ -123,16 +124,14 @@ def pw_notification_updater(devs, d_id, d_dict, notifs):
123124
124125
125126def update_helper (data , devs , d_dict , d_id , e_type , key ):
126- """Helper-function for _update_gw_devices ()."""
127+ """Helper-function for async_update ()."""
127128 for dummy in d_dict [e_type ]:
128129 if key != dummy [ATTR_ID ]:
129130 continue
130131 for idx , item in enumerate (devs [d_id ][e_type ]):
131132 if key != item [ATTR_ID ]:
132133 continue
133134 devs [d_id ][e_type ][idx ][ATTR_STATE ] = data [key ]
134- if isinstance (data [key ], list ):
135- devs [d_id ][e_type ][idx ][ATTR_STATE ] = data [key ][0 ]
136135
137136
138137def check_model (name , v_name ):
@@ -217,38 +216,37 @@ def power_data_energy_diff(measurement, net_string, f_val, direct_data):
217216 return direct_data
218217
219218
220- class SmileHelper :
221- """The SmileHelper class."""
219+ class SmileComm :
220+ """The SmileComm class."""
222221
223- def __init__ (self ):
222+ def __init__ (
223+ self ,
224+ host ,
225+ password ,
226+ username ,
227+ port ,
228+ timeout ,
229+ websession ,
230+ ):
224231 """Set the constructor for this class."""
225- self ._active_device_present = None
226- self ._appl_data = {}
227- self ._appliances = None
228- self ._auth = None
229- self ._cp_state = None
230- self ._domain_objects = None
231- self ._endpoint = None
232- self ._heater_id = None
233- self ._home_location = None
234- self ._locations = None
235- self ._modules = None
236- self ._smile_legacy = False
237- self ._host = None
238- self ._loc_data = {}
239- self ._port = None
240- self ._stretch_v2 = False
241- self ._stretch_v3 = False
242- self ._thermo_locs = None
243- self ._timeout = None
244- self ._websession = None
245-
246- self .gateway_id = None
247- self .notifications = {}
248- self .smile_hostname = None
249- self .smile_name = None
250- self .smile_type = None
251- self .smile_version = ()
232+ if not websession :
233+
234+ async def _create_session () -> aiohttp .ClientSession :
235+ return aiohttp .ClientSession () # pragma: no cover
236+
237+ loop = asyncio .get_event_loop ()
238+ if loop .is_running ():
239+ self ._websession = aiohttp .ClientSession ()
240+ else :
241+ self ._websession = loop .run_until_complete (
242+ _create_session ()
243+ ) # pragma: no cover
244+ else :
245+ self ._websession = websession
246+
247+ self ._auth = aiohttp .BasicAuth (username , password = password )
248+ self ._endpoint = f"http://{ host } :{ str (port )} "
249+ self ._timeout = timeout
252250
253251 async def _request_validate (self , resp , method ):
254252 """Helper-function for _request(): validate the returned data."""
@@ -289,7 +287,7 @@ async def _request(
289287 url = f"{ self ._endpoint } { command } "
290288
291289 try :
292- with async_timeout .timeout (self ._timeout ):
290+ async with async_timeout .timeout (self ._timeout ):
293291 if method == "get" :
294292 # Work-around for Stretchv2, should not hurt the other smiles
295293 headers = {"Accept-Encoding" : "gzip" }
@@ -311,6 +309,14 @@ async def _request(
311309
312310 return await self ._request_validate (resp , method )
313311
312+ async def close_connection (self ):
313+ """Close the Plugwise connection."""
314+ await self ._websession .close ()
315+
316+
317+ class SmileHelper :
318+ """The SmileHelper class."""
319+
314320 def _locations_legacy (self ):
315321 """Helper-function for _all_locations().
316322 Create locations for legacy devices.
@@ -513,6 +519,7 @@ def _appliance_types_finder(self, appliance, appl):
513519 def _all_appliances (self ):
514520 """Collect all appliances with relevant info."""
515521 self ._appl_data = {}
522+ self ._cp_state = None
516523
517524 self ._all_locations ()
518525
@@ -674,29 +681,6 @@ def _rule_ids_by_tag(self, tag, loc_id):
674681 if schema_ids != {}:
675682 return schema_ids
676683
677- async def _update_domain_objects (self ):
678- """Helper-function for smile.py: full_update_device() and update_gw_devices().
679- Request domain_objects data.
680- """
681- self ._domain_objects = await self ._request (DOMAIN_OBJECTS )
682-
683- # If Plugwise notifications present:
684- self .notifications = {}
685- url = f"{ self ._endpoint } { DOMAIN_OBJECTS } "
686- notifications = self ._domain_objects .findall (".//notification" )
687- for notification in notifications :
688- try :
689- msg_id = notification .attrib ["id" ]
690- msg_type = notification .find ("type" ).text
691- msg = notification .find ("message" ).text
692- self .notifications .update ({msg_id : {msg_type : msg }})
693- _LOGGER .debug ("Plugwise notifications: %s" , self .notifications )
694- except AttributeError : # pragma: no cover
695- _LOGGER .info (
696- "Plugwise notification present but unable to process, manually investigate: %s" ,
697- url ,
698- )
699-
700684 def _appliance_measurements (self , appliance , data , measurements ):
701685 """Helper-function for _get_appliance_data() - collect appliance measurement data."""
702686 for measurement , attrs in measurements :
@@ -729,9 +713,7 @@ def _appliance_measurements(self, appliance, data, measurements):
729713 if appliance .find (i_locator ) is not None :
730714 name = f"{ measurement } _interval"
731715 measure = appliance .find (i_locator ).text
732- log_date = parse (appliance .find (i_locator ).get ("log_date" ))
733- log_date = log_date .astimezone (tz .gettz ("UTC" )).replace (tzinfo = None )
734- data [name ] = [format_measure (measure , ENERGY_WATT_HOUR ), log_date ]
716+ data [name ] = format_measure (measure , ENERGY_WATT_HOUR )
735717
736718 return data
737719
@@ -955,8 +937,6 @@ def _power_data_peak_value(self, loc):
955937 loc .key_string = f"{ loc .measurement } _{ log_found } "
956938 loc .net_string = f"net_electricity_{ log_found } "
957939 val = loc .logs .find (loc .locator ).text
958- log_date = parse (loc .logs .find (loc .locator ).get ("log_date" ))
959- loc .log_date = log_date .astimezone (tz .gettz ("UTC" )).replace (tzinfo = None )
960940 loc .f_val = power_data_local_format (loc .attrs , loc .key_string , val )
961941
962942 return loc
@@ -1002,8 +982,6 @@ def _power_data_from_location(self, loc_id):
1002982 )
1003983
1004984 direct_data [loc .key_string ] = loc .f_val
1005- if "interval" in loc .key_string :
1006- direct_data [loc .key_string ] = [loc .f_val , loc .log_date ]
1007985
1008986 if direct_data != {}:
1009987 return direct_data
@@ -1178,8 +1156,6 @@ def _create_lists_from_data(self, data, bs_list, s_list, sw_list):
11781156 if item [ATTR_ID ] == key :
11791157 data .pop (item [ATTR_ID ])
11801158 item [ATTR_STATE ] = value
1181- if "interval" in item [ATTR_ID ] and isinstance (value , list ):
1182- item [ATTR_STATE ] = value [0 ]
11831159 s_list .append (item )
11841160 for item in SWITCHES :
11851161 if item [ATTR_ID ] == key :
0 commit comments