def __init__(self, device, manufacturer, model, application_listener, keepalive_interval=7200, **kwargs): """Init ZHA endpoint entity.""" self._device_state_attributes = { 'nwk': '0x{0:04x}'.format(device.nwk), 'ieee': str(device.ieee), 'lqi': device.lqi, 'rssi': device.rssi, } ieee = device.ieee ieeetail = ''.join(['%02x' % (o, ) for o in ieee[-4:]]) if manufacturer is not None and model is not None: self._unique_id = "{}_{}_{}".format( slugify(manufacturer), slugify(model), ieeetail, ) self._device_state_attributes['friendly_name'] = "{} {}".format( manufacturer, model, ) else: self._unique_id = str(ieeetail) self._device = device self._state = 'offline' self._keepalive_interval = keepalive_interval application_listener.register_entity(ieee, self)
async def test_gps_enter_and_exit_home(hass, geofency_client): """Test GPS based zone enter and exit.""" # Enter the Home zone req = await geofency_client.post(URL, data=GPS_ENTER_HOME) await hass.async_block_till_done() assert req.status == HTTP_OK device_name = slugify(GPS_ENTER_HOME['device']) state_name = hass.states.get('{}.{}'.format( 'device_tracker', device_name)).state assert STATE_HOME == state_name # Exit the Home zone req = await geofency_client.post(URL, data=GPS_EXIT_HOME) await hass.async_block_till_done() assert req.status == HTTP_OK device_name = slugify(GPS_EXIT_HOME['device']) state_name = hass.states.get('{}.{}'.format( 'device_tracker', device_name)).state assert STATE_NOT_HOME == state_name # 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 hass.async_block_till_done() assert req.status == HTTP_OK device_name = slugify(GPS_EXIT_HOME['device']) current_latitude = hass.states.get('{}.{}'.format( 'device_tracker', device_name)).attributes['latitude'] assert NOT_HOME_LATITUDE == current_latitude current_longitude = hass.states.get('{}.{}'.format( 'device_tracker', device_name)).attributes['longitude'] assert NOT_HOME_LONGITUDE == current_longitude
def _validate_data(data): """Validate POST payload.""" data = data.copy() required_attributes = ['address', 'device', 'entry', 'latitude', 'longitude', 'name'] valid = True for attribute in required_attributes: if attribute not in data: valid = False _LOGGER.error("'%s' not specified in message", attribute) if not valid: return {} data['address'] = data['address'].replace('\n', ' ') data['device'] = slugify(data['device']) data['name'] = slugify(data['name']) gps_attributes = [ATTR_LATITUDE, ATTR_LONGITUDE, ATTR_CURRENT_LATITUDE, ATTR_CURRENT_LONGITUDE] for attribute in gps_attributes: if attribute in data: data[attribute] = float(data[attribute]) return data
def _read_devices(self): """Read and process the device list.""" devices = self._client.devices.list() self._device_map = {} self.fibaro_devices = defaultdict(list) for device in devices: try: if device.roomID == 0: room_name = 'Unknown' else: room_name = self._room_map[device.roomID].name device.friendly_name = room_name + ' ' + device.name device.ha_id = '{}_{}_{}'.format( slugify(room_name), slugify(device.name), device.id) if device.enabled and \ ('isPlugin' not in device or (not device.isPlugin or self._import_plugins)): device.mapped_type = self._map_device_to_type(device) else: device.mapped_type = None if device.mapped_type: self._device_map[device.id] = device self.fibaro_devices[device.mapped_type].append(device) else: _LOGGER.debug("%s (%s, %s) not used", device.ha_id, device.type, device.baseType) except (KeyError, ValueError): pass
def __init__(self, zha_device, channels, keepalive_interval=7200, **kwargs): """Init ZHA endpoint entity.""" ieee = zha_device.ieee ieeetail = ''.join(['%02x' % (o, ) for o in ieee[-4:]]) unique_id = None if zha_device.manufacturer is not None and \ zha_device.model is not None: unique_id = "{}_{}_{}".format( slugify(zha_device.manufacturer), slugify(zha_device.model), ieeetail, ) else: unique_id = str(ieeetail) kwargs['component'] = 'zha' super().__init__(unique_id, zha_device, channels, skip_entity_id=True, **kwargs) self._keepalive_interval = keepalive_interval self._device_state_attributes.update({ 'nwk': '0x{0:04x}'.format(zha_device.nwk), 'ieee': str(zha_device.ieee), 'lqi': zha_device.lqi, 'rssi': zha_device.rssi, }) self._should_poll = True self._battery_channel = self.cluster_channels.get( POWER_CONFIGURATION_CHANNEL)
def __init__(self, endpoint, in_clusters, out_clusters, manufacturer, model, **kwargs): """Init ZHA entity.""" self._device_state_attributes = {} ieeetail = ''.join([ '%02x' % (o, ) for o in endpoint.device.ieee[-4:] ]) if manufacturer and model is not None: self.entity_id = '%s.%s_%s_%s_%s' % ( self._domain, slugify(manufacturer), slugify(model), ieeetail, endpoint.endpoint_id, ) self._device_state_attributes['friendly_name'] = '%s %s' % ( manufacturer, model, ) else: self.entity_id = "%s.zha_%s_%s" % ( self._domain, ieeetail, endpoint.endpoint_id, ) for cluster in in_clusters.values(): cluster.add_listener(self) for cluster in out_clusters.values(): cluster.add_listener(self) self._endpoint = endpoint self._in_clusters = in_clusters self._out_clusters = out_clusters self._state = ha_const.STATE_UNKNOWN
def __init__(self, tahoma_device, controller): """Initialize the device.""" self.tahoma_device = tahoma_device self.controller = controller self._unique_id = TAHOMA_ID_FORMAT.format( slugify(tahoma_device.label), slugify(tahoma_device.url)) self._name = self.tahoma_device.label
def setup(hass, config): """ Sets up the shell_command component. """ conf = config.get(DOMAIN) if not isinstance(conf, dict): _LOGGER.error('Expected configuration to be a dictionary') return False for name in conf.keys(): if name != slugify(name): _LOGGER.error('Invalid service name: %s. Try %s', name, slugify(name)) return False def service_handler(call): """ Execute a shell command service. """ try: subprocess.call(conf[call.service], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except subprocess.SubprocessError: _LOGGER.exception('Error running command') for name in conf.keys(): hass.services.register(DOMAIN, name, service_handler) return True
def __init__(self, node, network, new_entity_ids): """Initialize node.""" # pylint: disable=import-error super().__init__() from openzwave.network import ZWaveNetwork from pydispatch import dispatcher self._network = network self.node = node self.node_id = self.node.node_id self._name = node_name(self.node) self._product_name = node.product_name self._manufacturer_name = node.manufacturer_name self.old_entity_id = "{}.{}_{}".format( DOMAIN, slugify(self._name), self.node_id) self.new_entity_id = "{}.{}".format(DOMAIN, slugify(self._name)) if not new_entity_ids: self.entity_id = self.old_entity_id self._attributes = {} self.wakeup_interval = None self.location = None self.battery_level = None dispatcher.connect( self.network_node_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED) dispatcher.connect(self.network_node_changed, ZWaveNetwork.SIGNAL_NODE) dispatcher.connect( self.network_node_changed, ZWaveNetwork.SIGNAL_NOTIFICATION) dispatcher.connect( self.network_node_event, ZWaveNetwork.SIGNAL_NODE_EVENT) dispatcher.connect( self.network_scene_activated, ZWaveNetwork.SIGNAL_SCENE_EVENT)
def async_see(self, mac: str=None, dev_id: str=None, host_name: str=None, location_name: str=None, gps: GPSType=None, gps_accuracy=None, battery: str=None, attributes: dict=None): """Notify the device tracker that you see a device. This method is a coroutine. """ if mac is None and dev_id is None: raise HomeAssistantError('Neither mac or device id passed in') elif mac is not None: mac = str(mac).upper() device = self.mac_to_dev.get(mac) if not device: dev_id = util.slugify(host_name or '') or util.slugify(mac) else: dev_id = cv.slug(str(dev_id).lower()) device = self.devices.get(dev_id) if device: yield from device.async_seen(host_name, location_name, gps, gps_accuracy, battery, attributes) if device.track: yield from device.async_update_ha_state() return # If no device can be found, create it dev_id = util.ensure_unique_string(dev_id, self.devices.keys()) device = Device( self.hass, self.consider_home, self.track_new, dev_id, mac, (host_name or dev_id).replace('_', ' ')) self.devices[dev_id] = device if mac is not None: self.mac_to_dev[mac] = device yield from device.async_seen(host_name, location_name, gps, gps_accuracy, battery, attributes) if device.track: yield from device.async_update_ha_state() self.hass.bus.async_fire(EVENT_NEW_DEVICE, { ATTR_ENTITY_ID: device.entity_id, ATTR_HOST_NAME: device.host_name, }) # During init, we ignore the group if self.group is not None: yield from self.group.async_update_tracked_entity_ids( list(self.group.tracking) + [device.entity_id]) # lookup mac vendor string to be stored in config yield from device.set_vendor_for_mac() # update known_devices.yaml self.hass.async_add_job( self.async_update_config(self.hass.config.path(YAML_DEVICES), dev_id, device) )
def setup(hass, config): """Setup input select.""" if not isinstance(config.get(DOMAIN), dict): _LOGGER.error('Expected %s config to be a dictionary', DOMAIN) return False component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] for object_id, cfg in config[DOMAIN].items(): if object_id != slugify(object_id): _LOGGER.warning("Found invalid key for boolean input: %s. " "Use %s instead", object_id, slugify(object_id)) continue if not cfg: _LOGGER.warning("No configuration specified for %s", object_id) continue name = cfg.get(CONF_NAME) options = cfg.get(CONF_OPTIONS) if not isinstance(options, list) or len(options) == 0: _LOGGER.warning('Key %s should be a list of options', CONF_OPTIONS) continue options = [str(val) for val in options] state = cfg.get(CONF_INITIAL) if state not in options: state = options[0] icon = cfg.get(CONF_ICON) entities.append(InputSelect(object_id, name, state, options, icon)) if not entities: return False def select_option_service(call): """Handle a calls to the input select services.""" target_inputs = component.extract_from_service(call) for input_select in target_inputs: input_select.select_option(call.data[ATTR_OPTION]) hass.services.register(DOMAIN, SERVICE_SELECT_OPTION, select_option_service, schema=SERVICE_SELECT_OPTION_SCHEMA) component.add_entities(entities) return True
def __init__(self, connection, config, car_vid): """Initialize sensor with car connection.""" self._conn = connection self._name = config.name self._attr = config.attr self._type = config.device_class self._is_on = None self._car_vid = car_vid self.entity_id = ENTITY_ID_FORMAT.format( '{}_{}_{}'.format( MYCHEVY_DOMAIN, slugify(self._car.name), slugify(self._name)))
def __init__(self, client, config): """Initialize the sensor.""" self.client = client self._name = config.friendly_name self._attr = config.field self._state = None self._icon = config.icon self._unit_of_measurement = config.unit_of_measurement # This ensures that the sensors are isolated per waterfurnace unit self.entity_id = ENTITY_ID_FORMAT.format( 'wf_{}_{}'.format(slugify(self.client.unit), slugify(self._attr)))
def setup(hass, config): """Set up input slider.""" if not isinstance(config.get(DOMAIN), dict): _LOGGER.error('Expected %s config to be a dictionary', DOMAIN) return False component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] for object_id, cfg in config[DOMAIN].items(): if object_id != slugify(object_id): _LOGGER.warning("Found invalid key for boolean input: %s. " "Use %s instead", object_id, slugify(object_id)) continue if not cfg: _LOGGER.warning("No configuration specified for %s", object_id) continue name = cfg.get(CONF_NAME) minimum = cfg.get(CONF_MIN) maximum = cfg.get(CONF_MAX) state = cfg.get(CONF_INITIAL) step = cfg.get(CONF_STEP) icon = cfg.get(CONF_ICON) if state < minimum: state = minimum if state > maximum: state = maximum entities.append( InputSlider(object_id, name, state, minimum, maximum, step, icon) ) if not entities: return False def select_value_service(call): """Handle a calls to the input slider services.""" target_inputs = component.extract_from_service(call) for input_slider in target_inputs: input_slider.select_value(call.data[ATTR_VALUE]) hass.services.register(DOMAIN, SERVICE_SELECT_VALUE, select_value_service, schema=SERVICE_SELECT_VALUE_SCHEMA) component.add_entities(entities) return True
def setup(hass, config): """ Load the scripts from the configuration. """ component = EntityComponent(_LOGGER, DOMAIN, hass) def service_handler(service): """ Execute a service call to script.<script name>. """ entity_id = ENTITY_ID_FORMAT.format(service.service) script = component.entities.get(entity_id) if not script: return if script.is_on: _LOGGER.warning("Script %s already running.", entity_id) return script.turn_on() for object_id, cfg in config[DOMAIN].items(): if object_id != slugify(object_id): _LOGGER.warning("Found invalid key for script: %s. Use %s instead", object_id, slugify(object_id)) continue if not isinstance(cfg.get(CONF_SEQUENCE), list): _LOGGER.warning("Key 'sequence' for script %s should be a list", object_id) continue alias = cfg.get(CONF_ALIAS, object_id) script = Script(object_id, alias, cfg[CONF_SEQUENCE]) component.add_entities((script,)) hass.services.register(DOMAIN, object_id, service_handler) def turn_on_service(service): """ Calls a service to turn script on. """ # We could turn on script directly here, but we only want to offer # one way to do it. Otherwise no easy way to call invocations. for script in component.extract_from_service(service): turn_on(hass, script.entity_id) def turn_off_service(service): """ Cancels a script. """ for script in component.extract_from_service(service): script.turn_off() def toggle_service(service): """ Toggles a script. """ for script in component.extract_from_service(service): script.toggle() hass.services.register(DOMAIN, SERVICE_TURN_ON, turn_on_service) hass.services.register(DOMAIN, SERVICE_TURN_OFF, turn_off_service) hass.services.register(DOMAIN, SERVICE_TOGGLE, toggle_service) return True
def __init__(self, connection, config, car_vid): """Initialize sensor with car connection.""" self._conn = connection self._name = config.name self._attr = config.attr self._unit_of_measurement = config.unit_of_measurement self._icon = config.icon self._state = None self._car_vid = car_vid self.entity_id = ENTITY_ID_FORMAT.format( '{}_{}_{}'.format(MYCHEVY_DOMAIN, slugify(self._car.name), slugify(self._name)))
def setup_platform(hass, config, add_devices, discovery_info=None): """Setup template binary sensors.""" sensors = [] if config.get(CONF_SENSORS) is None: _LOGGER.error('Missing configuration data for binary_sensor platform') return False for device, device_config in config[CONF_SENSORS].items(): if device != slugify(device): _LOGGER.error('Found invalid key for binary_sensor.template: %s. ' 'Use %s instead', device, slugify(device)) continue if not isinstance(device_config, dict): _LOGGER.error('Missing configuration data for binary_sensor %s', device) continue friendly_name = device_config.get(ATTR_FRIENDLY_NAME, device) sensor_class = device_config.get('sensor_class') value_template = device_config.get(CONF_VALUE_TEMPLATE) if sensor_class not in SENSOR_CLASSES: _LOGGER.error('Sensor class is not valid') continue if value_template is None: _LOGGER.error( 'Missing %s for sensor %s', CONF_VALUE_TEMPLATE, device) continue entity_ids = device_config.get(ATTR_ENTITY_ID, MATCH_ALL) sensors.append( BinarySensorTemplate( hass, device, friendly_name, sensor_class, value_template, entity_ids) ) if not sensors: _LOGGER.error('No sensors added') return False add_devices(sensors) return True
def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Template switch.""" switches = [] if config.get(CONF_SWITCHES) is None: _LOGGER.error("Missing configuration data for switch platform") return False for device, device_config in config[CONF_SWITCHES].items(): if device != slugify(device): _LOGGER.error("Found invalid key for switch.template: %s. " "Use %s instead", device, slugify(device)) continue if not isinstance(device_config, dict): _LOGGER.error("Missing configuration data for switch %s", device) continue friendly_name = device_config.get(ATTR_FRIENDLY_NAME, device) state_template = device_config.get(CONF_VALUE_TEMPLATE) on_action = device_config.get(ON_ACTION) off_action = device_config.get(OFF_ACTION) if state_template is None: _LOGGER.error( "Missing %s for switch %s", CONF_VALUE_TEMPLATE, device) continue if on_action is None or off_action is None: _LOGGER.error( "Missing action for switch %s", device) continue entity_ids = device_config.get(ATTR_ENTITY_ID, MATCH_ALL) switches.append( SwitchTemplate( hass, device, friendly_name, state_template, on_action, off_action, entity_ids) ) if not switches: _LOGGER.error("No switches added") return False add_devices(switches) return True
def _read_devices(self): """Read and process the device list.""" devices = self._client.devices.list() self._device_map = {} self.fibaro_devices = defaultdict(list) last_climate_parent = None for device in devices: try: device.fibaro_controller = self if device.roomID == 0: room_name = 'Unknown' else: room_name = self._room_map[device.roomID].name device.room_name = room_name device.friendly_name = room_name + ' ' + device.name device.ha_id = '{}_{}_{}'.format( slugify(room_name), slugify(device.name), device.id) if device.enabled and \ ('isPlugin' not in device or (not device.isPlugin or self._import_plugins)) and \ device.ha_id not in self._excluded_devices: device.mapped_type = self._map_device_to_type(device) device.device_config = \ self._device_config.get(device.ha_id, {}) else: device.mapped_type = None dtype = device.mapped_type if dtype: device.unique_id_str = "{}.{}".format( self.hub_serial, device.id) self._device_map[device.id] = device if dtype != 'climate': self.fibaro_devices[dtype].append(device) else: # if a sibling of this has been added, skip this one # otherwise add the first visible device in the group # which is a hack, but solves a problem with FGT having # hidden compatibility devices before the real device if last_climate_parent != device.parentId and \ device.visible: self.fibaro_devices[dtype].append(device) last_climate_parent = device.parentId _LOGGER.debug("%s (%s, %s) -> %s %s", device.ha_id, device.type, device.baseType, dtype, str(device)) except (KeyError, ValueError): pass
async def async_update(self, now=None): """Ensure the information from Google Home is up to date.""" _LOGGER.debug('Checking Devices on %s', self.host) await self.client.update_bluetooth(self.host) data = self.hass.data[GOOGLEHOME_DOMAIN][self.host] info = data.get('info') bluetooth = data.get('bluetooth') if info is None or bluetooth is None: return google_home_name = info.get('name', NAME) for device in bluetooth: if (device['device_type'] not in self.device_types or device['rssi'] < self.rssi): continue name = "{} {}".format(self.host, device['mac_address']) attributes = {} attributes['btle_mac_address'] = device['mac_address'] attributes['ghname'] = google_home_name attributes['rssi'] = device['rssi'] attributes['source_type'] = 'bluetooth' if device['name']: attributes['name'] = device['name'] await self.async_see(dev_id=slugify(name), attributes=attributes)
def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Harmony platform.""" import pyharmony global DEVICES name = config.get(CONF_NAME) host = config.get(CONF_HOST) port = config.get(CONF_PORT) _LOGGER.debug("Loading Harmony platform: %s", name) harmony_conf_file = hass.config.path( '{}{}{}'.format('harmony_', slugify(name), '.conf')) try: _LOGGER.debug("Calling pyharmony.ha_get_token for remote at: %s:%s", host, port) token = urllib.parse.quote_plus(pyharmony.ha_get_token(host, port)) except ValueError as err: _LOGGER.warning("%s for remote: %s", err.args[0], name) return False _LOGGER.debug("Received token: %s", token) DEVICES = [HarmonyRemote( config.get(CONF_NAME), config.get(CONF_HOST), config.get(CONF_PORT), config.get(ATTR_ACTIVITY), harmony_conf_file, token)] add_devices(DEVICES, True) register_services(hass) return True
async def _set_location(device, gps_location, location_name): """Fire HA event to set location.""" await async_see( dev_id=slugify(device), gps=gps_location, location_name=location_name )
def async_owntracks_waypoint_update(topic, payload, qos): """List of waypoints published by a user.""" # Docs on available data: # http://owntracks.org/booklet/tech/json/#_typewaypoints data = validate_payload(topic, payload, VALIDATE_WAYPOINTS) if not data: return wayps = data['waypoints'] _LOGGER.info("Got %d waypoints from %s", len(wayps), topic) for wayp in wayps: name = wayp['desc'] pretty_name = parse_topic(topic, True)[1] + ' - ' + name lat = wayp[WAYPOINT_LAT_KEY] lon = wayp[WAYPOINT_LON_KEY] rad = wayp['rad'] # check zone exists entity_id = zone_comp.ENTITY_ID_FORMAT.format(slugify(pretty_name)) # Check if state already exists if hass.states.get(entity_id) is not None: continue zone = zone_comp.Zone(hass, pretty_name, lat, lon, rad, zone_comp.ICON_IMPORT, False) zone.entity_id = entity_id hass.async_add_job(zone.async_update_ha_state())
def test_scan_devices(self): """Test creating device info (MAC, name) from response. The created known_devices.yaml device info is compared to the DD-WRT Lan Status request response fixture. This effectively checks the data parsing functions. """ with requests_mock.Mocker() as mock_request: mock_request.register_uri( 'GET', r'http://%s/Status_Wireless.live.asp' % TEST_HOST, text=load_fixture('Ddwrt_Status_Wireless.txt')) mock_request.register_uri( 'GET', r'http://%s/Status_Lan.live.asp' % TEST_HOST, text=load_fixture('Ddwrt_Status_Lan.txt')) with assert_setup_component(1): assert setup_component( self.hass, DOMAIN, {DOMAIN: { CONF_PLATFORM: 'ddwrt', CONF_HOST: TEST_HOST, CONF_USERNAME: '******', CONF_PASSWORD: '******' }}) self.hass.block_till_done() path = self.hass.config.path(device_tracker.YAML_DEVICES) devices = config.load_yaml_config_file(path) for device in devices: self.assertIn( devices[device]['mac'], load_fixture('Ddwrt_Status_Lan.txt')) self.assertIn( slugify(devices[device]['name']), load_fixture('Ddwrt_Status_Lan.txt'))
async def async_step_init(self, user_input=None): """Handle a flow start.""" errors = {} if user_input is not None: name = slugify(user_input[CONF_NAME]) if name not in configured_zones(self.hass) and name != HOME_ZONE: return self.async_create_entry( title=user_input[CONF_NAME], data=user_input, ) errors['base'] = 'name_exists' return self.async_show_form( step_id='init', data_schema=vol.Schema({ vol.Required(CONF_NAME): str, vol.Required(CONF_LATITUDE): cv.latitude, vol.Required(CONF_LONGITUDE): cv.longitude, vol.Optional(CONF_RADIUS): vol.Coerce(float), vol.Optional(CONF_ICON): str, vol.Optional(CONF_PASSIVE): bool, }), errors=errors, )
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('{}_{}'.format(user, device)) kwargs = { 'dev_id': dev_id, 'host_name': user, 'gps': (message['lat'], message['lon']), 'attributes': {} } 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 't' in message: if message['t'] == 'c': kwargs['attributes'][ATTR_SOURCE_TYPE] = SOURCE_TYPE_GPS if message['t'] == 'b': kwargs['attributes'][ATTR_SOURCE_TYPE] = SOURCE_TYPE_BLUETOOTH_LE return dev_id, kwargs
async def _async_transition_message_leave(hass, context, message, location): """Execute leave event.""" dev_id, kwargs = _parse_see_args(message, context.mqtt_topic) regions = context.regions_entered[dev_id] if location in regions: regions.remove(location) beacons = context.mobile_beacons_active[dev_id] if location in beacons: beacons.remove(location) _LOGGER.info("Remove beacon %s", location) await context.async_see_beacons(hass, dev_id, kwargs) else: new_region = regions[-1] if regions else None if new_region: # Exit to previous region zone = hass.states.get( "zone.{}".format(slugify(new_region))) _set_gps_from_zone(kwargs, new_region, zone) _LOGGER.info("Exit to %s", new_region) await context.async_see(**kwargs) await context.async_see_beacons(hass, dev_id, kwargs) return _LOGGER.info("Exit to GPS") # Check for GPS accuracy if context.async_valid_accuracy(message): await context.async_see(**kwargs) await context.async_see_beacons(hass, dev_id, kwargs)
def _update_light_state(light_id, light_state): """ Update statemachine based on the LightState passed in. """ name = light_control.get_name(light_id) or "Unknown Light" try: entity_id = light_to_ent[light_id] except KeyError: # We have not seen this light before, set it up # Create entity id logger.info("Found new light {}".format(name)) entity_id = util.ensure_unique_string( ENTITY_ID_FORMAT.format(util.slugify(name)), list(ent_to_light.keys())) ent_to_light[entity_id] = light_id light_to_ent[light_id] = entity_id state_attr = {ATTR_FRIENDLY_NAME: name} if light_state.on: state = STATE_ON if light_state.brightness: state_attr[ATTR_BRIGHTNESS] = light_state.brightness if light_state.color: state_attr[ATTR_XY_COLOR] = light_state.color else: state = STATE_OFF hass.states.set(entity_id, state, state_attr)
def valid_entity_id(entity_id: str) -> bool: """Test if an entity ID is a valid format. Format: <domain>.<entity> where both are slugs. """ return ('.' in entity_id and slugify(entity_id) == entity_id.replace('.', '_', 1))
async def async_unload_entry(hass, config_entry): """Unload a config entry.""" zones = hass.data[DOMAIN] name = slugify(config_entry.data[CONF_NAME]) zone = zones.pop(name) await zone.async_remove() return True
async def async_see( self, mac: str = None, dev_id: str = None, host_name: str = None, location_name: str = None, gps: GPSType = None, gps_accuracy: int = None, battery: int = None, attributes: dict = None, source_type: str = SOURCE_TYPE_GPS, picture: str = None, icon: str = None, consider_home: timedelta = None, ): """Notify the device tracker that you see a device. This method is a coroutine. """ registry = await async_get_registry(self.hass) if mac is None and dev_id is None: raise HomeAssistantError("Neither mac or device id passed in") if mac is not None: mac = str(mac).upper() device = self.mac_to_dev.get(mac) if not device: dev_id = util.slugify(host_name or "") or util.slugify(mac) else: dev_id = cv.slug(str(dev_id).lower()) device = self.devices.get(dev_id) if device: await device.async_seen( host_name, location_name, gps, gps_accuracy, battery, attributes, source_type, consider_home, ) if device.track: await device.async_update_ha_state() return # Guard from calling see on entity registry entities. entity_id = f"{DOMAIN}.{dev_id}" if registry.async_is_registered(entity_id): LOGGER.error("The see service is not supported for this entity %s", entity_id) return # If no device can be found, create it dev_id = util.ensure_unique_string(dev_id, self.devices.keys()) device = Device( self.hass, consider_home or self.consider_home, self.track_new, dev_id, mac, picture=picture, icon=icon, ) self.devices[dev_id] = device if mac is not None: self.mac_to_dev[mac] = device await device.async_seen( host_name, location_name, gps, gps_accuracy, battery, attributes, source_type, ) if device.track: await device.async_update_ha_state() self.hass.bus.async_fire( EVENT_NEW_DEVICE, { ATTR_ENTITY_ID: device.entity_id, ATTR_HOST_NAME: device.host_name, ATTR_MAC: device.mac, }, ) # update known_devices.yaml self.hass.async_create_task( self.async_update_config(self.hass.config.path(YAML_DEVICES), dev_id, device))
def component_to_switch_type(component: str) -> str: """Convert a component to a switch type string.""" return slugify( f"{TYPE_HYPERION_COMPONENT_SWITCH_BASE} {COMPONENT_TO_NAME[component]}" )
def device_state_attributes(self): """Return the state attributes of the battery.""" attr = { ATTR_EVENT_ID: slugify(self._device.name), } return attr
def setup(hass, config): """Setup the notify services.""" success = False descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) targets = {} for platform, p_config in config_per_platform(config, DOMAIN): notify_implementation = bootstrap.prepare_setup_platform( hass, config, DOMAIN, platform) if notify_implementation is None: _LOGGER.error("Unknown notification service specified.") continue notify_service = notify_implementation.get_service(hass, p_config) if notify_service is None: _LOGGER.error("Failed to initialize notification service %s", platform) continue def notify_message(notify_service, call): """Handle sending notification message service calls.""" kwargs = {} message = call.data[ATTR_MESSAGE] title = call.data.get(ATTR_TITLE) if title: title.hass = hass kwargs[ATTR_TITLE] = title.render() if targets.get(call.service) is not None: kwargs[ATTR_TARGET] = [targets[call.service]] else: kwargs[ATTR_TARGET] = call.data.get(ATTR_TARGET) message.hass = hass kwargs[ATTR_MESSAGE] = message.render() kwargs[ATTR_DATA] = call.data.get(ATTR_DATA) notify_service.send_message(**kwargs) service_call_handler = partial(notify_message, notify_service) if hasattr(notify_service, 'targets'): platform_name = (p_config.get(CONF_NAME) or platform) for name, target in notify_service.targets.items(): target_name = slugify("{}_{}".format(platform_name, name)) targets[target_name] = target hass.services.register(DOMAIN, target_name, service_call_handler, descriptions.get(SERVICE_NOTIFY), schema=NOTIFY_SERVICE_SCHEMA) platform_name = (p_config.get(CONF_NAME) or SERVICE_NOTIFY) platform_name_slug = slugify(platform_name) hass.services.register(DOMAIN, platform_name_slug, service_call_handler, descriptions.get(SERVICE_NOTIFY), schema=NOTIFY_SERVICE_SCHEMA) success = True return success
async def async_update_info(self, now=None): """Get the gps info.""" HEADERS = { 'Host': 'ssl.gooddriver.cn', 'Content-Type': 'application/x-www-form-urlencoded', 'Cookie': self._cookie, 'Content-Length': '49', 'Connection': 'keep-alive', 'SDF': self._sdf, 'token': self._token, 'Accept': '\*/\*', 'Accept-Language': 'zh-cn', 'Accept-Encoding': 'gzip, deflate, br', 'User-Agent': 'gooddriver/.7.1 CFNetwork/1209 Darwin/20.2.0' } Data = '{\"UV_ID\":' + self._uvid + ',\"U_ID\":' + self._uid + ',\"QUERY_USAGE\":true}' def time_diff (timestamp): result = datetime.datetime.now() - datetime.datetime.fromtimestamp(timestamp) hours = int(result.seconds / 3600) minutes = int(result.seconds % 3600 / 60) seconds = result.seconds%3600%60 if result.days > 0: return("{0}天{1}小时{2}分钟".format(result.days,hours,minutes)) elif hours > 0: return("{0}小时{1}分钟".format(hours,minutes)) elif minutes > 0: return("{0}分钟{1}秒".format(minutes,seconds)) else: return("{0}秒".format(seconds)) try: async with timeout(10): ret = await self.hass.async_add_executor_job(self.post_data, self._url, HEADERS, Data) _Log.debug("请求结果: %s", ret) except ( ClientConnectorError ) as error: raise UpdateFailed(error) _Log.debug("Requests remaining: %s", self._url) if self._gddrtype == "taiyas" : if ret['ERROR_CODE'] == 0: _Log.info("请求服务器信息成功.....") if ret['MESSAGE']['UID_STATE'] == 1: status = "车辆点火" elif ret['MESSAGE']['UID_STATE'] == 2: status = "车辆熄火" elif ret['MESSAGE']['UID_STATE'] == 3: status = "车辆离线" else: status = "未知" kwargs = { "dev_id": slugify("gddr_{}".format(self._name)), "host_name": self._name, "attributes": { "icon": ICON, "status": status, "querytime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "statustime": re.sub(r'\/','-',ret['MESSAGE']['UID_UPLOAD_TIME']), "time": ret['MESSAGE']['UID_RECENT_PLACE']['Time'], "speed": ret['MESSAGE']['UID_RECENT_PLACE']['Speed'], "course": ret['MESSAGE']['UID_RECENT_PLACE']['Course'], "Parking_time": time_diff (int(time.mktime(time.strptime(ret['MESSAGE']['UID_RECENT_PLACE']['Time'], "%Y-%m-%d %H:%M:%S")))), }, } kwargs["gps"] = [ ret['MESSAGE']['UID_RECENT_PLACE']['Lat'] - 0.00101, ret['MESSAGE']['UID_RECENT_PLACE']['Lng'] - 0.00600, ] else: _Log.error("send request error....") elif self._gddrtype == "advanced" : if ret['UV_LAST_STATION'] != "": _Log.info("请求服务器信息成功.....") strlist = ret['UV_LAST_STATION'].split(',') if float(strlist[2]) == 0: status = "车辆熄火" else: status = "车辆点火" kwargs = { "dev_id": slugify("gddr_{}".format(self._name)), "host_name": self._name, "attributes": { "icon": ICON, "status": status, "querytime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "statustime": re.sub(r'\/','-',ret['UV_LAST_STAYTIME']), "Parking_time": time_diff (int(time.mktime(time.strptime(re.sub(r'\/','-',ret['UV_LAST_STAYTIME']), "%Y-%m-%d %H:%M:%S")))), }, } kwargs["gps"] = [ float(strlist[1]) - 0.00751, float(strlist[0]) - 0.01230, ] else: _Log.error("send request error....") result = await self.async_see(**kwargs) return result
def get_doorstation_by_slug(hass, slug): """Get doorstation by slug.""" for doorstation in hass.data[DOMAIN]: if slugify(doorstation.name) in slug: return doorstation
def configured_zones(hass): """Return a set of the configured hosts.""" return set((slugify(entry.data[CONF_NAME])) for entry in hass.config_entries.async_entries(DOMAIN))
async def migrate_old_configuration(hass: HomeAssistant, entry: ConfigEntry): """ Migrates 0.4.x configuration, where unique_id was based on IP to >0.5.0 configuration, where unique_id is based on the serial ID """ Logger.info("Migrating old integration to new one") host_ip = entry.unique_id api = aiohwenergy.HomeWizardEnergy(host_ip) try: with async_timeout.timeout(5): await api.initialize() except (asyncio.TimeoutError, aiohwenergy.RequestError): Logger.error( "(-1) Error connecting to the Energy device at %s", host_ip, ) return False except Exception: # pylint: disable=broad-except Logger.error( "(-2) Error connecting to the Energy device at %s", host_ip, ) return False finally: await api.close() if api.device == None: Logger.error( "Device (%s) API disabled, enable API and restart integration" % host_ip) return False # Update unique_id information unique_id = "%s_%s" % ( api.device.product_type, api.device.serial, ) # Update entities er = await entity_registry.async_get_registry(hass) entities = entity_registry.async_entries_for_config_entry( er, entry.entry_id) old_unique_id_prefix = "p1_meter_%s_" % slugify(host_ip) for entity in entities: new_unique_id_type = entity.unique_id.replace(old_unique_id_prefix, "") new_unique_id = "%s_%s" % (unique_id, new_unique_id_type) Logger.debug("Changing %s to %s" % (entity.unique_id, new_unique_id)) er.async_update_entity(entity.entity_id, new_unique_id=new_unique_id) # Update device information data = entry.data.copy() data["host"] = host_ip data["name"] = api.device.product_name data["custom_name"] = api.device.product_name data["unique_id"] = unique_id data.pop("ip_address") hass.config_entries.async_update_entry(entry, data=data, unique_id=unique_id) return True
def _slug(name): return 'sensor.arwn_{}'.format(slugify(name))
def __init__(self, vehicle, controller): """Initialisation of the Tesla device.""" self.vehicle = vehicle self.controller = controller self._name = vehicle.model self.lexus_id = slugify(vehicle.vehicle_id)
def unique_id(self) -> str: """Return a unique, Home Assistant friendly identifier for this entity.""" return "withings_{}_{}_{}".format(self._slug, self._user_id, slugify(self._attribute.measurement))
def setup_scanner(hass, config: dict, see, discovery_info=None): """Set up the iCloud Scanner.""" username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) account = config.get(CONF_ACCOUNTNAME, slugify(username.partition('@')[0])) icloudaccount = Icloud(hass, username, password, account, see) if icloudaccount.api is not None: ICLOUDTRACKERS[account] = icloudaccount else: _LOGGER.error("No ICLOUDTRACKERS added") return False def lost_iphone(call): """Call the lost iPhone function if the device is found.""" accounts = call.data.get(ATTR_ACCOUNTNAME, ICLOUDTRACKERS) devicename = call.data.get(ATTR_DEVICENAME) for account in accounts: if account in ICLOUDTRACKERS: ICLOUDTRACKERS[account].lost_iphone(devicename) hass.services.register(DOMAIN, 'icloud_lost_iphone', lost_iphone, schema=SERVICE_SCHEMA) def update_icloud(call): """Call the update function of an iCloud account.""" accounts = call.data.get(ATTR_ACCOUNTNAME, ICLOUDTRACKERS) devicename = call.data.get(ATTR_DEVICENAME) for account in accounts: if account in ICLOUDTRACKERS: ICLOUDTRACKERS[account].update_icloud(devicename) hass.services.register(DOMAIN, 'icloud_update', update_icloud, schema=SERVICE_SCHEMA) def reset_account_icloud(call): """Reset an iCloud account.""" accounts = call.data.get(ATTR_ACCOUNTNAME, ICLOUDTRACKERS) for account in accounts: if account in ICLOUDTRACKERS: ICLOUDTRACKERS[account].reset_account_icloud() hass.services.register(DOMAIN, 'icloud_reset_account', reset_account_icloud, schema=SERVICE_SCHEMA) def setinterval(call): """Call the update function of an iCloud account.""" accounts = call.data.get(ATTR_ACCOUNTNAME, ICLOUDTRACKERS) interval = call.data.get(ATTR_INTERVAL) devicename = call.data.get(ATTR_DEVICENAME) for account in accounts: if account in ICLOUDTRACKERS: ICLOUDTRACKERS[account].setinterval(interval, devicename) hass.services.register(DOMAIN, 'icloud_set_interval', setinterval, schema=SERVICE_SCHEMA) # Tells the bootstrapper that the component was successfully initialized return True
def _setup(hass, config, target_entity, name, keep_on): """Setup example component.""" object_id_enable = DOMAIN + '_' + slugify(name) + '_enable' object_id_hour = DOMAIN + '_' + slugify(name) + '_hour' object_id_temp = DOMAIN + '_' + slugify(name) + '_temp' def activate(now): if hass.states.get('input_boolean.' + object_id_enable).state == 'off': return if not str(now.hour) == str( int( float( hass.states.get('input_slider.' + object_id_hour).state))): return climate.set_temperature(hass, hass.states.get('input_slider.' + object_id_temp).state, entity_id='climate.' + target_entity) if not keep_on: hass.states.set('input_boolean.' + object_id_enable, 'off') _config = config['input_boolean'] _config[object_id_enable] = {'name': 'Enable', 'initial': False} print(config['input_boolean']) config['input_boolean'].append(_config) print(config['input_boolean']) _config = config['input_slider'] _config[object_id_hour] = { 'name': 'Hour', 'initial': 15, 'min': 7, 'max': 23, 'step': 1 } _config[object_id_temp] = { 'name': 'Temp', 'initial': 20, 'min': 13, 'max': 22, 'step': 1 } config['input_slider'] = _config #_config = {'platform': 'template', 'sensors': { object_id_hour: {'value_template': '{{ states("input_slider.' + object_id_hour + '") | round(0) }}'}}} #config['sensor'] = _config #sensor.setup(hass, config) group.Group.create_group(hass, name, [ 'input_boolean.' + object_id_enable, 'input_slider.' + object_id_hour, 'input_slider.' + object_id_temp ]) track_time_change(hass, activate, minute=0, second=2) def enable(entity_id, old_state, new_state): hass.states.set('input_boolean.' + object_id_enable, 'on') track_state_change( hass, ['input_slider.' + object_id_hour, 'input_slider.' + object_id_temp], enable) return config
def async_setup_platform(p_type, p_config=None, discovery_info=None): """Set up a notify platform.""" if p_config is None: p_config = {} if discovery_info is None: discovery_info = {} platform = yield from async_prepare_setup_platform( hass, config, DOMAIN, p_type) if platform is None: _LOGGER.error("Unknown notification service specified") return _LOGGER.info("Setting up %s.%s", DOMAIN, p_type) notify_service = None try: if hasattr(platform, 'async_get_service'): notify_service = yield from \ platform.async_get_service(hass, p_config, discovery_info) elif hasattr(platform, 'get_service'): notify_service = yield from hass.loop.run_in_executor( None, platform.get_service, hass, p_config, discovery_info) else: raise HomeAssistantError("Invalid notify platform.") if notify_service is None: _LOGGER.error("Failed to initialize notification service %s", p_type) return except Exception: # pylint: disable=broad-except _LOGGER.exception('Error setting up platform %s', p_type) return notify_service.hass = hass @asyncio.coroutine def async_notify_message(service): """Handle sending notification message service calls.""" kwargs = {} message = service.data[ATTR_MESSAGE] title = service.data.get(ATTR_TITLE) if title: title.hass = hass kwargs[ATTR_TITLE] = title.async_render() if targets.get(service.service) is not None: kwargs[ATTR_TARGET] = [targets[service.service]] elif service.data.get(ATTR_TARGET) is not None: kwargs[ATTR_TARGET] = service.data.get(ATTR_TARGET) message.hass = hass kwargs[ATTR_MESSAGE] = message.async_render() kwargs[ATTR_DATA] = service.data.get(ATTR_DATA) yield from notify_service.async_send_message(**kwargs) if hasattr(notify_service, 'targets'): platform_name = (p_config.get(CONF_NAME) or discovery_info.get(CONF_NAME) or p_type) for name, target in notify_service.targets.items(): target_name = slugify('{}_{}'.format(platform_name, name)) targets[target_name] = target hass.services.async_register(DOMAIN, target_name, async_notify_message, descriptions.get(SERVICE_NOTIFY), schema=NOTIFY_SERVICE_SCHEMA) platform_name = (p_config.get(CONF_NAME) or discovery_info.get(CONF_NAME) or SERVICE_NOTIFY) platform_name_slug = slugify(platform_name) hass.services.async_register(DOMAIN, platform_name_slug, async_notify_message, descriptions.get(SERVICE_NOTIFY), schema=NOTIFY_SERVICE_SCHEMA) return True
def async_handle_event(event: str, area_id: str, args: dict = {}): if not self._config[ATTR_MQTT][const.ATTR_ENABLED]: return topic = self._config[ATTR_MQTT][CONF_EVENT_TOPIC] if not topic: # do not publish if no topic is provided return if area_id and len(self.hass.data[const.DOMAIN]["areas"]) > 1: # handle the sending of a state update for a specific area area = self.hass.data[const.DOMAIN]["areas"][area_id] topic = topic.rsplit('/', 1) topic.insert(1, slugify(area.name)) topic = "/".join(topic) if event == const.EVENT_ARM: payload = { "event": "{}_{}".format( event.upper(), args["arm_mode"].split("_", 1).pop(1).upper() ), "delay": args["delay"], } elif event == const.EVENT_TRIGGER: payload = { "event": event.upper(), "delay": args["delay"], "sensors": [ { "entity_id": entity, "name": friendly_name_for_entity_id(entity, self.hass), } for (entity, state) in args["open_sensors"].items() ] } elif event == const.EVENT_FAILED_TO_ARM: payload = { "event": event.upper(), "sensors": [ { "entity_id": entity, "name": friendly_name_for_entity_id(entity, self.hass), } for (entity, state) in args["open_sensors"].items() ] } elif event == const.EVENT_COMMAND_NOT_ALLOWED: payload = { "event": event.upper(), "state": args["state"], "command": args["command"].upper() } elif event in [const.EVENT_INVALID_CODE_PROVIDED, const.EVENT_NO_CODE_PROVIDED]: payload = { "event": event.upper() } else: return payload = json.dumps(payload, cls=JSONEncoder) hass.async_create_task(mqtt.async_publish(self.hass, topic, payload))
def entity_id(self): """Return the entity_id of the sensor.""" if not self._name: return ENTITY_ID_FORMAT.format(slugify(self._sensor.name)) return ENTITY_ID_FORMAT.format(slugify(self._name))
async def async_message_received(self, msg): command = None code = None area = None try: payload = json.loads(msg.payload) payload = {k.lower(): v for k, v in payload.items()} if "command" in payload: command = payload["command"] elif "cmd" in payload: command = payload["cmd"] elif "action" in payload: command = payload["action"] elif "state" in payload: command = payload["state"] if "code" in payload: code = payload["code"] elif "pin" in payload: code = payload["pin"] elif "password" in payload: code = payload["password"] elif "pincode" in payload: code = payload["pincode"] if "area" in payload and payload["area"]: area = payload["area"] except ValueError: # no JSON structure found command = msg.payload code = None if type(command) is str: command = command.lower() else: _LOGGER.warning("Received unexpected command") return payload_config = self._config[ATTR_MQTT][const.ATTR_COMMAND_PAYLOAD] skip_code = not self._config[ATTR_MQTT][const.ATTR_REQUIRE_CODE] command_payloads = {} for item in const.COMMANDS: if item in payload_config and payload_config[item]: command_payloads[item] = payload_config[item].lower() elif item not in payload_config: command_payloads[item] = item.lower() if command not in list(command_payloads.values()): _LOGGER.warning("Received unexpected command: %s", command) return if area: res = list(filter(lambda el: slugify(el.name) == area, self.hass.data[const.DOMAIN]["areas"].values())) if not res: _LOGGER.warning("Area {} does not exist".format(area)) return entity = res[0] else: if self._config[const.ATTR_MASTER][const.ATTR_ENABLED] and len(self.hass.data[const.DOMAIN]["areas"]) > 1: entity = self.hass.data[const.DOMAIN]["master"] elif len(self.hass.data[const.DOMAIN]["areas"]) == 1: entity = list(self.hass.data[const.DOMAIN]["areas"].values())[0] else: _LOGGER.warning("No area specified") return _LOGGER.debug("Received command {}".format(command)) if command == command_payloads[const.COMMAND_DISARM]: await entity.async_alarm_disarm(code, skip_code) elif command == command_payloads[const.COMMAND_ARM_AWAY]: await entity.async_alarm_arm_away(code, skip_code) elif command == command_payloads[const.COMMAND_ARM_NIGHT]: await entity.async_alarm_arm_night(code, skip_code) elif command == command_payloads[const.COMMAND_ARM_HOME]: await entity.async_alarm_arm_home(code, skip_code) elif command == command_payloads[const.COMMAND_ARM_CUSTOM_BYPASS]: await entity.async_alarm_arm_custom_bypass(code, skip_code) elif command == command_payloads[const.COMMAND_ARM_VACATION]: await entity.async_alarm_arm_vacation(code, skip_code)
def slug(self): """Get device slug.""" return slugify(self._name)
def unique_id(self): """Return a unique, HASS-friendly identifier for this entity.""" return '{0}_{1}'.format(self._unique_id, slugify(self._allergen))
def dev_id(self): """Return the device id of the Automower (for device tracker).""" return slugify("{0}_{1}_{2}".format(DOMAIN, self._model, self._id))
def __init__(self, endpoint, in_clusters, out_clusters, manufacturer, model, **kwargs): """Init ZHA entity.""" self._device_state_attributes = {} self.entity_connect = {} self.sub_listener = dict() self._device_class = None ieeetail = ''.join(['%02x' % (o, ) for o in endpoint.device.ieee[-4:]]) self.uid = str(endpoint.device._ieee) + "_" + str(endpoint.endpoint_id) if 'cluster_key' in kwargs: self.cluster_key = kwargs['cluster_key'] self.uid += '_' self.uid += self.cluster_key if 'application' in kwargs: self._application = kwargs['application'] self._application._entity_list[self.entity_id] = self if model in self._application.custom_devices: self._custom_module = self._application.custom_devices[model] else: self._custom_module = {} if manufacturer is None: manufacturer = 'unknown' if model is None: model = 'unknown' self.entity_id = '%s.%s_%s_%s_%s' % ( self._domain, slugify(manufacturer), slugify(model), ieeetail, endpoint.endpoint_id, ) if 'application' in kwargs: self._application._entity_list[self.entity_id] = self self._device_state_attributes['friendly_name'] = '%s %s' % ( manufacturer, model, ) self._device_state_attributes['model'] = model self._device_state_attributes['manufacturer'] = manufacturer self._model = model # else: # self.entity_id = "%s.zha_%s_%s" % ( # self._domain, # ieeetail, # endpoint.endpoint_id, # ) if 'cluster_key' in kwargs: self.entity_id += '_' self.entity_id += kwargs['cluster_key'] self._device_state_attributes['friendly_name'] += '_' self._device_state_attributes['friendly_name'] += kwargs[ 'cluster_key'] self._endpoint = endpoint self._in_clusters = in_clusters self._out_clusters = out_clusters self._state = None self._device_state_attributes['lqi'] = endpoint.device.lqi self._device_state_attributes['rssi'] = endpoint.device.rssi self._device_state_attributes['last seen'] = None self._device_state_attributes['nwk'] = endpoint.device.nwk self._device_state_attributes['path'] = 'unknown' # _LOGGER.debug("dir entity:%s", dir(self)) if self._custom_module.get('_parse_attribute', None): self._parse_attribute = self._custom_module['_parse_attribute'] if self._custom_module.get('_custom_cluster_command', None): self._custom_cluster_command = self._custom_module[ '_custom_cluster_command'] if self._custom_module.get('_custom_endpoint_init', None): self._custom_endpoint_init = self._custom_module[ '_custom_endpoint_init']
def __init__(self, tesla_device, controller): """Initialise of the Tesla device.""" self.tesla_device = tesla_device self.controller = controller self._name = self.tesla_device.name self.tesla_id = slugify(self.tesla_device.uniq_name)
def _node_object_id(node): """Return the object_id of the node.""" node_object_id = '{}_{}'.format(slugify(_node_name(node)), node.node_id) return node_object_id
def unique_id(self) -> str: return slugify( f"{self._entry.unique_id}-{self._vm.id}_binary_sensor", )
def test_slugify(self): """ Test slugify. """ self.assertEqual("test", util.slugify("T-!@#$!#@$!$est")) self.assertEqual("test_more", util.slugify("Test More")) self.assertEqual("test_more", util.slugify("Test_(More)"))
def async_get_or_create( self, domain: str, platform: str, unique_id: str, *, # To influence entity ID generation known_object_ids: Iterable[str] | None = None, suggested_object_id: str | None = None, # To disable an entity if it gets created disabled_by: str | None = None, # Data that we want entry to have area_id: str | None = None, capabilities: Mapping[str, Any] | None = None, config_entry: ConfigEntry | None = None, device_class: str | None = None, device_id: str | None = None, entity_category: str | None = None, original_icon: str | None = None, original_name: str | None = None, supported_features: int | None = None, unit_of_measurement: str | None = None, ) -> RegistryEntry: """Get entity. Create if it doesn't exist.""" config_entry_id = None if config_entry: config_entry_id = config_entry.entry_id entity_id = self.async_get_entity_id(domain, platform, unique_id) if entity_id: return self._async_update_entity( entity_id, config_entry_id=config_entry_id or UNDEFINED, device_id=device_id or UNDEFINED, area_id=area_id or UNDEFINED, capabilities=capabilities or UNDEFINED, supported_features=supported_features or UNDEFINED, device_class=device_class or UNDEFINED, unit_of_measurement=unit_of_measurement or UNDEFINED, original_name=original_name or UNDEFINED, original_icon=original_icon or UNDEFINED, entity_category=entity_category or UNDEFINED, # When we changed our slugify algorithm, we invalidated some # stored entity IDs with either a __ or ending in _. # Fix introduced in 0.86 (Jan 23, 2019). Next line can be # removed when we release 1.0 or in 2020. new_entity_id=".".join( slugify(part) for part in entity_id.split(".", 1)), ) entity_id = self.async_generate_entity_id( domain, suggested_object_id or f"{platform}_{unique_id}", known_object_ids) if (disabled_by is None and config_entry and config_entry.pref_disable_new_entities): disabled_by = DISABLED_INTEGRATION entity = RegistryEntry( area_id=area_id, capabilities=capabilities, config_entry_id=config_entry_id, device_class=device_class, device_id=device_id, disabled_by=disabled_by, entity_category=entity_category, entity_id=entity_id, original_icon=original_icon, original_name=original_name, platform=platform, supported_features=supported_features or 0, unique_id=unique_id, unit_of_measurement=unit_of_measurement, ) self._register_entry(entity) _LOGGER.info("Registered new %s.%s entity: %s", domain, platform, entity_id) self.async_schedule_save() self.hass.bus.async_fire(EVENT_ENTITY_REGISTRY_UPDATED, { "action": "create", "entity_id": entity_id }) return entity
def binary_sensor_update(event): """Call for control updates from the RFXtrx gateway.""" if not isinstance(event, rfxtrxmod.ControlEvent): return device_id = slugify(event.device.id_string.lower()) if device_id in rfxtrx.RFX_DEVICES: sensor = rfxtrx.RFX_DEVICES[device_id] else: sensor = rfxtrx.get_pt2262_device(device_id) if sensor is None: # Add the entity if not exists and automatic_add is True if not config[CONF_AUTOMATIC_ADD]: return if event.device.packettype == 0x13: poss_dev = rfxtrx.find_possible_pt2262_device(device_id) if poss_dev is not None: poss_id = slugify(poss_dev.event.device.id_string.lower()) _LOGGER.debug("Found possible matching device ID: %s", poss_id) pkt_id = "".join("{0:02x}".format(x) for x in event.data) sensor = RfxtrxBinarySensor(event, pkt_id) sensor.hass = hass rfxtrx.RFX_DEVICES[device_id] = sensor add_entities([sensor]) _LOGGER.info( "Added binary sensor %s (Device ID: %s Class: %s Sub: %s)", pkt_id, slugify(event.device.id_string.lower()), event.device.__class__.__name__, event.device.subtype, ) elif not isinstance(sensor, RfxtrxBinarySensor): return else: _LOGGER.debug( "Binary sensor update (Device ID: %s Class: %s Sub: %s)", slugify(event.device.id_string.lower()), event.device.__class__.__name__, event.device.subtype, ) if sensor.is_lighting4: if sensor.data_bits is not None: cmd = rfxtrx.get_pt2262_cmd(device_id, sensor.data_bits) sensor.apply_cmd(int(cmd, 16)) else: sensor.update_state(True) else: rfxtrx.apply_received_command(event) if (sensor.is_on and sensor.off_delay is not None and sensor.delay_listener is None): def off_delay_listener(now): """Switch device off after a delay.""" sensor.delay_listener = None sensor.update_state(False) sensor.delay_listener = evt.track_point_in_time( hass, off_delay_listener, dt_util.utcnow() + sensor.off_delay)
def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Binary Sensor platform to RFXtrx.""" import RFXtrx as rfxtrxmod sensors = [] for packet_id, entity in config[CONF_DEVICES].items(): event = rfxtrx.get_rfx_object(packet_id) device_id = slugify(event.device.id_string.lower()) if device_id in rfxtrx.RFX_DEVICES: continue if entity.get(CONF_DATA_BITS) is not None: _LOGGER.debug( "Masked device id: %s", rfxtrx.get_pt2262_deviceid(device_id, entity.get(CONF_DATA_BITS)), ) _LOGGER.debug( "Add %s rfxtrx.binary_sensor (class %s)", entity[ATTR_NAME], entity.get(CONF_DEVICE_CLASS), ) device = RfxtrxBinarySensor( event, entity.get(CONF_NAME), entity.get(CONF_DEVICE_CLASS), entity[CONF_FIRE_EVENT], entity.get(CONF_OFF_DELAY), entity.get(CONF_DATA_BITS), entity.get(CONF_COMMAND_ON), entity.get(CONF_COMMAND_OFF), ) device.hass = hass sensors.append(device) rfxtrx.RFX_DEVICES[device_id] = device add_entities(sensors) def binary_sensor_update(event): """Call for control updates from the RFXtrx gateway.""" if not isinstance(event, rfxtrxmod.ControlEvent): return device_id = slugify(event.device.id_string.lower()) if device_id in rfxtrx.RFX_DEVICES: sensor = rfxtrx.RFX_DEVICES[device_id] else: sensor = rfxtrx.get_pt2262_device(device_id) if sensor is None: # Add the entity if not exists and automatic_add is True if not config[CONF_AUTOMATIC_ADD]: return if event.device.packettype == 0x13: poss_dev = rfxtrx.find_possible_pt2262_device(device_id) if poss_dev is not None: poss_id = slugify(poss_dev.event.device.id_string.lower()) _LOGGER.debug("Found possible matching device ID: %s", poss_id) pkt_id = "".join("{0:02x}".format(x) for x in event.data) sensor = RfxtrxBinarySensor(event, pkt_id) sensor.hass = hass rfxtrx.RFX_DEVICES[device_id] = sensor add_entities([sensor]) _LOGGER.info( "Added binary sensor %s (Device ID: %s Class: %s Sub: %s)", pkt_id, slugify(event.device.id_string.lower()), event.device.__class__.__name__, event.device.subtype, ) elif not isinstance(sensor, RfxtrxBinarySensor): return else: _LOGGER.debug( "Binary sensor update (Device ID: %s Class: %s Sub: %s)", slugify(event.device.id_string.lower()), event.device.__class__.__name__, event.device.subtype, ) if sensor.is_lighting4: if sensor.data_bits is not None: cmd = rfxtrx.get_pt2262_cmd(device_id, sensor.data_bits) sensor.apply_cmd(int(cmd, 16)) else: sensor.update_state(True) else: rfxtrx.apply_received_command(event) if (sensor.is_on and sensor.off_delay is not None and sensor.delay_listener is None): def off_delay_listener(now): """Switch device off after a delay.""" sensor.delay_listener = None sensor.update_state(False) sensor.delay_listener = evt.track_point_in_time( hass, off_delay_listener, dt_util.utcnow() + sensor.off_delay) # Subscribe to main RFXtrx events if binary_sensor_update not in rfxtrx.RECEIVED_EVT_SUBSCRIBERS: rfxtrx.RECEIVED_EVT_SUBSCRIBERS.append(binary_sensor_update)
async def async_see(self, mac: str = None, dev_id: str = None, host_name: str = None, location_name: str = None, gps: GPSType = None, gps_accuracy: int = None, battery: int = None, attributes: dict = None, source_type: str = SOURCE_TYPE_GPS, picture: str = None, icon: str = None, consider_home: timedelta = None): """Notify the device tracker that you see a device. This method is a coroutine. """ if mac is None and dev_id is None: raise HomeAssistantError('Neither mac or device id passed in') elif mac is not None: mac = str(mac).upper() device = self.mac_to_dev.get(mac) if not device: dev_id = util.slugify(host_name or '') or util.slugify(mac) else: dev_id = cv.slug(str(dev_id).lower()) device = self.devices.get(dev_id) if device: await device.async_seen(host_name, location_name, gps, gps_accuracy, battery, attributes, source_type, consider_home) if device.track: await device.async_update_ha_state() return # If no device can be found, create it dev_id = util.ensure_unique_string(dev_id, self.devices.keys()) device = Device(self.hass, consider_home or self.consider_home, self.track_new, dev_id, mac, (host_name or dev_id).replace('_', ' '), picture=picture, icon=icon, hide_if_away=self.defaults.get(CONF_AWAY_HIDE, DEFAULT_AWAY_HIDE)) self.devices[dev_id] = device if mac is not None: self.mac_to_dev[mac] = device await device.async_seen(host_name, location_name, gps, gps_accuracy, battery, attributes, source_type) if device.track: await device.async_update_ha_state() # During init, we ignore the group if self.group and self.track_new: self.hass.async_create_task( self.hass.async_call( DOMAIN_GROUP, SERVICE_SET, { ATTR_OBJECT_ID: util.slugify(GROUP_NAME_ALL_DEVICES), ATTR_VISIBLE: False, ATTR_NAME: GROUP_NAME_ALL_DEVICES, ATTR_ADD_ENTITIES: [device.entity_id] })) self.hass.bus.async_fire( EVENT_NEW_DEVICE, { ATTR_ENTITY_ID: device.entity_id, ATTR_HOST_NAME: device.host_name, ATTR_MAC: device.mac, }) # update known_devices.yaml self.hass.async_create_task( self.async_update_config(self.hass.config.path(YAML_DEVICES), dev_id, device))
def setup_platform(hass, config, add_devices_callback, discovery_info=None): """Setup the RFXtrx platform.""" from RFXtrx import SensorEvent sensors = [] for packet_id, entity_info in config[CONF_DEVICES].items(): event = rfxtrx.get_rfx_object(packet_id) device_id = "sensor_" + slugify(event.device.id_string.lower()) if device_id in rfxtrx.RFX_DEVICES: continue _LOGGER.info("Add %s rfxtrx.sensor", entity_info[ATTR_NAME]) sub_sensors = {} data_types = entity_info[ATTR_DATA_TYPE] if len(data_types) == 0: data_types = [''] for data_type in DATA_TYPES: if data_type in event.values: data_types = [data_type] break for _data_type in data_types: new_sensor = RfxtrxSensor(None, entity_info[ATTR_NAME], _data_type, entity_info[ATTR_FIREEVENT]) sensors.append(new_sensor) sub_sensors[_data_type] = new_sensor rfxtrx.RFX_DEVICES[device_id] = sub_sensors add_devices_callback(sensors) def sensor_update(event): """Callback for sensor updates from the RFXtrx gateway.""" if not isinstance(event, SensorEvent): return device_id = "sensor_" + slugify(event.device.id_string.lower()) if device_id in rfxtrx.RFX_DEVICES: sensors = rfxtrx.RFX_DEVICES[device_id] for key in sensors: sensor = sensors[key] sensor.event = event # Fire event if sensors[key].should_fire_event: sensor.hass.bus.fire( "signal_received", { ATTR_ENTITY_ID: sensors[key].entity_id, }) return # Add entity if not exist and the automatic_add is True if not config[ATTR_AUTOMATIC_ADD]: return pkt_id = "".join("{0:02x}".format(x) for x in event.data) _LOGGER.info("Automatic add rfxtrx.sensor: %s", pkt_id) data_type = '' for _data_type in DATA_TYPES: if _data_type in event.values: data_type = _data_type break new_sensor = RfxtrxSensor(event, pkt_id, data_type) sub_sensors = {} sub_sensors[new_sensor.data_type] = new_sensor rfxtrx.RFX_DEVICES[device_id] = sub_sensors add_devices_callback([new_sensor]) if sensor_update not in rfxtrx.RECEIVED_EVT_SUBSCRIBERS: rfxtrx.RECEIVED_EVT_SUBSCRIBERS.append(sensor_update)