예제 #1
0
    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)
예제 #2
0
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
예제 #3
0
    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
예제 #4
0
 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
예제 #5
0
    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)
예제 #6
0
 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
예제 #7
0
 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
예제 #8
0
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
예제 #9
0
 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)
예제 #10
0
    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)
        )
예제 #11
0
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
예제 #12
0
 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)))
예제 #13
0
    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)))
예제 #14
0
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
예제 #15
0
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
예제 #16
0
    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)))
예제 #17
0
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
예제 #18
0
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
예제 #19
0
 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
예제 #20
0
    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)
예제 #21
0
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
예제 #22
0
 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
     )
예제 #23
0
    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())
예제 #24
0
    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'))
예제 #25
0
    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,
        )
예제 #26
0
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
예제 #27
0
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)
예제 #28
0
    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)
예제 #29
0
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))
예제 #30
0
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
예제 #31
0
    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))
예제 #32
0
 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]}"
     )
예제 #33
0
 def device_state_attributes(self):
     """Return the state attributes of the battery."""
     attr = {
         ATTR_EVENT_ID: slugify(self._device.name),
     }
     return attr
예제 #34
0
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
예제 #35
0
    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
예제 #36
0
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
예제 #37
0
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))
예제 #38
0
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
예제 #39
0
def _slug(name):
    return 'sensor.arwn_{}'.format(slugify(name))
예제 #40
0
 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)
예제 #41
0
파일: sensor.py 프로젝트: dcnielsen90/core
 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))
예제 #42
0
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
예제 #43
0
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
예제 #44
0
    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
예제 #45
0
        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))
예제 #46
0
 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))
예제 #47
0
    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)
예제 #48
0
 def slug(self):
     """Get device slug."""
     return slugify(self._name)
예제 #49
0
 def unique_id(self):
     """Return a unique, HASS-friendly identifier for this entity."""
     return '{0}_{1}'.format(self._unique_id, slugify(self._allergen))
예제 #50
0
 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))
예제 #51
0
    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']
예제 #52
0
 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)
예제 #53
0
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
예제 #54
0
 def unique_id(self) -> str:
     return slugify(
         f"{self._entry.unique_id}-{self._vm.id}_binary_sensor", )
예제 #55
0
 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)"))
예제 #56
0
    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
예제 #57
0
    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)
예제 #58
0
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)
예제 #59
0
    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))
예제 #60
0
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)