66from typing import Optional
77import voluptuous as vol
88
9+ import async_timeout
10+
911from homeassistant .config_entries import ConfigEntry
10- from homeassistant .core import HomeAssistant , callback
11- from homeassistant .exceptions import PlatformNotReady
12+ from homeassistant .core import HomeAssistant
13+ from homeassistant .exceptions import ConfigEntryNotReady
1214from homeassistant .helpers import device_registry as dr
1315from homeassistant .helpers .aiohttp_client import async_get_clientsession
16+ from homeassistant .helpers .entity import Entity
1417from homeassistant .helpers .event import async_track_time_interval
18+ from homeassistant .helpers .update_coordinator import DataUpdateCoordinator , UpdateFailed
1519from Plugwise_Smile .Smile import Smile
1620
1721from .const import DOMAIN
2327SENSOR_PLATFORMS = ["sensor" ]
2428ALL_PLATFORMS = ["binary_sensor" , "climate" , "sensor" , "switch" ]
2529
26-
2730async def async_setup (hass : HomeAssistant , config : dict ):
2831 """Set up the Plugwise platform."""
2932 return True
3033
3134
32- async def async_setup_entry (hass : HomeAssistant , entry : ConfigEntry ) -> bool :
35+ async def async_setup_entry (hass , entry ) :
3336 """Set up Plugwise Smiles from a config entry."""
3437 websession = async_get_clientsession (hass , verify_ssl = False )
3538 api = Smile (
@@ -56,16 +59,36 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
5659 else :
5760 update_interval = timedelta (seconds = 60 )
5861
62+ async def async_update_data ():
63+ """Update data via API endpoint."""
64+ _LOGGER .debug ("Updating Smile %s" , api .smile_type )
65+ try :
66+ async with async_timeout .timeout (10 ):
67+ await api .full_update_device ()
68+ _LOGGER .debug ("Succesfully updated Smile %s" , api .smile_type )
69+ return True
70+ except Smile .XMLDataMissingError :
71+ _LOGGER .debug ("Updating Smile failed %s" , api .smile_type )
72+ raise UpdateFailed ("Smile update failed %s" , api .smile_type )
73+
74+
5975 api .get_all_devices ()
6076
77+ coordinator = DataUpdateCoordinator (
78+ hass ,
79+ _LOGGER ,
80+ name = "Smile" ,
81+ update_method = async_update_data ,
82+ update_interval = update_interval )
83+
84+ await coordinator .async_refresh ()
85+
86+ if not coordinator .last_update_success :
87+ raise ConfigEntryNotReady
88+
6189 _LOGGER .debug ("Async update interval %s" , update_interval )
6290
63- hass .data .setdefault (DOMAIN , {})[entry .entry_id ] = {
64- "api" : api ,
65- "updater" : SmileDataUpdater (
66- hass , "device" , entry .entry_id , api , "full_update_device" , update_interval
67- ),
68- }
91+ hass .data .setdefault (DOMAIN , {})[entry .entry_id ] = { "api" : api , "coordinator" : coordinator }
6992
7093 _LOGGER .debug ("Gateway is %s" , api .gateway_id )
7194
@@ -95,13 +118,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
95118 hass .config_entries .async_forward_entry_setup (entry , component )
96119 )
97120
98- async def async_refresh_all (_ ):
99- """Refresh all Smile data."""
100- for info in hass .data [DOMAIN ].values ():
101- await info ["updater" ].async_refresh_all ()
102-
103- hass .services .async_register (DOMAIN , "update" , async_refresh_all )
104-
105121 return True
106122
107123
@@ -121,61 +137,34 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
121137 return unload_ok
122138
123139
124- class SmileDataUpdater :
125- """Data storage for single Smile API endpoint."""
126-
127- def __init__ (
128- self ,
129- hass : HomeAssistant ,
130- data_type : str ,
131- config_entry_id : str ,
132- api : Smile ,
133- update_method : str ,
134- update_interval : timedelta ,
135- ):
136- """Initialize global data updater."""
137- self .hass = hass
138- self .data_type = data_type
139- self .config_entry_id = config_entry_id
140- self .api = api
141- self .update_method = update_method
142- self .update_interval = update_interval
143- self .listeners = []
144- self ._unsub_interval = None
145-
146- @callback
147- def async_add_listener (self , update_callback ):
148- """Listen for data updates."""
149- if not self .listeners :
150- self ._unsub_interval = async_track_time_interval (
151- self .hass , self .async_refresh_all , self .update_interval
152- )
153-
154- self .listeners .append (update_callback )
155-
156- @callback
157- def async_remove_listener (self , update_callback ):
158- """Remove data update."""
159- self .listeners .remove (update_callback )
160-
161- if not self .listeners :
162- self ._unsub_interval ()
163- self ._unsub_interval = None
164-
165- async def async_refresh_all (self , _now : Optional [int ] = None ) -> None :
166- """Time to update."""
167- _LOGGER .debug ("Smile updating with interval: %s" , self .update_interval )
168- if not self .listeners :
169- _LOGGER .error ("Smile has no listeners, not updating" )
170- return
171-
172- _LOGGER .debug ("Smile updating data using: %s" , self .update_method )
140+ class SmileGateway (Entity ):
141+ """Represent Smile Gateway."""
173142
174- try :
175- await self .api .full_update_device ()
176- except Smile .XMLDataMissingError as e :
177- _LOGGER .error ("Smile update failed" )
178- raise e
143+ def __init__ (self , api , coordinator ):
144+ """Initialise the sensor."""
145+ self ._api = api
146+ self ._coordinator = coordinator
179147
180- for update_callback in self .listeners :
181- update_callback ()
148+ @property
149+ def should_poll (self ):
150+ """Return False, updates are controlled via coordinator."""
151+ return False
152+
153+ @property
154+ def available (self ):
155+ """Return True if entity is available."""
156+ return self ._coordinator .last_update_success
157+
158+ async def async_added_to_hass (self ):
159+ """Subscribe to updates."""
160+ self .async_on_remove (
161+ self ._coordinator .async_add_listener (self ._process_data )
162+ )
163+
164+ def _process_data (self ):
165+ """Interpret and process API data."""
166+ raise NotImplementedError
167+
168+ async def async_update (self ):
169+ """Update the entity."""
170+ await self ._coordinator .async_request_refresh ()
0 commit comments