def test_setting_up_group(self):
        """Setup the setting of a group."""
        component = EntityComponent(_LOGGER, DOMAIN, self.hass,
                                    group_name='everyone')

        # No group after setup
        assert len(self.hass.states.entity_ids()) == 0

        component.add_entities([EntityTest(name='hello')])

        # group exists
        assert len(self.hass.states.entity_ids()) == 2
        assert self.hass.states.entity_ids('group') == ['group.everyone']

        group = self.hass.states.get('group.everyone')

        assert group.attributes.get('entity_id') == ('test_domain.hello',)

        # group extended
        component.add_entities([EntityTest(name='hello2')])

        assert len(self.hass.states.entity_ids()) == 3
        group = self.hass.states.get('group.everyone')

        assert sorted(group.attributes.get('entity_id')) == \
            ['test_domain.hello', 'test_domain.hello2']
Example #2
0
def setup(hass, config):
    """ Sets up scenes. """

    logger = logging.getLogger(__name__)

    scene_configs = config.get(DOMAIN)

    if not isinstance(scene_configs, list) or \
       any(not isinstance(item, dict) for item in scene_configs):
        logger.error('Scene config should be a list of dictionaries')
        return False

    component = EntityComponent(logger, DOMAIN, hass)

    component.add_entities(Scene(hass, _process_config(scene_config))
                           for scene_config in scene_configs)

    def handle_scene_service(service):
        """ Handles calls to the switch services. """
        target_scenes = component.extract_from_service(service)

        for scene in target_scenes:
            scene.activate()

    hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_scene_service)

    return True
Example #3
0
def setup(hass, config):
    """Setup input select."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        name = cfg.get(CONF_NAME)
        options = cfg.get(CONF_OPTIONS)
        state = cfg.get(CONF_INITIAL, 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 test_setting_up_group(self):
        component = EntityComponent(_LOGGER, DOMAIN, self.hass,
                                    group_name='everyone')

        # No group after setup
        assert 0 == len(self.hass.states.entity_ids())

        component.add_entities([EntityTest(name='hello')])

        # group exists
        assert 2 == len(self.hass.states.entity_ids())
        assert ['group.everyone'] == self.hass.states.entity_ids('group')

        group = self.hass.states.get('group.everyone')

        assert ('test_domain.hello',) == group.attributes.get('entity_id')

        # group extended
        component.add_entities([EntityTest(name='hello2')])

        assert 3 == len(self.hass.states.entity_ids())
        group = self.hass.states.get('group.everyone')

        assert ['test_domain.hello', 'test_domain.hello2'] == \
            sorted(group.attributes.get('entity_id'))
    def test_setting_up_group(self):
        """Setup the setting of a group."""
        setup_component(self.hass, 'group', {'group': {}})
        component = EntityComponent(_LOGGER, DOMAIN, self.hass,
                                    group_name='everyone')

        # No group after setup
        assert len(self.hass.states.entity_ids()) == 0

        component.add_entities([MockEntity()])
        self.hass.block_till_done()

        # group exists
        assert len(self.hass.states.entity_ids()) == 2
        assert self.hass.states.entity_ids('group') == ['group.everyone']

        group = self.hass.states.get('group.everyone')

        assert group.attributes.get('entity_id') == \
            ('test_domain.unnamed_device',)

        # group extended
        component.add_entities([MockEntity(name='goodbye')])
        self.hass.block_till_done()

        assert len(self.hass.states.entity_ids()) == 3
        group = self.hass.states.get('group.everyone')

        # Ordered in order of added to the group
        assert group.attributes.get('entity_id') == \
            ('test_domain.goodbye', 'test_domain.unnamed_device')
Example #6
0
def setup(hass, config):
    """Set up input slider."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        name = cfg.get(CONF_NAME)
        minimum = cfg.get(CONF_MIN)
        maximum = cfg.get(CONF_MAX)
        state = cfg.get(CONF_INITIAL, minimum)
        step = cfg.get(CONF_STEP)
        icon = cfg.get(CONF_ICON)
        unit = cfg.get(ATTR_UNIT_OF_MEASUREMENT)

        entities.append(InputSlider(object_id, name, state, minimum, maximum,
                                    step, icon, unit))

    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 test_not_assigning_entity_id_if_prescribes_one(self):
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)

        assert 'hello.world' not in self.hass.states.entity_ids()

        component.add_entities([EntityTest(entity_id='hello.world')])

        assert 'hello.world' in self.hass.states.entity_ids()
    def test_extract_from_service_filter_out_non_existing_entities(self):
        """Test the extraction of non existing entities from service."""
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)
        component.add_entities([EntityTest(name="test_1"), EntityTest(name="test_2")])

        call = ha.ServiceCall("test", "service", {"entity_id": ["test_domain.test_2", "test_domain.non_exist"]})

        assert ["test_domain.test_2"] == [ent.entity_id for ent in component.extract_from_service(call)]
    def test_not_assigning_entity_id_if_prescribes_one(self):
        """Test for not assigning an entity ID."""
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)

        assert "hello.world" not in self.hass.states.entity_ids()

        component.add_entities([EntityTest(entity_id="hello.world")])

        assert "hello.world" in self.hass.states.entity_ids()
    def test_extract_from_service_returns_all_if_no_entity_id(self):
        """Test the extraction of everything from service."""
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)
        component.add_entities([EntityTest(name="test_1"), EntityTest(name="test_2")])

        call = ha.ServiceCall("test", "service")

        assert ["test_domain.test_1", "test_domain.test_2"] == sorted(
            ent.entity_id for ent in component.extract_from_service(call)
        )
Example #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
    def test_update_state_adds_entities_with_update_befor_add_false(self):
        """Test if not call update befor add to state machine."""
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)

        ent = EntityTest()
        ent.update = Mock(spec_set=True)

        component.add_entities([ent], False)
        self.hass.block_till_done()

        assert 1 == len(self.hass.states.entity_ids())
        assert not ent.update.called
    def test_extract_from_service_returns_all_if_no_entity_id(self):
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)
        component.add_entities([
            EntityTest(name='test_1'),
            EntityTest(name='test_2'),
        ])

        call = ha.ServiceCall('test', 'service')

        assert ['test_domain.test_1', 'test_domain.test_2'] == \
            sorted(ent.entity_id for ent in
                   component.extract_from_service(call))
    def test_not_adding_duplicate_entities(self):
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)

        assert 0 == len(self.hass.states.entity_ids())

        component.add_entities([None, EntityTest(unique_id='not_very_unique')])

        assert 1 == len(self.hass.states.entity_ids())

        component.add_entities([EntityTest(unique_id='not_very_unique')])

        assert 1 == len(self.hass.states.entity_ids())
Example #15
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
Example #16
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
    def test_extract_from_service_no_group_expand(self):
        """Test not expanding a group."""
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)
        test_group = group.Group.create_group(
            self.hass, 'test_group', ['light.Ceiling', 'light.Kitchen'])
        component.add_entities([test_group])

        call = ha.ServiceCall('test', 'service', {
            'entity_id': ['group.test_group']
        })

        extracted = component.extract_from_service(call, expand_group=False)
        self.assertEqual([test_group], extracted)
    def test_extract_from_service_filter_out_non_existing_entities(self):
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)
        component.add_entities([
            EntityTest(name='test_1'),
            EntityTest(name='test_2'),
        ])

        call = ha.ServiceCall('test', 'service', {
            'entity_id': ['test_domain.test_2', 'test_domain.non_exist']
        })

        assert ['test_domain.test_2'] == \
               [ent.entity_id for ent in component.extract_from_service(call)]
    def test_update_state_adds_entities(self):
        """Test if updating poll entities cause an entity to be added works."""
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)

        ent1 = EntityTest()
        ent2 = EntityTest(should_poll=True)

        component.add_entities([ent2])
        assert 1 == len(self.hass.states.entity_ids())
        ent2.update_ha_state = lambda *_: component.add_entities([ent1])

        fire_time_changed(self.hass, dt_util.utcnow().replace(second=0))
        self.hass.pool.block_till_done()

        assert 2 == len(self.hass.states.entity_ids())
    def test_adding_entities_with_generator_and_thread_callback(self):
        """Test generator in add_entities that calls thread method.

        We should make sure we resolve the generator to a list before passing
        it into an async context.
        """
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)

        def create_entity(number):
            """Create entity helper."""
            entity = EntityTest()
            entity.entity_id = generate_entity_id(component.entity_id_format,
                                                  'Number', hass=self.hass)
            return entity

        component.add_entities(create_entity(i) for i in range(2))
    def test_update_state_adds_entities(self):
        """Test if updating poll entities cause an entity to be added works."""
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)

        ent1 = MockEntity()
        ent2 = MockEntity(should_poll=True)

        component.add_entities([ent2])
        assert 1 == len(self.hass.states.entity_ids())
        ent2.update = lambda *_: component.add_entities([ent1])

        fire_time_changed(
            self.hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL
        )
        self.hass.block_till_done()

        assert 2 == len(self.hass.states.entity_ids())
Example #22
0
def setup(hass, config):
    """Set up input boolean."""
    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:
            cfg = {}

        name = cfg.get(CONF_NAME)
        state = cfg.get(CONF_INITIAL, False)
        icon = cfg.get(CONF_ICON)

        entities.append(InputBoolean(object_id, name, state, icon))

    if not entities:
        return False

    def toggle_service(service):
        """Handle a calls to the input boolean services."""
        target_inputs = component.extract_from_service(service)

        for input_b in target_inputs:
            if service.service == SERVICE_TURN_ON:
                input_b.turn_on()
            else:
                input_b.turn_off()

    hass.services.register(DOMAIN, SERVICE_TURN_OFF, toggle_service,
                           schema=TOGGLE_SERVICE_SCHEMA)
    hass.services.register(DOMAIN, SERVICE_TURN_ON, toggle_service,
                           schema=TOGGLE_SERVICE_SCHEMA)

    component.add_entities(entities)

    return True
Example #23
0
def setup(hass, config):
    """Load the scripts from the configuration."""
    component = EntityComponent(_LOGGER, DOMAIN, hass,
                                group_name=GROUP_NAME_ALL_SCRIPTS)

    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 script.is_on:
            _LOGGER.warning("Script %s already running.", entity_id)
            return
        script.turn_on(variables=service.data)

    for object_id, cfg in config[DOMAIN].items():
        alias = cfg.get(CONF_ALIAS, object_id)
        script = ScriptEntity(hass, object_id, alias, cfg[CONF_SEQUENCE])
        component.add_entities((script,))
        hass.services.register(DOMAIN, object_id, service_handler,
                               schema=SCRIPT_SERVICE_SCHEMA)

    def turn_on_service(service):
        """Call 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 detect invocations.
        for script in component.extract_from_service(service):
            turn_on(hass, script.entity_id, service.data.get(ATTR_VARIABLES))

    def turn_off_service(service):
        """Cancel a script."""
        for script in component.extract_from_service(service):
            script.turn_off()

    def toggle_service(service):
        """Toggle a script."""
        for script in component.extract_from_service(service):
            script.toggle()

    hass.services.register(DOMAIN, SERVICE_TURN_ON, turn_on_service,
                           schema=SCRIPT_TURN_ONOFF_SCHEMA)
    hass.services.register(DOMAIN, SERVICE_TURN_OFF, turn_off_service,
                           schema=SCRIPT_TURN_ONOFF_SCHEMA)
    hass.services.register(DOMAIN, SERVICE_TOGGLE, toggle_service,
                           schema=SCRIPT_TURN_ONOFF_SCHEMA)
    return True
    def test_polling_only_updates_entities_it_should_poll(self):
        component = EntityComponent(_LOGGER, DOMAIN, self.hass, 20)

        no_poll_ent = EntityTest(should_poll=False)
        no_poll_ent.update_ha_state = Mock()
        poll_ent = EntityTest(should_poll=True)
        poll_ent.update_ha_state = Mock()

        component.add_entities([no_poll_ent, poll_ent])

        no_poll_ent.update_ha_state.reset_mock()
        poll_ent.update_ha_state.reset_mock()

        fire_time_changed(self.hass, dt_util.utcnow().replace(second=0))
        self.hass.pool.block_till_done()

        assert not no_poll_ent.update_ha_state.called
        assert poll_ent.update_ha_state.called
    def test_polling_only_updates_entities_it_should_poll(self):
        """Test the polling of only updated entities."""
        component = EntityComponent(
            _LOGGER, DOMAIN, self.hass, timedelta(seconds=20))

        no_poll_ent = EntityTest(should_poll=False)
        no_poll_ent.async_update = Mock()
        poll_ent = EntityTest(should_poll=True)
        poll_ent.async_update = Mock()

        component.add_entities([no_poll_ent, poll_ent])

        no_poll_ent.async_update.reset_mock()
        poll_ent.async_update.reset_mock()

        fire_time_changed(self.hass, dt_util.utcnow() + timedelta(seconds=20))
        self.hass.block_till_done()

        assert not no_poll_ent.async_update.called
        assert poll_ent.async_update.called
Example #26
0
def setup(hass, config):
    """Set up input boolean."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        if not cfg:
            cfg = {}

        name = cfg.get(CONF_NAME)
        state = cfg.get(CONF_INITIAL, False)
        icon = cfg.get(CONF_ICON)

        entities.append(InputBoolean(object_id, name, state, icon))

    if not entities:
        return False

    def handler_service(service):
        """Handle a calls to the input boolean services."""
        target_inputs = component.extract_from_service(service)

        for input_b in target_inputs:
            if service.service == SERVICE_TURN_ON:
                input_b.turn_on()
            elif service.service == SERVICE_TURN_OFF:
                input_b.turn_off()
            else:
                input_b.toggle()

    hass.services.register(DOMAIN, SERVICE_TURN_OFF, handler_service,
                           schema=SERVICE_SCHEMA)
    hass.services.register(DOMAIN, SERVICE_TURN_ON, handler_service,
                           schema=SERVICE_SCHEMA)
    hass.services.register(DOMAIN, SERVICE_TOGGLE, handler_service,
                           schema=SERVICE_SCHEMA)

    component.add_entities(entities)

    return True
Example #27
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 script:
            script.turn_on()

    for name, cfg in config[DOMAIN].items():
        if not cfg.get(CONF_SEQUENCE):
            _LOGGER.warn("Missing key 'sequence' for script %s", name)
            continue
        alias = cfg.get(CONF_ALIAS, name)
        script = Script(hass, alias, cfg[CONF_SEQUENCE])
        component.add_entities((script,))
        _, object_id = split_entity_id(script.entity_id)
        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()

    hass.services.register(DOMAIN, SERVICE_TURN_ON, turn_on_service)
    hass.services.register(DOMAIN, SERVICE_TURN_OFF, turn_off_service)

    return True
Example #28
0
    def setUp(self):
        """Setup things to be run when tests are started."""
        self.hass = get_test_home_assistant()

        component = EntityComponent(_LOGGER, DOMAIN, self.hass, SCAN_INTERVAL, GROUP_NAME_ALL_PP_ASSETS)


        pp_name = 'xxx'
        config = {
            "icon": "mdi:cancel",
        }
        self.pp = PowerPool(self.hass, name=pp_name, config=config)

        component.add_entities([self.pp], update_before_add=True)

        self.asset1 = EnergyAsset(name='asset1',
                             lat=10,
                             lon=90,
                             schedule=[1, 2, 3, 4, 5],
                             max_flex=[1, 1, 1, 1, 1],
                             min_flex=[1, 1, 1, 1, 1],
                             powerpool=pp_name,
                             hass=self.hass,
                             status='installed'
                             )
        self.hass.states.set(f"{ENERGY_ASSET_DOMAIN}.asset1", pp_name, self.asset1.state_attributes)

        self.asset2 = EnergyAsset(name='asset2',
                             lat=11,
                             lon=99,
                             schedule=[11, 22, 33, 44, 55],
                             max_flex=[1.1, 1.1, 1.1, 1.1, 1.1],
                             min_flex=[1.1, 1.1, 1.1, 1.1, 1.1],
                             powerpool=pp_name,
                             hass=self.hass,
                             status='installed'
                             )
        self.hass.states.set(f"{ENERGY_ASSET_DOMAIN}.asset2", pp_name, self.asset2.state_attributes)
    def test_adds_entities_with_update_befor_add_true_deadlock_protect(self):
        """Test if call update befor add to state machine.

        It need to run update inside executor and never call
        async_add_entities with True
        """
        call = []
        component = EntityComponent(_LOGGER, DOMAIN, self.hass)

        @asyncio.coroutine
        def async_add_entities_fake(entities, update_befor_add):
            """Fake add_entities_call."""
            call.append(update_befor_add)
        component._platforms['core'].async_add_entities = \
            async_add_entities_fake

        ent = EntityTest()
        ent.update = Mock(spec_set=True)
        component.add_entities([ent], True)

        assert ent.update.called
        assert len(call) == 1
        assert not call[0]
Example #30
0
def setup(hass, config):
    """Set up is called when Home Assistant is loading our component."""
    dominos = Dominos(hass, config)

    component = EntityComponent(_LOGGER, DOMAIN, hass)
    hass.data[DOMAIN] = {}
    entities = []
    conf = config[DOMAIN]

    hass.services.register(DOMAIN, 'order', dominos.handle_order)

    if conf.get(ATTR_SHOW_MENU):
        hass.http.register_view(DominosProductListView(dominos))

    for order_info in conf.get(ATTR_ORDERS):
        order = DominosOrder(order_info, dominos)
        entities.append(order)

    if entities:
        component.add_entities(entities)

    # Return boolean to indicate that initialization was successfully.
    return True
def setup(hass, config):
  host = config[DOMAIN].get(CONF_HOST)
  password = config[DOMAIN].get(CONF_PASSWORD)
  opensprinkler = Opensprinkler(host, password)
  stationIndexes = config[DOMAIN].get(CONF_STATIONS)

  hass.data[DOMAIN] = {
    DOMAIN: opensprinkler,
    CONF_CONFIG: {
      CONF_STATIONS: stationIndexes,
      CONF_PROGRAMS: config[DOMAIN].get(CONF_PROGRAMS),
    },
  }

  component = EntityComponent(_LOGGER, 'input_number', hass)
  entities = []
  for station in opensprinkler.stations():
    if len(stationIndexes) == 0 or (station.index in stationIndexes):
      object_id = '{}_timer'.format(slugify(station.name))
      name = station.name
      minimum = 1
      maximum = 10
      initial = 1
      step = 1
      unit = 'minutes'

      inputNumber = InputNumber(object_id, name, initial, minimum, maximum, step, None, unit, 'slider')
      entities.append(inputNumber)

  component.add_entities(entities)

  load_platform(hass, 'binary_sensor', DOMAIN)
  load_platform(hass, 'scene', DOMAIN)
  load_platform(hass, 'switch', DOMAIN)

  return True
    def test_polling_updates_entities_with_exception(self):
        """Test the updated entities that not break with an exception."""
        component = EntityComponent(_LOGGER, DOMAIN, self.hass,
                                    timedelta(seconds=20))

        update_ok = []
        update_err = []

        def update_mock():
            """Mock normal update."""
            update_ok.append(None)

        def update_mock_err():
            """Mock error update."""
            update_err.append(None)
            raise AssertionError("Fake error update")

        ent1 = MockEntity(should_poll=True)
        ent1.update = update_mock_err
        ent2 = MockEntity(should_poll=True)
        ent2.update = update_mock
        ent3 = MockEntity(should_poll=True)
        ent3.update = update_mock
        ent4 = MockEntity(should_poll=True)
        ent4.update = update_mock

        component.add_entities([ent1, ent2, ent3, ent4])

        update_ok.clear()
        update_err.clear()

        fire_time_changed(self.hass, dt_util.utcnow() + timedelta(seconds=20))
        self.hass.block_till_done()

        assert len(update_ok) == 3
        assert len(update_err) == 1
Example #33
0
async def test_update_state_adds_entities(hass):
    """Test if updating poll entities cause an entity to be added works."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    ent1 = MockEntity()
    ent2 = MockEntity(should_poll=True)

    await component.async_add_entities([ent2])
    assert len(hass.states.async_entity_ids()) == 1
    ent2.update = lambda *_: component.add_entities([ent1])

    async_fire_time_changed(hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL)
    await hass.async_block_till_done()

    assert len(hass.states.async_entity_ids()) == 2
Example #34
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Plant component."""
    _LOGGER.info(
        "__init__ setup_platform 'sensor' start for %s with config %s.",
        DOMAIN, config)

    if config.get(CONF_PLANT_ID) is None:
        return True

    if not hasattr(hass.data[DOMAIN], ATTR_FLOWER_CARE_DATA):
        hass.data[DOMAIN][ATTR_FLOWER_CARE_DATA] = {}

    params = {}
    sensors = config.get(CONF_SENSORS)

    if not (sensors is None):
        params[CONF_SENSORS] = sensors
    else:
        params[CONF_SENSORS] = dict()

    plant_key = config.get(CONF_PLANT_ID).replace(" ", "_")
    app_api = hass.data[DOMAIN][SERVICE_API]

    if not (app_api is None):
        if not hasattr(hass.data[DOMAIN][ATTR_FLOWER_CARE_DATA], plant_key):
            flower_info = app_api.retrieve_flower_details(
                config.get(CONF_PLANT_ID))
            _LOGGER.debug(
                "__init__ setup_platform 'sensor' start for %s. Retrieved Flower: %s",
                DOMAIN, flower_info)

            if not (flower_info is None):
                hass.data[DOMAIN][ATTR_FLOWER_CARE_DATA][
                    plant_key] = flower_info
        else:
            flower_info = hass.data[DOMAIN][ATTR_FLOWER_CARE_DATA][plant_key]
            _LOGGER.debug(
                "__init__ setup_platform 'sensor' start for %s. Reused Flower: %s",
                DOMAIN, flower_info)

        if not (flower_info is None):
            params[ATTR_RANGES] = flower_info[API_PARAMETER]
            params[CONF_MIN_TEMPERATURE] = flower_info[API_PARAMETER][
                API_PARAMETER_MIN_TEMP]
            params[CONF_MAX_TEMPERATURE] = flower_info[API_PARAMETER][
                API_PARAMETER_MAX_TEMP]
            params[CONF_MIN_MOISTURE] = flower_info[API_PARAMETER][
                API_PARAMETER_MIN_SOIL_MOIST]
            params[CONF_MAX_MOISTURE] = flower_info[API_PARAMETER][
                API_PARAMETER_MAX_SOIL_MOIST]
            params[CONF_MIN_CONDUCTIVITY] = flower_info[API_PARAMETER][
                API_PARAMETER_MIN_SOIL_EC]
            params[CONF_MAX_CONDUCTIVITY] = flower_info[API_PARAMETER][
                API_PARAMETER_MAX_SOIL_EC]
            params[CONF_MIN_BRIGHTNESS] = flower_info[API_PARAMETER][
                API_PARAMETER_MIN_LIGHT_LUX]
            params[CONF_MAX_BRIGHTNESS] = flower_info[API_PARAMETER][
                API_PARAMETER_MAX_LIGHT_LUX]

            params[ATTR_BASIC] = flower_info[ATTR_BASIC]
            params[ATTR_MAINTENANCE] = flower_info[ATTR_MAINTENANCE]
            params[ATTR_IMAGE] = flower_info[ATTR_IMAGE]

    # if not (sensors is None):
    component = EntityComponent(_LOGGER, DOMAIN_PLANT, hass)

    entities = []

    name = config.get(CONF_NAME)
    entity = Plant(name, params)
    entities.append(entity)

    component.add_entities(entities)
    _LOGGER.debug(
        "__init__ setup_platform 'sensor' %s in platform %s. Component added with %s.",
        name, DOMAIN, params)

    _LOGGER.info("__init__ setup_platform 'sensor' done for %s.", DOMAIN)
    return True
Example #35
0
def setup(hass, config):
    """Set up the Wink component."""

    if hass.data.get(DOMAIN) is None:
        hass.data[DOMAIN] = {
            "unique_ids": [],
            "entities": {},
            "oauth": {},
            "configuring": {},
            "pubnub": None,
            "configurator": False,
        }

    if config.get(DOMAIN) is not None:
        client_id = config[DOMAIN].get(CONF_CLIENT_ID)
        client_secret = config[DOMAIN].get(CONF_CLIENT_SECRET)
        email = config[DOMAIN].get(CONF_EMAIL)
        password = config[DOMAIN].get(CONF_PASSWORD)
        local_control = config[DOMAIN].get(CONF_LOCAL_CONTROL)
    else:
        client_id = None
        client_secret = None
        email = None
        password = None
        local_control = None
        hass.data[DOMAIN]["configurator"] = True
    if None not in [client_id, client_secret]:
        _LOGGER.info("Using legacy OAuth authentication")
        if not local_control:
            pywink.disable_local_control()
        hass.data[DOMAIN]["oauth"][CONF_CLIENT_ID] = client_id
        hass.data[DOMAIN]["oauth"][CONF_CLIENT_SECRET] = client_secret
        hass.data[DOMAIN]["oauth"]["email"] = email
        hass.data[DOMAIN]["oauth"]["password"] = password
        pywink.legacy_set_wink_credentials(email, password, client_id,
                                           client_secret)
    else:
        _LOGGER.info("Using OAuth authentication")
        if not local_control:
            pywink.disable_local_control()
        config_path = hass.config.path(WINK_CONFIG_FILE)
        if os.path.isfile(config_path):
            config_file = load_json(config_path)
            if config_file == DEFAULT_CONFIG:
                _request_app_setup(hass, config)
                return True
            # else move on because the user modified the file
        else:
            save_json(config_path, DEFAULT_CONFIG)
            _request_app_setup(hass, config)
            return True

        if DOMAIN in hass.data[DOMAIN]["configuring"]:
            _configurator = hass.data[DOMAIN]["configuring"]
            hass.components.configurator.request_done(
                _configurator.pop(DOMAIN))

        # Using oauth
        access_token = config_file.get(ATTR_ACCESS_TOKEN)
        refresh_token = config_file.get(ATTR_REFRESH_TOKEN)

        # This will be called after authorizing Home-Assistant
        if None not in (access_token, refresh_token):
            pywink.set_wink_credentials(
                config_file.get(CONF_CLIENT_ID),
                config_file.get(CONF_CLIENT_SECRET),
                access_token=access_token,
                refresh_token=refresh_token,
            )
        # This is called to create the redirect so the user can Authorize
        # Home .
        else:

            redirect_uri = f"{get_url(hass)}{WINK_AUTH_CALLBACK_PATH}"

            wink_auth_start_url = pywink.get_authorization_url(
                config_file.get(CONF_CLIENT_ID), redirect_uri)
            hass.http.register_redirect(WINK_AUTH_START, wink_auth_start_url)
            hass.http.register_view(
                WinkAuthCallbackView(config, config_file,
                                     pywink.request_token))
            _request_oauth_completion(hass, config)
            return True

    pywink.set_user_agent(USER_AGENT)
    sub_details = pywink.get_subscription_details()
    hass.data[DOMAIN]["pubnub"] = PubNubSubscriptionHandler(
        sub_details[0], origin=sub_details[1])

    def _subscribe():
        hass.data[DOMAIN]["pubnub"].subscribe()

    # Call subscribe after the user sets up wink via the configurator
    # All other methods will complete setup before
    # EVENT_HOMEASSISTANT_START is called meaning they
    # will call subscribe via the method below. (start_subscription)
    if hass.data[DOMAIN]["configurator"]:
        _subscribe()

    def keep_alive_call(event_time):
        """Call the Wink API endpoints to keep PubNub working."""
        _LOGGER.info("Polling the Wink API to keep PubNub updates flowing")
        pywink.set_user_agent(str(int(time.time())))
        _temp_response = pywink.get_user()
        _LOGGER.debug(str(json.dumps(_temp_response)))
        time.sleep(1)
        pywink.set_user_agent(USER_AGENT)
        _temp_response = pywink.wink_api_fetch()
        _LOGGER.debug("%s", _temp_response)
        _temp_response = pywink.post_session()
        _LOGGER.debug("%s", _temp_response)

    # Call the Wink API every hour to keep PubNub updates flowing
    track_time_interval(hass, keep_alive_call, timedelta(minutes=60))

    def start_subscription(event):
        """Start the PubNub subscription."""
        _subscribe()

    hass.bus.listen(EVENT_HOMEASSISTANT_START, start_subscription)

    def stop_subscription(event):
        """Stop the PubNub subscription."""
        hass.data[DOMAIN]["pubnub"].unsubscribe()
        hass.data[DOMAIN]["pubnub"] = None

    hass.bus.listen(EVENT_HOMEASSISTANT_STOP, stop_subscription)

    def save_credentials(event):
        """Save currently set OAuth credentials."""
        if hass.data[DOMAIN]["oauth"].get("email") is None:
            config_path = hass.config.path(WINK_CONFIG_FILE)
            _config = pywink.get_current_oauth_credentials()
            save_json(config_path, _config)

    hass.bus.listen(EVENT_HOMEASSISTANT_STOP, save_credentials)

    # Save the users potentially updated oauth credentials at a regular
    # interval to prevent them from being expired after a HA reboot.
    track_time_interval(hass, save_credentials, timedelta(minutes=60))

    def force_update(call):
        """Force all devices to poll the Wink API."""
        _LOGGER.info("Refreshing Wink states from API")
        for entity_list in hass.data[DOMAIN]["entities"].values():
            # Throttle the calls to Wink API
            for entity in entity_list:
                time.sleep(1)
                entity.schedule_update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_REFRESH_STATES, force_update)

    def pull_new_devices(call):
        """Pull new devices added to users Wink account since startup."""
        _LOGGER.info("Getting new devices from Wink API")
        for _component in WINK_COMPONENTS:
            discovery.load_platform(hass, _component, DOMAIN, {}, config)

    hass.services.register(DOMAIN, SERVICE_ADD_NEW_DEVICES, pull_new_devices)

    def set_pairing_mode(call):
        """Put the hub in provided pairing mode."""
        hub_name = call.data.get("hub_name")
        pairing_mode = call.data.get("pairing_mode")
        kidde_code = call.data.get("kidde_radio_code")
        for hub in WINK_HUBS:
            if hub.name() == hub_name:
                hub.pair_new_device(pairing_mode, kidde_radio_code=kidde_code)

    def rename_device(call):
        """Set specified device's name."""
        # This should only be called on one device at a time.
        found_device = None
        entity_id = call.data.get("entity_id")[0]
        all_devices = []
        for list_of_devices in hass.data[DOMAIN]["entities"].values():
            all_devices += list_of_devices
        for device in all_devices:
            if device.entity_id == entity_id:
                found_device = device
        if found_device is not None:
            name = call.data.get("name")
            found_device.wink.set_name(name)

    hass.services.register(DOMAIN,
                           SERVICE_RENAME_DEVICE,
                           rename_device,
                           schema=RENAME_DEVICE_SCHEMA)

    def delete_device(call):
        """Delete specified device."""
        # This should only be called on one device at a time.
        found_device = None
        entity_id = call.data.get("entity_id")[0]
        all_devices = []
        for list_of_devices in hass.data[DOMAIN]["entities"].values():
            all_devices += list_of_devices
        for device in all_devices:
            if device.entity_id == entity_id:
                found_device = device
        if found_device is not None:
            found_device.wink.remove_device()

    hass.services.register(DOMAIN,
                           SERVICE_DELETE_DEVICE,
                           delete_device,
                           schema=DELETE_DEVICE_SCHEMA)

    hubs = pywink.get_hubs()
    for hub in hubs:
        if hub.device_manufacturer() == "wink":
            WINK_HUBS.append(hub)

    if WINK_HUBS:
        hass.services.register(
            DOMAIN,
            SERVICE_SET_PAIRING_MODE,
            set_pairing_mode,
            schema=SET_PAIRING_MODE_SCHEMA,
        )

    def nimbus_service_handle(service):
        """Handle nimbus services."""
        entity_id = service.data.get("entity_id")[0]
        _all_dials = []
        for sensor in hass.data[DOMAIN]["entities"]["sensor"]:
            if isinstance(sensor, WinkNimbusDialDevice):
                _all_dials.append(sensor)
        for _dial in _all_dials:
            if _dial.entity_id == entity_id:
                if service.service == SERVICE_SET_DIAL_CONFIG:
                    _dial.set_configuration(**service.data)
                if service.service == SERVICE_SET_DIAL_STATE:
                    _dial.wink.set_state(service.data.get("value"),
                                         service.data.get("labels"))

    def siren_service_handle(service):
        """Handle siren services."""
        entity_ids = service.data.get("entity_id")
        all_sirens = []
        for switch in hass.data[DOMAIN]["entities"]["switch"]:
            if isinstance(switch, WinkSirenDevice):
                all_sirens.append(switch)
        sirens_to_set = []
        if entity_ids is None:
            sirens_to_set = all_sirens
        else:
            for siren in all_sirens:
                if siren.entity_id in entity_ids:
                    sirens_to_set.append(siren)

        for siren in sirens_to_set:
            _man = siren.wink.device_manufacturer()
            if (service.service != SERVICE_SET_AUTO_SHUTOFF
                    and service.service != SERVICE_ENABLE_SIREN
                    and _man not in ("dome", "wink")):
                _LOGGER.error("Service only valid for Dome or Wink sirens")
                return

            if service.service == SERVICE_ENABLE_SIREN:
                siren.wink.set_state(service.data.get(ATTR_ENABLED))
            elif service.service == SERVICE_SET_AUTO_SHUTOFF:
                siren.wink.set_auto_shutoff(
                    service.data.get(ATTR_AUTO_SHUTOFF))
            elif service.service == SERVICE_SET_CHIME_VOLUME:
                siren.wink.set_chime_volume(service.data.get(ATTR_VOLUME))
            elif service.service == SERVICE_SET_SIREN_VOLUME:
                siren.wink.set_siren_volume(service.data.get(ATTR_VOLUME))
            elif service.service == SERVICE_SET_SIREN_TONE:
                siren.wink.set_siren_sound(service.data.get(ATTR_TONE))
            elif service.service == SERVICE_ENABLE_CHIME:
                siren.wink.set_chime(service.data.get(ATTR_TONE))
            elif service.service == SERVICE_SIREN_STROBE_ENABLED:
                siren.wink.set_siren_strobe_enabled(
                    service.data.get(ATTR_ENABLED))
            elif service.service == SERVICE_CHIME_STROBE_ENABLED:
                siren.wink.set_chime_strobe_enabled(
                    service.data.get(ATTR_ENABLED))

    # Load components for the devices in Wink that we support
    for wink_component in WINK_COMPONENTS:
        hass.data[DOMAIN]["entities"][wink_component] = []
        discovery.load_platform(hass, wink_component, DOMAIN, {}, config)

    component = EntityComponent(_LOGGER, DOMAIN, hass)

    sirens = []
    has_dome_or_wink_siren = False
    for siren in pywink.get_sirens():
        _man = siren.device_manufacturer()
        if _man in ("dome", "wink"):
            has_dome_or_wink_siren = True
        _id = siren.object_id() + siren.name()
        if _id not in hass.data[DOMAIN]["unique_ids"]:
            sirens.append(WinkSirenDevice(siren, hass))

    if sirens:

        hass.services.register(
            DOMAIN,
            SERVICE_SET_AUTO_SHUTOFF,
            siren_service_handle,
            schema=SET_AUTO_SHUTOFF_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_ENABLE_SIREN,
            siren_service_handle,
            schema=ENABLED_SIREN_SCHEMA,
        )

    if has_dome_or_wink_siren:

        hass.services.register(
            DOMAIN,
            SERVICE_SET_SIREN_TONE,
            siren_service_handle,
            schema=SET_SIREN_TONE_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_ENABLE_CHIME,
            siren_service_handle,
            schema=SET_CHIME_MODE_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_SET_SIREN_VOLUME,
            siren_service_handle,
            schema=SET_VOLUME_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_SET_CHIME_VOLUME,
            siren_service_handle,
            schema=SET_VOLUME_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_SIREN_STROBE_ENABLED,
            siren_service_handle,
            schema=SET_STROBE_ENABLED_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_CHIME_STROBE_ENABLED,
            siren_service_handle,
            schema=SET_STROBE_ENABLED_SCHEMA,
        )

    component.add_entities(sirens)

    nimbi = []
    dials = {}
    all_nimbi = pywink.get_cloud_clocks()
    all_dials = []
    for nimbus in all_nimbi:
        if nimbus.object_type() == "cloud_clock":
            nimbi.append(nimbus)
            dials[nimbus.object_id()] = []
    for nimbus in all_nimbi:
        if nimbus.object_type() == "dial":
            dials[nimbus.parent_id()].append(nimbus)

    for nimbus in nimbi:
        for dial in dials[nimbus.object_id()]:
            all_dials.append(WinkNimbusDialDevice(nimbus, dial, hass))

    if nimbi:
        hass.services.register(
            DOMAIN,
            SERVICE_SET_DIAL_CONFIG,
            nimbus_service_handle,
            schema=DIAL_CONFIG_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_SET_DIAL_STATE,
            nimbus_service_handle,
            schema=DIAL_STATE_SCHEMA,
        )

    component.add_entities(all_dials)

    return True
Example #36
0
def setup(hass, config):
    """Setup the Homematic component."""
    from pyhomematic import HMConnection

    component = EntityComponent(_LOGGER, DOMAIN, hass)

    hass.data[DATA_DELAY] = config[DOMAIN].get(CONF_DELAY)
    hass.data[DATA_DEVINIT] = {}
    hass.data[DATA_STORE] = []

    # create hosts list for pyhomematic
    remotes = {}
    hosts = {}
    for rname, rconfig in config[DOMAIN][CONF_HOSTS].items():
        server = rconfig.get(CONF_IP)

        remotes[rname] = {}
        remotes[rname][CONF_IP] = server
        remotes[rname][CONF_PORT] = rconfig.get(CONF_PORT)
        remotes[rname][CONF_RESOLVENAMES] = rconfig.get(CONF_RESOLVENAMES)
        remotes[rname][CONF_USERNAME] = rconfig.get(CONF_USERNAME)
        remotes[rname][CONF_PASSWORD] = rconfig.get(CONF_PASSWORD)

        if server not in hosts or rconfig.get(CONF_PRIMARY):
            hosts[server] = {
                CONF_VARIABLES: rconfig.get(CONF_VARIABLES),
                CONF_NAME: rname,
            }
        hass.data[DATA_DEVINIT][rname] = rconfig.get(CONF_DEVICES)

    # Create server thread
    bound_system_callback = partial(_system_callback_handler, hass, config)
    hass.data[DATA_HOMEMATIC] = HMConnection(
        local=config[DOMAIN].get(CONF_LOCAL_IP),
        localport=config[DOMAIN].get(CONF_LOCAL_PORT),
        remotes=remotes,
        systemcallback=bound_system_callback,
        interface_id="homeassistant")

    # Start server thread, connect to peer, initialize to receive events
    hass.data[DATA_HOMEMATIC].start()

    # Stops server when Homeassistant is shutting down
    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP,
                         hass.data[DATA_HOMEMATIC].stop)
    hass.config.components.append(DOMAIN)

    # init homematic hubs
    hub_entities = []
    for _, hub_data in hosts.items():
        hub_entities.append(
            HMHub(hass, component, hub_data[CONF_NAME],
                  hub_data[CONF_VARIABLES]))
    component.add_entities(hub_entities)

    # regeister homematic services
    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    def _hm_service_virtualkey(service):
        """Service handle virtualkey services."""
        address = service.data.get(ATTR_ADDRESS)
        channel = service.data.get(ATTR_CHANNEL)
        param = service.data.get(ATTR_PARAM)

        # device not found
        hmdevice = _device_from_servicecall(hass, service)
        if hmdevice is None:
            _LOGGER.error("%s not found for service virtualkey!", address)
            return

        # if param exists for this device
        if param not in hmdevice.ACTIONNODE:
            _LOGGER.error("%s not datapoint in hm device %s", param, address)
            return

        # channel exists?
        if channel not in hmdevice.ACTIONNODE[param]:
            _LOGGER.error("%i is not a channel in hm device %s", channel,
                          address)
            return

        # call key
        hmdevice.actionNodeData(param, True, channel)

    hass.services.register(DOMAIN,
                           SERVICE_VIRTUALKEY,
                           _hm_service_virtualkey,
                           descriptions[DOMAIN][SERVICE_VIRTUALKEY],
                           schema=SCHEMA_SERVICE_VIRTUALKEY)

    def _service_handle_value(service):
        """Set value on homematic variable object."""
        variable_list = component.extract_from_service(service)

        value = service.data[ATTR_VALUE]

        for hm_variable in variable_list:
            if isinstance(hm_variable, HMVariable):
                hm_variable.hm_set(value)

    hass.services.register(DOMAIN,
                           SERVICE_SET_VAR_VALUE,
                           _service_handle_value,
                           descriptions[DOMAIN][SERVICE_SET_VAR_VALUE],
                           schema=SCHEMA_SERVICE_SET_VAR_VALUE)

    def _service_handle_reconnect(service):
        """Reconnect to all homematic hubs."""
        hass.data[DATA_HOMEMATIC].reconnect()

    hass.services.register(DOMAIN,
                           SERVICE_RECONNECT,
                           _service_handle_reconnect,
                           descriptions[DOMAIN][SERVICE_RECONNECT],
                           schema=SCHEMA_SERVICE_RECONNECT)

    def _service_handle_device(service):
        """Service handle set_dev_value services."""
        address = service.data.get(ATTR_ADDRESS)
        channel = service.data.get(ATTR_CHANNEL)
        param = service.data.get(ATTR_PARAM)
        value = service.data.get(ATTR_VALUE)

        # device not found
        hmdevice = _device_from_servicecall(hass, service)
        if hmdevice is None:
            _LOGGER.error("%s not found!", address)
            return

        # call key
        hmdevice.setValue(param, value, channel)

    hass.services.register(DOMAIN,
                           SERVICE_SET_DEV_VALUE,
                           _service_handle_device,
                           descriptions[DOMAIN][SERVICE_SET_DEV_VALUE],
                           schema=SCHEMA_SERVICE_SET_DEV_VALUE)

    return True
Example #37
0
def setup(hass, config):
    """Set up variables."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    items = config.get(DOMAIN)
    if items is not None:

        for variable_id, variable_config in items.items():
            if not variable_config:
                variable_config = {}

            name = variable_config.get(CONF_NAME)
            default_temp = variable_config.get(ATTR_DEFAULT_TEMP)

            entities.append(TemperatureControl(variable_id, name,
                                               default_temp))

    def get_temperature_service(call):
        """Handle calls to the set_variable service."""
        entity_id = ENTITY_ID_FORMAT.format(call.data.get(ATTR_CONTROLLER))
        entity = component.get_entity(entity_id)

        if entity:
            return entity.get_temperature(call.data.get(CONF_TIME_STEP))
        else:
            _LOGGER.warning("Failed to set unknown variable: %s", entity_id)

    def set_period_service(call):
        """Handle calls to the set_variable service."""

        entity_id = ENTITY_ID_FORMAT.format(call.data.get(CONF_NAME))
        entity = component.get_entity(entity_id)
        _LOGGER.warning(
            f'Start updating (set_period_service) period on {entity_id}')

        if entity:
            entity.set_period(
                call.data.get(CONF_PERIOD_ID),
                call.data.get(CONF_TIME_START),
                call.data.get(CONF_TIME_STOP),
                call.data.get(CONF_PERIOD_TEMP),
                call.data.get(CONF_DAYS),
            )
        else:
            _LOGGER.warning("Failed to set unknown variable: %s", entity_id)

    hass.services.register(
        DOMAIN,
        SERVICE_GET_TEMPERATURE,
        get_temperature_service,
        schema=SERVICE_GET_TEMPERATURE_SCHEMA,
    )

    hass.services.register(
        DOMAIN,
        SERVICE_SET_PERIOD,
        set_period_service,
        schema=SERVICE_SET_PERIOD_SCHEMA,
    )

    component.add_entities(entities)
    return True
Example #38
0
def setup(hass, config):
    """Setup zigate platform."""
    port = config[DOMAIN].get(CONF_PORT)
    host = config[DOMAIN].get(CONF_HOST)
    gpio = config[DOMAIN].get('gpio', False)
    enable_led = config[DOMAIN].get('enable_led', True)
    polling = config[DOMAIN].get('polling', True)
    channel = config[DOMAIN].get('channel')
    scan_interval = datetime.timedelta(
        seconds=config[DOMAIN].get(CONF_SCAN_INTERVAL, SCAN_INTERVAL))
    admin_panel = config[DOMAIN].get('admin_panel', True)

    persistent_file = os.path.join(hass.config.config_dir, 'zigate.json')

    _LOGGER.debug('Port : %s', port)
    _LOGGER.debug('Host : %s', host)
    _LOGGER.debug('GPIO : %s', gpio)
    _LOGGER.debug('Led : %s', enable_led)
    _LOGGER.debug('Channel : %s', channel)
    _LOGGER.debug('Scan interval : %s', scan_interval)

    myzigate = zigate.connect(port=port,
                              host=host,
                              path=persistent_file,
                              auto_start=False,
                              gpio=gpio)
    _LOGGER.debug('ZiGate object created %s', myzigate)

    hass.data[DOMAIN] = myzigate
    hass.data[DATA_ZIGATE_DEVICES] = {}
    hass.data[DATA_ZIGATE_ATTRS] = {}

    component = EntityComponent(_LOGGER, DOMAIN, hass, scan_interval)
    #     component.setup(config)
    entity = ZiGateComponentEntity(myzigate)
    hass.data[DATA_ZIGATE_DEVICES]['zigate'] = entity
    component.add_entities([entity])

    def device_added(**kwargs):
        device = kwargs['device']
        _LOGGER.debug('Add device {}'.format(device))
        ieee = device.ieee
        if ieee not in hass.data[DATA_ZIGATE_DEVICES]:
            hass.data[DATA_ZIGATE_DEVICES][ieee] = None  # reserve
            entity = ZiGateDeviceEntity(hass, device, polling)
            hass.data[DATA_ZIGATE_DEVICES][ieee] = entity
            component.add_entities([entity])
            if 'signal' in kwargs:
                hass.components.persistent_notification.create(
                    ('A new ZiGate device "{}"'
                     ' has been added !').format(device),
                    title='ZiGate')

    def device_removed(**kwargs):
        # component.async_remove_entity
        device = kwargs['device']
        ieee = device.ieee
        hass.components.persistent_notification.create(
            'The ZiGate device {}({}) is gone.'.format(device.ieee,
                                                       device.addr),
            title='ZiGate')
        entity = hass.data[DATA_ZIGATE_DEVICES][ieee]
        component.async_remove_entity(entity.entity_id)
        del hass.data[DATA_ZIGATE_DEVICES][ieee]

    def device_need_discovery(**kwargs):
        device = kwargs['device']
        hass.components.persistent_notification.create(
            ('The ZiGate device {}({}) needs to be discovered'
             ' (missing important'
             ' information)').format(device.ieee, device.addr),
            title='ZiGate')

    zigate.dispatcher.connect(device_added,
                              zigate.ZIGATE_DEVICE_ADDED,
                              weak=False)
    zigate.dispatcher.connect(device_removed,
                              zigate.ZIGATE_DEVICE_REMOVED,
                              weak=False)
    zigate.dispatcher.connect(device_need_discovery,
                              zigate.ZIGATE_DEVICE_NEED_DISCOVERY,
                              weak=False)

    def attribute_updated(**kwargs):
        device = kwargs['device']
        ieee = device.ieee
        attribute = kwargs['attribute']
        _LOGGER.debug('Update attribute for device {} {}'.format(
            device, attribute))
        entity = hass.data[DATA_ZIGATE_DEVICES].get(ieee)
        event_data = attribute.copy()
        if type(event_data.get('type')) == type:
            event_data['type'] = event_data['type'].__name__
        event_data['ieee'] = device.ieee
        event_data['addr'] = device.addr
        event_data['device_type'] = device.get_property_value('type')
        if entity:
            event_data['entity_id'] = entity.entity_id
        hass.bus.fire('zigate.attribute_updated', event_data)

    zigate.dispatcher.connect(attribute_updated,
                              zigate.ZIGATE_ATTRIBUTE_UPDATED,
                              weak=False)

    def device_updated(**kwargs):
        device = kwargs['device']
        _LOGGER.debug('Update device {}'.format(device))
        ieee = device.ieee
        entity = hass.data[DATA_ZIGATE_DEVICES].get(ieee)
        if not entity:
            _LOGGER.debug('Device not found {}, adding it'.format(device))
            device_added(device=device)
        event_data = {}
        event_data['ieee'] = device.ieee
        event_data['addr'] = device.addr
        event_data['device_type'] = device.get_property_value('type')
        if entity:
            event_data['entity_id'] = entity.entity_id
        hass.bus.fire('zigate.device_updated', event_data)

    zigate.dispatcher.connect(device_updated,
                              zigate.ZIGATE_DEVICE_UPDATED,
                              weak=False)
    zigate.dispatcher.connect(device_updated,
                              zigate.ZIGATE_ATTRIBUTE_ADDED,
                              weak=False)
    zigate.dispatcher.connect(device_updated,
                              zigate.ZIGATE_DEVICE_ADDRESS_CHANGED,
                              weak=False)

    def zigate_reset(service):
        myzigate.reset()

    def permit_join(service):
        myzigate.permit_join()

    def zigate_cleanup(service):
        '''
        Remove missing device
        '''
        myzigate.cleanup_devices()

    def start_zigate(service_event=None):
        myzigate.autoStart(channel)
        myzigate.start_auto_save()
        myzigate.set_led(enable_led)
        version = myzigate.get_version_text()
        if version < '3.1a':
            hass.components.persistent_notification.create(
                ('Your zigate firmware is outdated, '
                 'Please upgrade to 3.1a or later !'),
                title='ZiGate')
        # first load
        for device in myzigate.devices:
            device_added(device=device)

        for platform in SUPPORTED_PLATFORMS:
            load_platform(hass, platform, DOMAIN, {}, config)

        hass.bus.fire('zigate.started')

    def stop_zigate(service=None):
        myzigate.save_state()
        myzigate.close()

        hass.bus.fire('zigate.stopped')

    def refresh_devices_list(service):
        myzigate.get_devices_list()

    def generate_templates(service):
        myzigate.generate_templates(hass.config.config_dir)

    def _get_addr_from_service_request(service):
        entity_id = service.data.get(ATTR_ENTITY_ID)
        ieee = service.data.get(IEEE)
        addr = service.data.get(ADDR)
        if entity_id:
            entity = component.get_entity(entity_id)
            if entity:
                addr = entity._device.addr
        elif ieee:
            device = myzigate.get_device_from_ieee(ieee)
            if device:
                addr = device.addr
        return addr

    def _to_int(value):
        '''
        convert str to int
        '''
        if 'x' in value:
            return int(value, 16)
        return int(value)

    def refresh_device(service):
        full = service.data.get('full', False)
        addr = _get_addr_from_service_request(service)
        if addr:
            myzigate.refresh_device(addr, full=full)
        else:
            for device in myzigate.devices:
                device.refresh_device(full=full)

    def discover_device(service):
        addr = _get_addr_from_service_request(service)
        if addr:
            myzigate.discover_device(addr, True)

    def network_scan(service):
        myzigate.start_network_scan()

    def raw_command(service):
        cmd = _to_int(service.data.get('cmd'))
        data = service.data.get('data', '')
        myzigate.send_data(cmd, data)

    def identify_device(service):
        addr = _get_addr_from_service_request(service)
        myzigate.identify_device(addr)

    def remove_device(service):
        addr = _get_addr_from_service_request(service)
        myzigate.remove_device(addr)

    def initiate_touchlink(service):
        myzigate.initiate_touchlink()

    def touchlink_factory_reset(service):
        myzigate.touchlink_factory_reset()

    def read_attribute(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint'))
        cluster = _to_int(service.data.get('cluster'))
        attribute_id = _to_int(service.data.get('attribute_id'))
        manufacturer_code = _to_int(service.data.get('manufacturer_code', '0'))
        myzigate.read_attribute_request(addr,
                                        endpoint,
                                        cluster,
                                        attribute_id,
                                        manufacturer_code=manufacturer_code)

    def write_attribute(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint'))
        cluster = _to_int(service.data.get('cluster'))
        attribute_id = _to_int(service.data.get('attribute_id'))
        attribute_type = _to_int(service.data.get('attribute_type'))
        value = _to_int(service.data.get('value'))
        attributes = [(attribute_id, attribute_type, value)]
        manufacturer_code = _to_int(service.data.get('manufacturer_code', '0'))
        myzigate.write_attribute_request(addr,
                                         endpoint,
                                         cluster,
                                         attributes,
                                         manufacturer_code=manufacturer_code)

    def add_group(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint'))
        groupaddr = service.data.get('group_addr')
        myzigate.add_group(addr, endpoint, groupaddr)

    def remove_group(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint'))
        groupaddr = service.data.get('group_addr')
        myzigate.remove_group(addr, endpoint, groupaddr)

    def get_group_membership(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint'))
        myzigate.get_group_membership(addr, endpoint)

    def action_onoff(service):
        addr = _get_addr_from_service_request(service)
        onoff = _to_int(service.data.get('onoff'))
        endpoint = _to_int(service.data.get('endpoint', '0'))
        ontime = _to_int(service.data.get('on_time', '0'))
        offtime = _to_int(service.data.get('off_time', '0'))
        effect = _to_int(service.data.get('effect', '0'))
        gradient = _to_int(service.data.get('gradient', '0'))
        myzigate.action_onoff(addr, endpoint, onoff, ontime, offtime, effect,
                              gradient)

    def build_network_table(service):
        table = myzigate.build_neighbours_table(
            service.data.get('force', False))
        _LOGGER.debug('Neighbours table {}'.format(table))

    def ota_load_image(service):
        ota_image_path = service.data.get('imagepath')
        myzigate.ota_load_image(ota_image_path)

    def ota_image_notify(service):
        addr = _get_addr_from_service_request(service)
        destination_endpoint = _to_int(
            service.data.get('destination_endpoint', '1'))
        payload_type = _to_int(service.data.get('payload_type', '0'))
        myzigate.ota_image_notify(addr, destination_endpoint, payload_type)

    def get_ota_status(service):
        myzigate.get_ota_status()

    def view_scene(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        groupaddr = service.data.get('group_addr')
        scene = _to_int(service.data.get('scene'))
        myzigate.view_scene(addr, endpoint, groupaddr, scene)

    def add_scene(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        groupaddr = service.data.get('group_addr')
        scene = _to_int(service.data.get('scene'))
        name = service.data.get('scene_name')
        transition = _to_int(service.data.get('transition', '0'))
        myzigate.add_scene(addr, endpoint, groupaddr, scene, name, transition)

    def remove_scene(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        groupaddr = service.data.get('group_addr')
        scene = _to_int(service.data.get('scene', -1))
        if scene == -1:
            scene = None
        myzigate.remove_scene(addr, endpoint, groupaddr, scene)

    def store_scene(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        groupaddr = service.data.get('group_addr')
        scene = _to_int(service.data.get('scene'))
        myzigate.store_scene(addr, endpoint, groupaddr, scene)

    def recall_scene(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        groupaddr = service.data.get('group_addr')
        scene = _to_int(service.data.get('scene'))
        myzigate.recall_scene(addr, endpoint, groupaddr, scene)

    def scene_membership_request(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        groupaddr = service.data.get('group_addr')
        myzigate.scene_membership_request(addr, endpoint, groupaddr)

    def copy_scene(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        fromgroupaddr = service.data.get('from_group_addr')
        fromscene = _to_int(service.data.get('from_scene'))
        togroupaddr = service.data.get('to_group_addr')
        toscene = _to_int(service.data.get('to_scene'))
        myzigate.copy_scene(addr, endpoint, fromgroupaddr, fromscene,
                            togroupaddr, toscene)

    def ias_warning(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        mode = service.data.get('mode', 'burglar')
        strobe = service.data.get('strobe', True)
        level = service.data.get('level', 'low')
        duration = service.data.get('duration', 60)
        strobe_cycle = service.data.get('strobe_cycle', 10)
        strobe_level = service.data.get('strobe_level', 'low')
        myzigate.action_ias_warning(addr, endpoint, mode, strobe, level,
                                    duration, strobe_cycle, strobe_level)

    def ias_squawk(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        mode = service.data.get('mode', 'armed')
        strobe = service.data.get('strobe', True)
        level = service.data.get('level', 'low')
        myzigate.action_ias_squawk(addr, endpoint, mode, strobe, level)

    def upgrade_firmware(service):
        from zigate.flasher import flash
        from zigate.firmware import download_latest
        port = myzigate._port
        pizigate = False
        if isinstance(myzigate, zigate.ZiGateGPIO):
            pizigate = True
        if myzigate._started and not pizigate:
            msg = 'You should stop zigate first using service zigate.stop_zigate and put zigate in download mode.'
            hass.components.persistent_notification.create(msg, title='ZiGate')
            return
        if pizigate:
            stop_zigate()
            myzigate.set_bootloader_mode()
        backup_filename = 'zigate_backup_{:%Y%m%d%H%M%S}.bin'.format(
            datetime.datetime.now())
        backup_filename = os.path.join(hass.config.config_dir, backup_filename)
        flash(port, save=backup_filename)
        msg = 'ZiGate backup created {}'.format(backup_filename)
        hass.components.persistent_notification.create(msg, title='ZiGate')
        firmware_path = service.data.get('path')
        if not firmware_path:
            firmware_path = download_latest()
        flash(port, write=firmware_path)
        msg = 'ZiGate flashed with {}'.format(firmware_path)
        hass.components.persistent_notification.create(msg, title='ZiGate')
        myzigate._version = None
        if pizigate:
            myzigate.set_running_mode()
            start_zigate()
        else:
            msg = 'Now you have to unplug/replug the ZiGate USB key and then call service zigate.start_zigate'
            hass.components.persistent_notification.create(msg, title='ZiGate')

    hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zigate)
    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zigate)

    hass.services.register(DOMAIN, 'refresh_devices_list',
                           refresh_devices_list)
    hass.services.register(DOMAIN, 'generate_templates', generate_templates)
    hass.services.register(DOMAIN, 'reset', zigate_reset)
    hass.services.register(DOMAIN, 'permit_join', permit_join)
    hass.services.register(DOMAIN, 'start_zigate', start_zigate)
    hass.services.register(DOMAIN, 'stop_zigate', stop_zigate)
    hass.services.register(DOMAIN, 'cleanup_devices', zigate_cleanup)
    hass.services.register(DOMAIN,
                           'refresh_device',
                           refresh_device,
                           schema=REFRESH_DEVICE_SCHEMA)
    hass.services.register(DOMAIN,
                           'discover_device',
                           discover_device,
                           schema=DISCOVER_DEVICE_SCHEMA)
    hass.services.register(DOMAIN, 'network_scan', network_scan)
    hass.services.register(DOMAIN,
                           'raw_command',
                           raw_command,
                           schema=RAW_COMMAND_SCHEMA)
    hass.services.register(DOMAIN,
                           'identify_device',
                           identify_device,
                           schema=IDENTIFY_SCHEMA)
    hass.services.register(DOMAIN,
                           'remove_device',
                           remove_device,
                           schema=REMOVE_SCHEMA)
    hass.services.register(DOMAIN, 'initiate_touchlink', initiate_touchlink)
    hass.services.register(DOMAIN, 'touchlink_factory_reset',
                           touchlink_factory_reset)
    hass.services.register(DOMAIN,
                           'read_attribute',
                           read_attribute,
                           schema=READ_ATTRIBUTE_SCHEMA)
    hass.services.register(DOMAIN,
                           'write_attribute',
                           write_attribute,
                           schema=WRITE_ATTRIBUTE_SCHEMA)
    hass.services.register(DOMAIN,
                           'add_group',
                           add_group,
                           schema=ADD_GROUP_SCHEMA)
    hass.services.register(DOMAIN,
                           'get_group_membership',
                           get_group_membership,
                           schema=GET_GROUP_MEMBERSHIP_SCHEMA)
    hass.services.register(DOMAIN,
                           'remove_group',
                           remove_group,
                           schema=REMOVE_GROUP_SCHEMA)
    hass.services.register(DOMAIN,
                           'action_onoff',
                           action_onoff,
                           schema=ACTION_ONOFF_SCHEMA)
    hass.services.register(DOMAIN,
                           'build_network_table',
                           build_network_table,
                           schema=BUILD_NETWORK_TABLE_SCHEMA)
    hass.services.register(DOMAIN,
                           'ias_warning',
                           ias_warning,
                           schema=ACTION_IAS_WARNING_SCHEMA)
    hass.services.register(DOMAIN,
                           'ias_squawk',
                           ias_squawk,
                           schema=ACTION_IAS_SQUAWK_SCHEMA)

    hass.services.register(DOMAIN,
                           'ota_load_image',
                           ota_load_image,
                           schema=OTA_LOAD_IMAGE_SCHEMA)
    hass.services.register(DOMAIN,
                           'ota_image_notify',
                           ota_image_notify,
                           schema=OTA_IMAGE_NOTIFY_SCHEMA)
    hass.services.register(DOMAIN, 'ota_get_status', get_ota_status)
    hass.services.register(DOMAIN,
                           'view_scene',
                           view_scene,
                           schema=VIEW_SCENE_SCHEMA)
    hass.services.register(DOMAIN,
                           'add_scene',
                           add_scene,
                           schema=ADD_SCENE_SCHEMA)
    hass.services.register(DOMAIN,
                           'remove_scene',
                           remove_scene,
                           schema=REMOVE_SCENE_SCHEMA)
    hass.services.register(DOMAIN,
                           'store_scene',
                           store_scene,
                           schema=STORE_SCENE_SCHEMA)
    hass.services.register(DOMAIN,
                           'recall_scene',
                           recall_scene,
                           schema=RECALL_SCENE_SCHEMA)
    hass.services.register(DOMAIN,
                           'scene_membership_request',
                           scene_membership_request,
                           schema=SCENE_MEMBERSHIP_REQUEST_SCHEMA)
    hass.services.register(DOMAIN,
                           'copy_scene',
                           copy_scene,
                           schema=COPY_SCENE_SCHEMA)
    hass.services.register(DOMAIN, 'upgrade_firmware', upgrade_firmware)
    track_time_change(hass, refresh_devices_list, hour=0, minute=0, second=0)

    if admin_panel:
        _LOGGER.debug('Start ZiGate Admin Panel on port 9998')
        myzigate.start_adminpanel(prefix='/zigateproxy')

        hass.http.register_view(ZiGateAdminPanel())
        hass.http.register_view(ZiGateProxy())
        custom_panel_config = {
            "name": "zigateadmin",
            "embed_iframe": False,
            "trust_external": False,
            "html_url": "/zigateadmin.html",
        }

        config = {}
        config["_panel_custom"] = custom_panel_config

        hass.components.frontend.async_register_built_in_panel(
            component_name="custom",
            sidebar_title='Zigate Admin',
            sidebar_icon='mdi:zigbee',
            frontend_url_path="zigateadmin",
            config=config,
            require_admin=True,
        )

#     hass.async_create_task(
#         hass.config_entries.flow.async_init(
#             DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data={}
#         )
#     )

    return True
Example #39
0
class SmartReminders:
    """Main Smart Reminders Service"""
    def __init__(self, hass, config):
        self.hass = hass
        self.conf = config
        self.db = SmartReminderDB(config)

        items = []
        try:
            self.items = self.db.get_all_reminders()
        except:
            self.items = []

        self.component = EntityComponent(_LOGGER, DOMAIN, hass)
        entities = []

        if self.items:
            for item in self.items:
                ent = SmartReminderItem(hass, item, self.db)
                entities.append(ent)
            if entities:
                self.component.add_entities(entities)

        hass.services.register(DOMAIN, "add_task", self.handle_add_task)
        hass.services.register(DOMAIN, "complete_task",
                               self.handle_complete_task)
        hass.services.register(DOMAIN, "delete_task", self.handle_delete_task)

    async def handle_add_task(self, call):
        """Handle the service call."""
        await self.add_task(call.data)

    async def handle_delete_task(self, call):
        try:
            entity_id = call.data.get('id')
            ent = self.component.get_entity(entity_id)
            idx = ent._id
            await self.db.delete_reminder(idx)
            await self.component.async_remove_entity(entity_id)
        except Exception as e:
            logging.error(traceback.format_exc())

    async def handle_complete_task(self, call):
        """Handle completing the task and removing it from entities"""
        try:
            entity_id = call.data.get('id')
            ent = self.component.get_entity(entity_id)
            idx = ent._id
            self.db.complete_reminder(idx)
            if ent.is_repeatable:
                derp = {ent._repeat_type: ent._repeat_number}
                due_date = ent._original_due_date + timedelta(**derp)
                data = {
                    ATTR_TITLE: ent._title,
                    "user": ent._username,
                    ATTR_DUE: due_date,
                    "repeat_type": ent._repeat_type,
                    "repeat_number": ent._repeat_number,
                    "repeatable": True
                }
                await self.add_task(data)
            await self.component.async_remove_entity(entity_id)
        except Exception as e:
            logging.error(traceback.format_exc())

    async def add_task(self, data):
        try:
            new_item = await self.db.add_reminder(data)
            ent = SmartReminderItem(self.hass, new_item, self.db)
            await self.component.async_add_entities([ent])
        except Exception as e:
            logging.error(traceback.format_exc())
Example #40
0
def setup(hass, config):
    """Setup zigate platform."""
    import zigate

    port = config[DOMAIN].get(CONF_PORT)
    host = config[DOMAIN].get(CONF_HOST)
    gpio = config[DOMAIN].get('gpio', False)
    enable_led = config[DOMAIN].get('enable_led', True)
    polling = config[DOMAIN].get('polling', True)
    channel = config[DOMAIN].get('channel')
    persistent_file = os.path.join(hass.config.config_dir,
                                   'zigate.json')

    _LOGGER.debug('Port : %s', port)
    _LOGGER.debug('Host : %s', host)
    _LOGGER.debug('GPIO : %s', gpio)
    _LOGGER.debug('Led : %s', enable_led)
    _LOGGER.debug('Channel : %s', channel)

    myzigate = zigate.connect(port=port, host=host,
                              path=persistent_file,
                              auto_start=False,
                              gpio=gpio
                              )
    _LOGGER.debug('ZiGate object created %s', myzigate)

    hass.data[DOMAIN] = myzigate
    hass.data[DATA_ZIGATE_DEVICES] = {}
    hass.data[DATA_ZIGATE_ATTRS] = {}

    component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_ZIGATE)
    component.setup(config)
    entity = ZiGateComponentEntity(myzigate)
    hass.data[DATA_ZIGATE_DEVICES]['zigate'] = entity
    component.add_entities([entity])

    def device_added(**kwargs):
        device = kwargs['device']
        _LOGGER.debug('Add device {}'.format(device))
        ieee = device.ieee or device.addr  # compatibility
        if ieee not in hass.data[DATA_ZIGATE_DEVICES]:
            entity = ZiGateDeviceEntity(hass, device, polling)
            hass.data[DATA_ZIGATE_DEVICES][ieee] = entity
            component.add_entities([entity])
            if 'signal' in kwargs:
                hass.components.persistent_notification.create(
                    ('A new ZiGate device "{}"'
                     ' has been added !'
                     ).format(device),
                    title='ZiGate')

    def device_removed(**kwargs):
        # component.async_remove_entity
        device = kwargs['device']
        ieee = device.ieee or device.addr  # compatibility
        hass.components.persistent_notification.create(
            'The ZiGate device {}({}) is gone.'.format(device.ieee,
                                                       device.addr),
            title='ZiGate')
        entity = hass.data[DATA_ZIGATE_DEVICES][ieee]
        component.async_remove_entity(entity.entity_id)
        del hass.data[DATA_ZIGATE_DEVICES][ieee]

    def device_need_discovery(**kwargs):
        device = kwargs['device']
        hass.components.persistent_notification.create(
            ('The ZiGate device {}({}) needs to be discovered'
             ' (missing important'
             ' information)').format(device.ieee, device.addr),
            title='ZiGate')

    zigate.dispatcher.connect(device_added,
                              zigate.ZIGATE_DEVICE_ADDED, weak=False)
    zigate.dispatcher.connect(device_removed,
                              zigate.ZIGATE_DEVICE_REMOVED, weak=False)
    zigate.dispatcher.connect(device_need_discovery,
                              zigate.ZIGATE_DEVICE_NEED_DISCOVERY, weak=False)

    def attribute_updated(**kwargs):
        device = kwargs['device']
        ieee = device.ieee or device.addr  # compatibility
        attribute = kwargs['attribute']
        _LOGGER.debug('Update attribute for device {} {}'.format(device,
                                                                 attribute))
        entity = hass.data[DATA_ZIGATE_DEVICES].get(ieee)
        event_data = attribute.copy()
        if type(event_data.get('type')) == type:
            event_data['type'] = event_data['type'].__name__
        event_data['ieee'] = device.ieee
        event_data['addr'] = device.addr
        event_data['device_type'] = device.get_property_value('type')
        if entity:
            event_data['entity_id'] = entity.entity_id
        hass.bus.fire('zigate.attribute_updated', event_data)

    zigate.dispatcher.connect(attribute_updated,
                              zigate.ZIGATE_ATTRIBUTE_UPDATED, weak=False)

    def device_updated(**kwargs):
        device = kwargs['device']
        _LOGGER.debug('Update device {}'.format(device))
        ieee = device.ieee or device.addr  # compatibility
        entity = hass.data[DATA_ZIGATE_DEVICES].get(ieee)
        if not entity:
            _LOGGER.debug('Device not found {}, adding it'.format(device))
            device_added(device=device)
        event_data = {}
        event_data['ieee'] = device.ieee
        event_data['addr'] = device.addr
        event_data['device_type'] = device.get_property_value('type')
        if entity:
            event_data['entity_id'] = entity.entity_id
        hass.bus.fire('zigate.device_updated', event_data)

    zigate.dispatcher.connect(device_updated,
                              zigate.ZIGATE_DEVICE_UPDATED, weak=False)
    zigate.dispatcher.connect(device_updated,
                              zigate.ZIGATE_ATTRIBUTE_ADDED, weak=False)
    zigate.dispatcher.connect(device_updated,
                              zigate.ZIGATE_DEVICE_ADDRESS_CHANGED, weak=False)

    def zigate_reset(service):
        myzigate.reset()

    def permit_join(service):
        myzigate.permit_join()

    def zigate_cleanup(service):
        '''
        Remove missing device
        '''
        myzigate.cleanup_devices()

    def start_zigate(service_event=None):
        myzigate.autoStart(channel)
        myzigate.start_auto_save()
        myzigate.set_led(enable_led)
        version = myzigate.get_version_text()
        if version < '3.0f':
            hass.components.persistent_notification.create(
                ('Your zigate firmware is outdated, '
                 'Please upgrade to 3.0f or later !'),
                title='ZiGate')
        # first load
        for device in myzigate.devices:
            device_added(device=device)

        for platform in SUPPORTED_PLATFORMS:
            load_platform(hass, platform, DOMAIN, {}, config)

        hass.bus.fire('zigate.started')

    def stop_zigate(service_event):
        myzigate.save_state()
        myzigate.close()

        hass.bus.fire('zigate.stopped')

    def refresh_devices_list(service):
        myzigate.get_devices_list()

    def generate_templates(service):
        myzigate.generate_templates(hass.config.config_dir)

    def _get_addr_from_service_request(service):
        entity_id = service.data.get(ATTR_ENTITY_ID)
        ieee = service.data.get(IEEE)
        addr = service.data.get(ADDR)
        if entity_id:
            entity = component.get_entity(entity_id)
            if entity:
                addr = entity._device.addr
        elif ieee:
            device = myzigate.get_device_from_ieee(ieee)
            if device:
                addr = device.addr
        return addr

    def _to_int(value):
        '''
        convert str to int
        '''
        if 'x' in value:
            return int(value, 16)
        return int(value)

    def refresh_device(service):
        addr = _get_addr_from_service_request(service)
        if addr:
            myzigate.refresh_device(addr, full=True)
        else:
            for device in myzigate.devices:
                device.refresh_device(full=True)

    def discover_device(service):
        addr = _get_addr_from_service_request(service)
        if addr:
            myzigate.discover_device(addr, True)

    def network_scan(service):
        myzigate.start_network_scan()

    def raw_command(service):
        cmd = _to_int(service.data.get('cmd'))
        data = service.data.get('data', '')
        myzigate.send_data(cmd, data)

    def identify_device(service):
        addr = _get_addr_from_service_request(service)
        myzigate.identify_device(addr)

    def remove_device(service):
        addr = _get_addr_from_service_request(service)
        myzigate.remove_device(addr)

    def initiate_touchlink(service):
        myzigate.initiate_touchlink()

    def touchlink_factory_reset(service):
        myzigate.touchlink_factory_reset()

    def read_attribute(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint'))
        cluster = _to_int(service.data.get('cluster'))
        attribute_id = _to_int(service.data.get('attribute_id'))
        manufacturer_code = _to_int(service.data.get('manufacturer_code', '0'))
        myzigate.read_attribute_request(addr, endpoint, cluster, attribute_id,
                                        manufacturer_code=manufacturer_code)

    def write_attribute(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint'))
        cluster = _to_int(service.data.get('cluster'))
        attribute_id = _to_int(service.data.get('attribute_id'))
        attribute_type = _to_int(service.data.get('attribute_type'))
        value = _to_int(service.data.get('value'))
        attributes = [(attribute_id, attribute_type, value)]
        manufacturer_code = _to_int(service.data.get('manufacturer_code', '0'))
        myzigate.write_attribute_request(addr, endpoint, cluster, attributes,
                                         manufacturer_code=manufacturer_code)

    def add_group(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint'))
        groupaddr = service.data.get('group_addr')
        myzigate.add_group(addr, endpoint, groupaddr)

    def remove_group(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint'))
        groupaddr = service.data.get('group_addr')
        myzigate.remove_group(addr, endpoint, groupaddr)

    def get_group_membership(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint'))
        myzigate.get_group_membership(addr, endpoint)

    def action_onoff(service):
        addr = _get_addr_from_service_request(service)
        onoff = _to_int(service.data.get('onoff'))
        endpoint = _to_int(service.data.get('endpoint', '0'))
        ontime = _to_int(service.data.get('on_time', '0'))
        offtime = _to_int(service.data.get('off_time', '0'))
        effect = _to_int(service.data.get('effect', '0'))
        gradient = _to_int(service.data.get('gradient', '0'))
        myzigate.action_onoff(addr, endpoint, onoff, ontime, offtime, effect, gradient)

    def build_network_table(service):
        table = myzigate.build_neighbours_table(service.data.get('force', False))
        _LOGGER.debug('Neighbours table {}'.format(table))
        entity = hass.data[DATA_ZIGATE_DEVICES].get('zigate')
        if entity:
            entity.network_table = table

    def ota_load_image(service):
        ota_image_path = service.data.get('imagepath')
        myzigate.ota_load_image(ota_image_path)

    def ota_image_notify(service):
        addr = _get_addr_from_service_request(service)
        destination_endpoint = _to_int(service.data.get('destination_endpoint', '1'))
        payload_type = _to_int(service.data.get('payload_type', '0'))
        myzigate.ota_image_notify(addr, destination_endpoint, payload_type)

    def get_ota_status(service):
        myzigate.get_ota_status()

    def view_scene(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        groupaddr = service.data.get('group_addr')
        scene = _to_int(service.data.get('scene'))
        myzigate.view_scene(addr, endpoint, groupaddr, scene)

    def add_scene(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        groupaddr = service.data.get('group_addr')
        scene = _to_int(service.data.get('scene'))
        name = service.data.get('scene_name')
        transition = _to_int(service.data.get('transition', '0'))
        myzigate.add_scene(addr, endpoint, groupaddr, scene, name, transition)

    def remove_scene(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        groupaddr = service.data.get('group_addr')
        scene = _to_int(service.data.get('scene', -1))
        if scene == -1:
            scene = None
        myzigate.remove_scene(addr, endpoint, groupaddr, scene)

    def store_scene(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        groupaddr = service.data.get('group_addr')
        scene = _to_int(service.data.get('scene'))
        myzigate.store_scene(addr, endpoint, groupaddr, scene)

    def recall_scene(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        groupaddr = service.data.get('group_addr')
        scene = _to_int(service.data.get('scene'))
        myzigate.recall_scene(addr, endpoint, groupaddr, scene)

    def scene_membership_request(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        groupaddr = service.data.get('group_addr')
        myzigate.scene_membership_request(addr, endpoint, groupaddr)

    def copy_scene(service):
        addr = _get_addr_from_service_request(service)
        endpoint = _to_int(service.data.get('endpoint', '1'))
        fromgroupaddr = service.data.get('from_group_addr')
        fromscene = _to_int(service.data.get('from_scene'))
        togroupaddr = service.data.get('to_group_addr')
        toscene = _to_int(service.data.get('to_scene'))
        myzigate.copy_scene(addr, endpoint, fromgroupaddr, fromscene, togroupaddr, toscene)

    hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zigate)
    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zigate)

    hass.services.register(DOMAIN, 'refresh_devices_list',
                           refresh_devices_list)
    hass.services.register(DOMAIN, 'generate_templates',
                           generate_templates)
    hass.services.register(DOMAIN, 'reset', zigate_reset)
    hass.services.register(DOMAIN, 'permit_join', permit_join)
    hass.services.register(DOMAIN, 'start_zigate', start_zigate)
    hass.services.register(DOMAIN, 'stop_zigate', stop_zigate)
    hass.services.register(DOMAIN, 'cleanup_devices', zigate_cleanup)
    hass.services.register(DOMAIN, 'refresh_device',
                           refresh_device,
                           schema=REFRESH_DEVICE_SCHEMA)
    hass.services.register(DOMAIN, 'discover_device',
                           discover_device,
                           schema=DISCOVER_DEVICE_SCHEMA)
    hass.services.register(DOMAIN, 'network_scan', network_scan)
    hass.services.register(DOMAIN, 'raw_command', raw_command,
                           schema=RAW_COMMAND_SCHEMA)
    hass.services.register(DOMAIN, 'identify_device', identify_device,
                           schema=IDENTIFY_SCHEMA)
    hass.services.register(DOMAIN, 'remove_device', remove_device,
                           schema=REMOVE_SCHEMA)
    hass.services.register(DOMAIN, 'initiate_touchlink', initiate_touchlink)
    hass.services.register(DOMAIN, 'touchlink_factory_reset',
                           touchlink_factory_reset)
    hass.services.register(DOMAIN, 'read_attribute', read_attribute,
                           schema=READ_ATTRIBUTE_SCHEMA)
    hass.services.register(DOMAIN, 'write_attribute', write_attribute,
                           schema=WRITE_ATTRIBUTE_SCHEMA)
    hass.services.register(DOMAIN, 'add_group', add_group,
                           schema=ADD_GROUP_SCHEMA)
    hass.services.register(DOMAIN, 'get_group_membership', get_group_membership,
                           schema=GET_GROUP_MEMBERSHIP_SCHEMA)
    hass.services.register(DOMAIN, 'remove_group', remove_group,
                           schema=REMOVE_GROUP_SCHEMA)
    hass.services.register(DOMAIN, 'action_onoff', action_onoff,
                           schema=ACTION_ONOFF_SCHEMA)
    hass.services.register(DOMAIN, 'build_network_table', build_network_table,
                           schema=BUILD_NETWORK_TABLE_SCHEMA)

    hass.services.register(DOMAIN, 'ota_load_image', ota_load_image,
                           schema=OTA_LOAD_IMAGE_SCHEMA)
    hass.services.register(DOMAIN, 'ota_image_notify', ota_image_notify,
                           schema=OTA_IMAGE_NOTIFY_SCHEMA)
    hass.services.register(DOMAIN, 'ota_get_status', get_ota_status)
    hass.services.register(DOMAIN, 'view_scene', view_scene,
                           schema=VIEW_SCENE_SCHEMA)
    hass.services.register(DOMAIN, 'add_scene', add_scene,
                           schema=ADD_SCENE_SCHEMA)
    hass.services.register(DOMAIN, 'remove_scene', remove_scene,
                           schema=REMOVE_SCENE_SCHEMA)
    hass.services.register(DOMAIN, 'store_scene', store_scene,
                           schema=STORE_SCENE_SCHEMA)
    hass.services.register(DOMAIN, 'recall_scene', recall_scene,
                           schema=RECALL_SCENE_SCHEMA)
    hass.services.register(DOMAIN, 'scene_membership_request', scene_membership_request,
                           schema=SCENE_MEMBERSHIP_REQUEST_SCHEMA)
    hass.services.register(DOMAIN, 'copy_scene', copy_scene,
                           schema=COPY_SCENE_SCHEMA)
    track_time_change(hass, refresh_devices_list,
                      hour=0, minute=0, second=0)

    return True
Example #41
0
def setup(hass, config):
    """Setup the Homematic component."""
    global HOMEMATIC, HOMEMATIC_LINK_DELAY
    from pyhomematic import HMConnection

    component = EntityComponent(_LOGGER, DOMAIN, hass)

    local_ip = config[DOMAIN].get(CONF_LOCAL_IP)
    local_port = config[DOMAIN].get(CONF_LOCAL_PORT)
    remote_ip = config[DOMAIN].get(CONF_REMOTE_IP)
    remote_port = config[DOMAIN].get(CONF_REMOTE_PORT)
    resolvenames = config[DOMAIN].get(CONF_RESOLVENAMES)
    username = config[DOMAIN].get(CONF_USERNAME)
    password = config[DOMAIN].get(CONF_PASSWORD)
    HOMEMATIC_LINK_DELAY = config[DOMAIN].get(CONF_DELAY)
    use_variables = config[DOMAIN].get(CONF_VARIABLES)

    if remote_ip is None or local_ip is None:
        _LOGGER.error("Missing remote CCU/Homegear or local address")
        return False

    # Create server thread
    bound_system_callback = partial(_system_callback_handler, hass, config)
    HOMEMATIC = HMConnection(local=local_ip,
                             localport=local_port,
                             remote=remote_ip,
                             remoteport=remote_port,
                             systemcallback=bound_system_callback,
                             resolvenames=resolvenames,
                             rpcusername=username,
                             rpcpassword=password,
                             interface_id="homeassistant")

    # Start server thread, connect to peer, initialize to receive events
    HOMEMATIC.start()

    # Stops server when Homeassistant is shutting down
    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, HOMEMATIC.stop)
    hass.config.components.append(DOMAIN)

    # regeister homematic services
    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    hass.services.register(DOMAIN,
                           SERVICE_VIRTUALKEY,
                           _hm_service_virtualkey,
                           descriptions[DOMAIN][SERVICE_VIRTUALKEY],
                           schema=SCHEMA_SERVICE_VIRTUALKEY)

    entities = []

    ##
    # init HM variable
    variables = HOMEMATIC.getAllSystemVariables() if use_variables else {}
    hm_var_store = {}
    if variables is not None:
        for key, value in variables.items():
            varia = HMVariable(key, value)
            hm_var_store.update({key: varia})
            entities.append(varia)

    # add homematic entites
    entities.append(HMHub(hm_var_store, use_variables))
    component.add_entities(entities)

    ##
    # register set_value service if exists variables
    if not variables:
        return True

    def _service_handle_value(service):
        """Set value on homematic variable object."""
        variable_list = component.extract_from_service(service)

        value = service.data[ATTR_VALUE]

        for hm_variable in variable_list:
            hm_variable.hm_set(value)

    hass.services.register(DOMAIN,
                           SERVICE_SET_VALUE,
                           _service_handle_value,
                           descriptions[DOMAIN][SERVICE_SET_VALUE],
                           schema=SCHEMA_SERVICE_SET_VALUE)

    return True
Example #42
0
def setup(hass, config):
    """Setup the OpenAlpr component."""
    engine = config[DOMAIN].get(CONF_ENGINE)
    region = config[DOMAIN].get(CONF_REGION)
    confidence = config[DOMAIN].get(CONF_CONFIDENCE)
    api_key = config[DOMAIN].get(CONF_API_KEY)
    binary = config[DOMAIN].get(CONF_ALPR_BINARY)
    use_render_fffmpeg = False

    component = EntityComponent(_LOGGER, DOMAIN, hass)
    openalpr_device = []

    for device in config[DOMAIN].get(CONF_ENTITIES):
        input_source = device.get(CONF_INPUT)
        render = device.get(CONF_RENDER)

        ##
        # create api
        if engine == ENGINE_LOCAL:
            alpr_api = OpenalprApiLocal(
                confidence=confidence,
                region=region,
                binary=binary,
            )
        else:
            alpr_api = OpenalprApiCloud(
                confidence=confidence,
                region=region,
                api_key=api_key,
            )

        ##
        # Create Alpr device / render engine
        if render == RENDER_FFMPEG:
            use_render_fffmpeg = True
            if not run_test(input_source):
                _LOGGER.error("'%s' is not valid ffmpeg input", input_source)
                continue

            alpr_dev = OpenalprDeviceFFmpeg(
                name=device.get(CONF_NAME),
                interval=device.get(CONF_INTERVAL),
                api=alpr_api,
                input_source=input_source,
                extra_arguments=device.get(CONF_EXTRA_ARGUMENTS),
            )
        else:
            alpr_dev = OpenalprDeviceImage(
                name=device.get(CONF_NAME),
                interval=device.get(CONF_INTERVAL),
                api=alpr_api,
                input_source=input_source,
                username=device.get(CONF_USERNAME),
                password=device.get(CONF_PASSWORD),
            )

        # register shutdown event
        openalpr_device.append(alpr_dev)
        hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, alpr_dev.shutdown)

    component.add_entities(openalpr_device)

    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    def _handle_service_scan(service):
        """Handle service for immediately scan."""
        device_list = component.extract_from_service(service)

        for device in device_list:
            device.scan()

    hass.services.register(DOMAIN,
                           SERVICE_SCAN,
                           _handle_service_scan,
                           descriptions[DOMAIN][SERVICE_SCAN],
                           schema=SERVICE_SCAN_SCHEMA)

    # Add restart service only if a device use ffmpeg as render
    if not use_render_fffmpeg:
        return True

    def _handle_service_restart(service):
        """Handle service for restart ffmpeg process."""
        device_list = component.extract_from_service(service)

        for device in device_list:
            device.restart()

    hass.services.register(DOMAIN,
                           SERVICE_RESTART,
                           _handle_service_restart,
                           descriptions[DOMAIN][SERVICE_RESTART],
                           schema=SERVICE_RESTART_SCHEMA)

    return True
Example #43
0
def setup(hass, config):
    """Set up the Wink component."""
    import pywink
    from pubnubsubhandler import PubNubSubscriptionHandler

    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    if hass.data.get(DOMAIN) is None:
        hass.data[DOMAIN] = {
            'unique_ids': [],
            'entities': {},
            'oauth': {},
            'configuring': {},
            'pubnub': None,
            'configurator': False
        }

    if config.get(DOMAIN) is not None:
        client_id = config[DOMAIN].get(ATTR_CLIENT_ID)
        client_secret = config[DOMAIN].get(ATTR_CLIENT_SECRET)
        email = config[DOMAIN].get(CONF_EMAIL)
        password = config[DOMAIN].get(CONF_PASSWORD)
        local_control = config[DOMAIN].get(CONF_LOCAL_CONTROL)
    else:
        client_id = None
        client_secret = None
        email = None
        password = None
        local_control = None
        hass.data[DOMAIN]['configurator'] = True
    if None not in [client_id, client_secret]:
        _LOGGER.info("Using legacy oauth authentication")
        if not local_control:
            pywink.disable_local_control()
        hass.data[DOMAIN]["oauth"]["client_id"] = client_id
        hass.data[DOMAIN]["oauth"]["client_secret"] = client_secret
        hass.data[DOMAIN]["oauth"]["email"] = email
        hass.data[DOMAIN]["oauth"]["password"] = password
        pywink.legacy_set_wink_credentials(email, password,
                                           client_id, client_secret)
    else:
        _LOGGER.info("Using oauth authentication")
        if not local_control:
            pywink.disable_local_control()
        config_path = hass.config.path(WINK_CONFIG_FILE)
        if os.path.isfile(config_path):
            config_file = load_json(config_path)
            if config_file == DEFAULT_CONFIG:
                _request_app_setup(hass, config)
                return True
            # else move on because the user modified the file
        else:
            save_json(config_path, DEFAULT_CONFIG)
            _request_app_setup(hass, config)
            return True

        if DOMAIN in hass.data[DOMAIN]['configuring']:
            _configurator = hass.data[DOMAIN]['configuring']
            hass.components.configurator.request_done(_configurator.pop(
                DOMAIN))

        # Using oauth
        access_token = config_file.get(ATTR_ACCESS_TOKEN)
        refresh_token = config_file.get(ATTR_REFRESH_TOKEN)

        # This will be called after authorizing Home-Assistant
        if None not in (access_token, refresh_token):
            pywink.set_wink_credentials(config_file.get(ATTR_CLIENT_ID),
                                        config_file.get(ATTR_CLIENT_SECRET),
                                        access_token=access_token,
                                        refresh_token=refresh_token)
        # This is called to create the redirect so the user can Authorize
        # Home-Assistant
        else:

            redirect_uri = '{}{}'.format(hass.config.api.base_url,
                                         WINK_AUTH_CALLBACK_PATH)

            wink_auth_start_url = pywink.get_authorization_url(
                config_file.get(ATTR_CLIENT_ID), redirect_uri)
            hass.http.register_redirect(WINK_AUTH_START, wink_auth_start_url)
            hass.http.register_view(WinkAuthCallbackView(config,
                                                         config_file,
                                                         pywink.request_token))
            _request_oauth_completion(hass, config)
            return True

    pywink.set_user_agent(USER_AGENT)
    hass.data[DOMAIN]['pubnub'] = PubNubSubscriptionHandler(
        pywink.get_subscription_key())

    def _subscribe():
        hass.data[DOMAIN]['pubnub'].subscribe()

    # Call subscribe after the user sets up wink via the configurator
    # All other methods will complete setup before
    # EVENT_HOMEASSISTANT_START is called meaning they
    # will call subscribe via the method below. (start_subscription)
    if hass.data[DOMAIN]['configurator']:
        _subscribe()

    def keep_alive_call(event_time):
        """Call the Wink API endpoints to keep PubNub working."""
        _LOGGER.info("Polling the Wink API to keep PubNub updates flowing.")
        pywink.set_user_agent(str(int(time.time())))
        _temp_response = pywink.get_user()
        _LOGGER.debug(str(json.dumps(_temp_response)))
        time.sleep(1)
        pywink.set_user_agent(USER_AGENT)
        _temp_response = pywink.wink_api_fetch()
        _LOGGER.debug(str(json.dumps(_temp_response)))

    # Call the Wink API every hour to keep PubNub updates flowing
    track_time_interval(hass, keep_alive_call, timedelta(minutes=60))

    def start_subscription(event):
        """Start the pubnub subscription."""
        _subscribe()

    hass.bus.listen(EVENT_HOMEASSISTANT_START, start_subscription)

    def stop_subscription(event):
        """Stop the pubnub subscription."""
        hass.data[DOMAIN]['pubnub'].unsubscribe()
        hass.data[DOMAIN]['pubnub'] = None

    hass.bus.listen(EVENT_HOMEASSISTANT_STOP, stop_subscription)

    def save_credentials(event):
        """Save currently set oauth credentials."""
        if hass.data[DOMAIN]["oauth"].get("email") is None:
            config_path = hass.config.path(WINK_CONFIG_FILE)
            _config = pywink.get_current_oauth_credentials()
            save_json(config_path, _config)

    hass.bus.listen(EVENT_HOMEASSISTANT_STOP, save_credentials)

    def force_update(call):
        """Force all devices to poll the Wink API."""
        _LOGGER.info("Refreshing Wink states from API")
        for entity_list in hass.data[DOMAIN]['entities'].values():
            # Throttle the calls to Wink API
            for entity in entity_list:
                time.sleep(1)
                entity.schedule_update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_REFRESH_STATES, force_update,
                           descriptions.get(SERVICE_REFRESH_STATES))

    def pull_new_devices(call):
        """Pull new devices added to users Wink account since startup."""
        _LOGGER.info("Getting new devices from Wink API")
        for _component in WINK_COMPONENTS:
            discovery.load_platform(hass, _component, DOMAIN, {}, config)

    hass.services.register(DOMAIN, SERVICE_ADD_NEW_DEVICES, pull_new_devices,
                           descriptions.get(SERVICE_ADD_NEW_DEVICES))

    def set_pairing_mode(call):
        """Put the hub in provided pairing mode."""
        hub_name = call.data.get('hub_name')
        pairing_mode = call.data.get('pairing_mode')
        kidde_code = call.data.get('kidde_radio_code')
        for hub in WINK_HUBS:
            if hub.name() == hub_name:
                hub.pair_new_device(pairing_mode,
                                    kidde_radio_code=kidde_code)

    def rename_device(call):
        """Set specified device's name."""
        # This should only be called on one device at a time.
        found_device = None
        entity_id = call.data.get('entity_id')[0]
        all_devices = []
        for list_of_devices in hass.data[DOMAIN]['entities'].values():
            all_devices += list_of_devices
        for device in all_devices:
            if device.entity_id == entity_id:
                found_device = device
        if found_device is not None:
            name = call.data.get('name')
            found_device.wink.set_name(name)

    hass.services.register(DOMAIN, SERVICE_RENAME_DEVICE, rename_device,
                           descriptions.get(SERVICE_RENAME_DEVICE),
                           schema=RENAME_DEVICE_SCHEMA)

    def delete_device(call):
        """Delete specified device."""
        # This should only be called on one device at a time.
        found_device = None
        entity_id = call.data.get('entity_id')[0]
        all_devices = []
        for list_of_devices in hass.data[DOMAIN]['entities'].values():
            all_devices += list_of_devices
        for device in all_devices:
            if device.entity_id == entity_id:
                found_device = device
        if found_device is not None:
            found_device.wink.remove_device()

    hass.services.register(DOMAIN, SERVICE_DELETE_DEVICE, delete_device,
                           descriptions.get(SERVICE_DELETE_DEVICE),
                           schema=DELETE_DEVICE_SCHEMA)

    hubs = pywink.get_hubs()
    for hub in hubs:
        if hub.device_manufacturer() == 'wink':
            WINK_HUBS.append(hub)

    if WINK_HUBS:
        hass.services.register(
            DOMAIN, SERVICE_SET_PAIRING_MODE, set_pairing_mode,
            descriptions.get(SERVICE_SET_PAIRING_MODE),
            schema=SET_PAIRING_MODE_SCHEMA)

    def service_handle(service):
        """Handler for services."""
        entity_ids = service.data.get('entity_id')
        all_sirens = []
        for switch in hass.data[DOMAIN]['entities']['switch']:
            if isinstance(switch, WinkSirenDevice):
                all_sirens.append(switch)
        sirens_to_set = []
        if entity_ids is None:
            sirens_to_set = all_sirens
        else:
            for siren in all_sirens:
                if siren.entity_id in entity_ids:
                    sirens_to_set.append(siren)

        for siren in sirens_to_set:
            if (service.service != SERVICE_SET_AUTO_SHUTOFF and
                    service.service != SERVICE_ENABLE_SIREN and
                    siren.wink.device_manufacturer() != 'dome'):
                _LOGGER.error("Service only valid for Dome sirens.")
                return

            if service.service == SERVICE_ENABLE_SIREN:
                siren.wink.set_state(service.data.get(ATTR_ENABLED))
            elif service.service == SERVICE_SET_AUTO_SHUTOFF:
                siren.wink.set_auto_shutoff(
                    service.data.get(ATTR_AUTO_SHUTOFF))
            elif service.service == SERVICE_SET_CHIME_VOLUME:
                siren.wink.set_chime_volume(service.data.get(ATTR_VOLUME))
            elif service.service == SERVICE_SET_SIREN_VOLUME:
                siren.wink.set_siren_volume(service.data.get(ATTR_VOLUME))
            elif service.service == SERVICE_SET_SIREN_TONE:
                siren.wink.set_siren_sound(service.data.get(ATTR_TONE))
            elif service.service == SERVICE_ENABLE_CHIME:
                siren.wink.set_chime(service.data.get(ATTR_TONE))
            elif service.service == SERVICE_SIREN_STROBE_ENABLED:
                siren.wink.set_siren_strobe_enabled(
                    service.data.get(ATTR_ENABLED))
            elif service.service == SERVICE_CHIME_STROBE_ENABLED:
                siren.wink.set_chime_strobe_enabled(
                    service.data.get(ATTR_ENABLED))

    # Load components for the devices in Wink that we support
    for wink_component in WINK_COMPONENTS:
        hass.data[DOMAIN]['entities'][wink_component] = []
        discovery.load_platform(hass, wink_component, DOMAIN, {}, config)

    component = EntityComponent(_LOGGER, DOMAIN, hass)

    sirens = []
    has_dome_siren = False
    for siren in pywink.get_sirens():
        if siren.device_manufacturer() == "dome":
            has_dome_siren = True
        _id = siren.object_id() + siren.name()
        if _id not in hass.data[DOMAIN]['unique_ids']:
            sirens.append(WinkSirenDevice(siren, hass))

    if sirens:

        hass.services.register(DOMAIN, SERVICE_SET_AUTO_SHUTOFF,
                               service_handle,
                               descriptions.get(SERVICE_SET_AUTO_SHUTOFF),
                               schema=SET_AUTO_SHUTOFF_SCHEMA)

        hass.services.register(DOMAIN, SERVICE_ENABLE_SIREN,
                               service_handle,
                               descriptions.get(SERVICE_ENABLE_SIREN),
                               schema=ENABLED_SIREN_SCHEMA)

    if has_dome_siren:

        hass.services.register(DOMAIN, SERVICE_SET_SIREN_TONE,
                               service_handle,
                               descriptions.get(SERVICE_SET_SIREN_TONE),
                               schema=SET_SIREN_TONE_SCHEMA)

        hass.services.register(DOMAIN, SERVICE_ENABLE_CHIME,
                               service_handle,
                               descriptions.get(SERVICE_ENABLE_CHIME),
                               schema=SET_CHIME_MODE_SCHEMA)

        hass.services.register(DOMAIN, SERVICE_SET_SIREN_VOLUME,
                               service_handle,
                               descriptions.get(SERVICE_SET_SIREN_VOLUME),
                               schema=SET_VOLUME_SCHEMA)

        hass.services.register(DOMAIN, SERVICE_SET_CHIME_VOLUME,
                               service_handle,
                               descriptions.get(SERVICE_SET_CHIME_VOLUME),
                               schema=SET_VOLUME_SCHEMA)

        hass.services.register(DOMAIN, SERVICE_SIREN_STROBE_ENABLED,
                               service_handle,
                               descriptions.get(SERVICE_SIREN_STROBE_ENABLED),
                               schema=SET_STROBE_ENABLED_SCHEMA)

        hass.services.register(DOMAIN, SERVICE_CHIME_STROBE_ENABLED,
                               service_handle,
                               descriptions.get(SERVICE_CHIME_STROBE_ENABLED),
                               schema=SET_STROBE_ENABLED_SCHEMA)

    component.add_entities(sirens)

    return True