1- """The sma integration."""
1+ """The SMA integration."""
22
33from __future__ import annotations
44
5- from datetime import timedelta
65import logging
7- from typing import TYPE_CHECKING
86
9- import pysma
7+ from pysma import SMA
108
119from homeassistant .config_entries import ConfigEntry
1210from homeassistant .const import (
13- ATTR_CONNECTIONS ,
1411 CONF_HOST ,
15- CONF_MAC ,
1612 CONF_PASSWORD ,
17- CONF_SCAN_INTERVAL ,
1813 CONF_SSL ,
1914 CONF_VERIFY_SSL ,
2015 EVENT_HOMEASSISTANT_STOP ,
16+ Platform ,
2117)
22- from homeassistant .core import HomeAssistant
23- from homeassistant .exceptions import ConfigEntryAuthFailed , ConfigEntryNotReady
24- from homeassistant .helpers import device_registry as dr
18+ from homeassistant .core import Event , HomeAssistant
2519from homeassistant .helpers .aiohttp_client import async_get_clientsession
26- from homeassistant .helpers .device_registry import DeviceInfo
27- from homeassistant .helpers .update_coordinator import DataUpdateCoordinator , UpdateFailed
28-
29- from .const import (
30- CONF_GROUP ,
31- DEFAULT_SCAN_INTERVAL ,
32- DOMAIN ,
33- PLATFORMS ,
34- PYSMA_COORDINATOR ,
35- PYSMA_DEVICE_INFO ,
36- PYSMA_OBJECT ,
37- PYSMA_REMOVE_LISTENER ,
38- PYSMA_SENSORS ,
39- )
20+
21+ from .const import CONF_GROUP
22+ from .coordinator import SMADataUpdateCoordinator
23+
24+ PLATFORMS = [Platform .SENSOR ]
4025
4126_LOGGER = logging .getLogger (__name__ )
4227
4328
44- async def async_setup_entry (hass : HomeAssistant , entry : ConfigEntry ) -> bool :
29+ type SMAConfigEntry = ConfigEntry [SMADataUpdateCoordinator ]
30+
31+
32+ async def async_setup_entry (hass : HomeAssistant , entry : SMAConfigEntry ) -> bool :
4533 """Set up sma from a config entry."""
46- # Init the SMA interface
34+
4735 protocol = "https" if entry .data [CONF_SSL ] else "http"
4836 url = f"{ protocol } ://{ entry .data [CONF_HOST ]} "
49- verify_ssl = entry .data [CONF_VERIFY_SSL ]
50- group = entry .data [CONF_GROUP ]
51- password = entry .data [CONF_PASSWORD ]
52-
53- session = async_get_clientsession (hass , verify_ssl = verify_ssl )
54- sma = pysma .SMA (session , url , password , group )
55-
56- try :
57- # Get updated device info
58- sma_device_info = await sma .device_info ()
59- # Get all device sensors
60- sensor_def = await sma .get_sensors ()
61- except (
62- pysma .exceptions .SmaReadException ,
63- pysma .exceptions .SmaConnectionException ,
64- ) as exc :
65- raise ConfigEntryNotReady from exc
66- except pysma .exceptions .SmaAuthenticationException as exc :
67- raise ConfigEntryAuthFailed from exc
68-
69- if TYPE_CHECKING :
70- assert entry .unique_id
71-
72- # Create DeviceInfo object from sma_device_info
73- device_info = DeviceInfo (
74- configuration_url = url ,
75- identifiers = {(DOMAIN , entry .unique_id )},
76- manufacturer = sma_device_info ["manufacturer" ],
77- model = sma_device_info ["type" ],
78- name = sma_device_info ["name" ],
79- sw_version = sma_device_info ["sw_version" ],
80- serial_number = sma_device_info ["serial" ],
81- )
8237
83- # Add the MAC address to connections, if it comes via DHCP
84- if CONF_MAC in entry .data :
85- device_info [ATTR_CONNECTIONS ] = {
86- (dr .CONNECTION_NETWORK_MAC , entry .data [CONF_MAC ])
87- }
88-
89- # Define the coordinator
90- async def async_update_data ():
91- """Update the used SMA sensors."""
92- try :
93- await sma .read (sensor_def )
94- except (
95- pysma .exceptions .SmaReadException ,
96- pysma .exceptions .SmaConnectionException ,
97- ) as exc :
98- raise UpdateFailed (exc ) from exc
99-
100- interval = timedelta (
101- seconds = entry .options .get (CONF_SCAN_INTERVAL , DEFAULT_SCAN_INTERVAL )
38+ sma = SMA (
39+ session = async_get_clientsession (
40+ hass = hass , verify_ssl = entry .data [CONF_VERIFY_SSL ]
41+ ),
42+ url = url ,
43+ password = entry .data [CONF_PASSWORD ],
44+ group = entry .data [CONF_GROUP ],
10245 )
10346
104- coordinator = DataUpdateCoordinator (
105- hass ,
106- _LOGGER ,
107- config_entry = entry ,
108- name = "sma" ,
109- update_method = async_update_data ,
110- update_interval = interval ,
111- )
47+ coordinator = SMADataUpdateCoordinator (hass , entry , sma )
48+ await coordinator .async_config_entry_first_refresh ()
11249
113- try :
114- await coordinator .async_config_entry_first_refresh ()
115- except ConfigEntryNotReady :
116- await sma .close_session ()
117- raise
50+ entry .runtime_data = coordinator
51+ await hass .config_entries .async_forward_entry_setups (entry , PLATFORMS )
11852
119- # Ensure we logout on shutdown
120- async def async_close_session (event ):
121- """Close the session."""
122- await sma .close_session ()
53+ # Ensure the SMA session closes when Home Assistant stops
54+ async def _async_handle_shutdown (event : Event ) -> None :
55+ await coordinator .async_close_sma_session ()
12356
124- remove_stop_listener = hass . bus . async_listen_once (
125- EVENT_HOMEASSISTANT_STOP , async_close_session
57+ entry . async_on_unload (
58+ hass . bus . async_listen_once ( EVENT_HOMEASSISTANT_STOP , _async_handle_shutdown )
12659 )
12760
128- hass .data .setdefault (DOMAIN , {})
129- hass .data [DOMAIN ][entry .entry_id ] = {
130- PYSMA_OBJECT : sma ,
131- PYSMA_COORDINATOR : coordinator ,
132- PYSMA_SENSORS : sensor_def ,
133- PYSMA_REMOVE_LISTENER : remove_stop_listener ,
134- PYSMA_DEVICE_INFO : device_info ,
135- }
136-
137- await hass .config_entries .async_forward_entry_setups (entry , PLATFORMS )
138-
13961 return True
14062
14163
142- async def async_unload_entry (hass : HomeAssistant , entry : ConfigEntry ) -> bool :
64+ async def async_unload_entry (hass : HomeAssistant , entry : SMAConfigEntry ) -> bool :
14365 """Unload a config entry."""
144- unload_ok = await hass .config_entries .async_unload_platforms (entry , PLATFORMS )
145- if unload_ok :
146- data = hass .data [DOMAIN ].pop (entry .entry_id )
147- await data [PYSMA_OBJECT ].close_session ()
148- data [PYSMA_REMOVE_LISTENER ]()
149-
150- return unload_ok
66+ return await hass .config_entries .async_unload_platforms (entry , PLATFORMS )
15167
15268
15369async def async_migrate_entry (hass : HomeAssistant , entry : ConfigEntry ) -> bool :
@@ -156,7 +72,6 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
15672 _LOGGER .debug ("Migrating from version %s" , entry .version )
15773
15874 if entry .version == 1 :
159- # 1 -> 2: Unique ID from integer to string
16075 if entry .minor_version == 1 :
16176 minor_version = 2
16277 hass .config_entries .async_update_entry (
0 commit comments