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, }
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, }
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, }
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)
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}.")
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)
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, }
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, }
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)
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, }
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, }