def test_generate_entity_id_given_keys(): """Test generating an entity id given current ids.""" fmt = 'test.{}' assert entity.generate_entity_id( fmt, 'overwrite hidden true', current_ids=[ 'test.overwrite_hidden_true']) == 'test.overwrite_hidden_true_2' assert entity.generate_entity_id( fmt, 'overwrite hidden true', current_ids=[ 'test.another_entity']) == 'test.overwrite_hidden_true'
def test_generate_entity_id_given_keys(self): """Test generating an entity id given current ids.""" fmt = 'test.{}' self.assertEqual( 'test.overwrite_hidden_true_2', entity.generate_entity_id( fmt, 'overwrite hidden true', current_ids=['test.overwrite_hidden_true'])) self.assertEqual( 'test.overwrite_hidden_true', entity.generate_entity_id(fmt, 'overwrite hidden true', current_ids=['test.another_entity']))
def setup(hass, config): """ Setup zone. """ entities = set() for key in extract_domain_configs(config, DOMAIN): entries = config[key] if not isinstance(entries, list): entries = entries, for entry in entries: name = entry.get(CONF_NAME, DEFAULT_NAME) latitude = entry.get(ATTR_LATITUDE) longitude = entry.get(ATTR_LONGITUDE) radius = entry.get(ATTR_RADIUS, DEFAULT_RADIUS) icon = entry.get(ATTR_ICON) passive = entry.get(ATTR_PASSIVE, DEFAULT_PASSIVE) if None in (latitude, longitude): logging.getLogger(__name__).error( 'Each zone needs a latitude and longitude.') continue zone = Zone(hass, name, latitude, longitude, radius, icon, passive) zone.entity_id = generate_entity_id(ENTITY_ID_FORMAT, name, entities) zone.update_ha_state() entities.add(zone.entity_id) if ENTITY_ID_HOME not in entities: zone = Zone(hass, hass.config.location_name, hass.config.latitude, hass.config.longitude, DEFAULT_RADIUS, ICON_HOME, False) zone.entity_id = ENTITY_ID_HOME zone.update_ha_state() return True
def test_generate_entity_id_given_hass(self): """Test generating an entity id given hass object.""" fmt = 'test.{}' self.assertEqual( 'test.overwrite_hidden_true_2', entity.generate_entity_id(fmt, 'overwrite hidden true', hass=self.hass))
def create_service(call): """Handle a create notification service call.""" title = call.data.get(ATTR_TITLE) message = call.data.get(ATTR_MESSAGE) notification_id = call.data.get(ATTR_NOTIFICATION_ID) if notification_id is not None: entity_id = ENTITY_ID_FORMAT.format(slugify(notification_id)) else: entity_id = generate_entity_id(ENTITY_ID_FORMAT, DEFAULT_OBJECT_ID, hass=hass) attr = {} if title is not None: try: title = template.render(hass, title) except TemplateError as ex: _LOGGER.error('Error rendering title %s: %s', title, ex) attr[ATTR_TITLE] = title try: message = template.render(hass, message) except TemplateError as ex: _LOGGER.error('Error rendering message %s: %s', message, ex) hass.states.set(entity_id, message, attr)
def request_config( self, name, callback, description, description_image, submit_caption, fields, link_name, link_url, entity_picture): """Set up a request for configuration.""" entity_id = generate_entity_id(ENTITY_ID_FORMAT, name, hass=self.hass) if fields is None: fields = [] request_id = self._generate_unique_id() self._requests[request_id] = (entity_id, fields, callback) data = { ATTR_CONFIGURE_ID: request_id, ATTR_FIELDS: fields, ATTR_FRIENDLY_NAME: name, ATTR_ENTITY_PICTURE: entity_picture, } data.update({ key: value for key, value in [ (ATTR_DESCRIPTION, description), (ATTR_DESCRIPTION_IMAGE, description_image), (ATTR_SUBMIT_CAPTION, submit_caption), (ATTR_LINK_NAME, link_name), (ATTR_LINK_URL, link_url), ] if value is not None }) self.hass.states.set(entity_id, STATE_CONFIGURE, data) return request_id
def __init__(self, hass, device_id, friendly_name, target_entity, attribute, sensor_class, invert): """Initialize the sensor.""" self._hass = hass self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, device_id, hass=hass) self._name = friendly_name self._target_entity = target_entity self._attribute = attribute self._sensor_class = sensor_class self._invert = invert self._state = None self.from_state = None self.to_state = None self.update() def trend_sensor_state_listener(entity, old_state, new_state): """Called when the target device changes state.""" self.from_state = old_state self.to_state = new_state self.update_ha_state(True) track_state_change(hass, target_entity, trend_sensor_state_listener)
def __init__(self, slug_id, hass, name, host, icon): """initialize the sensor entity""" self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, slug_id, hass=hass) self.hass = hass self._name = name self._host = host self._icon = icon self._state = get_device_status(host)
def __init__(self, hass, scene_data, room_data, pv_instance): """Initialize the scene.""" self.pv_instance = pv_instance self.hass = hass self.scene_data = scene_data self._sync_room_data(room_data) self.entity_id_format = DOMAIN + ".{}" self.entity_id = generate_entity_id(self.entity_id_format, str(self.scene_data["id"]), hass=hass)
def _add_node_to_component(): name = node_name(node) generated_id = generate_entity_id(DOMAIN + '.{}', name, []) node_config = device_config.get(generated_id) if node_config.get(CONF_IGNORED): _LOGGER.info( "Ignoring node entity %s due to device settings", generated_id) return component.add_entities([entity])
def node_added(node): """Handle a new node on the network.""" entity = ZWaveNodeEntity(node, network) name = node_name(node) generated_id = generate_entity_id(DOMAIN + '.{}', name, []) node_config = device_config.get(generated_id) if node_config.get(CONF_IGNORED): _LOGGER.info( "Ignoring node entity %s due to device settings", generated_id) return component.add_entities([entity])
def __init__(self, hass, device_id, friendly_name, state_template, on_action, off_action): """Initialize the Template switch.""" self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, device_id, hass=hass) self.hass = hass self._name = friendly_name self._template = state_template self._on_action = on_action self._off_action = off_action self.update() self.hass.bus.listen(EVENT_STATE_CHANGED, self._event_listener)
def __init__(self, hass, device_id, friendly_name, unit_of_measurement, state_template): """Initialize the sensor.""" self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, device_id, hass=hass) self.hass = hass self._name = friendly_name self._unit_of_measurement = unit_of_measurement self._template = state_template self.update() self.hass.bus.listen(EVENT_STATE_CHANGED, self._event_listener)
def get_calendar_info(hass, calendar): """Convert data from Google into DEVICE_SCHEMA.""" calendar_info = DEVICE_SCHEMA({ CONF_CAL_ID: calendar['id'], CONF_ENTITIES: [{ CONF_TRACK: calendar['track'], CONF_NAME: calendar['summary'], CONF_DEVICE_ID: generate_entity_id( '{}', calendar['summary'], hass=hass), }] }) return calendar_info
def __init__(self, hass, domain, area_name, lutron_device, controller): """Initialize the device.""" self._lutron_device = lutron_device self._controller = controller self._area_name = area_name self.hass = hass object_id = '{} {}'.format(area_name, lutron_device.name) self.entity_id = generate_entity_id(domain + '.{}', object_id, hass=hass) self._controller.subscribe(self._lutron_device, self._update_callback)
def _add_node_to_component(): if hass.data[DATA_DEVICES].get(entity.unique_id): return name = node_name(node) generated_id = generate_entity_id(DOMAIN + '.{}', name, []) node_config = device_config.get(generated_id) if node_config.get(CONF_IGNORED): _LOGGER.info( "Ignoring node entity %s due to device settings", generated_id) return hass.data[DATA_DEVICES][entity.unique_id] = entity component.add_entities([entity])
def __init__(self, hass, device, friendly_name, sensor_class, value_template): self._hass = hass self._device = device self._name = friendly_name self._sensor_class = sensor_class self._template = value_template self._state = None self.entity_id = generate_entity_id( ENTITY_ID_FORMAT, device, hass=hass) _LOGGER.info('Started template sensor %s', device) hass.bus.listen(EVENT_STATE_CHANGED, self._event_listener)
def __init__(self, hass, device_id, friendly_name, unit_of_measurement, state_template): self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, device_id, hass=hass) self.hass = hass self._name = friendly_name self._unit_of_measurement = unit_of_measurement self._template = state_template self.update() def _update_callback(_event): """ Called when the target device changes state. """ self.update_ha_state(True) self.hass.bus.listen(EVENT_STATE_CHANGED, _update_callback)
def add_entity(self, entity): """Add entity to component.""" if entity is None or entity in self.entities.values(): return False entity.hass = self.hass if getattr(entity, 'entity_id', None) is None: entity.entity_id = generate_entity_id( self.entity_id_format, entity.name, self.entities.keys()) self.entities[entity.entity_id] = entity entity.update_ha_state() return True
def __init__(self, hass, device_id, friendly_name, unit_of_measurement, state_template, entity_ids): """Initialize the sensor.""" self.hass = hass self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, device_id, hass=hass) self._name = friendly_name self._unit_of_measurement = unit_of_measurement self._template = state_template self._state = None self.update() def template_sensor_state_listener(entity, old_state, new_state): """Called when the target device changes state.""" self.update_ha_state(True) track_state_change(hass, entity_ids, template_sensor_state_listener)
def add_zone(hass, name, zone, entities=None): """Add a zone from other components.""" _LOGGER.info("Adding new zone %s", name) if entities is None: _entities = set() else: _entities = entities zone.entity_id = generate_entity_id(ENTITY_ID_FORMAT, name, _entities) zone_exists = hass.states.get(zone.entity_id) if zone_exists is None: zone.update_ha_state() _entities.add(zone.entity_id) return zone else: _LOGGER.info("Zone already exists") return zone_exists
def __init__(self, hass, device_id, friendly_name, entity_id, attribute, device_class, invert, max_samples, min_gradient, sample_duration): """Initialize the sensor.""" self._hass = hass self.entity_id = generate_entity_id( ENTITY_ID_FORMAT, device_id, hass=hass) self._name = friendly_name self._entity_id = entity_id self._attribute = attribute self._device_class = device_class self._invert = invert self._sample_duration = sample_duration self._min_gradient = min_gradient self._gradient = None self._state = None self.samples = deque(maxlen=max_samples)
def __init__(self, hass, name, entity_ids=None, user_defined=True, icon=None, view=False, object_id=None): self.hass = hass self._name = name self._state = STATE_UNKNOWN self._order = len(hass.states.entity_ids(DOMAIN)) self._user_defined = user_defined self._icon = icon self._view = view self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, object_id or name, hass=hass) self.tracking = [] self.group_on = None self.group_off = None if entity_ids is not None: self.update_tracked_entity_ids(entity_ids) else: self.update_ha_state(True)
def __init__(self, hass, device, friendly_name, sensor_class, value_template, entity_ids): """Initialize the Template binary sensor.""" self.hass = hass self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, device, hass=hass) self._name = friendly_name self._sensor_class = sensor_class self._template = value_template self._state = None self.update() def template_bsensor_state_listener(entity, old_state, new_state): """Called when the target device changes state.""" self.update_ha_state(True) track_state_change(hass, entity_ids, template_bsensor_state_listener)
def add_entity(self, entity, platform=None): """Add entity to component.""" if entity is None or entity in self.entities.values(): return False entity.hass = self.hass if getattr(entity, "entity_id", None) is None: object_id = entity.name or DEVICE_DEFAULT_NAME if platform is not None and platform.entity_namespace is not None: object_id = "{} {}".format(platform.entity_namespace, object_id) entity.entity_id = generate_entity_id(self.entity_id_format, object_id, self.entities.keys()) self.entities[entity.entity_id] = entity entity.update_ha_state() return True
def __init__(self, hass, device, friendly_name, sensor_class, value_template): """Initialize the Template binary sensor.""" self.hass = hass self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, device, hass=hass) self._name = friendly_name self._sensor_class = sensor_class self._template = value_template self._state = None self.update() def template_bsensor_event_listener(event): """Called when the target device changes state.""" self.update_ha_state(True) hass.bus.listen(EVENT_STATE_CHANGED, template_bsensor_event_listener)
def __init__(self, hass, data): """Create the Calendar Event Device.""" self._name = data.get(CONF_NAME) self.dev_id = data.get(CONF_DEVICE_ID) self._offset = data.get(CONF_OFFSET, DEFAULT_CONF_OFFSET) self.entity_id = generate_entity_id( ENTITY_ID_FORMAT, self.dev_id, hass=hass) self._cal_data = { 'all_day': False, 'offset_time': dt.dt.timedelta(), 'message': '', 'start': None, 'end': None, 'location': '', 'description': '', } self.update()
def __init__(self, hass, device_id, friendly_name, state_template, on_action, off_action, entity_ids): """Initialize the Template switch.""" self.hass = hass self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, device_id, hass=hass) self._name = friendly_name self._template = state_template self._on_script = Script(hass, on_action) self._off_script = Script(hass, off_action) self._state = False self.update() def template_switch_state_listener(entity, old_state, new_state): """Called when the target device changes state.""" self.update_ha_state(True) track_state_change(hass, entity_ids, template_switch_state_listener)
def __init__(self, hass, icloudobject, name, identifier): # pylint: disable=too-many-arguments self.hass = hass self.icloudobject = icloudobject self.devicename = name self.identifier = identifier self._request_interval_seconds = 60 self._interval = 1 self.api = icloudobject.api self._distance = None self._battery = None self._overridestate = None self._devicestatuscode = None self._devicestatus = None self._lowPowerMode = None self._batteryStatus = None self.entity_id = generate_entity_id( ENTITY_ID_FORMAT_DEVICE, self.devicename, hass=self.hass)
def __init__(self, hass, device_id, friendly_name, state_template, on_action, off_action): """Initialize the Template switch.""" self.hass = hass self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, device_id, hass=hass) self._name = friendly_name self._template = state_template self._on_action = on_action self._off_action = off_action self._state = False self.update() def template_switch_event_listener(event): """Called when the target device changes state.""" self.update_ha_state(True) hass.bus.listen(EVENT_STATE_CHANGED, template_switch_event_listener)
def test_generate_entity_id_requires_hass_or_ids(self): """Ensure we require at least hass or current ids.""" fmt = 'test.{}' with self.assertRaises(ValueError): entity.generate_entity_id(fmt, 'hello world')
def _check_entity_ready(self): """Check if all required values are discovered and create entity.""" if self._workaround_ignore: return if self._entity is not None: return for name in self._schema[const.DISC_VALUES]: if self._values[name] is None and not self._schema[ const.DISC_VALUES][name].get(const.DISC_OPTIONAL): return component = self._schema[const.DISC_COMPONENT] workaround_component = workaround.get_device_component_mapping( self.primary) if workaround_component and workaround_component != component: if workaround_component == workaround.WORKAROUND_IGNORE: _LOGGER.info( "Ignoring Node %d Value %d due to workaround.", self.primary.node.node_id, self.primary.value_id, ) # No entity will be created for this value self._workaround_ignore = True return _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component entity_id = self._registry.async_get_entity_id( component, DOMAIN, compute_value_unique_id(self._node, self.primary)) if entity_id is None: value_name = _value_name(self.primary) entity_id = generate_entity_id(component + ".{}", value_name, []) node_config = self._device_config.get(entity_id) # Configure node _LOGGER.debug( "Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s as %s", self._node.node_id, self._node.generic, self._node.specific, self.primary.command_class, self.primary.type, self.primary.genre, component, ) if node_config.get(CONF_IGNORED): _LOGGER.info("Ignoring entity %s due to device settings", entity_id) # No entity will be created for this value self._workaround_ignore = True return polling_intensity = convert(node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: self.primary.enable_poll(polling_intensity) platform = import_module(f".{component}", __name__) device = platform.get_device(node=self._node, values=self, node_config=node_config, hass=self._hass) if device is None: # No entity will be created for this value self._workaround_ignore = True return self._entity = device @callback def _on_ready(sec): _LOGGER.info( "Z-Wave entity %s (node_id: %d) ready after %d seconds", device.name, self._node.node_id, sec, ) self._hass.async_add_job(discover_device, component, device) @callback def _on_timeout(sec): _LOGGER.warning( "Z-Wave entity %s (node_id: %d) not ready after %d seconds, " "continuing anyway", device.name, self._node.node_id, sec, ) self._hass.async_add_job(discover_device, component, device) async def discover_device(component, device): """Put device in a dictionary and call discovery on it.""" if self._hass.data[DATA_DEVICES].get(device.unique_id): return self._hass.data[DATA_DEVICES][device.unique_id] = device if component in SUPPORTED_PLATFORMS: async_dispatcher_send(self._hass, f"zwave_new_{component}", device) else: await discovery.async_load_platform( self._hass, component, DOMAIN, {const.DISCOVERY_DEVICE: device.unique_id}, self._zwave_config, ) if device.unique_id: self._hass.add_job(discover_device, component, device) else: self._hass.add_job(check_has_unique_id, device, _on_ready, _on_timeout)
def create_entity(number): """Create entity helper.""" entity = MockEntity() entity.entity_id = generate_entity_id(DOMAIN + '.{}', 'Number', hass=self.hass) return entity
def __init__(self, hass, username, password, name, ignored_devices, getevents): # pylint: disable=too-many-arguments self.hass = hass self.username = username self.password = password self.accountname = name self._max_wait_seconds = 120 self._request_interval_seconds = 10 self._interval = 1 self.api = None self.devices = {} self.getevents = getevents self.events = {} self.currentevents = {} self.nextevents = {} self._ignored_devices = ignored_devices self._ignored_identifiers = {} self.entity_id = generate_entity_id( ENTITY_ID_FORMAT_ICLOUD, self.accountname, hass=self.hass) if self.username is None or self.password is None: _LOGGER.error('Must specify a username and password') else: try: # Attempt the login to iCloud self.api = PyiCloudService(self.username, self.password, verify=True) for device in self.api.devices: status = device.status(DEVICESTATUSSET) devicename = re.sub(r"(\s|\W|')", '', status['name']).lower() if (devicename not in self.devices and devicename not in self._ignored_devices): idevice = IDevice(self.hass, self, devicename, device) idevice.update_ha_state() self.devices[devicename] = idevice elif devicename in self._ignored_devices: self._ignored_identifiers[devicename] = device if self.getevents: from_dt = dt_util.now() to_dt = from_dt + timedelta(days=7) events = self.api.calendar.events(from_dt, to_dt) new_events = sorted(events.list_of_dict, key=operator.attrgetter('startDate')) starttime = None endtime = None duration = None title = None tz = pytz.utc location = None guid = None for event in new_events: tz = event['tz'] if tz is None: tz = pytz.utc else: tz = timezone(tz) tempnow = dt_util.now(tz) guid = event['guid'] starttime = event['startDate'] startdate = datetime(starttime[1], starttime[2], starttime[3], starttime[4], starttime[5], 0, 0, tz) endtime = event['endDate'] enddate = datetime(endtime[1], endtime[2], endtime[3], endtime[4], endtime[5], 0, 0, tz) duration = event['duration'] title = event['title'] location = event['location'] strnow = tempnow.strftime("%Y%m%d%H%M%S") strstart = startdate.strftime("%Y%m%d%H%M%S") strend = enddate.strftime("%Y%m%d%H%M%S") if strnow > strstart and strend > strnow: ievent = IEvent(self.hass, self, guid, TYPE_CURRENT) ievent.update_ha_state() self.currentevents[guid] = ievent self.currentevents[guid].keep_alive(starttime, endtime, duration, title, tz, location) starttime = None endtime = None duration = None title = None tz = pytz.utc location = None guid = None starttime = None endtime = None duration = None title = None tz = pytz.utc location = None guid = None for event in new_events: tz = event['tz'] if tz is None: tz = pytz.utc else: tz = timezone(tz) tempnow = dt_util.now(tz) guid = event['guid'] starttime = event['startDate'] startdate = datetime(starttime[1], starttime[2], starttime[3], starttime[4], starttime[5], 0, 0, tz) endtime = event['endDate'] enddate = datetime(endtime[1], endtime[2], endtime[3], endtime[4], endtime[5], 0, 0, tz) duration = event['duration'] title = event['title'] location = event['location'] strnow = tempnow.strftime("%Y%m%d%H%M%S") strstart = startdate.strftime("%Y%m%d%H%M%S") strend = enddate.strftime("%Y%m%d%H%M%S") if strnow < strstart: ievent = IEvent(self.hass, self, guid, TYPE_NEXT) ievent.update_ha_state() self.nextevents[guid] = ievent self.nextevents[guid].keep_alive(starttime, endtime, duration, title, tz, location) except PyiCloudFailedLoginException as error: _LOGGER.error('Error logging into iCloud Service: %s', error)
def keep_alive(self): """ Keeps the api alive """ if self.api is None: try: # Attempt the login to iCloud self.api = PyiCloudService(self.username, self.password, verify=True) except PyiCloudFailedLoginException as error: _LOGGER.error('Error logging into iCloud Service: %s', error) if self.api is not None: self.api.authenticate() for devicename in self.devices: self.devices[devicename].keep_alive() if self.getevents: from_dt = dt_util.now() to_dt = from_dt + timedelta(days=7) events = self.api.calendar.events(from_dt, to_dt) new_events = sorted(events.list_of_dict, key=operator.attrgetter('startDate')) starttime = None endtime = None duration = None title = None tz = pytz.utc location = None guid = None for event in new_events: tz = event['tz'] if tz is None: tz = pytz.utc else: tz = timezone(tz) tempnow = dt_util.now(tz) guid = event['guid'] starttime = event['startDate'] startdate = datetime(starttime[1], starttime[2], starttime[3], starttime[4], starttime[5], 0, 0, tz) endtime = event['endDate'] enddate = datetime(endtime[1], endtime[2], endtime[3], endtime[4], endtime[5], 0, 0, tz) duration = event['duration'] title = event['title'] location = event['location'] strnow = tempnow.strftime("%Y%m%d%H%M%S") strstart = startdate.strftime("%Y%m%d%H%M%S") strend = enddate.strftime("%Y%m%d%H%M%S") if strnow > strstart and strend > strnow: if guid not in self.currentevents: ievent = IEvent(self.hass, self, guid, TYPE_CURRENT) ievent.update_ha_state() self.currentevents[guid] = ievent self.currentevents[guid].keep_alive(starttime, endtime, duration, title, tz, location) starttime = None endtime = None duration = None title = None tz = pytz.utc location = None guid = None for addedevent in self.currentevents: found = False eventguid = self.currentevents[addedevent].eventguid for event in new_events: if event['guid'] == eventguid: found = True if not found: ent_id = generate_entity_id(ENTITY_ID_FORMAT_EVENT, eventguid, hass=self.hass) self.hass.states.remove(ent_id) del self.currentevents[addedevent] else: self.currentevents[addedevent].check_alive() starttime = None endtime = None duration = None title = None tz = pytz.utc location = None guid = None for event in new_events: tz = event['tz'] if tz is None: tz = pytz.utc else: tz = timezone(tz) tempnow = dt_util.now(tz) guid = event['guid'] starttime = event['startDate'] startdate = datetime(starttime[1], starttime[2], starttime[3], starttime[4], starttime[5], 0, 0, tz) endtime = event['endDate'] enddate = datetime(endtime[1], endtime[2], endtime[3], endtime[4], endtime[5], 0, 0, tz) duration = event['duration'] title = event['title'] location = event['location'] strnow = tempnow.strftime("%Y%m%d%H%M%S") strstart = startdate.strftime("%Y%m%d%H%M%S") strend = enddate.strftime("%Y%m%d%H%M%S") if strnow < strstart: if guid not in self.nextevents: ievent = IEvent(self.hass, self, guid, TYPE_NEXT) ievent.update_ha_state() self.nextevents[guid] = ievent self.nextevents[guid].keep_alive(starttime, endtime, duration, title, tz, location) for addedevent in self.nextevents: found = False eventguid = self.nextevents[addedevent].eventguid for event in new_events: if event['guid'] == eventguid: found = True if not found: ent_id = generate_entity_id(ENTITY_ID_FORMAT_EVENT, eventguid, hass=self.hass) self.hass.states.remove(ent_id) del self.nextevents[addedevent] else: self.nextevents[addedevent].check_alive()
def test_generate_entity_id_given_hass(self): """Test generating an entity id given hass object.""" fmt = 'test.{}' assert entity.generate_entity_id( fmt, 'overwrite hidden true', hass=self.hass) == 'test.overwrite_hidden_true_2'
async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the google calendar platform.""" calendar_service = hass.data[DOMAIN][config_entry.entry_id][DATA_SERVICE] try: result = await calendar_service.async_list_calendars() except ApiException as err: raise PlatformNotReady(str(err)) from err entity_registry = er.async_get(hass) registry_entries = er.async_entries_for_config_entry( entity_registry, config_entry.entry_id) entity_entry_map = { entity_entry.unique_id: entity_entry for entity_entry in registry_entries } # Yaml configuration may override objects from the API calendars = await hass.async_add_executor_job( load_config, hass.config.path(YAML_DEVICES)) new_calendars = [] entities = [] for calendar_item in result.items: calendar_id = calendar_item.id if calendars and calendar_id in calendars: calendar_info = calendars[calendar_id] else: calendar_info = get_calendar_info( hass, calendar_item.dict(exclude_unset=True)) new_calendars.append(calendar_info) # Yaml calendar config may map one calendar to multiple entities with extra options like # offsets or search criteria. num_entities = len(calendar_info[CONF_ENTITIES]) for data in calendar_info[CONF_ENTITIES]: entity_enabled = data.get(CONF_TRACK, True) if not entity_enabled: _LOGGER.warning( "The 'track' option in google_calendars.yaml has been deprecated. The setting " "has been imported to the UI, and should now be removed from google_calendars.yaml" ) entity_name = data[CONF_DEVICE_ID] # The unique id is based on the config entry and calendar id since multiple accounts # can have a common calendar id (e.g. `en.usa#[email protected]`). # When using google_calendars.yaml with multiple entities for a single calendar, we # have no way to set a unique id. if num_entities > 1: unique_id = None else: unique_id = f"{config_entry.unique_id}-{calendar_id}" # Migrate to new unique_id format which supports multiple config entries as of 2022.7 for old_unique_id in (calendar_id, f"{calendar_id}-{entity_name}"): if not (entity_entry := entity_entry_map.get(old_unique_id)): continue if unique_id: _LOGGER.debug( "Migrating unique_id for %s from %s to %s", entity_entry.entity_id, old_unique_id, unique_id, ) entity_registry.async_update_entity( entity_entry.entity_id, new_unique_id=unique_id) else: _LOGGER.debug( "Removing entity registry entry for %s from %s", entity_entry.entity_id, old_unique_id, ) entity_registry.async_remove(entity_entry.entity_id, ) coordinator = CalendarUpdateCoordinator( hass, calendar_service, data[CONF_NAME], calendar_id, data.get(CONF_SEARCH), ) entities.append( GoogleCalendarEntity( coordinator, calendar_id, data, generate_entity_id(ENTITY_ID_FORMAT, entity_name, hass=hass), unique_id, entity_enabled, ))
def keep_alive(self): """Keep the api alive.""" # pylint: disable=too-many-locals,too-many-branches,too-many-statements if self.api is None: from pyicloud import PyiCloudService from pyicloud.exceptions import PyiCloudFailedLoginException try: # Attempt the login to iCloud self.api = PyiCloudService(self.username, self.password, cookie_directory=self.cookiedir, verify=True) except PyiCloudFailedLoginException as error: _LOGGER.error('Error logging into iCloud Service: %s', error) if self.api is not None: if not self.getevents: self.api.authenticate() for devicename in self.devices: self.devices[devicename].keep_alive() if self.getevents: from_dt = dt_util.now() to_dt = from_dt + timedelta(days=7) events = self.api.calendar.events(from_dt, to_dt) new_events = sorted(events, key=self.get_key) for event in new_events: tzone = event['tz'] if tzone is None: tzone = pytz.utc else: tzone = timezone(tzone) tempnow = dt_util.now(tzone) guid = event['guid'] starttime = event['startDate'] startdate = datetime(starttime[1], starttime[2], starttime[3], starttime[4], starttime[5], 0, 0, tzone) endtime = event['endDate'] enddate = datetime(endtime[1], endtime[2], endtime[3], endtime[4], endtime[5], 0, 0, tzone) duration = event['duration'] title = event['title'] location = event['location'] strnow = tempnow.strftime("%Y%m%d%H%M%S") strstart = startdate.strftime("%Y%m%d%H%M%S") strend = enddate.strftime("%Y%m%d%H%M%S") if strnow > strstart and strend > strnow: if guid not in self.currentevents: ievent = IEvent(self.hass, self, guid, TYPE_CURRENT) ievent.update_ha_state() self.currentevents[guid] = ievent self.currentevents[guid].keep_alive( starttime, endtime, duration, title, tzone, location) for addedevent in self.currentevents: found = False eventguid = self.currentevents[addedevent].eventguid for event in new_events: if event['guid'] == eventguid: found = True if not found: ent_id = generate_entity_id(ENTITY_ID_FORMAT_EVENT, eventguid, hass=self.hass) self.hass.states.remove(ent_id) del self.currentevents[addedevent] else: self.currentevents[addedevent].check_alive() for event in new_events: tzone = event['tz'] if tzone is None: tzone = pytz.utc else: tzone = timezone(tzone) tempnow = dt_util.now(tzone) guid = event['guid'] starttime = event['startDate'] startdate = datetime(starttime[1], starttime[2], starttime[3], starttime[4], starttime[5], 0, 0, tzone) endtime = event['endDate'] enddate = datetime(endtime[1], endtime[2], endtime[3], endtime[4], endtime[5], 0, 0, tzone) duration = event['duration'] title = event['title'] location = event['location'] strnow = tempnow.strftime("%Y%m%d%H%M%S") strstart = startdate.strftime("%Y%m%d%H%M%S") strend = enddate.strftime("%Y%m%d%H%M%S") if strnow < strstart: if guid not in self.nextevents: ievent = IEvent(self.hass, self, guid, TYPE_NEXT) ievent.update_ha_state() self.nextevents[guid] = ievent self.nextevents[guid].keep_alive( starttime, endtime, duration, title, tzone, location) for addedevent in self.nextevents: found = False eventguid = self.nextevents[addedevent].eventguid for event in new_events: if event['guid'] == eventguid: found = True if not found: ent_id = generate_entity_id(ENTITY_ID_FORMAT_EVENT, eventguid, hass=self.hass) self.hass.states.remove(ent_id) del self.nextevents[addedevent] else: self.nextevents[addedevent].check_alive() self._currentevents = 0 self._nextevents = 0 for entity_id in self.hass.states.entity_ids('ievent'): state = self.hass.states.get(entity_id) friendlyname = state.attributes.get(ATTR_FRIENDLY_NAME) if friendlyname == 'nextevent': self._nextevents = self._nextevents + 1 elif friendlyname == 'currentevent': self._currentevents = self._currentevents + 1 self.update_ha_state()
def __init__(self, hass, username, password, cookiedirectory, name, ignored_devices, getevents, googletraveltime): """Initialize an iCloud account.""" # pylint: disable=too-many-arguments,too-many-branches # pylint: disable=too-many-statements,too-many-locals self.hass = hass self.username = username self.password = password self.cookiedir = cookiedirectory self.accountname = name self._max_wait_seconds = 120 self._request_interval_seconds = 10 self._interval = 1 self.api = None self.devices = {} self.getevents = getevents self.events = {} self.currentevents = {} self.nextevents = {} self._ignored_devices = ignored_devices self._ignored_identifiers = {} self.googletraveltime = googletraveltime self._currentevents = 0 self._nextevents = 0 self.entity_id = generate_entity_id(ENTITY_ID_FORMAT_ICLOUD, self.accountname, hass=self.hass) if self.username is None or self.password is None: _LOGGER.error('Must specify a username and password') else: from pyicloud import PyiCloudService from pyicloud.exceptions import PyiCloudFailedLoginException try: # Attempt the login to iCloud self.api = PyiCloudService(self.username, self.password, cookie_directory=self.cookiedir, verify=True) for device in self.api.devices: status = device.status(DEVICESTATUSSET) devicename = slugify(status['name'].replace(' ', '', 99)) if (devicename not in self.devices and devicename not in self._ignored_devices): gtt = None if devicename in self.googletraveltime: gtt = self.googletraveltime[devicename] idevice = IDevice(self.hass, self, devicename, device, gtt) idevice.update_ha_state() self.devices[devicename] = idevice elif devicename in self._ignored_devices: self._ignored_identifiers[devicename] = device if self.getevents: from_dt = dt_util.now() to_dt = from_dt + timedelta(days=7) events = self.api.calendar.events(from_dt, to_dt) new_events = sorted(events, key=self.get_key) for event in new_events: tzone = event['tz'] if tzone is None: tzone = pytz.utc else: tzone = timezone(tzone) tempnow = dt_util.now(tzone) guid = event['guid'] starttime = event['startDate'] startdate = datetime(starttime[1], starttime[2], starttime[3], starttime[4], starttime[5], 0, 0, tzone) endtime = event['endDate'] enddate = datetime(endtime[1], endtime[2], endtime[3], endtime[4], endtime[5], 0, 0, tzone) duration = event['duration'] title = event['title'] location = event['location'] strnow = tempnow.strftime("%Y%m%d%H%M%S") strstart = startdate.strftime("%Y%m%d%H%M%S") strend = enddate.strftime("%Y%m%d%H%M%S") if strnow > strstart and strend > strnow: ievent = IEvent(self.hass, self, guid, TYPE_CURRENT) ievent.update_ha_state() self.currentevents[guid] = ievent self.currentevents[guid].keep_alive( starttime, endtime, duration, title, tzone, location) for event in new_events: tzone = event['tz'] if tzone is None: tzone = pytz.utc else: tzone = timezone(tzone) tempnow = dt_util.now(tzone) guid = event['guid'] starttime = event['startDate'] startdate = datetime(starttime[1], starttime[2], starttime[3], starttime[4], starttime[5], 0, 0, tzone) endtime = event['endDate'] enddate = datetime(endtime[1], endtime[2], endtime[3], endtime[4], endtime[5], 0, 0, tzone) duration = event['duration'] title = event['title'] location = event['location'] strnow = tempnow.strftime("%Y%m%d%H%M%S") strstart = startdate.strftime("%Y%m%d%H%M%S") strend = enddate.strftime("%Y%m%d%H%M%S") if strnow < strstart: ievent = IEvent(self.hass, self, guid, TYPE_NEXT) ievent.update_ha_state() self.nextevents[guid] = ievent self.nextevents[guid].keep_alive( starttime, endtime, duration, title, tzone, location) except PyiCloudFailedLoginException as error: _LOGGER.error('Error logging into iCloud Service: %s', error)
def zone_from_place(place, entity_id=None): zone = Zone(hass, *place, None, DEFAULT_PASSIVE) zone.entity_id = (entity_id or generate_entity_id( ZN_ENTITY_ID_FORMAT, place.name, None, hass)) zone.schedule_update_ha_state() return zone
def test_generate_entity_id_given_hass(self): """Test generating an entity id given hass object.""" fmt = "test.{}" assert (entity.generate_entity_id( fmt, "overwrite hidden true", hass=self.hass) == "test.overwrite_hidden_true_2")
def test_generate_entity_id_with_nonlatin_name(): """Test generate_entity_id given a name containing non-latin characters.""" fmt = 'test.{}' assert entity.generate_entity_id(fmt, 'ホームアシスタント', current_ids=[]) == 'test.unnamed_device'
def create_entity(number): """Create entity helper.""" entity = EntityTest() entity.entity_id = generate_entity_id(component.entity_id_format, 'Number', hass=self.hass) return entity
def test_generate_entity_id_requires_hass_or_ids(): """Ensure we require at least hass or current ids.""" with pytest.raises(ValueError): entity.generate_entity_id("test.{}", "hello world")
def _check_entity_ready(self): """Check if all required values are discovered and create entity.""" if self._workaround_ignore: return if self._entity is not None: return for name in self._schema[const.DISC_VALUES]: if self._values[name] is None and \ not self._schema[const.DISC_VALUES][name].get( const.DISC_OPTIONAL): return component = self._schema[const.DISC_COMPONENT] workaround_component = workaround.get_device_component_mapping( self.primary) if workaround_component and workaround_component != component: if workaround_component == workaround.WORKAROUND_IGNORE: _LOGGER.info("Ignoring Node %d Value %d due to workaround.", self.primary.node.node_id, self.primary.value_id) # No entity will be created for this value self._workaround_ignore = True return _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component value_name = _value_name(self.primary) if self._zwave_config[DOMAIN][CONF_NEW_ENTITY_IDS]: generated_id = generate_entity_id(component + '.{}', value_name, []) else: generated_id = "{}.{}".format(component, object_id(self.primary)) node_config = self._device_config.get(generated_id) # Configure node _LOGGER.debug( "Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s as %s", self._node.node_id, self._node.generic, self._node.specific, self.primary.command_class, self.primary.type, self.primary.genre, component) if node_config.get(CONF_IGNORED): _LOGGER.info("Ignoring entity %s due to device settings", generated_id) # No entity will be created for this value self._workaround_ignore = True return polling_intensity = convert(node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: self.primary.enable_poll(polling_intensity) else: self.primary.disable_poll() platform = get_platform(component, DOMAIN) device = platform.get_device(node=self._node, values=self, node_config=node_config, hass=self._hass) if device is None: # No entity will be created for this value self._workaround_ignore = True return device.old_entity_id = "{}.{}".format(component, object_id(self.primary)) device.new_entity_id = "{}.{}".format(component, slugify(device.name)) if not self._zwave_config[DOMAIN][CONF_NEW_ENTITY_IDS]: device.entity_id = device.old_entity_id self._entity = device dict_id = id(self) @asyncio.coroutine def discover_device(component, device, dict_id): """Put device in a dictionary and call discovery on it.""" self._hass.data[DATA_DEVICES][dict_id] = device yield from discovery.async_load_platform( self._hass, component, DOMAIN, {const.DISCOVERY_DEVICE: dict_id}, self._zwave_config) self._hass.add_job(discover_device, component, device, dict_id)