예제 #1
0
def setup(hass, base_config):
    """Common setup for Envisalink devices."""
    from pyenvisalink import EnvisalinkAlarmPanel
    from pydispatch import dispatcher

    global EVL_CONTROLLER

    config = base_config.get(DOMAIN)

    _host = config.get(CONF_EVL_HOST)
    _port = config.get(CONF_EVL_PORT)
    _code = config.get(CONF_CODE)
    _panel_type = config.get(CONF_PANEL_TYPE)
    _panic_type = config.get(CONF_PANIC)
    _version = config.get(CONF_EVL_VERSION)
    _user = config.get(CONF_USERNAME)
    _pass = config.get(CONF_PASS)
    _keep_alive = config.get(CONF_EVL_KEEPALIVE)
    _zone_dump = config.get(CONF_ZONEDUMP_INTERVAL)
    _zones = config.get(CONF_ZONES)
    _partitions = config.get(CONF_PARTITIONS)
    _connect_status = {}
    EVL_CONTROLLER = EnvisalinkAlarmPanel(_host,
                                          _port,
                                          _panel_type,
                                          _version,
                                          _user,
                                          _pass,
                                          _zone_dump,
                                          _keep_alive,
                                          hass.loop)

    def login_fail_callback(data):
        """Callback for when the evl rejects our login."""
        _LOGGER.error("The envisalink rejected your credentials.")
        _connect_status['fail'] = 1

    def connection_fail_callback(data):
        """Network failure callback."""
        _LOGGER.error("Could not establish a connection with the envisalink.")
        _connect_status['fail'] = 1

    def connection_success_callback(data):
        """Callback for a successful connection."""
        _LOGGER.info("Established a connection with the envisalink.")
        _connect_status['success'] = 1

    def zones_updated_callback(data):
        """Handle zone timer updates."""
        _LOGGER.info("Envisalink sent a zone update event.  Updating zones...")
        dispatcher.send(signal=SIGNAL_ZONE_UPDATE,
                        sender=None,
                        zone=data)

    def alarm_data_updated_callback(data):
        """Handle non-alarm based info updates."""
        _LOGGER.info("Envisalink sent new alarm info. Updating alarms...")
        dispatcher.send(signal=SIGNAL_KEYPAD_UPDATE,
                        sender=None,
                        partition=data)

    def partition_updated_callback(data):
        """Handle partition changes thrown by evl (including alarms)."""
        _LOGGER.info("The envisalink sent a partition update event.")
        dispatcher.send(signal=SIGNAL_PARTITION_UPDATE,
                        sender=None,
                        partition=data)

    def stop_envisalink(event):
        """Shutdown envisalink connection and thread on exit."""
        _LOGGER.info("Shutting down envisalink.")
        EVL_CONTROLLER.stop()

    def start_envisalink(event):
        """Startup process for the Envisalink."""
        hass.loop.call_soon_threadsafe(EVL_CONTROLLER.start)
        for _ in range(10):
            if 'success' in _connect_status:
                hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_envisalink)
                return True
            elif 'fail' in _connect_status:
                return False
            else:
                time.sleep(1)

        _LOGGER.error("Timeout occurred while establishing evl connection.")
        return False

    EVL_CONTROLLER.callback_zone_timer_dump = zones_updated_callback
    EVL_CONTROLLER.callback_zone_state_change = zones_updated_callback
    EVL_CONTROLLER.callback_partition_state_change = partition_updated_callback
    EVL_CONTROLLER.callback_keypad_update = alarm_data_updated_callback
    EVL_CONTROLLER.callback_login_failure = login_fail_callback
    EVL_CONTROLLER.callback_login_timeout = connection_fail_callback
    EVL_CONTROLLER.callback_login_success = connection_success_callback

    _result = start_envisalink(None)
    if not _result:
        return False

    # Load sub-components for Envisalink
    if _partitions:
        load_platform(hass, 'alarm_control_panel', 'envisalink',
                      {CONF_PARTITIONS: _partitions,
                       CONF_CODE: _code,
                       CONF_PANIC: _panic_type}, base_config)
        load_platform(hass, 'sensor', 'envisalink',
                      {CONF_PARTITIONS: _partitions,
                       CONF_CODE: _code}, base_config)
    if _zones:
        load_platform(hass, 'binary_sensor', 'envisalink',
                      {CONF_ZONES: _zones}, base_config)

    return True
예제 #2
0
def async_setup(hass, config):
    """Common setup for Envisalink devices."""
    from pyenvisalink import EnvisalinkAlarmPanel

    conf = config.get(DOMAIN)

    host = conf.get(CONF_EVL_HOST)
    port = conf.get(CONF_EVL_PORT)
    code = conf.get(CONF_CODE)
    panel_type = conf.get(CONF_PANEL_TYPE)
    panic_type = conf.get(CONF_PANIC)
    version = conf.get(CONF_EVL_VERSION)
    user = conf.get(CONF_USERNAME)
    password = conf.get(CONF_PASS)
    keep_alive = conf.get(CONF_EVL_KEEPALIVE)
    zone_dump = conf.get(CONF_ZONEDUMP_INTERVAL)
    zones = conf.get(CONF_ZONES)
    partitions = conf.get(CONF_PARTITIONS)
    sync_connect = asyncio.Future(loop=hass.loop)

    controller = EnvisalinkAlarmPanel(
        host, port, panel_type, version, user, password, zone_dump,
        keep_alive, hass.loop)
    hass.data[DATA_EVL] = controller

    @callback
    def login_fail_callback(data):
        """Callback for when the evl rejects our login."""
        _LOGGER.error("The envisalink rejected your credentials.")
        sync_connect.set_result(False)

    @callback
    def connection_fail_callback(data):
        """Network failure callback."""
        _LOGGER.error("Could not establish a connection with the envisalink.")
        sync_connect.set_result(False)

    @callback
    def connection_success_callback(data):
        """Callback for a successful connection."""
        _LOGGER.info("Established a connection with the envisalink.")
        hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_envisalink)
        sync_connect.set_result(True)

    @callback
    def zones_updated_callback(data):
        """Handle zone timer updates."""
        _LOGGER.info("Envisalink sent a zone update event.  Updating zones...")
        async_dispatcher_send(hass, SIGNAL_ZONE_UPDATE, data)

    @callback
    def alarm_data_updated_callback(data):
        """Handle non-alarm based info updates."""
        _LOGGER.info("Envisalink sent new alarm info. Updating alarms...")
        async_dispatcher_send(hass, SIGNAL_KEYPAD_UPDATE, data)

    @callback
    def partition_updated_callback(data):
        """Handle partition changes thrown by evl (including alarms)."""
        _LOGGER.info("The envisalink sent a partition update event.")
        async_dispatcher_send(hass, SIGNAL_PARTITION_UPDATE, data)

    @callback
    def stop_envisalink(event):
        """Shutdown envisalink connection and thread on exit."""
        _LOGGER.info("Shutting down envisalink.")
        controller.stop()

    controller.callback_zone_timer_dump = zones_updated_callback
    controller.callback_zone_state_change = zones_updated_callback
    controller.callback_partition_state_change = partition_updated_callback
    controller.callback_keypad_update = alarm_data_updated_callback
    controller.callback_login_failure = login_fail_callback
    controller.callback_login_timeout = connection_fail_callback
    controller.callback_login_success = connection_success_callback

    _LOGGER.info("Start envisalink.")
    controller.start()

    result = yield from sync_connect
    if not result:
        return False

    # Load sub-components for Envisalink
    if partitions:
        hass.async_add_job(async_load_platform(
            hass, 'alarm_control_panel', 'envisalink', {
                CONF_PARTITIONS: partitions,
                CONF_CODE: code,
                CONF_PANIC: panic_type
            }, config
        ))
        hass.async_add_job(async_load_platform(
            hass, 'sensor', 'envisalink', {
                CONF_PARTITIONS: partitions,
                CONF_CODE: code
            }, config
        ))
    if zones:
        hass.async_add_job(async_load_platform(
            hass, 'binary_sensor', 'envisalink', {
                CONF_ZONES: zones
            }, config
        ))

    return True
예제 #3
0
def async_setup(hass, config):
    """Set up for Envisalink devices."""
    from pyenvisalink import EnvisalinkAlarmPanel

    conf = config.get(DOMAIN)

    host = conf.get(CONF_EVL_HOST)
    port = conf.get(CONF_EVL_PORT)
    code = conf.get(CONF_CODE)
    panel_type = conf.get(CONF_PANEL_TYPE)
    panic_type = conf.get(CONF_PANIC)
    version = conf.get(CONF_EVL_VERSION)
    user = conf.get(CONF_USERNAME)
    password = conf.get(CONF_PASS)
    keep_alive = conf.get(CONF_EVL_KEEPALIVE)
    zone_dump = conf.get(CONF_ZONEDUMP_INTERVAL)
    zones = conf.get(CONF_ZONES)
    partitions = conf.get(CONF_PARTITIONS)
    sync_connect = asyncio.Future(loop=hass.loop)

    controller = EnvisalinkAlarmPanel(host, port, panel_type, version, user,
                                      password, zone_dump, keep_alive,
                                      hass.loop)
    hass.data[DATA_EVL] = controller

    @callback
    def login_fail_callback(data):
        """Handle when the evl rejects our login."""
        _LOGGER.error("The Envisalink rejected your credentials")
        if not sync_connect.done():
            sync_connect.set_result(False)

    @callback
    def connection_fail_callback(data):
        """Network failure callback."""
        _LOGGER.error("Could not establish a connection with the Envisalink")
        if not sync_connect.done():
            sync_connect.set_result(False)

    @callback
    def connection_success_callback(data):
        """Handle a successful connection."""
        _LOGGER.info("Established a connection with the Envisalink")
        if not sync_connect.done():
            hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP,
                                       stop_envisalink)
            sync_connect.set_result(True)

    @callback
    def zones_updated_callback(data):
        """Handle zone timer updates."""
        _LOGGER.info("Envisalink sent a zone update event. Updating zones...")
        async_dispatcher_send(hass, SIGNAL_ZONE_UPDATE, data)

    @callback
    def alarm_data_updated_callback(data):
        """Handle non-alarm based info updates."""
        _LOGGER.info("Envisalink sent new alarm info. Updating alarms...")
        async_dispatcher_send(hass, SIGNAL_KEYPAD_UPDATE, data)

    @callback
    def partition_updated_callback(data):
        """Handle partition changes thrown by evl (including alarms)."""
        _LOGGER.info("The envisalink sent a partition update event")
        async_dispatcher_send(hass, SIGNAL_PARTITION_UPDATE, data)

    @callback
    def stop_envisalink(event):
        """Shutdown envisalink connection and thread on exit."""
        _LOGGER.info("Shutting down Envisalink")
        controller.stop()

    controller.callback_zone_timer_dump = zones_updated_callback
    controller.callback_zone_state_change = zones_updated_callback
    controller.callback_partition_state_change = partition_updated_callback
    controller.callback_keypad_update = alarm_data_updated_callback
    controller.callback_login_failure = login_fail_callback
    controller.callback_login_timeout = connection_fail_callback
    controller.callback_login_success = connection_success_callback

    _LOGGER.info("Start envisalink.")
    controller.start()

    result = yield from sync_connect
    if not result:
        return False

    # Load sub-components for Envisalink
    if partitions:
        hass.async_create_task(
            async_load_platform(
                hass, 'alarm_control_panel', 'envisalink', {
                    CONF_PARTITIONS: partitions,
                    CONF_CODE: code,
                    CONF_PANIC: panic_type
                }, config))
        hass.async_create_task(
            async_load_platform(hass, 'sensor', 'envisalink', {
                CONF_PARTITIONS: partitions,
                CONF_CODE: code
            }, config))
    if zones:
        hass.async_create_task(
            async_load_platform(hass, 'binary_sensor', 'envisalink',
                                {CONF_ZONES: zones}, config))

    return True
예제 #4
0
def setup(hass, base_config):
    """Common setup for Envisalink devices."""
    from pyenvisalink import EnvisalinkAlarmPanel
    from pydispatch import dispatcher

    global EVL_CONTROLLER

    config = base_config.get(DOMAIN)

    _host = config.get(CONF_EVL_HOST)
    _port = config.get(CONF_EVL_PORT)
    _code = config.get(CONF_CODE)
    _panel_type = config.get(CONF_PANEL_TYPE)
    _panic_type = config.get(CONF_PANIC)
    _version = config.get(CONF_EVL_VERSION)
    _user = config.get(CONF_USERNAME)
    _pass = config.get(CONF_PASS)
    _keep_alive = config.get(CONF_EVL_KEEPALIVE)
    _zone_dump = config.get(CONF_ZONEDUMP_INTERVAL)
    _zones = config.get(CONF_ZONES)
    _partitions = config.get(CONF_PARTITIONS)
    _connect_status = {}
    EVL_CONTROLLER = EnvisalinkAlarmPanel(_host, _port, _panel_type, _version,
                                          _user, _pass, _zone_dump,
                                          _keep_alive, hass.loop)

    def login_fail_callback(data):
        """Callback for when the evl rejects our login."""
        _LOGGER.error("The envisalink rejected your credentials.")
        _connect_status['fail'] = 1

    def connection_fail_callback(data):
        """Network failure callback."""
        _LOGGER.error("Could not establish a connection with the envisalink.")
        _connect_status['fail'] = 1

    def connection_success_callback(data):
        """Callback for a successful connection."""
        _LOGGER.info("Established a connection with the envisalink.")
        _connect_status['success'] = 1

    def zones_updated_callback(data):
        """Handle zone timer updates."""
        _LOGGER.info("Envisalink sent a zone update event.  Updating zones...")
        dispatcher.send(signal=SIGNAL_ZONE_UPDATE, sender=None, zone=data)

    def alarm_data_updated_callback(data):
        """Handle non-alarm based info updates."""
        _LOGGER.info("Envisalink sent new alarm info. Updating alarms...")
        dispatcher.send(signal=SIGNAL_KEYPAD_UPDATE,
                        sender=None,
                        partition=data)

    def partition_updated_callback(data):
        """Handle partition changes thrown by evl (including alarms)."""
        _LOGGER.info("The envisalink sent a partition update event.")
        dispatcher.send(signal=SIGNAL_PARTITION_UPDATE,
                        sender=None,
                        partition=data)

    def stop_envisalink(event):
        """Shutdown envisalink connection and thread on exit."""
        _LOGGER.info("Shutting down envisalink.")
        EVL_CONTROLLER.stop()

    def start_envisalink(event):
        """Startup process for the Envisalink."""
        hass.loop.call_soon_threadsafe(EVL_CONTROLLER.start)
        for _ in range(10):
            if 'success' in _connect_status:
                hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_envisalink)
                return True
            elif 'fail' in _connect_status:
                return False
            else:
                time.sleep(1)

        _LOGGER.error("Timeout occurred while establishing evl connection.")
        return False

    EVL_CONTROLLER.callback_zone_timer_dump = zones_updated_callback
    EVL_CONTROLLER.callback_zone_state_change = zones_updated_callback
    EVL_CONTROLLER.callback_partition_state_change = partition_updated_callback
    EVL_CONTROLLER.callback_keypad_update = alarm_data_updated_callback
    EVL_CONTROLLER.callback_login_failure = login_fail_callback
    EVL_CONTROLLER.callback_login_timeout = connection_fail_callback
    EVL_CONTROLLER.callback_login_success = connection_success_callback

    _result = start_envisalink(None)
    if not _result:
        return False

    # Load sub-components for Envisalink
    if _partitions:
        load_platform(
            hass, 'alarm_control_panel', 'envisalink', {
                CONF_PARTITIONS: _partitions,
                CONF_CODE: _code,
                CONF_PANIC: _panic_type
            }, base_config)
        load_platform(hass, 'sensor', 'envisalink', {
            CONF_PARTITIONS: _partitions,
            CONF_CODE: _code
        }, base_config)
    if _zones:
        load_platform(hass, 'binary_sensor', 'envisalink',
                      {CONF_ZONES: _zones}, base_config)

    return True
예제 #5
0
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
    """Set up for Envisalink devices."""
    conf = config[DOMAIN]

    host = conf.get(CONF_HOST)
    port = conf.get(CONF_EVL_PORT)
    code = conf.get(CONF_CODE)
    panel_type = conf.get(CONF_PANEL_TYPE)
    panic_type = conf.get(CONF_PANIC)
    version = conf.get(CONF_EVL_VERSION)
    user = conf.get(CONF_USERNAME)
    password = conf.get(CONF_PASS)
    keep_alive = conf.get(CONF_EVL_KEEPALIVE)
    zone_dump = conf.get(CONF_ZONEDUMP_INTERVAL)
    zones = conf.get(CONF_ZONES)
    partitions = conf.get(CONF_PARTITIONS)
    connection_timeout = conf.get(CONF_TIMEOUT)
    create_zone_bypass_switches = conf.get(CONF_CREATE_ZONE_BYPASS_SWITCHES)
    sync_connect: asyncio.Future[bool] = asyncio.Future()

    controller = EnvisalinkAlarmPanel(
        host,
        port,
        panel_type,
        version,
        user,
        password,
        zone_dump,
        keep_alive,
        hass.loop,
        connection_timeout,
        create_zone_bypass_switches,
    )
    hass.data[DATA_EVL] = controller

    @callback
    def async_login_fail_callback(data):
        """Handle when the evl rejects our login."""
        _LOGGER.error("The Envisalink rejected your credentials")
        if not sync_connect.done():
            sync_connect.set_result(False)

    @callback
    def async_connection_fail_callback(data):
        """Network failure callback."""
        _LOGGER.error(
            "Could not establish a connection with the Envisalink- retrying")
        if not sync_connect.done():
            hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP,
                                       stop_envisalink)
            sync_connect.set_result(True)

    @callback
    def async_connection_success_callback(data):
        """Handle a successful connection."""
        _LOGGER.info("Established a connection with the Envisalink")
        if not sync_connect.done():
            hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP,
                                       stop_envisalink)
            sync_connect.set_result(True)

    @callback
    def async_zones_updated_callback(data):
        """Handle zone timer updates."""
        _LOGGER.debug("Envisalink sent a zone update event. Updating zones")
        async_dispatcher_send(hass, SIGNAL_ZONE_UPDATE, data)

    @callback
    def async_alarm_data_updated_callback(data):
        """Handle non-alarm based info updates."""
        _LOGGER.debug("Envisalink sent new alarm info. Updating alarms")
        async_dispatcher_send(hass, SIGNAL_KEYPAD_UPDATE, data)

    @callback
    def async_partition_updated_callback(data):
        """Handle partition changes thrown by evl (including alarms)."""
        _LOGGER.debug("The envisalink sent a partition update event")
        async_dispatcher_send(hass, SIGNAL_PARTITION_UPDATE, data)

    @callback
    def async_zone_bypass_update(data):
        """Handle zone bypass status updates."""
        _LOGGER.debug(
            "Envisalink sent a zone bypass update event. Updating zones")
        async_dispatcher_send(hass, SIGNAL_ZONE_BYPASS_UPDATE, data)

    @callback
    def stop_envisalink(event):
        """Shutdown envisalink connection and thread on exit."""
        _LOGGER.info("Shutting down Envisalink")
        controller.stop()

    async def handle_custom_function(call: ServiceCall) -> None:
        """Handle custom/PGM service."""
        custom_function = call.data.get(ATTR_CUSTOM_FUNCTION)
        partition = call.data.get(ATTR_PARTITION)
        controller.command_output(code, partition, custom_function)

    controller.callback_zone_timer_dump = async_zones_updated_callback
    controller.callback_zone_state_change = async_zones_updated_callback
    controller.callback_partition_state_change = async_partition_updated_callback
    controller.callback_keypad_update = async_alarm_data_updated_callback
    controller.callback_login_failure = async_login_fail_callback
    controller.callback_login_timeout = async_connection_fail_callback
    controller.callback_login_success = async_connection_success_callback
    controller.callback_zone_bypass_update = async_zone_bypass_update

    _LOGGER.info("Start envisalink")
    controller.start()

    if not await sync_connect:
        return False

    # Load sub-components for Envisalink
    if partitions:
        hass.async_create_task(
            async_load_platform(
                hass,
                Platform.ALARM_CONTROL_PANEL,
                "dscalarm",
                {
                    CONF_PARTITIONS: partitions,
                    CONF_CODE: code,
                    CONF_PANIC: panic_type
                },
                config,
            ))
        hass.async_create_task(
            async_load_platform(
                hass,
                Platform.SENSOR,
                "dscalarm",
                {
                    CONF_PARTITIONS: partitions,
                    CONF_CODE: code
                },
                config,
            ))
    if zones:
        hass.async_create_task(
            async_load_platform(hass, Platform.BINARY_SENSOR, "dscalarm",
                                {CONF_ZONES: zones}, config))

        # Create zone bypass switches only if enabled and only for DSC panels
        if create_zone_bypass_switches and panel_type == PANEL_TYPE_DSC:
            hass.async_create_task(
                async_load_platform(hass, "switch", "dscalarm",
                                    {CONF_ZONES: zones}, config))

    hass.services.async_register(DOMAIN,
                                 SERVICE_CUSTOM_FUNCTION,
                                 handle_custom_function,
                                 schema=SERVICE_SCHEMA)

    return True
예제 #6
0
#!/usr/bin/env python3
import signal
import sys
from pyenvisalink import EnvisalinkAlarmPanel

#This is a test harness for the pyenvisalink library.  It will assist in testing the library against both Honeywell and DSC.

#Get Details from the user...
ip = input("Please input the IP address of your envisalink device: ")
port = input("Please input the port of your envisalink device (4025 is default): ")
version = input("Which envisalink device do you have? Enter 3 for evl3 or 4 for evl4: ")
panel = input("Input DSC if you have a DSC panel, or HONEYWELL if you have a honeywell panel: ")
pw = input("Please input your envisalink password: "******"Config complete. Please press enter now to connect to the envisalink.  When finished, use Ctrl+C to disconnect and exit")
testpanel = EnvisalinkAlarmPanel(ip, int(port), panel, int(version), pw, pw)
testpanel.start()

def signal_handler(signal, frame):
        print('You pressed Ctrl+C!')
        testpanel.stop()
        sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)
signal.pause()
예제 #7
0
from pyenvisalink import EnvisalinkAlarmPanel

#This is a test harness for the pyenvisalink library.  It will assist in testing the library against both Honeywell and DSC.

#Get Details from the user...
ip = input("Please input the IP address of your envisalink device: ")
port = input(
    "Please input the port of your envisalink device (4025 is default): ")
version = input(
    "Which envisalink device do you have? Enter 3 for evl3 or 4 for evl4: ")
panel = input(
    "Input DSC if you have a DSC panel, or HONEYWELL if you have a honeywell panel: "
)
pw = input("Please input your envisalink password: "******"Config complete. Please press enter now to connect to the envisalink.  When finished, use Ctrl+C to disconnect and exit"
)
testpanel = EnvisalinkAlarmPanel(ip, int(port), panel, int(version), pw, pw)
testpanel.start()


def signal_handler(signal, frame):
    print('You pressed Ctrl+C!')
    testpanel.stop()
    sys.exit(0)


signal.signal(signal.SIGINT, signal_handler)
signal.pause()
예제 #8
0
async def async_setup(opp, config):
    """Set up for Envisalink devices."""
    conf = config.get(DOMAIN)

    host = conf.get(CONF_HOST)
    port = conf.get(CONF_EVL_PORT)
    code = conf.get(CONF_CODE)
    panel_type = conf.get(CONF_PANEL_TYPE)
    panic_type = conf.get(CONF_PANIC)
    version = conf.get(CONF_EVL_VERSION)
    user = conf.get(CONF_USERNAME)
    password = conf.get(CONF_PASS)
    keep_alive = conf.get(CONF_EVL_KEEPALIVE)
    zone_dump = conf.get(CONF_ZONEDUMP_INTERVAL)
    zones = conf.get(CONF_ZONES)
    partitions = conf.get(CONF_PARTITIONS)
    connection_timeout = conf.get(CONF_TIMEOUT)
    sync_connect = asyncio.Future()

    controller = EnvisalinkAlarmPanel(
        host,
        port,
        panel_type,
        version,
        user,
        password,
        zone_dump,
        keep_alive,
        opp.loop,
        connection_timeout,
    )
    opp.data[DATA_EVL] = controller

    @callback
    def login_fail_callback(data):
        """Handle when the evl rejects our login."""
        _LOGGER.error("The Envisalink rejected your credentials")
        if not sync_connect.done():
            sync_connect.set_result(False)

    @callback
    def connection_fail_callback(data):
        """Network failure callback."""
        _LOGGER.error("Could not establish a connection with the Envisalink- retrying")
        if not sync_connect.done():
            opp.bus.async_listen_once(EVENT_OPENPEERPOWER_STOP, stop_envisalink)
            sync_connect.set_result(True)

    @callback
    def connection_success_callback(data):
        """Handle a successful connection."""
        _LOGGER.info("Established a connection with the Envisalink")
        if not sync_connect.done():
            opp.bus.async_listen_once(EVENT_OPENPEERPOWER_STOP, stop_envisalink)
            sync_connect.set_result(True)

    @callback
    def zones_updated_callback(data):
        """Handle zone timer updates."""
        _LOGGER.debug("Envisalink sent a zone update event. Updating zones")
        async_dispatcher_send(opp, SIGNAL_ZONE_UPDATE, data)

    @callback
    def alarm_data_updated_callback(data):
        """Handle non-alarm based info updates."""
        _LOGGER.debug("Envisalink sent new alarm info. Updating alarms")
        async_dispatcher_send(opp, SIGNAL_KEYPAD_UPDATE, data)

    @callback
    def partition_updated_callback(data):
        """Handle partition changes thrown by evl (including alarms)."""
        _LOGGER.debug("The envisalink sent a partition update event")
        async_dispatcher_send(opp, SIGNAL_PARTITION_UPDATE, data)

    @callback
    def stop_envisalink(event):
        """Shutdown envisalink connection and thread on exit."""
        _LOGGER.info("Shutting down Envisalink")
        controller.stop()

    async def handle_custom_function(call):
        """Handle custom/PGM service."""
        custom_function = call.data.get(ATTR_CUSTOM_FUNCTION)
        partition = call.data.get(ATTR_PARTITION)
        controller.command_output(code, partition, custom_function)

    controller.callback_zone_timer_dump = zones_updated_callback
    controller.callback_zone_state_change = zones_updated_callback
    controller.callback_partition_state_change = partition_updated_callback
    controller.callback_keypad_update = alarm_data_updated_callback
    controller.callback_login_failure = login_fail_callback
    controller.callback_login_timeout = connection_fail_callback
    controller.callback_login_success = connection_success_callback

    _LOGGER.info("Start envisalink")
    controller.start()

    result = await sync_connect
    if not result:
        return False

    # Load sub-components for Envisalink
    if partitions:
        opp.async_create_task(
            async_load_platform(
                opp,
                "alarm_control_panel",
                "envisalink",
                {CONF_PARTITIONS: partitions, CONF_CODE: code, CONF_PANIC: panic_type},
                config,
            )
        )
        opp.async_create_task(
            async_load_platform(
                opp,
                "sensor",
                "envisalink",
                {CONF_PARTITIONS: partitions, CONF_CODE: code},
                config,
            )
        )
    if zones:
        opp.async_create_task(
            async_load_platform(
                opp, "binary_sensor", "envisalink", {CONF_ZONES: zones}, config
            )
        )

    opp.services.async_register(
        DOMAIN, SERVICE_CUSTOM_FUNCTION, handle_custom_function, schema=SERVICE_SCHEMA
    )

    return True