11"""Support for Satel Integra devices."""
22
3- import collections
43import logging
54
65from satel_integra .satel_integra import AsyncSatel
76import voluptuous as vol
87
9- from homeassistant .const import CONF_HOST , CONF_PORT , EVENT_HOMEASSISTANT_STOP , Platform
10- from homeassistant .core import HomeAssistant , callback
11- from homeassistant .helpers import config_validation as cv
12- from homeassistant .helpers .discovery import async_load_platform
8+ from homeassistant .config_entries import SOURCE_IMPORT
9+ from homeassistant .const import (
10+ CONF_CODE ,
11+ CONF_HOST ,
12+ CONF_NAME ,
13+ CONF_PORT ,
14+ EVENT_HOMEASSISTANT_STOP ,
15+ Platform ,
16+ )
17+ from homeassistant .core import DOMAIN as HOMEASSISTANT_DOMAIN , HomeAssistant , callback
18+ from homeassistant .data_entry_flow import FlowResultType
19+ from homeassistant .exceptions import ConfigEntryNotReady
20+ from homeassistant .helpers import config_validation as cv , issue_registry as ir
1321from homeassistant .helpers .dispatcher import async_dispatcher_send
1422from homeassistant .helpers .typing import ConfigType
1523
16- DEFAULT_ALARM_NAME = "satel_integra"
17- DEFAULT_PORT = 7094
18- DEFAULT_CONF_ARM_HOME_MODE = 1
19- DEFAULT_DEVICE_PARTITION = 1
20- DEFAULT_ZONE_TYPE = "motion"
24+ from .const import (
25+ CONF_ARM_HOME_MODE ,
26+ CONF_DEVICE_PARTITIONS ,
27+ CONF_OUTPUT_NUMBER ,
28+ CONF_OUTPUTS ,
29+ CONF_PARTITION_NUMBER ,
30+ CONF_SWITCHABLE_OUTPUT_NUMBER ,
31+ CONF_SWITCHABLE_OUTPUTS ,
32+ CONF_ZONE_NUMBER ,
33+ CONF_ZONE_TYPE ,
34+ CONF_ZONES ,
35+ DEFAULT_CONF_ARM_HOME_MODE ,
36+ DEFAULT_PORT ,
37+ DEFAULT_ZONE_TYPE ,
38+ DOMAIN ,
39+ SIGNAL_OUTPUTS_UPDATED ,
40+ SIGNAL_PANEL_MESSAGE ,
41+ SIGNAL_ZONES_UPDATED ,
42+ SUBENTRY_TYPE_OUTPUT ,
43+ SUBENTRY_TYPE_PARTITION ,
44+ SUBENTRY_TYPE_SWITCHABLE_OUTPUT ,
45+ SUBENTRY_TYPE_ZONE ,
46+ ZONES ,
47+ SatelConfigEntry ,
48+ )
2149
2250_LOGGER = logging .getLogger (__name__ )
2351
24- DOMAIN = "satel_integra"
25-
26- DATA_SATEL = "satel_integra"
27-
28- CONF_DEVICE_CODE = "code"
29- CONF_DEVICE_PARTITIONS = "partitions"
30- CONF_ARM_HOME_MODE = "arm_home_mode"
31- CONF_ZONE_NAME = "name"
32- CONF_ZONE_TYPE = "type"
33- CONF_ZONES = "zones"
34- CONF_OUTPUTS = "outputs"
35- CONF_SWITCHABLE_OUTPUTS = "switchable_outputs"
36-
37- ZONES = "zones"
52+ PLATFORMS = [Platform .ALARM_CONTROL_PANEL , Platform .BINARY_SENSOR , Platform .SWITCH ]
3853
39- SIGNAL_PANEL_MESSAGE = "satel_integra.panel_message"
40- SIGNAL_PANEL_ARM_AWAY = "satel_integra.panel_arm_away"
41- SIGNAL_PANEL_ARM_HOME = "satel_integra.panel_arm_home"
42- SIGNAL_PANEL_DISARM = "satel_integra.panel_disarm"
43-
44- SIGNAL_ZONES_UPDATED = "satel_integra.zones_updated"
45- SIGNAL_OUTPUTS_UPDATED = "satel_integra.outputs_updated"
4654
4755ZONE_SCHEMA = vol .Schema (
4856 {
49- vol .Required (CONF_ZONE_NAME ): cv .string ,
57+ vol .Required (CONF_NAME ): cv .string ,
5058 vol .Optional (CONF_ZONE_TYPE , default = DEFAULT_ZONE_TYPE ): cv .string ,
5159 }
5260)
53- EDITABLE_OUTPUT_SCHEMA = vol .Schema ({vol .Required (CONF_ZONE_NAME ): cv .string })
61+ EDITABLE_OUTPUT_SCHEMA = vol .Schema ({vol .Required (CONF_NAME ): cv .string })
5462PARTITION_SCHEMA = vol .Schema (
5563 {
56- vol .Required (CONF_ZONE_NAME ): cv .string ,
64+ vol .Required (CONF_NAME ): cv .string ,
5765 vol .Optional (CONF_ARM_HOME_MODE , default = DEFAULT_CONF_ARM_HOME_MODE ): vol .In (
5866 [1 , 2 , 3 ]
5967 ),
6371
6472def is_alarm_code_necessary (value ):
6573 """Check if alarm code must be configured."""
66- if value .get (CONF_SWITCHABLE_OUTPUTS ) and CONF_DEVICE_CODE not in value :
74+ if value .get (CONF_SWITCHABLE_OUTPUTS ) and CONF_CODE not in value :
6775 raise vol .Invalid ("You need to specify alarm code to use switchable_outputs" )
6876
6977 return value
@@ -75,7 +83,7 @@ def is_alarm_code_necessary(value):
7583 {
7684 vol .Required (CONF_HOST ): cv .string ,
7785 vol .Optional (CONF_PORT , default = DEFAULT_PORT ): cv .port ,
78- vol .Optional (CONF_DEVICE_CODE ): cv .string ,
86+ vol .Optional (CONF_CODE ): cv .string ,
7987 vol .Optional (CONF_DEVICE_PARTITIONS , default = {}): {
8088 vol .Coerce (int ): PARTITION_SCHEMA
8189 },
@@ -92,64 +100,106 @@ def is_alarm_code_necessary(value):
92100)
93101
94102
95- async def async_setup (hass : HomeAssistant , config : ConfigType ) -> bool :
96- """Set up the Satel Integra component."""
97- conf = config [DOMAIN ]
103+ async def async_setup (hass : HomeAssistant , hass_config : ConfigType ) -> bool :
104+ """Set up Satel Integra from YAML."""
105+
106+ if config := hass_config .get (DOMAIN ):
107+ hass .async_create_task (_async_import (hass , config ))
108+
109+ return True
110+
98111
99- zones = conf .get (CONF_ZONES )
100- outputs = conf .get (CONF_OUTPUTS )
101- switchable_outputs = conf .get (CONF_SWITCHABLE_OUTPUTS )
102- host = conf .get (CONF_HOST )
103- port = conf .get (CONF_PORT )
104- partitions = conf .get (CONF_DEVICE_PARTITIONS )
112+ async def _async_import (hass : HomeAssistant , config : ConfigType ) -> None :
113+ """Process YAML import."""
105114
106- monitored_outputs = collections .OrderedDict (
107- list (outputs .items ()) + list (switchable_outputs .items ())
115+ if not hass .config_entries .async_entries (DOMAIN ):
116+ # Start import flow
117+ result = await hass .config_entries .flow .async_init (
118+ DOMAIN , context = {"source" : SOURCE_IMPORT }, data = config
119+ )
120+
121+ if result .get ("type" ) == FlowResultType .ABORT :
122+ ir .async_create_issue (
123+ hass ,
124+ DOMAIN ,
125+ "deprecated_yaml_import_issue_cannot_connect" ,
126+ breaks_in_ha_version = "2026.4.0" ,
127+ is_fixable = False ,
128+ issue_domain = DOMAIN ,
129+ severity = ir .IssueSeverity .WARNING ,
130+ translation_key = "deprecated_yaml_import_issue_cannot_connect" ,
131+ translation_placeholders = {
132+ "domain" : DOMAIN ,
133+ "integration_title" : "Satel Integra" ,
134+ },
135+ )
136+ return
137+
138+ ir .async_create_issue (
139+ hass ,
140+ HOMEASSISTANT_DOMAIN ,
141+ f"deprecated_yaml_{ DOMAIN } " ,
142+ breaks_in_ha_version = "2026.4.0" ,
143+ is_fixable = False ,
144+ issue_domain = DOMAIN ,
145+ severity = ir .IssueSeverity .WARNING ,
146+ translation_key = "deprecated_yaml" ,
147+ translation_placeholders = {
148+ "domain" : DOMAIN ,
149+ "integration_title" : "Satel Integra" ,
150+ },
108151 )
109152
110- controller = AsyncSatel (host , port , hass .loop , zones , monitored_outputs , partitions )
111153
112- hass .data [DATA_SATEL ] = controller
154+ async def async_setup_entry (hass : HomeAssistant , entry : SatelConfigEntry ) -> bool :
155+ """Set up Satel Integra from a config entry."""
156+
157+ host = entry .data [CONF_HOST ]
158+ port = entry .data [CONF_PORT ]
159+
160+ # Make sure we initialize the Satel controller with the configured entries to monitor
161+ partitions = [
162+ subentry .data [CONF_PARTITION_NUMBER ]
163+ for subentry in entry .subentries .values ()
164+ if subentry .subentry_type == SUBENTRY_TYPE_PARTITION
165+ ]
166+
167+ zones = [
168+ subentry .data [CONF_ZONE_NUMBER ]
169+ for subentry in entry .subentries .values ()
170+ if subentry .subentry_type == SUBENTRY_TYPE_ZONE
171+ ]
172+
173+ outputs = [
174+ subentry .data [CONF_OUTPUT_NUMBER ]
175+ for subentry in entry .subentries .values ()
176+ if subentry .subentry_type == SUBENTRY_TYPE_OUTPUT
177+ ]
178+
179+ switchable_outputs = [
180+ subentry .data [CONF_SWITCHABLE_OUTPUT_NUMBER ]
181+ for subentry in entry .subentries .values ()
182+ if subentry .subentry_type == SUBENTRY_TYPE_SWITCHABLE_OUTPUT
183+ ]
184+
185+ monitored_outputs = outputs + switchable_outputs
186+
187+ controller = AsyncSatel (host , port , hass .loop , zones , monitored_outputs , partitions )
113188
114189 result = await controller .connect ()
115190
116191 if not result :
117- return False
192+ raise ConfigEntryNotReady ("Controller failed to connect" )
193+
194+ entry .runtime_data = controller
118195
119196 @callback
120197 def _close (* _ ):
121198 controller .close ()
122199
123- hass .bus .async_listen_once (EVENT_HOMEASSISTANT_STOP , _close )
124-
125- _LOGGER .debug ("Arm home config: %s, mode: %s " , conf , conf .get (CONF_ARM_HOME_MODE ))
200+ entry .async_on_unload (hass .bus .async_listen_once (EVENT_HOMEASSISTANT_STOP , _close ))
126201
127- hass .async_create_task (
128- async_load_platform (hass , Platform .ALARM_CONTROL_PANEL , DOMAIN , conf , config )
129- )
130-
131- hass .async_create_task (
132- async_load_platform (
133- hass ,
134- Platform .BINARY_SENSOR ,
135- DOMAIN ,
136- {CONF_ZONES : zones , CONF_OUTPUTS : outputs },
137- config ,
138- )
139- )
140-
141- hass .async_create_task (
142- async_load_platform (
143- hass ,
144- Platform .SWITCH ,
145- DOMAIN ,
146- {
147- CONF_SWITCHABLE_OUTPUTS : switchable_outputs ,
148- CONF_DEVICE_CODE : conf .get (CONF_DEVICE_CODE ),
149- },
150- config ,
151- )
152- )
202+ await hass .config_entries .async_forward_entry_setups (entry , PLATFORMS )
153203
154204 @callback
155205 def alarm_status_update_callback ():
@@ -179,3 +229,13 @@ def outputs_update_callback(status):
179229 )
180230
181231 return True
232+
233+
234+ async def async_unload_entry (hass : HomeAssistant , entry : SatelConfigEntry ) -> bool :
235+ """Unloading the Satel platforms."""
236+
237+ if unload_ok := await hass .config_entries .async_unload_platforms (entry , PLATFORMS ):
238+ controller = entry .runtime_data
239+ controller .close ()
240+
241+ return unload_ok
0 commit comments