Exemplo n.º 1
0
    def get_updates(self) -> dict:
        """Fetch data from Yale."""

        if self.yale is None:
            try:
                self.yale = YaleSmartAlarmClient(
                    self.entry.data[CONF_USERNAME],
                    self.entry.data[CONF_PASSWORD])
            except AuthenticationError as error:
                raise ConfigEntryAuthFailed from error
            except (ConnectionError, TimeoutError, UnknownError) as error:
                raise UpdateFailed from error

        try:
            arm_status = self.yale.get_armed_status()
            cycle = self.yale.get_cycle()
            status = self.yale.get_status()
            online = self.yale.get_online()

        except AuthenticationError as error:
            raise ConfigEntryAuthFailed from error
        except (ConnectionError, TimeoutError, UnknownError) as error:
            raise UpdateFailed from error

        return {
            "arm_status": arm_status,
            "cycle": cycle,
            "status": status,
            "online": online,
        }
Exemplo n.º 2
0
    def get_updates(self) -> dict[str, Any]:
        """Fetch data from Yale."""

        if self.yale is None:
            try:
                self.yale = YaleSmartAlarmClient(
                    self.entry.data[CONF_USERNAME],
                    self.entry.data[CONF_PASSWORD])
            except AuthenticationError as error:
                raise ConfigEntryAuthFailed from error
            except YALE_BASE_ERRORS as error:
                raise UpdateFailed from error

        try:
            arm_status = self.yale.get_armed_status()
            data = self.yale.get_all()
            cycle = data["CYCLE"]
            status = data["STATUS"]
            online = data["ONLINE"]
            panel_info = data["PANEL INFO"]

        except AuthenticationError as error:
            raise ConfigEntryAuthFailed from error
        except YALE_BASE_ERRORS as error:
            raise UpdateFailed from error

        return {
            "arm_status": arm_status,
            "cycle": cycle,
            "status": status,
            "online": online,
            "panel_info": panel_info,
        }
Exemplo n.º 3
0
    def get_updates(self) -> dict:
        """Fetch data from Yale."""

        if self.yale is None:
            self.yale = YaleSmartAlarmClient(
                self.entry.data[CONF_USERNAME], self.entry.data[CONF_PASSWORD]
            )

        try:
            arm_status = self.yale.get_armed_status()
            cycle = self.yale.get_cycle()
            status = self.yale.get_status()
            online = self.yale.get_online()

        except AuthenticationError as error:
            LOGGER.error("Authentication failed. Check credentials %s", error)
            self.hass.async_create_task(
                self.hass.config_entries.flow.async_init(
                    DOMAIN,
                    context={"source": SOURCE_REAUTH, "entry_id": self.entry.entry_id},
                    data=self.entry.data,
                )
            )
            raise UpdateFailed from error

        return {
            "arm_status": arm_status,
            "cycle": cycle,
            "status": status,
            "online": online,
        }
Exemplo n.º 4
0
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the alarm platform."""
    name = config[CONF_NAME]
    username = config[CONF_USERNAME]
    password = config[CONF_PASSWORD]
    area_id = config[CONF_AREA_ID]
    additional = config[CONF_ADDITIONAL]

    try:
        client = YaleSmartAlarmClient(username, password, area_id)
    except AuthenticationError:
        _LOGGER.error
        ("Authentication failed. Check credentials")
        return

    object_status = client._get_authenticated(_ENDPOINT_DEVICES_STATUS)

    for object in object_status['data']:
        if (additional):
            add_entities([
                YaleBinarySensor2(hass, client,
                                  object['name'], object['type'].replace(
                                      'device_type.', ''), object)
            ], True)
        elif object['type'] == "device_type.door_contact":
            add_entities([
                YaleBinarySensor2(hass, client,
                                  object['name'], object['type'].replace(
                                      'device_type.', ''), object)
            ], True)
Exemplo n.º 5
0
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the alarm platform."""
    name = config[CONF_NAME]
    username = config[CONF_USERNAME]
    password = config[CONF_PASSWORD]
    area_id = config[CONF_AREA_ID]
    additional = config[CONF_ADDITIONAL]

    try:
        client = YaleSmartAlarmClient(username, password, area_id)
    except:
        _LOGGER.error
        ("Authentication failed. Check credentials")
        return

    object_status = client.get_all_devices()

    for object in object_status:
        if additional:
            add_entities(
                [
                    YaleBinarySensor2(
                        hass,
                        client,
                        object["name"],
                        object["type"].replace("device_type.", ""),
                        object,
                    )
                ],
                True,
            )
        elif (
            object["type"] == "device_type.door_contact"
            or object["type"] == "device_type.door_lock"
        ):
            add_entities(
                [
                    YaleBinarySensor2(
                        hass,
                        client,
                        object["name"],
                        object["type"].replace("device_type.", ""),
                        object,
                    )
                ],
                True,
            )
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the alarm platform."""
    name = config[CONF_NAME]
    username = config[CONF_USERNAME]
    password = config[CONF_PASSWORD]
    area_id = config[CONF_AREA_ID]

    try:
        client = YaleSmartAlarmClient(username, password, area_id)
    except AuthenticationError:
        _LOGGER.error
        ("Authentication failed. Check credentials")
        return

    doors = client.get_doors_status()

    status = client._get_authenticated("/api/panel/device_status/")

    for door in doors:
        add_entities([YaleBinarySensor(hass, client, door, doors)], True)
    def __init__(self,
                 yale_email: str,
                 yale_password: str,
                 arm_schedule: Schedule):
        """
        Constructor
        :param yale_email:
        :param yale_password:
        :param arm_schedule:
        """
        Thread.__init__(self)

        self._schedule = arm_schedule

        self._send_grid_api_key = None
        self._sendgrid_from_email = None
        self._sendgrid_to_email = None

        self._yale_client = YaleSmartAlarmClient(yale_email, yale_password)

        self.__print_log(f"Using Yale account: {yale_email}.")
Exemplo n.º 8
0
def setup_platform(opp, config, add_entities, discovery_info=None):
    """Set up the alarm platform."""
    name = config[CONF_NAME]
    username = config[CONF_USERNAME]
    password = config[CONF_PASSWORD]
    area_id = config[CONF_AREA_ID]

    try:
        client = YaleSmartAlarmClient(username, password, area_id)
    except AuthenticationError:
        _LOGGER.error("Authentication failed. Check credentials")
        return

    add_entities([YaleAlarmDevice(name, client)], True)
Exemplo n.º 9
0
    def get_updates(self) -> dict:
        """Fetch data from Yale."""

        if self.yale is None:
            try:
                self.yale = YaleSmartAlarmClient(
                    self.entry.data[CONF_USERNAME],
                    self.entry.data[CONF_PASSWORD])
            except AuthenticationError as error:
                raise ConfigEntryAuthFailed from error
            except requests.HTTPError as error:
                if error.response.status_code == 401:
                    raise ConfigEntryAuthFailed from error
                raise UpdateFailed from error

        try:
            arm_status = self.yale.get_armed_status()
            cycle = self.yale.get_cycle()
            status = self.yale.get_status()
            online = self.yale.get_online()

        except AuthenticationError as error:
            raise ConfigEntryAuthFailed from error
        except requests.HTTPError as error:
            if error.response.status_code == 401:
                raise ConfigEntryAuthFailed from error
            raise UpdateFailed from error
        except requests.RequestException as error:
            raise UpdateFailed from error

        return {
            "arm_status": arm_status,
            "cycle": cycle,
            "status": status,
            "online": online,
        }
Exemplo n.º 10
0
class YaleDataUpdateCoordinator(DataUpdateCoordinator):
    """A Yale Data Update Coordinator."""
    def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
        """Initialize the Yale hub."""
        self.entry = entry
        self.yale: YaleSmartAlarmClient | None = None
        super().__init__(
            hass,
            LOGGER,
            name=DOMAIN,
            update_interval=timedelta(seconds=DEFAULT_SCAN_INTERVAL),
        )

    async def _async_update_data(self) -> dict[str, Any]:
        """Fetch data from Yale."""

        updates = await self.hass.async_add_executor_job(self.get_updates)

        locks = []
        door_windows = []

        for device in updates["cycle"]["device_status"]:
            state = device["status1"]
            if device["type"] == "device_type.door_lock":
                lock_status_str = device["minigw_lock_status"]
                lock_status = int(str(lock_status_str or 0), 16)
                closed = (lock_status & 16) == 16
                locked = (lock_status & 1) == 1
                if not lock_status and "device_status.lock" in state:
                    device["_state"] = "locked"
                    device["_state2"] = "unknown"
                    locks.append(device)
                    continue
                if not lock_status and "device_status.unlock" in state:
                    device["_state"] = "unlocked"
                    device["_state2"] = "unknown"
                    locks.append(device)
                    continue
                if (lock_status and ("device_status.lock" in state
                                     or "device_status.unlock" in state)
                        and closed and locked):
                    device["_state"] = "locked"
                    device["_state2"] = "closed"
                    locks.append(device)
                    continue
                if (lock_status and ("device_status.lock" in state
                                     or "device_status.unlock" in state)
                        and closed and not locked):
                    device["_state"] = "unlocked"
                    device["_state2"] = "closed"
                    locks.append(device)
                    continue
                if (lock_status and ("device_status.lock" in state
                                     or "device_status.unlock" in state)
                        and not closed):
                    device["_state"] = "unlocked"
                    device["_state2"] = "open"
                    locks.append(device)
                    continue
                device["_state"] = "unavailable"
                locks.append(device)
                continue
            if device["type"] == "device_type.door_contact":
                if "device_status.dc_close" in state:
                    device["_state"] = "closed"
                    door_windows.append(device)
                    continue
                if "device_status.dc_open" in state:
                    device["_state"] = "open"
                    door_windows.append(device)
                    continue
                device["_state"] = "unavailable"
                door_windows.append(device)
                continue

        _sensor_map = {
            contact["address"]: contact["_state"]
            for contact in door_windows
        }
        _lock_map = {lock["address"]: lock["_state"] for lock in locks}

        return {
            "alarm": updates["arm_status"],
            "locks": locks,
            "door_windows": door_windows,
            "status": updates["status"],
            "online": updates["online"],
            "sensor_map": _sensor_map,
            "lock_map": _lock_map,
            "panel_info": updates["panel_info"],
        }

    def get_updates(self) -> dict[str, Any]:
        """Fetch data from Yale."""

        if self.yale is None:
            try:
                self.yale = YaleSmartAlarmClient(
                    self.entry.data[CONF_USERNAME],
                    self.entry.data[CONF_PASSWORD])
            except AuthenticationError as error:
                raise ConfigEntryAuthFailed from error
            except YALE_BASE_ERRORS as error:
                raise UpdateFailed from error

        try:
            arm_status = self.yale.get_armed_status()
            data = self.yale.get_all()
            cycle = data["CYCLE"]
            status = data["STATUS"]
            online = data["ONLINE"]
            panel_info = data["PANEL INFO"]

        except AuthenticationError as error:
            raise ConfigEntryAuthFailed from error
        except YALE_BASE_ERRORS as error:
            raise UpdateFailed from error

        return {
            "arm_status": arm_status,
            "cycle": cycle,
            "status": status,
            "online": online,
            "panel_info": panel_info,
        }
Exemplo n.º 11
0
class YaleAlarmScheduler(Thread):
    def __init__(self,
                 yale_email: str,
                 yale_password: str,
                 arm_schedule: Schedule):
        """
        Constructor
        :param yale_email:
        :param yale_password:
        :param arm_schedule:
        """
        Thread.__init__(self)

        self._schedule = arm_schedule

        self._send_grid_api_key = None
        self._sendgrid_from_email = None
        self._sendgrid_to_email = None

        self._yale_client = YaleSmartAlarmClient(yale_email, yale_password)

        self.__print_log(f"Using Yale account: {yale_email}.")

    def arm(self, partial=True):
        """
        Arm the alarm system and send notification.
        :param partial:
        :return:
        """
        if partial:
            self._yale_client.arm_partial()
        else:
            self._yale_client.arm_full()

        self.__print_log("Alarm has been armed.")

        self.__send_notification("House Alarm Armed",
                                 "yale_alarm_scheduler has armed your house alarm.")

    def is_send_grid_active(self) -> bool:
        """
        Check if Send Grid is properly initialized
        :return:
        """
        return True if self._send_grid_api_key and self._sendgrid_from_email and self._sendgrid_to_email else False

    def disarm(self):
        """
        Disarm the alarm system and send notification.
        :return:
        """
        self._yale_client.disarm()
        self.__print_log("Alarm has been disarmed.")
        self.__send_notification("House Alarm Disarmed",
                                 "yale_alarm_scheduler has disarmed your house alarm.")

    def run(self):
        """
        Working thread that will handle the arming and disarming.
        :return:
        """
        for schedule_time, schedule_mode in self._schedule.items():
            self.__print_log(f"Alarm state will be set to '{schedule_mode}' at '{schedule_time}'.")

            if schedule_mode == 'arm':
                schedule.every().day.at(schedule_time).do(lambda: self.arm(False))
            elif schedule_mode == 'home':
                schedule.every().day.at(schedule_time).do(lambda: self.arm(True))
            elif schedule_mode == 'disarm':
                schedule.every().day.at(schedule_time).do(lambda: self.arm())

        self.__print_log("Ready and waiting.")

        while True:
            schedule.run_pending()
            time.sleep(60)

    @staticmethod
    def __print_log(message):
        """
        Simple function to print a log message.
        :param message:
        :return:
        """
        log = logging.getLogger("yale_alarm_scheduler")
        log.info(message)

    def __send_notification(self, subject, message):
        """
        Send a notification using the SendGrid API.
        :param subject:
        :param message:
        :return:
        """
        if not self.is_send_grid_active():
            return

        mail_message = Mail(
            from_email=self._sendgrid_from_email,
            to_emails=self._sendgrid_to_email,
            subject=subject,
            html_content=message)

        sg = SendGridAPIClient(self._send_grid_api_key)
        sg.send(mail_message)
Exemplo n.º 12
0
class YaleDataUpdateCoordinator(DataUpdateCoordinator):
    """A Yale Data Update Coordinator."""
    def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
        """Initialize the Yale hub."""
        self.entry = entry
        self.yale: YaleSmartAlarmClient | None = None
        super().__init__(
            hass,
            LOGGER,
            name=DOMAIN,
            update_interval=timedelta(seconds=DEFAULT_SCAN_INTERVAL),
        )

    async def _async_update_data(self) -> dict:
        """Fetch data from Yale."""

        updates = await self.hass.async_add_executor_job(self.get_updates)

        locks = []
        door_windows = []

        for device in updates["cycle"]["device_status"]:
            state = device["status1"]
            if device["type"] == "device_type.door_lock":
                lock_status_str = device["minigw_lock_status"]
                lock_status = int(str(lock_status_str or 0), 16)
                jammed = (lock_status & 48) == 48
                closed = (lock_status & 16) == 16
                locked = (lock_status & 1) == 1
                if not lock_status and "device_status.lock" in state:
                    device["_state"] = "locked"
                    device["_state2"] = "unknown"
                    locks.append(device)
                    continue
                if not lock_status and "device_status.unlock" in state:
                    device["_state"] = "unlocked"
                    device["_state2"] = "unknown"
                    locks.append(device)
                    continue
                if (lock_status and ("device_status.lock" in state
                                     or "device_status.unlock" in state)
                        and jammed):
                    device["_state"] = "jammed"
                    device["_state2"] = "closed"
                    locks.append(device)
                    continue
                if (lock_status and ("device_status.lock" in state
                                     or "device_status.unlock" in state)
                        and closed and locked):
                    device["_state"] = "locked"
                    device["_state2"] = "closed"
                    locks.append(device)
                    continue
                if (lock_status and ("device_status.lock" in state
                                     or "device_status.unlock" in state)
                        and closed and not locked):
                    device["_state"] = "unlocked"
                    device["_state2"] = "closed"
                    locks.append(device)
                    continue
                if (lock_status and ("device_status.lock" in state
                                     or "device_status.unlock" in state)
                        and not closed):
                    device["_state"] = "unlocked"
                    device["_state2"] = "open"
                    locks.append(device)
                    continue
                device["_state"] = "unavailable"
                locks.append(device)
                continue
            if device["type"] == "device_type.door_contact":
                if "device_status.dc_close" in state:
                    device["_state"] = "closed"
                    door_windows.append(device)
                    continue
                if "device_status.dc_open" in state:
                    device["_state"] = "open"
                    door_windows.append(device)
                    continue
                device["_state"] = "unavailable"
                door_windows.append(device)
                continue

        return {
            "alarm": updates["arm_status"],
            "locks": locks,
            "door_windows": door_windows,
            "status": updates["status"],
            "online": updates["online"],
        }

    def get_updates(self) -> dict:
        """Fetch data from Yale."""

        if self.yale is None:
            try:
                self.yale = YaleSmartAlarmClient(
                    self.entry.data[CONF_USERNAME],
                    self.entry.data[CONF_PASSWORD])
            except AuthenticationError as error:
                raise ConfigEntryAuthFailed from error
            except requests.HTTPError as error:
                if error.response.status_code == 401:
                    raise ConfigEntryAuthFailed from error
                raise UpdateFailed from error

        try:
            arm_status = self.yale.get_armed_status()
            cycle = self.yale.get_cycle()
            status = self.yale.get_status()
            online = self.yale.get_online()

        except AuthenticationError as error:
            raise ConfigEntryAuthFailed from error
        except requests.HTTPError as error:
            if error.response.status_code == 401:
                raise ConfigEntryAuthFailed from error
            raise UpdateFailed from error
        except requests.RequestException as error:
            raise UpdateFailed from error

        return {
            "arm_status": arm_status,
            "cycle": cycle,
            "status": status,
            "online": online,
        }
Exemplo n.º 13
0
class YaleDataUpdateCoordinator(DataUpdateCoordinator):
    """A Yale Data Update Coordinator."""

    def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
        """Initialize the Yale hub."""
        self.entry = entry
        self.yale: YaleSmartAlarmClient | None = None
        super().__init__(
            hass,
            LOGGER,
            name=DOMAIN,
            update_interval=timedelta(seconds=DEFAULT_SCAN_INTERVAL),
        )

    async def _async_update_data(self) -> dict:
        """Fetch data from Yale."""

        updates = await self.hass.async_add_executor_job(self.get_updates)

        locks = []
        door_windows = []

        for device in updates["cycle"]["device_status"]:
            state = device["status1"]
            if device["type"] == "device_type.door_lock":
                lock_status_str = device["minigw_lock_status"]
                lock_status = int(str(lock_status_str or 0), 16)
                closed = (lock_status & 16) == 16
                locked = (lock_status & 1) == 1
                if not lock_status and "device_status.lock" in state:
                    device["_state"] = "locked"
                    locks.append(device)
                    continue
                if not lock_status and "device_status.unlock" in state:
                    device["_state"] = "unlocked"
                    locks.append(device)
                    continue
                if (
                    lock_status
                    and (
                        "device_status.lock" in state or "device_status.unlock" in state
                    )
                    and closed
                    and locked
                ):
                    device["_state"] = "locked"
                    locks.append(device)
                    continue
                if (
                    lock_status
                    and (
                        "device_status.lock" in state or "device_status.unlock" in state
                    )
                    and closed
                    and not locked
                ):
                    device["_state"] = "unlocked"
                    locks.append(device)
                    continue
                if (
                    lock_status
                    and (
                        "device_status.lock" in state or "device_status.unlock" in state
                    )
                    and not closed
                ):
                    device["_state"] = "unlocked"
                    locks.append(device)
                    continue
                device["_state"] = "unavailable"
                locks.append(device)
                continue
            if device["type"] == "device_type.door_contact":
                if "device_status.dc_close" in state:
                    device["_state"] = "closed"
                    door_windows.append(device)
                    continue
                if "device_status.dc_open" in state:
                    device["_state"] = "open"
                    door_windows.append(device)
                    continue
                device["_state"] = "unavailable"
                door_windows.append(device)
                continue

        return {
            "alarm": updates["arm_status"],
            "locks": locks,
            "door_windows": door_windows,
            "status": updates["status"],
            "online": updates["online"],
        }

    def get_updates(self) -> dict:
        """Fetch data from Yale."""

        if self.yale is None:
            self.yale = YaleSmartAlarmClient(
                self.entry.data[CONF_USERNAME], self.entry.data[CONF_PASSWORD]
            )

        try:
            arm_status = self.yale.get_armed_status()
            cycle = self.yale.get_cycle()
            status = self.yale.get_status()
            online = self.yale.get_online()

        except AuthenticationError as error:
            LOGGER.error("Authentication failed. Check credentials %s", error)
            self.hass.async_create_task(
                self.hass.config_entries.flow.async_init(
                    DOMAIN,
                    context={"source": SOURCE_REAUTH, "entry_id": self.entry.entry_id},
                    data=self.entry.data,
                )
            )
            raise UpdateFailed from error

        return {
            "arm_status": arm_status,
            "cycle": cycle,
            "status": status,
            "online": online,
        }