async def async_step_profile(self, data: dict) -> dict: """Prompt the user to select a user profile.""" errors = {} reauth_profile = (self.context.get(const.PROFILE) if self.context.get("source") == SOURCE_REAUTH else None) profile = data.get(const.PROFILE) or reauth_profile if profile: existing_entries = [ config_entry for config_entry in self._async_current_entries() if slugify( config_entry.data.get(const.PROFILE)) == slugify(profile) ] if reauth_profile or not existing_entries: new_data = { **self._current_data, **data, const.PROFILE: profile } self._current_data = {} return await self.async_step_finish(new_data) errors["base"] = "already_configured" return self.async_show_form( step_id="profile", data_schema=vol.Schema({vol.Required(const.PROFILE): str}), errors=errors, )
def get_devices_with_name(self, name: str) -> [any]: """Get devices by name.""" result = [] name_slug = slugify(name.replace(" ", "", 99)) for device in self.devices.values(): if slugify(device.name.replace(" ", "", 99)) == name_slug: result.append(device) if not result: raise Exception(f"No device with name {name}") return result
def __init__(self, opp, area_name, keypad, button): """Register callback for activity on the button.""" name = f"{keypad.name}: {button.name}" self._opp = opp self._has_release_event = (button.button_type is not None and "RaiseLower" in button.button_type) self._id = slugify(name) self._keypad = keypad self._area_name = area_name self._button_name = button.name self._button = button self._event = "lutron_event" self._full_id = slugify(f"{area_name} {keypad.name}: {button.name}") button.subscribe(self.button_callback, None)
async def async_step_user(self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Handle a flow initialized by the user.""" self._errors = {} if user_input is not None: is_ok = await self._check_location(user_input[CONF_LONGITUDE], user_input[CONF_LATITUDE]) if is_ok: name = slugify(user_input[CONF_NAME]) if not self._name_in_configuration_exists(name): return self.async_create_entry(title=user_input[CONF_NAME], data=user_input) self._errors[CONF_NAME] = "name_exists" else: self._errors["base"] = "wrong_location" # If opp.config has the location set and is a valid coordinate the # default location is set as default values in the form if not smhi_locations( self.opp) and await self._openpeerpower_location_exists(): return await self._show_config_form( name=HOME_LOCATION_NAME, latitude=self.opp.config.latitude, longitude=self.opp.config.longitude, ) return await self._show_config_form()
async def test_load_unload_entry(opp, geofency_client, webhook_id): """Test that the appropriate dispatch signals are added and removed.""" url = f"/api/webhook/{webhook_id}" # Enter the Home zone req = await geofency_client.post(url, data=GPS_ENTER_HOME) await opp.async_block_till_done() assert req.status == HTTP_OK device_name = slugify(GPS_ENTER_HOME["device"]) state_1 = opp.states.get(f"device_tracker.{device_name}") assert state_1.state == STATE_HOME assert len(opp.data[DOMAIN]["devices"]) == 1 entry = opp.config_entries.async_entries(DOMAIN)[0] assert await opp.config_entries.async_unload(entry.entry_id) await opp.async_block_till_done() assert len(opp.data[DOMAIN]["devices"]) == 0 assert await opp.config_entries.async_setup(entry.entry_id) await opp.async_block_till_done() state_2 = opp.states.get(f"device_tracker.{device_name}") assert state_2 is not None assert state_1 is not state_2 assert state_2.state == STATE_HOME assert state_2.attributes[ATTR_LATITUDE] == HOME_LATITUDE assert state_2.attributes[ATTR_LONGITUDE] == HOME_LONGITUDE
async def async_step_user(self, user_input=None): """Step when user initializes a integration.""" self._errors = {} if user_input is not None: name = slugify(user_input[CONF_NAME]) prt = user_input[CONF_PORT] if not self._prt_in_configuration_exists(prt): if self._test_connection(prt): return self._create_device(name, prt) else: self._errors[CONF_PORT] = "already_configured" else: user_input = {} user_input[CONF_NAME] = "" user_input[CONF_PORT] = "" return self.async_show_form( step_id="user", data_schema=vol.Schema( { vol.Required(CONF_NAME, default=user_input[CONF_NAME]): str, vol.Required(CONF_PORT, default=user_input[CONF_PORT]): str, } ), errors=self._errors, )
async def validate_input(data): """Validate the user input allows us to connect. Data has the keys from DATA_SCHEMA with values provided by the user. """ userid = data.get(CONF_USERNAME) password = data.get(CONF_PASSWORD) prefix = data[CONF_PREFIX] url = _make_url_from_data(data) requires_password = url.startswith("elks://") if requires_password and (not userid or not password): raise InvalidAuth elk = elkm1.Elk( {"url": url, "userid": userid, "password": password, "element_list": ["panel"]} ) elk.connect() if not await async_wait_for_elk_to_sync(elk, VALIDATE_TIMEOUT, url): raise InvalidAuth device_name = data[CONF_PREFIX] if data[CONF_PREFIX] else "ElkM1" # Return info that you want to store in the config entry. return {"title": device_name, CONF_HOST: url, CONF_PREFIX: slugify(prefix)}
def _parse_see_args(message, subscribe_topic): """Parse the OwnTracks location parameters, into the format see expects. Async friendly. """ user, device = _parse_topic(message["topic"], subscribe_topic) dev_id = slugify(f"{user}_{device}") kwargs = {"dev_id": dev_id, "host_name": user, "attributes": {}} if message["lat"] is not None and message["lon"] is not None: kwargs["gps"] = (message["lat"], message["lon"]) else: kwargs["gps"] = None if "acc" in message: kwargs["gps_accuracy"] = message["acc"] if "batt" in message: kwargs["battery"] = message["batt"] if "vel" in message: kwargs["attributes"]["velocity"] = message["vel"] if "tid" in message: kwargs["attributes"]["tid"] = message["tid"] if "addr" in message: kwargs["attributes"]["address"] = message["addr"] if "cog" in message: kwargs["attributes"]["course"] = message["cog"] if "bs" in message: kwargs["attributes"]["battery_status"] = message["bs"] if "t" in message: if message["t"] in ("c", "u"): kwargs["source_type"] = SOURCE_TYPE_GPS if message["t"] == "b": kwargs["source_type"] = SOURCE_TYPE_BLUETOOTH_LE return dev_id, kwargs
async def async_handle_waypoint(opp, name_base, waypoint): """Handle a waypoint.""" name = waypoint["desc"] pretty_name = f"{name_base} - {name}" lat = waypoint["lat"] lon = waypoint["lon"] rad = waypoint["rad"] # check zone exists entity_id = zone_comp.ENTITY_ID_FORMAT.format(slugify(pretty_name)) # Check if state already exists if opp.states.get(entity_id) is not None: return zone = zone_comp.Zone.from_yaml( { zone_comp.CONF_NAME: pretty_name, zone_comp.CONF_LATITUDE: lat, zone_comp.CONF_LONGITUDE: lon, zone_comp.CONF_RADIUS: rad, zone_comp.CONF_ICON: zone_comp.ICON_IMPORT, zone_comp.CONF_PASSIVE: False, }, ) zone.opp = opp zone.entity_id = entity_id zone.async_write_op_state()
def __init__(self, tesla_device, coordinator): """Initialise the Tesla device.""" super().__init__(coordinator) self.tesla_device = tesla_device self._name = self.tesla_device.name self._unique_id = slugify(self.tesla_device.uniq_name) self._attributes = self.tesla_device.attrs.copy()
def _update_info(self, now=None) -> None: """Update the device info.""" _LOGGER.debug("Updating devices %s", now) # Update self.devices to collect new devices added # to the users account. self.devices = self.api.get_trackrs() for trackr in self.devices: trackr.update_state() trackr_id = trackr.tracker_id() trackr_device_id = trackr.id() lost = trackr.lost() dev_id = slugify(trackr.name()) if dev_id is None: dev_id = trackr_id location = trackr.last_known_location() lat = location["latitude"] lon = location["longitude"] attrs = { "last_updated": trackr.last_updated(), "last_seen": trackr.last_time_seen(), "trackr_id": trackr_id, "id": trackr_device_id, "lost": lost, "battery_level": trackr.battery_level(), } self.see(dev_id=dev_id, gps=(lat, lon), attributes=attrs)
def play_sound(service: ServiceDataType) -> None: """Play sound on the device.""" account = service.data[ATTR_ACCOUNT] device_name = service.data.get(ATTR_DEVICE_NAME) device_name = slugify(device_name.replace(" ", "", 99)) for device in _get_account(account).get_devices_with_name(device_name): device.play_sound()
def __init__(self, opp, addr, name): """Register callback that will be used for signals.""" self._opp = opp self._addr = addr self._name = name self._id = slugify(self._name) signal = f"homeworks_entity_{self._addr}" async_dispatcher_connect(self._opp, signal, self._update_callback)
def attrs(self): """Return device attributes.""" attr_data = self._wireless_params if self._wireless_params else self._params for attr in ATTR_DEVICE_TRACKER: if attr in attr_data: self._attrs[slugify(attr)] = attr_data[attr] self._attrs["ip_address"] = self._params.get("active-address") return self._attrs
def _parse_update_data(topic, data): """Parse the room presence update.""" parts = topic.split("/") room = parts[-1] device_id = slugify(data.get(ATTR_ID)).upper() distance = data.get("distance") parsed_data = {ATTR_DEVICE_ID: device_id, ATTR_ROOM: room, ATTR_DISTANCE: distance} return parsed_data
def _name_validator(config): """Validate the name.""" config = copy.deepcopy(config) for address, device_config in config[CONF_DEVICES].items(): if CONF_NAME not in device_config: device_config[CONF_NAME] = util.slugify(address) return config
def __init__(self, device, gateway): """Register callback that will be used for signals.""" super().__init__(device, gateway) self._device.register_callback(self.async_update_callback) self.device_id = None self.event_id = slugify(self._device.name) LOGGER.debug("deCONZ event created: %s", self.event_id)
def display_message(service: ServiceDataType) -> None: """Display a message on the device.""" account = service.data[ATTR_ACCOUNT] device_name = service.data.get(ATTR_DEVICE_NAME) device_name = slugify(device_name.replace(" ", "", 99)) message = service.data.get(ATTR_LOST_DEVICE_MESSAGE) sound = service.data.get(ATTR_LOST_DEVICE_SOUND, False) for device in _get_account(account).get_devices_with_name(device_name): device.display_message(message, sound)
def append_keys(self, resource: dict, prefix: str | None = None) -> None: """Properly format key val pairs to append to attributes.""" for attr, val in resource.items(): if val == "" or val is None or attr == "feed_id": continue key = attr if prefix and not key.startswith(prefix): key = f"{prefix} {key}" key = slugify(key) self._attributes[key] = val
def lost_device(service: ServiceDataType) -> None: """Make the device in lost state.""" account = service.data[ATTR_ACCOUNT] device_name = service.data.get(ATTR_DEVICE_NAME) device_name = slugify(device_name.replace(" ", "", 99)) number = service.data.get(ATTR_LOST_DEVICE_NUMBER) message = service.data.get(ATTR_LOST_DEVICE_MESSAGE) for device in _get_account(account).get_devices_with_name(device_name): device.lost_device(number, message)
def _component_to_unique_id(server_id: str, component: str, instance_num: int) -> str: """Convert a component to a unique_id.""" return get_hyperion_unique_id( server_id, instance_num, slugify( f"{TYPE_HYPERION_COMPONENT_SWITCH_BASE} {KEY_COMPONENTID_TO_NAME[component]}" ), )
def __init__(self, vera_scene: veraApi.VeraScene, controller_data: ControllerData) -> None: """Initialize the scene.""" self.vera_scene = vera_scene self.controller = controller_data.controller self._name = self.vera_scene.name # Append device id to prevent name clashes in HA. self.vera_id = VERA_ID_FORMAT.format(slugify(vera_scene.name), vera_scene.scene_id)
async def test_beacon_enter_and_exit_home(opp, geofency_client, webhook_id): """Test iBeacon based zone enter and exit - a.k.a stationary iBeacon.""" url = f"/api/webhook/{webhook_id}" # Enter the Home zone req = await geofency_client.post(url, data=BEACON_ENTER_HOME) await opp.async_block_till_done() assert req.status == HTTP_OK device_name = slugify(f"beacon_{BEACON_ENTER_HOME['name']}") state_name = opp.states.get(f"device_tracker.{device_name}").state assert state_name == STATE_HOME # Exit the Home zone req = await geofency_client.post(url, data=BEACON_EXIT_HOME) await opp.async_block_till_done() assert req.status == HTTP_OK device_name = slugify(f"beacon_{BEACON_ENTER_HOME['name']}") state_name = opp.states.get(f"device_tracker.{device_name}").state assert state_name == STATE_NOT_HOME
async def async_setup(opp, opp_config): """Set up the Geofency component.""" config = opp_config.get(DOMAIN, {}) mobile_beacons = config.get(CONF_MOBILE_BEACONS, []) opp.data[DOMAIN] = { "beacons": [slugify(beacon) for beacon in mobile_beacons], "devices": set(), "unsub_device_tracker": {}, } return True
def generate_id(self, suggestion: str) -> str: """Generate an ID.""" base = slugify(suggestion) proposal = base attempt = 1 while self.has_id(proposal): attempt += 1 proposal = f"{base}_{attempt}" return proposal
async def async_register_services(self) -> None: """Create or update the notify services.""" if hasattr(self, "targets"): stale_targets = set(self.registered_targets) # pylint: disable=no-member for name, target in self.targets.items(): # type: ignore target_name = slugify(f"{self._target_service_name_prefix}_{name}") if target_name in stale_targets: stale_targets.remove(target_name) if ( target_name in self.registered_targets and target == self.registered_targets[target_name] ): continue self.registered_targets[target_name] = target self.opp.services.async_register( DOMAIN, target_name, self._async_notify_message_service, schema=NOTIFY_SERVICE_SCHEMA, ) # Register the service description service_desc = { CONF_NAME: f"Send a notification via {target_name}", CONF_DESCRIPTION: f"Sends a notification message using the {target_name} integration.", CONF_FIELDS: self.services_dict[SERVICE_NOTIFY][CONF_FIELDS], } async_set_service_schema(self.opp, DOMAIN, target_name, service_desc) for stale_target_name in stale_targets: del self.registered_targets[stale_target_name] self.opp.services.async_remove( DOMAIN, stale_target_name, ) if self.opp.services.has_service(DOMAIN, self._service_name): return self.opp.services.async_register( DOMAIN, self._service_name, self._async_notify_message_service, schema=NOTIFY_SERVICE_SCHEMA, ) # Register the service description service_desc = { CONF_NAME: f"Send a notification with {self._service_name}", CONF_DESCRIPTION: f"Sends a notification message using the {self._service_name} service.", CONF_FIELDS: self.services_dict[SERVICE_NOTIFY][CONF_FIELDS], } async_set_service_schema(self.opp, DOMAIN, self._service_name, service_desc)
def url_slug(value: Any) -> str: """Validate value is a valid url slug.""" if value is None: raise vol.Invalid("Slug should not be None") if "-" not in value: raise vol.Invalid("Url path needs to contain a hyphen (-)") str_value = str(value) slg = slugify(str_value, separator="-") if str_value == slg: return str_value raise vol.Invalid(f"invalid slug {value} (try {slg})")
def __init__(self, name, state_topic, device_id, timeout, consider_home): """Initialize the sensor.""" self._state = STATE_NOT_HOME self._name = name self._state_topic = "{}{}".format(state_topic, "/+") self._device_id = slugify(device_id).upper() self._timeout = timeout self._consider_home = (timedelta( seconds=consider_home) if consider_home else None) self._distance = None self._updated = None
async def test_gps_enter_and_exit_home(opp, geofency_client, webhook_id): """Test GPS based zone enter and exit.""" url = f"/api/webhook/{webhook_id}" # Enter the Home zone req = await geofency_client.post(url, data=GPS_ENTER_HOME) await opp.async_block_till_done() assert req.status == HTTP_OK device_name = slugify(GPS_ENTER_HOME["device"]) state_name = opp.states.get(f"device_tracker.{device_name}").state assert state_name == STATE_HOME # Exit the Home zone req = await geofency_client.post(url, data=GPS_EXIT_HOME) await opp.async_block_till_done() assert req.status == HTTP_OK device_name = slugify(GPS_EXIT_HOME["device"]) state_name = opp.states.get(f"device_tracker.{device_name}").state assert state_name == STATE_NOT_HOME # Exit the Home zone with "Send Current Position" enabled data = GPS_EXIT_HOME.copy() data["currentLatitude"] = NOT_HOME_LATITUDE data["currentLongitude"] = NOT_HOME_LONGITUDE req = await geofency_client.post(url, data=data) await opp.async_block_till_done() assert req.status == HTTP_OK device_name = slugify(GPS_EXIT_HOME["device"]) current_latitude = opp.states.get( f"device_tracker.{device_name}").attributes["latitude"] assert current_latitude == NOT_HOME_LATITUDE current_longitude = opp.states.get( f"device_tracker.{device_name}").attributes["longitude"] assert current_longitude == NOT_HOME_LONGITUDE dev_reg = dr.async_get(opp) assert len(dev_reg.devices) == 1 ent_reg = er.async_get(opp) assert len(ent_reg.entities) == 1
async def import_device_data(self): """Import device data from Traccar.""" for device_unique_id in self._api.device_info: device_info = self._api.device_info[device_unique_id] device = None attr = {} skip_accuracy_filter = False attr[ATTR_TRACKER] = "traccar" if device_info.get("address") is not None: attr[ATTR_ADDRESS] = device_info["address"] if device_info.get("geofence") is not None: attr[ATTR_GEOFENCE] = device_info["geofence"] if device_info.get("category") is not None: attr[ATTR_CATEGORY] = device_info["category"] if device_info.get("speed") is not None: attr[ATTR_SPEED] = device_info["speed"] if device_info.get("motion") is not None: attr[ATTR_MOTION] = device_info["motion"] if device_info.get("traccar_id") is not None: attr[ATTR_TRACCAR_ID] = device_info["traccar_id"] for dev in self._api.devices: if dev["id"] == device_info["traccar_id"]: device = dev break if device is not None and device.get("status") is not None: attr[ATTR_STATUS] = device["status"] for custom_attr in self._custom_attributes: if device_info.get(custom_attr) is not None: attr[custom_attr] = device_info[custom_attr] if custom_attr in self._skip_accuracy_on: skip_accuracy_filter = True accuracy = 0.0 if device_info.get("accuracy") is not None: accuracy = device_info["accuracy"] if (not skip_accuracy_filter and self._max_accuracy > 0 and accuracy > self._max_accuracy): _LOGGER.debug( "Excluded position by accuracy filter: %f (%s)", accuracy, attr[ATTR_TRACCAR_ID], ) continue await self._async_see( dev_id=slugify(device_info["device_id"]), gps=(device_info.get("latitude"), device_info.get("longitude")), gps_accuracy=accuracy, battery=device_info.get("battery"), attributes=attr, )