Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Support for Satel Integra devices."""
2 
3 import collections
4 import logging
5 
6 from satel_integra.satel_integra import AsyncSatel
7 import voluptuous as vol
8 
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
13 from homeassistant.helpers.dispatcher import async_dispatcher_send
14 from homeassistant.helpers.typing import ConfigType
15 
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"
21 
22 _LOGGER = logging.getLogger(__name__)
23 
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"
38 
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"
46 
47 ZONE_SCHEMA = vol.Schema(
48  {
49  vol.Required(CONF_ZONE_NAME): cv.string,
50  vol.Optional(CONF_ZONE_TYPE, default=DEFAULT_ZONE_TYPE): cv.string,
51  }
52 )
53 EDITABLE_OUTPUT_SCHEMA = vol.Schema({vol.Required(CONF_ZONE_NAME): cv.string})
54 PARTITION_SCHEMA = vol.Schema(
55  {
56  vol.Required(CONF_ZONE_NAME): cv.string,
57  vol.Optional(CONF_ARM_HOME_MODE, default=DEFAULT_CONF_ARM_HOME_MODE): vol.In(
58  [1, 2, 3]
59  ),
60  }
61 )
62 
63 
65  """Check if alarm code must be configured."""
66  if value.get(CONF_SWITCHABLE_OUTPUTS) and CONF_DEVICE_CODE not in value:
67  raise vol.Invalid("You need to specify alarm code to use switchable_outputs")
68 
69  return value
70 
71 
72 CONFIG_SCHEMA = vol.Schema(
73  {
74  DOMAIN: vol.All(
75  {
76  vol.Required(CONF_HOST): cv.string,
77  vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
78  vol.Optional(CONF_DEVICE_CODE): cv.string,
79  vol.Optional(CONF_DEVICE_PARTITIONS, default={}): {
80  vol.Coerce(int): PARTITION_SCHEMA
81  },
82  vol.Optional(CONF_ZONES, default={}): {vol.Coerce(int): ZONE_SCHEMA},
83  vol.Optional(CONF_OUTPUTS, default={}): {vol.Coerce(int): ZONE_SCHEMA},
84  vol.Optional(CONF_SWITCHABLE_OUTPUTS, default={}): {
85  vol.Coerce(int): EDITABLE_OUTPUT_SCHEMA
86  },
87  },
88  is_alarm_code_necessary,
89  )
90  },
91  extra=vol.ALLOW_EXTRA,
92 )
93 
94 
95 async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
96  """Set up the Satel Integra component."""
97  conf = config[DOMAIN]
98 
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)
105 
106  monitored_outputs = collections.OrderedDict(
107  list(outputs.items()) + list(switchable_outputs.items())
108  )
109 
110  controller = AsyncSatel(host, port, hass.loop, zones, monitored_outputs, partitions)
111 
112  hass.data[DATA_SATEL] = controller
113 
114  result = await controller.connect()
115 
116  if not result:
117  return False
118 
119  @callback
120  def _close(*_):
121  controller.close()
122 
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))
126 
127  hass.async_create_task(
128  async_load_platform(hass, Platform.ALARM_CONTROL_PANEL, DOMAIN, conf, config)
129  )
130 
131  hass.async_create_task(
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(
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  )
153 
154  @callback
155  def alarm_status_update_callback():
156  """Send status update received from alarm to Home Assistant."""
157  _LOGGER.debug("Sending request to update panel state")
158  async_dispatcher_send(hass, SIGNAL_PANEL_MESSAGE)
159 
160  @callback
161  def zones_update_callback(status):
162  """Update zone objects as per notification from the alarm."""
163  _LOGGER.debug("Zones callback, status: %s", status)
164  async_dispatcher_send(hass, SIGNAL_ZONES_UPDATED, status[ZONES])
165 
166  @callback
167  def outputs_update_callback(status):
168  """Update zone objects as per notification from the alarm."""
169  _LOGGER.debug("Outputs updated callback , status: %s", status)
170  async_dispatcher_send(hass, SIGNAL_OUTPUTS_UPDATED, status["outputs"])
171 
172  # Create a task instead of adding a tracking job, since this task will
173  # run until the connection to satel_integra is closed.
174  hass.loop.create_task(controller.keep_alive())
175  hass.loop.create_task(
176  controller.monitor_status(
177  alarm_status_update_callback, zones_update_callback, outputs_update_callback
178  )
179  )
180 
181  return True
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:95
None async_load_platform(core.HomeAssistant hass, Platform|str component, str platform, DiscoveryInfoType|None discovered, ConfigType hass_config)
Definition: discovery.py:152
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)
Definition: dispatcher.py:193