예제 #1
0
    def test_load_yaml_config_raises_error_if_malformed_yaml(self):
        """Test error raised if invalid YAML."""
        with open(YAML_PATH, 'w') as f:
            f.write(':')

        with pytest.raises(HomeAssistantError):
            config_util.load_yaml_config_file(YAML_PATH)
예제 #2
0
    def test_load_yaml_config_raises_error_if_not_dict(self):
        """Test error raised when YAML file is not a dict."""
        with open(YAML_PATH, 'w') as f:
            f.write('5')

        with pytest.raises(HomeAssistantError):
            config_util.load_yaml_config_file(YAML_PATH)
예제 #3
0
    def test_load_yaml_config_raises_error_if_not_dict(self):
        """ Test error raised when YAML file is not a dict. """
        with open(YAML_PATH, "w") as f:
            f.write("5")

        with self.assertRaises(HomeAssistantError):
            config_util.load_yaml_config_file(YAML_PATH)
예제 #4
0
    def test_load_yaml_config_raises_error_if_unsafe_yaml(self):
        """Test error raised if unsafe YAML."""
        with open(YAML_PATH, 'w') as f:
            f.write('hello: !!python/object/apply:os.system')

        with pytest.raises(HomeAssistantError):
            config_util.load_yaml_config_file(YAML_PATH)
예제 #5
0
    def test_load_yaml_config_raises_error_if_malformed_yaml(self):
        """ Test error raised if invalid YAML. """
        with open(YAML_PATH, "w") as f:
            f.write(":")

        with self.assertRaises(HomeAssistantError):
            config_util.load_yaml_config_file(YAML_PATH)
예제 #6
0
def setup(hass, config):
    """Set up the Verisure component."""
    import verisure
    global HUB
    HUB = VerisureHub(config[DOMAIN], verisure)
    if not HUB.login():
        return False
    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP,
                         lambda event: HUB.logout())
    HUB.update_overview()

    for component in ('sensor', 'switch', 'alarm_control_panel', 'lock',
                      'camera', 'binary_sensor'):
        discovery.load_platform(hass, component, DOMAIN, {}, config)

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

    def capture_smartcam(service):
        """Capture a new picture from a smartcam."""
        device_id = service.data.get(ATTR_DEVICE_SERIAL)
        HUB.smartcam_capture(device_id)
        _LOGGER.debug("Capturing new image from %s", ATTR_DEVICE_SERIAL)

    hass.services.register(DOMAIN, SERVICE_CAPTURE_SMARTCAM,
                           capture_smartcam,
                           descriptions[DOMAIN][SERVICE_CAPTURE_SMARTCAM],
                           schema=CAPTURE_IMAGE_SCHEMA)

    return True
예제 #7
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the Dyson fan components."""
    _LOGGER.info("Creating new Dyson fans")
    if DYSON_FAN_DEVICES not in hass.data:
        hass.data[DYSON_FAN_DEVICES] = []

    # Get Dyson Devices from parent component
    for device in hass.data[DYSON_DEVICES]:
        dyson_entity = DysonPureCoolLinkDevice(hass, device)
        hass.data[DYSON_FAN_DEVICES].append(dyson_entity)

    add_devices(hass.data[DYSON_FAN_DEVICES])

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

    def service_handle(service):
        """Handle dyson services."""
        entity_id = service.data.get('entity_id')
        night_mode = service.data.get('night_mode')
        fan_device = next([fan for fan in hass.data[DYSON_FAN_DEVICES] if
                           fan.entity_id == entity_id].__iter__(), None)
        if fan_device is None:
            _LOGGER.warning("Unable to find Dyson fan device %s",
                            str(entity_id))
            return

        if service.service == SERVICE_SET_NIGHT_MODE:
            fan_device.night_mode(night_mode)

    # Register dyson service(s)
    hass.services.register(DOMAIN, SERVICE_SET_NIGHT_MODE,
                           service_handle,
                           descriptions.get(SERVICE_SET_NIGHT_MODE),
                           schema=DYSON_SET_NIGHT_MODE_SCHEMA)
예제 #8
0
    def test_scan_devices(self):
        """Test creating device info (MAC, name) from response.

        The created known_devices.yaml device info is compared
        to the DD-WRT Lan Status request response fixture.
        This effectively checks the data parsing functions.
        """
        with requests_mock.Mocker() as mock_request:
            mock_request.register_uri(
                'GET', r'http://%s/Status_Wireless.live.asp' % TEST_HOST,
                text=load_fixture('Ddwrt_Status_Wireless.txt'))
            mock_request.register_uri(
                'GET', r'http://%s/Status_Lan.live.asp' % TEST_HOST,
                text=load_fixture('Ddwrt_Status_Lan.txt'))

            with assert_setup_component(1):
                assert setup_component(
                    self.hass, DOMAIN, {DOMAIN: {
                        CONF_PLATFORM: 'ddwrt',
                        CONF_HOST: TEST_HOST,
                        CONF_USERNAME: '******',
                        CONF_PASSWORD: '******'
                    }})
                self.hass.block_till_done()

            path = self.hass.config.path(device_tracker.YAML_DEVICES)
            devices = config.load_yaml_config_file(path)
            for device in devices:
                self.assertIn(
                    devices[device]['mac'],
                    load_fixture('Ddwrt_Status_Lan.txt'))
                self.assertIn(
                    slugify(devices[device]['name']),
                    load_fixture('Ddwrt_Status_Lan.txt'))
예제 #9
0
def autosetup_ihc_products(hass: HomeAssistantType, config, ihc_controller):
    """Auto setup of IHC products from the ihc project file."""
    project_xml = ihc_controller.get_project()
    if not project_xml:
        _LOGGER.error("Unable to read project from ihc controller.")
        return False
    project = xml.etree.ElementTree.fromstring(project_xml)

    # if an auto setup file exist in the configuration it will override
    yaml_path = hass.config.path(AUTO_SETUP_YAML)
    if not os.path.isfile(yaml_path):
        yaml_path = os.path.join(os.path.dirname(__file__), AUTO_SETUP_YAML)
    yaml = load_yaml_config_file(yaml_path)
    try:
        auto_setup_conf = AUTO_SETUP_SCHEMA(yaml)
    except vol.Invalid as exception:
        _LOGGER.error("Invalid IHC auto setup data: %s", exception)
        return False
    groups = project.findall('.//group')
    for component in IHC_PLATFORMS:
        component_setup = auto_setup_conf[component]
        discovery_info = get_discovery_info(component_setup, groups)
        if discovery_info:
            discovery.load_platform(hass, component, DOMAIN, discovery_info,
                                    config)
    return True
예제 #10
0
def setup(hass, config):
    """Track states and offer events for sensors."""
    component = EntityComponent(
        logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL,
        DISCOVERY_PLATFORMS)

    component.setup(config)

    def alarm_service_handler(service):
        """Map services to methods on Alarm."""
        target_alarms = component.extract_from_service(service)

        if ATTR_CODE not in service.data:
            code = None
        else:
            code = service.data[ATTR_CODE]

        method = SERVICE_TO_METHOD[service.service]

        for alarm in target_alarms:
            getattr(alarm, method)(code)
            if alarm.should_poll:
                alarm.update_ha_state(True)

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

    for service in SERVICE_TO_METHOD:
        hass.services.register(DOMAIN, service, alarm_service_handler,
                               descriptions.get(service))

    return True
예제 #11
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the Bose Soundtouch platform."""
    name = config.get(CONF_NAME)

    remote_config = {
        'name': 'HomeAssistant',
        'description': config.get(CONF_NAME),
        'id': 'ha.component.soundtouch',
        'port': config.get(CONF_PORT),
        'host': config.get(CONF_HOST)
    }

    soundtouch_device = SoundTouchDevice(name, remote_config)
    DEVICES.append(soundtouch_device)
    add_devices([soundtouch_device])

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

    hass.services.register(DOMAIN, SERVICE_PLAY_EVERYWHERE,
                           play_everywhere_service,
                           descriptions.get(SERVICE_PLAY_EVERYWHERE),
                           schema=SOUNDTOUCH_PLAY_EVERYWHERE)
    hass.services.register(DOMAIN, SERVICE_CREATE_ZONE,
                           create_zone_service,
                           descriptions.get(SERVICE_CREATE_ZONE),
                           schema=SOUNDTOUCH_CREATE_ZONE_SCHEMA)
    hass.services.register(DOMAIN, SERVICE_REMOVE_ZONE_SLAVE,
                           remove_zone_slave,
                           descriptions.get(SERVICE_REMOVE_ZONE_SLAVE),
                           schema=SOUNDTOUCH_REMOVE_ZONE_SCHEMA)
    hass.services.register(DOMAIN, SERVICE_ADD_ZONE_SLAVE,
                           add_zone_slave,
                           descriptions.get(SERVICE_ADD_ZONE_SLAVE),
                           schema=SOUNDTOUCH_ADD_ZONE_SCHEMA)
예제 #12
0
def get_service(hass, config):
    """Return push service."""
    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    name = config.get("name")
    if name is None:
        logging.error("Name must be specified.")
        return None

    cert_file = config.get('cert_file')
    if cert_file is None:
        logging.error("Certificate must be specified.")
        return None

    topic = config.get('topic')
    if topic is None:
        logging.error("Topic must be specified.")
        return None

    sandbox = bool(config.get('sandbox', False))

    service = ApnsNotificationService(hass, name, topic, sandbox, cert_file)
    hass.services.register(DOMAIN,
                           name,
                           service.register,
                           descriptions.get(SERVICE_REGISTER),
                           schema=REGISTER_SERVICE_SCHEMA)
    return service
예제 #13
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Nuki lock platform."""
    from pynuki import NukiBridge
    bridge = NukiBridge(config.get(CONF_HOST), config.get(CONF_TOKEN))
    add_devices([NukiLock(lock) for lock in bridge.locks])

    def service_handler(service):
        """Service handler for nuki services."""
        entity_ids = extract_entity_ids(hass, service)
        all_locks = hass.data[NUKI_DATA][DOMAIN]
        target_locks = []
        if not entity_ids:
            target_locks = all_locks
        else:
            for lock in all_locks:
                if lock.entity_id in entity_ids:
                    target_locks.append(lock)
        for lock in target_locks:
            if service.service == SERVICE_LOCK_N_GO:
                unlatch = service.data[ATTR_UNLATCH]
                lock.lock_n_go(unlatch=unlatch)
            elif service.service == SERVICE_UNLATCH:
                lock.unlatch()

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

    hass.services.register(
        DOMAIN, SERVICE_LOCK_N_GO, service_handler,
        descriptions.get(SERVICE_LOCK_N_GO), schema=LOCK_N_GO_SERVICE_SCHEMA)
    hass.services.register(
        DOMAIN, SERVICE_UNLATCH, service_handler,
        descriptions.get(SERVICE_UNLATCH), schema=UNLATCH_SERVICE_SCHEMA)
예제 #14
0
def register_services(hass):
    """Register all services for sonos devices."""
    descriptions = load_yaml_config_file(
        path.join(path.dirname(__file__), 'services.yaml'))

    hass.services.register(DOMAIN, SERVICE_GROUP_PLAYERS,
                           _group_players_service,
                           descriptions.get(SERVICE_GROUP_PLAYERS),
                           schema=SONOS_SCHEMA)

    hass.services.register(DOMAIN, SERVICE_UNJOIN,
                           _unjoin_service,
                           descriptions.get(SERVICE_UNJOIN),
                           schema=SONOS_SCHEMA)

    hass.services.register(DOMAIN, SERVICE_SNAPSHOT,
                           _snapshot_service,
                           descriptions.get(SERVICE_SNAPSHOT),
                           schema=SONOS_SCHEMA)

    hass.services.register(DOMAIN, SERVICE_RESTORE,
                           _restore_service,
                           descriptions.get(SERVICE_RESTORE),
                           schema=SONOS_SCHEMA)

    hass.services.register(DOMAIN, SERVICE_SET_TIMER,
                           _set_sleep_timer_service,
                           descriptions.get(SERVICE_SET_TIMER),
                           schema=SONOS_SET_TIMER_SCHEMA)

    hass.services.register(DOMAIN, SERVICE_CLEAR_TIMER,
                           _clear_sleep_timer_service,
                           descriptions.get(SERVICE_CLEAR_TIMER),
                           schema=SONOS_SCHEMA)
예제 #15
0
def from_config_file(config_path: str,
                     hass: Optional[core.HomeAssistant]=None,
                     verbose: bool=False,
                     skip_pip: bool=True,
                     log_rotate_days: Any=None):
    """Read the configuration file and try to start all the functionality.

    Will add functionality to 'hass' parameter if given,
    instantiates a new Home Assistant object if 'hass' is not given.
    """
    if hass is None:
        hass = core.HomeAssistant()

    # Set config dir to directory holding config file
    config_dir = os.path.abspath(os.path.dirname(config_path))
    hass.config.config_dir = config_dir
    mount_local_lib_path(config_dir)

    enable_logging(hass, verbose, log_rotate_days)

    try:
        config_dict = conf_util.load_yaml_config_file(config_path)
    except HomeAssistantError:
        return None

    return from_config_dict(config_dict, hass, enable_log=False,
                            skip_pip=skip_pip)
예제 #16
0
def setup(hass, config):
    """Setup the Foursquare component."""
    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    config = config[DOMAIN]

    def checkin_user(call):
        """Check a user in on Swarm."""
        url = ("https://api.foursquare.com/v2/checkins/add"
               "?oauth_token={}"
               "&v=20160802"
               "&m=swarm").format(config[CONF_ACCESS_TOKEN])
        response = requests.post(url, data=call.data, timeout=10)

        if response.status_code not in (200, 201):
            _LOGGER.exception(
                "Error checking in user. Response %d: %s:",
                response.status_code, response.reason)

        hass.bus.fire(EVENT_CHECKIN, response.text)

    # Register our service with Home Assistant.
    hass.services.register(DOMAIN, 'checkin', checkin_user,
                           descriptions[DOMAIN][SERVICE_CHECKIN],
                           schema=CHECKIN_SERVICE_SCHEMA)

    hass.wsgi.register_view(FoursquarePushReceiver(
        hass, config[CONF_PUSH_SECRET]))

    return True
예제 #17
0
def setup(hass, config):
    """Set up the media extractor service."""
    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__),
                     'media_player', 'services.yaml'))

    def play_media(call):
        """Get stream URL and send it to the media_player.play_media."""
        media_url = call.data.get(ATTR_MEDIA_CONTENT_ID)

        try:
            stream_url = get_media_stream_url(media_url)
        except YDException:
            _LOGGER.error("Could not retrieve data for the URL: %s",
                          media_url)
            return
        else:
            data = {k: v for k, v in call.data.items()
                    if k != ATTR_MEDIA_CONTENT_ID}
            data[ATTR_MEDIA_CONTENT_ID] = stream_url

            hass.async_add_job(
                hass.services.async_call(
                    MEDIA_PLAYER_DOMAIN, SERVICE_PLAY_MEDIA, data)
            )

    hass.services.register(DOMAIN,
                           SERVICE_PLAY_MEDIA,
                           play_media,
                           description=descriptions[SERVICE_PLAY_MEDIA],
                           schema=MEDIA_PLAYER_PLAY_MEDIA_SCHEMA)

    return True
예제 #18
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Wink platform."""
    import pywink

    for lock in pywink.get_locks():
        _id = lock.object_id() + lock.name()
        if _id not in hass.data[DOMAIN]['unique_ids']:
            add_devices([WinkLockDevice(lock, hass)])

    def service_handle(service):
        """Handler for services."""
        entity_ids = service.data.get('entity_id')
        all_locks = hass.data[DOMAIN]['entities']['lock']
        locks_to_set = []
        if entity_ids is None:
            locks_to_set = all_locks
        else:
            for lock in all_locks:
                if lock.entity_id in entity_ids:
                    locks_to_set.append(lock)

        for lock in locks_to_set:
            if service.service == SERVICE_SET_VACATION_MODE:
                lock.set_vacation_mode(service.data.get(ATTR_ENABLED))
            elif service.service == SERVICE_SET_ALARM_STATE:
                lock.set_alarm_state(service.data.get(ATTR_ENABLED))
            elif service.service == SERVICE_SET_BEEPER_STATE:
                lock.set_beeper_state(service.data.get(ATTR_ENABLED))
            elif service.service == SERVICE_SET_ALARM_MODE:
                lock.set_alarm_mode(service.data.get(ATTR_MODE))
            elif service.service == SERVICE_SET_ALARM_SENSITIVITY:
                lock.set_alarm_sensitivity(service.data.get(ATTR_SENSITIVITY))

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

    hass.services.register(DOMAIN, SERVICE_SET_VACATION_MODE,
                           service_handle,
                           descriptions.get(SERVICE_SET_VACATION_MODE),
                           schema=SET_ENABLED_SCHEMA)

    hass.services.register(DOMAIN, SERVICE_SET_ALARM_STATE,
                           service_handle,
                           descriptions.get(SERVICE_SET_ALARM_STATE),
                           schema=SET_ENABLED_SCHEMA)

    hass.services.register(DOMAIN, SERVICE_SET_BEEPER_STATE,
                           service_handle,
                           descriptions.get(SERVICE_SET_BEEPER_STATE),
                           schema=SET_ENABLED_SCHEMA)

    hass.services.register(DOMAIN, SERVICE_SET_ALARM_MODE,
                           service_handle,
                           descriptions.get(SERVICE_SET_ALARM_MODE),
                           schema=SET_ALARM_MODES_SCHEMA)

    hass.services.register(DOMAIN, SERVICE_SET_ALARM_SENSITIVITY,
                           service_handle,
                           descriptions.get(SERVICE_SET_ALARM_SENSITIVITY),
                           schema=SET_SENSITIVITY_SCHEMA)
예제 #19
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Perform the setup for Envisalink alarm panels."""
    _configured_partitions = discovery_info['partitions']
    _code = discovery_info[CONF_CODE]
    _panic_type = discovery_info[CONF_PANIC]
    for part_num in _configured_partitions:
        _device_config_data = PARTITION_SCHEMA(
            _configured_partitions[part_num])
        _device = EnvisalinkAlarm(
            part_num,
            _device_config_data[CONF_PARTITIONNAME],
            _code,
            _panic_type,
            EVL_CONTROLLER.alarm_state['partition'][part_num],
            EVL_CONTROLLER)
        DEVICES.append(_device)

    add_devices(DEVICES)

    # Register Envisalink specific services
    descriptions = load_yaml_config_file(
        path.join(path.dirname(__file__), 'services.yaml'))

    hass.services.register(alarm.DOMAIN, SERVICE_ALARM_KEYPRESS,
                           alarm_keypress_handler,
                           descriptions.get(SERVICE_ALARM_KEYPRESS),
                           schema=ALARM_KEYPRESS_SCHEMA)
    return True
예제 #20
0
def register_services(hass):
    """Register all services for harmony devices."""
    descriptions = load_yaml_config_file(path.join(path.dirname(__file__), "services.yaml"))

    hass.services.register(
        DOMAIN, SERVICE_SYNC, _sync_service, descriptions.get(SERVICE_SYNC), schema=HARMONY_SYNC_SCHEMA
    )
예제 #21
0
def load_config(path: str, hass: HomeAssistantType, consider_home: timedelta):
    """Load devices from YAML configuration file."""
    dev_schema = vol.Schema({
        vol.Required('name'): cv.string,
        vol.Optional('track', default=False): cv.boolean,
        vol.Optional('mac', default=None): vol.Any(None, vol.All(cv.string,
                                                                 vol.Upper)),
        vol.Optional(CONF_AWAY_HIDE, default=DEFAULT_AWAY_HIDE): cv.boolean,
        vol.Optional('gravatar', default=None): vol.Any(None, cv.string),
        vol.Optional('picture', default=None): vol.Any(None, cv.string),
        vol.Optional(CONF_CONSIDER_HOME, default=consider_home): vol.All(
            cv.time_period, cv.positive_timedelta)
    })
    try:
        result = []
        devices = load_yaml_config_file(path)
        for dev_id, device in devices.items():
            try:
                device = dev_schema(device)
                device['dev_id'] = cv.slugify(dev_id)
            except vol.Invalid as exp:
                log_exception(exp, dev_id, devices)
            else:
                result.append(Device(hass, **device))
        return result
    except (HomeAssistantError, FileNotFoundError):
        # When YAML file could not be loaded/did not contain a dict
        return []
예제 #22
0
파일: __init__.py 프로젝트: Bart274/remote
def setup(hass, config):
    """ Track states and offer events for remote. """
    component = EntityComponent(
        logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL,
        DISCOVERY_PLATFORMS)

    component.setup(config)

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

    def remote_service_handler(service):
        """ Maps services to methods on RemoteDevice. """
        target_remotes = component.extract_from_service(service)

        method = SERVICE_TO_METHOD[service.service]

        for remote in target_remotes:
            getattr(remote, method)()

            if remote.should_poll:
                remote.update_ha_state(True)

    for service in SERVICE_TO_METHOD:
        hass.services.register(DOMAIN, service, remote_service_handler,
                               descriptions.get(service))

    return True
예제 #23
0
def setup(hass, config):
    """Track states and offer events for locks."""
    component = EntityComponent(
        _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS,
        GROUP_NAME_ALL_LOCKS)
    component.setup(config)

    def handle_lock_service(service):
        """Handle calls to the lock services."""
        target_locks = component.extract_from_service(service)

        if ATTR_CODE not in service.data:
            code = None
        else:
            code = service.data[ATTR_CODE]

        for item in target_locks:
            if service.service == SERVICE_LOCK:
                item.lock(code=code)
            else:
                item.unlock(code=code)

            if item.should_poll:
                item.update_ha_state(True)

    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))
    hass.services.register(DOMAIN, SERVICE_UNLOCK, handle_lock_service,
                           descriptions.get(SERVICE_UNLOCK))
    hass.services.register(DOMAIN, SERVICE_LOCK, handle_lock_service,
                           descriptions.get(SERVICE_LOCK))

    return True
예제 #24
0
    def test_update_existing_device_with_tracking_id(self):
        """Test updating an existing device that has a tracking id."""
        devices_path = self.hass.config.path("test_app_apns.yaml")
        with open(devices_path, "w+") as out:
            out.write("1234: {name: test device 1, " "tracking_device_id: tracking123}\n")
            out.write("5678: {name: test device 2, " "tracking_device_id: tracking456}\n")

        self._setup_notify()
        self.assertTrue(
            self.hass.services.call(
                notify.DOMAIN, "apns_test_app", {"push_id": "1234", "name": "updated device 1"}, blocking=True
            )
        )

        devices = {str(key): value for (key, value) in load_yaml_config_file(devices_path).items()}

        test_device_1 = devices.get("1234")
        test_device_2 = devices.get("5678")

        self.assertIsNotNone(test_device_1)
        self.assertIsNotNone(test_device_2)

        self.assertEqual("tracking123", test_device_1.get("tracking_device_id"))
        self.assertEqual("tracking456", test_device_2.get("tracking_device_id"))

        os.remove(devices_path)
예제 #25
0
def setup(hass, config):
    """ Track states and offer events for garage door. """
    component = EntityComponent(
        _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS,
        GROUP_NAME_ALL_GARAGE_DOORS)
    component.setup(config)

    def handle_garage_door_service(service):
        """ Handles calls to the garage door services. """
        target_locks = component.extract_from_service(service)

        for item in target_locks:
            if service.service == SERVICE_CLOSE:
                item.close_door()
            else:
                item.open_door()

            if item.should_poll:
                item.update_ha_state(True)

    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))
    hass.services.register(DOMAIN, SERVICE_OPEN, handle_garage_door_service,
                           descriptions.get(SERVICE_OPEN))
    hass.services.register(DOMAIN, SERVICE_CLOSE, handle_garage_door_service,
                           descriptions.get(SERVICE_CLOSE))

    return True
예제 #26
0
def setup(hass, config):
    """Track states and offer events for covers."""
    component = EntityComponent(
        _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_COVERS)
    component.setup(config)

    def handle_cover_service(service):
        """Handle calls to the cover services."""
        method = SERVICE_TO_METHOD.get(service.service)
        params = service.data.copy()
        params.pop(ATTR_ENTITY_ID, None)

        if method:
            for cover in component.extract_from_service(service):
                getattr(cover, method['method'])(**params)

                if cover.should_poll:
                    cover.update_ha_state(True)

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

    for service_name in SERVICE_TO_METHOD:
        schema = SERVICE_TO_METHOD[service_name].get(
            'schema', COVER_SERVICE_SCHEMA)
        hass.services.register(DOMAIN, service_name, handle_cover_service,
                               descriptions.get(service_name), schema=schema)
    return True
예제 #27
0
    def test_register_new_device(self):
        """Test registering a new device with a name."""
        config = {
            'notify': {
                'platform': 'apns',
                'name': 'test_app',
                'topic': 'testapp.appname',
                'cert_file': 'test_app.pem'
            }
        }
        hass = get_test_home_assistant()

        devices_path = hass.config.path('test_app_apns.yaml')
        with open(devices_path, 'w+') as out:
            out.write('5678: {name: test device 2}\n')

        notify.setup(hass, config)
        self.assertTrue(hass.services.call('apns',
                                           'test_app',
                                           {'push_id': '1234',
                                            'name': 'test device'},
                                           blocking=True))

        devices = {str(key): value for (key, value) in
                   load_yaml_config_file(devices_path).items()}

        test_device_1 = devices.get('1234')
        test_device_2 = devices.get('5678')

        self.assertIsNotNone(test_device_1)
        self.assertIsNotNone(test_device_2)

        self.assertEqual('test device', test_device_1.get('name'))

        os.remove(devices_path)
예제 #28
0
    def test_device_name_no_dhcp(self):
        """Test creating device info (MAC) when missing dhcp response."""
        with requests_mock.Mocker() as mock_request:
            mock_request.register_uri(
                'GET', r'http://%s/Status_Wireless.live.asp' % TEST_HOST,
                text=load_fixture('Ddwrt_Status_Wireless.txt'))
            mock_request.register_uri(
                'GET', r'http://%s/Status_Lan.live.asp' % TEST_HOST,
                text=load_fixture('Ddwrt_Status_Lan.txt').
                replace('dhcp_leases', 'missing'))

            with assert_setup_component(1):
                assert setup_component(
                    self.hass, DOMAIN, {DOMAIN: {
                        CONF_PLATFORM: 'ddwrt',
                        CONF_HOST: TEST_HOST,
                        CONF_USERNAME: '******',
                        CONF_PASSWORD: '******'
                    }})
                self.hass.block_till_done()

            path = self.hass.config.path(device_tracker.YAML_DEVICES)
            devices = config.load_yaml_config_file(path)
            for device in devices:
                _LOGGER.error(devices[device])
                self.assertIn(
                    devices[device]['mac'],
                    load_fixture('Ddwrt_Status_Lan.txt'))
예제 #29
0
def setup(hass, config):
    """Track states and offer events for switches."""
    component = EntityComponent(
        _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_SWITCHES)
    component.setup(config)

    def handle_switch_service(service):
        """Handle calls to the switch services."""
        target_switches = component.extract_from_service(service)

        for switch in target_switches:
            if service.service == SERVICE_TURN_ON:
                switch.turn_on()
            elif service.service == SERVICE_TOGGLE:
                switch.toggle()
            else:
                switch.turn_off()

            if switch.should_poll:
                switch.update_ha_state(True)

    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))
    hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_switch_service,
                           descriptions.get(SERVICE_TURN_OFF),
                           schema=SWITCH_SERVICE_SCHEMA)
    hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_switch_service,
                           descriptions.get(SERVICE_TURN_ON),
                           schema=SWITCH_SERVICE_SCHEMA)
    hass.services.register(DOMAIN, SERVICE_TOGGLE, handle_switch_service,
                           descriptions.get(SERVICE_TOGGLE),
                           schema=SWITCH_SERVICE_SCHEMA)

    return True
예제 #30
0
    def __init__(self, hass, app_name, topic, sandbox, cert_file):
        """Initialize APNS application."""
        self.hass = hass
        self.app_name = app_name
        self.sandbox = sandbox
        self.certificate = cert_file
        self.yaml_path = hass.config.path(app_name + '_' + APNS_DEVICES)
        self.devices = {}
        self.device_states = {}
        self.topic = topic
        if os.path.isfile(self.yaml_path):
            self.devices = {
                str(key): ApnsDevice(
                    str(key),
                    value.get('name'),
                    value.get('tracking_device_id'),
                    value.get('disabled', False)
                )
                for (key, value) in
                load_yaml_config_file(self.yaml_path).items()
            }

        tracking_ids = [
            device.full_tracking_device_id
            for (key, device) in self.devices.items()
            if device.tracking_device_id is not None
        ]
        track_state_change(
            hass, tracking_ids, self.device_state_changed_listener)
예제 #31
0
def setup(hass, config):
    """Setup all groups found definded in the configuration."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    success = _process_config(hass, config, component)

    if not success:
        return False

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

    def reload_service_handler(service_call):
        """Remove all groups and load new ones from config."""
        conf = component.prepare_reload()
        if conf is None:
            return
        _process_config(hass, conf, component)

    hass.services.register(DOMAIN, SERVICE_RELOAD, reload_service_handler,
                           descriptions[DOMAIN][SERVICE_RELOAD],
                           schema=RELOAD_SERVICE_SCHEMA)

    return True
예제 #32
0
def from_config_file(config_path, hass=None, verbose=False, daemon=False,
                     skip_pip=True, log_rotate_days=None):
    """Read the configuration file and try to start all the functionality.

    Will add functionality to 'hass' parameter if given,
    instantiates a new Home Assistant object if 'hass' is not given.
    """
    if hass is None:
        hass = core.HomeAssistant()

    # Set config dir to directory holding config file
    config_dir = os.path.abspath(os.path.dirname(config_path))
    hass.config.config_dir = config_dir
    mount_local_lib_path(config_dir)

    enable_logging(hass, verbose, daemon, log_rotate_days)

    try:
        config_dict = config_util.load_yaml_config_file(config_path)
    except HomeAssistantError:
        return None

    return from_config_dict(config_dict, hass, enable_log=False,
                            skip_pip=skip_pip)
예제 #33
0
def register_services(hass):
    """Register all services for sonos devices."""
    descriptions = load_yaml_config_file(
        path.join(path.dirname(__file__), 'services.yaml'))

    hass.services.register(DOMAIN, SERVICE_GROUP_PLAYERS,
                           _group_players_service,
                           descriptions.get(SERVICE_GROUP_PLAYERS),
                           schema=SONOS_SCHEMA)

    hass.services.register(DOMAIN, SERVICE_UNJOIN,
                           _unjoin_service,
                           descriptions.get(SERVICE_UNJOIN),
                           schema=SONOS_SCHEMA)

    hass.services.register(DOMAIN, SERVICE_SNAPSHOT,
                           _snapshot_service,
                           descriptions.get(SERVICE_SNAPSHOT),
                           schema=SONOS_SCHEMA)

    hass.services.register(DOMAIN, SERVICE_RESTORE,
                           _restore_service,
                           descriptions.get(SERVICE_RESTORE),
                           schema=SONOS_SCHEMA)
    def test_scan_devices(self):
        """Test creating device info (MAC, name) from response.

        The created known_devices.yaml device info is compared
        to the DD-WRT Lan Status request response fixture.
        This effectively checks the data parsing functions.
        """
        with requests_mock.Mocker() as mock_request:
            mock_request.register_uri(
                'GET',
                r'http://%s/Status_Wireless.live.asp' % TEST_HOST,
                text=load_fixture('Ddwrt_Status_Wireless.txt'))
            mock_request.register_uri(
                'GET',
                r'http://%s/Status_Lan.live.asp' % TEST_HOST,
                text=load_fixture('Ddwrt_Status_Lan.txt'))

            with assert_setup_component(1, DOMAIN):
                assert setup_component(
                    self.hass, DOMAIN, {
                        DOMAIN: {
                            CONF_PLATFORM: 'ddwrt',
                            CONF_HOST: TEST_HOST,
                            CONF_USERNAME: '******',
                            CONF_PASSWORD: '******'
                        }
                    })
                self.hass.block_till_done()

            path = self.hass.config.path(device_tracker.YAML_DEVICES)
            devices = config.load_yaml_config_file(path)
            for device in devices:
                self.assertIn(devices[device]['mac'],
                              load_fixture('Ddwrt_Status_Lan.txt'))
                self.assertIn(slugify(devices[device]['name']),
                              load_fixture('Ddwrt_Status_Lan.txt'))
예제 #35
0
    def test_update_existing_device(self):
        """Test updating an existing device."""
        config = {
            'notify': {
                'platform': 'apns',
                'name': 'test_app',
                'topic': 'testapp.appname',
                'cert_file': 'test_app.pem'
            }
        }
        hass = get_test_home_assistant()

        devices_path = hass.config.path('test_app_apns.yaml')
        with open(devices_path, 'w+') as out:
            out.write('1234: {name: test device 1}\n')
            out.write('5678: {name: test device 2}\n')

        notify.setup(hass, config)
        self.assertTrue(hass.services.call('apns',
                                           'test_app',
                                           {'push_id': '1234',
                                            'name': 'updated device 1'},
                                           blocking=True))

        devices = {str(key): value for (key, value) in
                   load_yaml_config_file(devices_path).items()}

        test_device_1 = devices.get('1234')
        test_device_2 = devices.get('5678')

        self.assertIsNotNone(test_device_1)
        self.assertIsNotNone(test_device_2)

        self.assertEqual('updated device 1', test_device_1.get('name'))

        os.remove(devices_path)
예제 #36
0
def test_load_yaml_config_converts_empty_files_to_dict():
    """Test that loading an empty file returns an empty dict."""
    create_file(YAML_PATH)

    assert isinstance(config_util.load_yaml_config_file(YAML_PATH), dict)
예제 #37
0
def setup(hass, config):
    """Setup Z-Wave.

    Will automatically load components to support devices found on the network.
    """
    # pylint: disable=global-statement, import-error
    global NETWORK

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

    try:
        import libopenzwave
    except ImportError:
        _LOGGER.error("You are missing required dependency Python Open "
                      "Z-Wave. Please follow instructions at: "
                      "https://home-assistant.io/components/zwave/")
        return False
    from pydispatch import dispatcher
    from openzwave.option import ZWaveOption
    from openzwave.network import ZWaveNetwork
    from openzwave.group import ZWaveGroup

    default_zwave_config_path = os.path.join(
        os.path.dirname(libopenzwave.__file__), 'config')

    # Load configuration
    use_debug = config[DOMAIN].get(CONF_DEBUG)
    autoheal = config[DOMAIN].get(CONF_AUTOHEAL)
    hass.data[DATA_DEVICE_CONFIG] = EntityValues(
        config[DOMAIN][CONF_DEVICE_CONFIG],
        config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN],
        config[DOMAIN][CONF_DEVICE_CONFIG_GLOB])

    # Setup options
    options = ZWaveOption(config[DOMAIN].get(CONF_USB_STICK_PATH),
                          user_path=hass.config.config_dir,
                          config_path=config[DOMAIN].get(
                              CONF_CONFIG_PATH, default_zwave_config_path))

    options.set_console_output(use_debug)
    options.lock()

    NETWORK = ZWaveNetwork(options, autostart=False)

    if use_debug:

        def log_all(signal, value=None):
            """Log all the signals."""
            print("")
            print("SIGNAL *****", signal)
            if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED,
                                    ZWaveNetwork.SIGNAL_VALUE_ADDED,
                                    ZWaveNetwork.SIGNAL_SCENE_EVENT,
                                    ZWaveNetwork.SIGNAL_NODE_EVENT,
                                    ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED,
                                    ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED):
                pprint(_obj_to_dict(value))

            print("")

        dispatcher.connect(log_all, weak=False)

    def value_added(node, value):
        """Called when a value is added to a node on the network."""
        for (component, generic_device_class, specific_device_class,
             command_class, value_type, value_genre) in DISCOVERY_COMPONENTS:

            _LOGGER.debug("Component=%s Node_id=%s query start", component,
                          node.node_id)
            if node.generic not in generic_device_class and \
               None not in generic_device_class:
                _LOGGER.debug(
                    "node.generic %s not None and in "
                    "generic_device_class %s", node.generic,
                    generic_device_class)
                continue
            if node.specific not in specific_device_class and \
               None not in specific_device_class:
                _LOGGER.debug(
                    "node.specific %s is not None and in "
                    "specific_device_class %s", node.specific,
                    specific_device_class)
                continue
            if value.command_class not in command_class and \
               None not in command_class:
                _LOGGER.debug(
                    "value.command_class %s is not None "
                    "and in command_class %s", value.command_class,
                    command_class)
                continue
            if value_type != value.type and value_type is not None:
                _LOGGER.debug("value.type %s != value_type %s", value.type,
                              value_type)
                continue
            if value_genre != value.genre and value_genre is not None:
                _LOGGER.debug("value.genre %s != value_genre %s", value.genre,
                              value_genre)
                continue

            # Configure node
            _LOGGER.debug(
                "Adding Node_id=%s Generic_command_class=%s, "
                "Specific_command_class=%s, "
                "Command_class=%s, Value type=%s, "
                "Genre=%s as %s", node.node_id, node.generic, node.specific,
                value.command_class, value.type, value.genre, component)
            workaround_component = workaround.get_device_component_mapping(
                value)
            if workaround_component and workaround_component != component:
                if workaround_component == workaround.WORKAROUND_IGNORE:
                    _LOGGER.info("Ignoring device %s due to workaround.",
                                 "{}.{}".format(component, object_id(value)))
                    continue
                _LOGGER.debug("Using %s instead of %s", workaround_component,
                              component)
                component = workaround_component

            name = "{}.{}".format(component, object_id(value))
            node_config = hass.data[DATA_DEVICE_CONFIG].get(name)

            if node_config.get(CONF_IGNORED):
                _LOGGER.info("Ignoring device %s due to device settings.",
                             name)
                return

            polling_intensity = convert(
                node_config.get(CONF_POLLING_INTENSITY), int)
            if polling_intensity:
                value.enable_poll(polling_intensity)
            else:
                value.disable_poll()

            discovery.load_platform(
                hass, component, DOMAIN, {
                    const.ATTR_NODE_ID: node.node_id,
                    const.ATTR_VALUE_ID: value.value_id,
                }, config)

    def scene_activated(node, scene_id):
        """Called when a scene is activated on any node in the network."""
        hass.bus.fire(
            const.EVENT_SCENE_ACTIVATED, {
                ATTR_ENTITY_ID: _node_object_id(node),
                const.ATTR_OBJECT_ID: _node_object_id(node),
                const.ATTR_SCENE_ID: scene_id
            })

    def node_event_activated(node, value):
        """Called when a nodeevent is activated on any node in the network."""
        hass.bus.fire(
            const.EVENT_NODE_EVENT, {
                const.ATTR_OBJECT_ID: _node_object_id(node),
                const.ATTR_BASIC_LEVEL: value
            })

    def network_ready():
        """Called when all awake nodes have been queried."""
        _LOGGER.info("Zwave network is ready for use. All awake nodes"
                     " have been queried. Sleeping nodes will be"
                     " queried when they awake.")
        hass.bus.fire(const.EVENT_NETWORK_READY)

    def network_complete():
        """Called when all nodes on network have been queried."""
        _LOGGER.info("Zwave network is complete. All nodes on the network"
                     " have been queried")
        hass.bus.fire(const.EVENT_NETWORK_COMPLETE)

    dispatcher.connect(value_added,
                       ZWaveNetwork.SIGNAL_VALUE_ADDED,
                       weak=False)
    dispatcher.connect(scene_activated,
                       ZWaveNetwork.SIGNAL_SCENE_EVENT,
                       weak=False)
    dispatcher.connect(node_event_activated,
                       ZWaveNetwork.SIGNAL_NODE_EVENT,
                       weak=False)
    dispatcher.connect(network_ready,
                       ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED,
                       weak=False)
    dispatcher.connect(network_complete,
                       ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED,
                       weak=False)

    def add_node(service):
        """Switch into inclusion mode."""
        _LOGGER.info("Zwave add_node have been initialized.")
        NETWORK.controller.add_node()

    def add_node_secure(service):
        """Switch into secure inclusion mode."""
        _LOGGER.info("Zwave add_node_secure have been initialized.")
        NETWORK.controller.add_node(True)

    def remove_node(service):
        """Switch into exclusion mode."""
        _LOGGER.info("Zwave remove_node have been initialized.")
        NETWORK.controller.remove_node()

    def cancel_command(service):
        """Cancel a running controller command."""
        _LOGGER.info("Cancel running ZWave command.")
        NETWORK.controller.cancel_command()

    def heal_network(service):
        """Heal the network."""
        _LOGGER.info("ZWave heal running.")
        NETWORK.heal()

    def soft_reset(service):
        """Soft reset the controller."""
        _LOGGER.info("Zwave soft_reset have been initialized.")
        NETWORK.controller.soft_reset()

    def test_network(service):
        """Test the network by sending commands to all the nodes."""
        _LOGGER.info("Zwave test_network have been initialized.")
        NETWORK.test()

    def stop_zwave(_service_or_event):
        """Stop Z-Wave network."""
        _LOGGER.info("Stopping ZWave network.")
        NETWORK.stop()
        if hass.state == 'RUNNING':
            hass.bus.fire(const.EVENT_NETWORK_STOP)

    def rename_node(service):
        """Rename a node."""
        state = hass.states.get(service.data.get(ATTR_ENTITY_ID))
        node_id = state.attributes.get(const.ATTR_NODE_ID)
        node = NETWORK.nodes[node_id]
        name = service.data.get(const.ATTR_NAME)
        node.name = name
        _LOGGER.info("Renamed ZWave node %d to %s", node_id, name)

    def set_config_parameter(service):
        """Set a config parameter to a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = NETWORK.nodes[node_id]
        param = service.data.get(const.ATTR_CONFIG_PARAMETER)
        selection = service.data.get(const.ATTR_CONFIG_VALUE)
        size = service.data.get(const.ATTR_CONFIG_SIZE, 2)
        i = 0
        for value in (node.get_values(
                class_id=const.COMMAND_CLASS_CONFIGURATION).values()):
            if value.index == param and value.type == const.TYPE_LIST:
                _LOGGER.debug('Values for parameter %s: %s', param,
                              value.data_items)
                i = len(value.data_items) - 1
        if i == 0:
            node.set_config_param(param, selection, size)
        else:
            if selection > i:
                _LOGGER.info(
                    'Config parameter selection does not exist!'
                    ' Please check zwcfg_[home_id].xml in'
                    ' your homeassistant config directory. '
                    ' Available selections are 0 to %s', i)
                return
            node.set_config_param(param, selection, size)
            _LOGGER.info(
                'Setting config parameter %s on Node %s '
                'with selection %s and size=%s', param, node_id, selection,
                size)

    def print_config_parameter(service):
        """Print a config parameter from a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = NETWORK.nodes[node_id]
        param = service.data.get(const.ATTR_CONFIG_PARAMETER)
        _LOGGER.info("Config parameter %s on Node %s : %s", param, node_id,
                     get_config_value(node, param))

    def print_node(service):
        """Print all information about z-wave node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = NETWORK.nodes[node_id]
        nice_print_node(node)

    def set_wakeup(service):
        """Set wake-up interval of a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = NETWORK.nodes[node_id]
        value = service.data.get(const.ATTR_CONFIG_VALUE)
        if node.can_wake_up():
            for value_id in node.get_values(
                    class_id=const.COMMAND_CLASS_WAKE_UP):
                node.values[value_id].data = value
                _LOGGER.info("Node %s wake-up set to %d", node_id, value)
        else:
            _LOGGER.info("Node %s is not wakeable", node_id)

    def change_association(service):
        """Change an association in the zwave network."""
        association_type = service.data.get(const.ATTR_ASSOCIATION)
        node_id = service.data.get(const.ATTR_NODE_ID)
        target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID)
        group = service.data.get(const.ATTR_GROUP)
        instance = service.data.get(const.ATTR_INSTANCE)

        node = ZWaveGroup(group, NETWORK, node_id)
        if association_type == 'add':
            node.add_association(target_node_id, instance)
            _LOGGER.info(
                "Adding association for node:%s in group:%s "
                "target node:%s, instance=%s", node_id, group, target_node_id,
                instance)
        if association_type == 'remove':
            node.remove_association(target_node_id, instance)
            _LOGGER.info(
                "Removing association for node:%s in group:%s "
                "target node:%s, instance=%s", node_id, group, target_node_id,
                instance)

    def start_zwave(_service_or_event):
        """Startup Z-Wave network."""
        _LOGGER.info("Starting ZWave network.")
        NETWORK.start()
        hass.bus.fire(const.EVENT_NETWORK_START)

        # Need to be in STATE_AWAKED before talking to nodes.
        # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network
        # to be ready.
        for i in range(const.NETWORK_READY_WAIT_SECS):
            _LOGGER.debug("network state: %d %s", NETWORK.state,
                          NETWORK.state_str)
            if NETWORK.state >= NETWORK.STATE_AWAKED:
                _LOGGER.info("zwave ready after %d seconds", i)
                break
            time.sleep(1)
        else:
            _LOGGER.warning(
                "zwave not ready after %d seconds, continuing anyway",
                const.NETWORK_READY_WAIT_SECS)
            _LOGGER.info("final network state: %d %s", NETWORK.state,
                         NETWORK.state_str)

        polling_interval = convert(config[DOMAIN].get(CONF_POLLING_INTERVAL),
                                   int)
        if polling_interval is not None:
            NETWORK.set_poll_interval(polling_interval, False)

        poll_interval = NETWORK.get_poll_interval()
        _LOGGER.info("zwave polling interval set to %d ms", poll_interval)

        hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zwave)

        # Register node services for Z-Wave network
        hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node,
                               descriptions[const.SERVICE_ADD_NODE])
        hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE,
                               add_node_secure,
                               descriptions[const.SERVICE_ADD_NODE_SECURE])
        hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node,
                               descriptions[const.SERVICE_REMOVE_NODE])
        hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND,
                               cancel_command,
                               descriptions[const.SERVICE_CANCEL_COMMAND])
        hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK,
                               heal_network,
                               descriptions[const.SERVICE_HEAL_NETWORK])
        hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset,
                               descriptions[const.SERVICE_SOFT_RESET])
        hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK,
                               test_network,
                               descriptions[const.SERVICE_TEST_NETWORK])
        hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_zwave,
                               descriptions[const.SERVICE_STOP_NETWORK])
        hass.services.register(DOMAIN, const.SERVICE_START_NETWORK,
                               start_zwave,
                               descriptions[const.SERVICE_START_NETWORK])
        hass.services.register(DOMAIN,
                               const.SERVICE_RENAME_NODE,
                               rename_node,
                               descriptions[const.SERVICE_RENAME_NODE],
                               schema=RENAME_NODE_SCHEMA)
        hass.services.register(
            DOMAIN,
            const.SERVICE_SET_CONFIG_PARAMETER,
            set_config_parameter,
            descriptions[const.SERVICE_SET_CONFIG_PARAMETER],
            schema=SET_CONFIG_PARAMETER_SCHEMA)
        hass.services.register(
            DOMAIN,
            const.SERVICE_PRINT_CONFIG_PARAMETER,
            print_config_parameter,
            descriptions[const.SERVICE_PRINT_CONFIG_PARAMETER],
            schema=PRINT_CONFIG_PARAMETER_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_CHANGE_ASSOCIATION,
                               change_association,
                               descriptions[const.SERVICE_CHANGE_ASSOCIATION],
                               schema=CHANGE_ASSOCIATION_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_SET_WAKEUP,
                               set_wakeup,
                               descriptions[const.SERVICE_SET_WAKEUP],
                               schema=SET_WAKEUP_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_PRINT_NODE,
                               print_node,
                               descriptions[const.SERVICE_PRINT_NODE],
                               schema=PRINT_NODE_SCHEMA)

    # Setup autoheal
    if autoheal:
        _LOGGER.info("ZWave network autoheal is enabled.")
        track_time_change(hass, heal_network, hour=0, minute=0, second=0)

    hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave)

    return True
예제 #38
0
def setup(hass, config):
    """Expose light control via statemachine and services."""
    component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL,
                                GROUP_NAME_ALL_LIGHTS)
    component.setup(config)

    # Load built-in profiles and custom profiles
    profile_paths = [
        os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE),
        hass.config.path(LIGHT_PROFILES_FILE)
    ]
    profiles = {}

    for profile_path in profile_paths:
        if not os.path.isfile(profile_path):
            continue
        with open(profile_path) as inp:
            reader = csv.reader(inp)

            # Skip the header
            next(reader, None)

            try:
                for rec in reader:
                    profile, color_x, color_y, brightness = PROFILE_SCHEMA(rec)
                    profiles[profile] = (color_x, color_y, brightness)
            except vol.MultipleInvalid as ex:
                _LOGGER.error("Error parsing light profile from %s: %s",
                              profile_path, ex)
                return False

    def handle_light_service(service):
        """Hande a turn light on or off service call."""
        # Get the validated data
        params = service.data.copy()

        # Convert the entity ids to valid light ids
        target_lights = component.extract_from_service(service)
        params.pop(ATTR_ENTITY_ID, None)

        service_fun = None
        if service.service == SERVICE_TURN_OFF:
            service_fun = 'turn_off'
        elif service.service == SERVICE_TOGGLE:
            service_fun = 'toggle'

        if service_fun:
            for light in target_lights:
                getattr(light, service_fun)(**params)

            for light in target_lights:
                if light.should_poll:
                    light.update_ha_state(True)
            return

        # Processing extra data for turn light on request.
        profile = profiles.get(params.pop(ATTR_PROFILE, None))

        if profile:
            params.setdefault(ATTR_XY_COLOR, profile[:2])
            params.setdefault(ATTR_BRIGHTNESS, profile[2])

        color_name = params.pop(ATTR_COLOR_NAME, None)

        if color_name is not None:
            params[ATTR_RGB_COLOR] = color_util.color_name_to_rgb(color_name)

        for light in target_lights:
            light.turn_on(**params)

        for light in target_lights:
            if light.should_poll:
                light.update_ha_state(True)

    # Listen for light on and light off service calls.
    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))
    hass.services.register(DOMAIN,
                           SERVICE_TURN_ON,
                           handle_light_service,
                           descriptions.get(SERVICE_TURN_ON),
                           schema=LIGHT_TURN_ON_SCHEMA)

    hass.services.register(DOMAIN,
                           SERVICE_TURN_OFF,
                           handle_light_service,
                           descriptions.get(SERVICE_TURN_OFF),
                           schema=LIGHT_TURN_OFF_SCHEMA)

    hass.services.register(DOMAIN,
                           SERVICE_TOGGLE,
                           handle_light_service,
                           descriptions.get(SERVICE_TOGGLE),
                           schema=LIGHT_TOGGLE_SCHEMA)

    return True
예제 #39
0
def setup(hass, config):
    """Track states and offer events for media_players."""
    component = EntityComponent(
        logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL)

    component.setup(config)

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

    def media_player_service_handler(service):
        """Map services to methods on MediaPlayerDevice."""
        method = SERVICE_TO_METHOD[service.service]

        for player in component.extract_from_service(service):
            getattr(player, method)()

            if player.should_poll:
                player.update_ha_state(True)

    for service in SERVICE_TO_METHOD:
        hass.services.register(DOMAIN, service, media_player_service_handler,
                               descriptions.get(service),
                               schema=MEDIA_PLAYER_SCHEMA)

    def volume_set_service(service):
        """Set specified volume on the media player."""
        volume = service.data.get(ATTR_MEDIA_VOLUME_LEVEL)

        for player in component.extract_from_service(service):
            player.set_volume_level(volume)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_VOLUME_SET, volume_set_service,
                           descriptions.get(SERVICE_VOLUME_SET),
                           schema=MEDIA_PLAYER_SET_VOLUME_SCHEMA)

    def volume_mute_service(service):
        """Mute (true) or unmute (false) the media player."""
        mute = service.data.get(ATTR_MEDIA_VOLUME_MUTED)

        for player in component.extract_from_service(service):
            player.mute_volume(mute)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE, volume_mute_service,
                           descriptions.get(SERVICE_VOLUME_MUTE),
                           schema=MEDIA_PLAYER_MUTE_VOLUME_SCHEMA)

    def media_seek_service(service):
        """Seek to a position."""
        position = service.data.get(ATTR_MEDIA_SEEK_POSITION)

        for player in component.extract_from_service(service):
            player.media_seek(position)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK, media_seek_service,
                           descriptions.get(SERVICE_MEDIA_SEEK),
                           schema=MEDIA_PLAYER_MEDIA_SEEK_SCHEMA)

    def select_source_service(service):
        """Change input to selected source."""
        input_source = service.data.get(ATTR_INPUT_SOURCE)

        for player in component.extract_from_service(service):
            player.select_source(input_source)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_SELECT_SOURCE,
                           select_source_service,
                           descriptions.get(SERVICE_SELECT_SOURCE),
                           schema=MEDIA_PLAYER_SELECT_SOURCE_SCHEMA)

    def play_media_service(service):
        """Play specified media_id on the media player."""
        media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE)
        media_id = service.data.get(ATTR_MEDIA_CONTENT_ID)
        enqueue = service.data.get(ATTR_MEDIA_ENQUEUE)

        kwargs = {
            ATTR_MEDIA_ENQUEUE: enqueue,
        }

        for player in component.extract_from_service(service):
            player.play_media(media_type, media_id, **kwargs)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_PLAY_MEDIA, play_media_service,
                           descriptions.get(SERVICE_PLAY_MEDIA),
                           schema=MEDIA_PLAYER_PLAY_MEDIA_SCHEMA)

    return True
예제 #40
0
def setup(hass, config):
    """Common setup for Axis devices."""
    def _shutdown(call):  # pylint: disable=unused-argument
        """Stop the event stream on shutdown."""
        for serialnumber, device in AXIS_DEVICES.items():
            _LOGGER.info("Stopping event stream for %s.", serialnumber)
            device.stop()

    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, _shutdown)

    def axis_device_discovered(service, discovery_info):
        """Called when axis devices has been found."""
        host = discovery_info[CONF_HOST]
        name = discovery_info['hostname']
        serialnumber = discovery_info['properties']['macaddress']

        if serialnumber not in AXIS_DEVICES:
            config_file = _read_config(hass)
            if serialnumber in config_file:
                # Device config previously saved to file
                try:
                    device_config = DEVICE_SCHEMA(config_file[serialnumber])
                    device_config[CONF_HOST] = host
                except vol.Invalid as err:
                    _LOGGER.error("Bad data from %s. %s", CONFIG_FILE, err)
                    return False
                if not setup_device(hass, config, device_config):
                    _LOGGER.error("Couldn\'t set up %s",
                                  device_config[CONF_NAME])
            else:
                # New device, create configuration request for UI
                request_configuration(hass, config, name, host, serialnumber)
        else:
            # Device already registered, but on a different IP
            device = AXIS_DEVICES[serialnumber]
            device.config.host = host
            dispatcher_send(hass, DOMAIN + '_' + device.name + '_new_ip', host)

    # Register discovery service
    discovery.listen(hass, SERVICE_AXIS, axis_device_discovered)

    if DOMAIN in config:
        for device in config[DOMAIN]:
            device_config = config[DOMAIN][device]
            if CONF_NAME not in device_config:
                device_config[CONF_NAME] = device
            if not setup_device(hass, config, device_config):
                _LOGGER.error("Couldn\'t set up %s", device_config[CONF_NAME])

    # Services to communicate with device.
    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    def vapix_service(call):
        """Service to send a message."""
        for _, device in AXIS_DEVICES.items():
            if device.name == call.data[CONF_NAME]:
                response = device.vapix.do_request(call.data[SERVICE_CGI],
                                                   call.data[SERVICE_ACTION],
                                                   call.data[SERVICE_PARAM])
                hass.bus.fire(SERVICE_VAPIX_CALL_RESPONSE, response)
                return True
        _LOGGER.info("Couldn\'t find device %s", call.data[CONF_NAME])
        return False

    # Register service with Home Assistant.
    hass.services.register(DOMAIN,
                           SERVICE_VAPIX_CALL,
                           vapix_service,
                           descriptions[DOMAIN][SERVICE_VAPIX_CALL],
                           schema=SERVICE_SCHEMA)
    return True
예제 #41
0
def get_device(hass, node, value, **kwargs):
    """Create zwave entity device."""
    descriptions = load_yaml_config_file(
        path.join(path.dirname(__file__), 'services.yaml'))

    def set_usercode(service):
        """Set the usercode to index X on the lock."""
        node_id = service.data.get(zwave.const.ATTR_NODE_ID)
        lock_node = zwave.NETWORK.nodes[node_id]
        code_slot = service.data.get(ATTR_CODE_SLOT)
        usercode = service.data.get(ATTR_USERCODE)

        for value in lock_node.get_values(
                class_id=zwave.const.COMMAND_CLASS_USER_CODE).values():
            if value.index != code_slot:
                continue
            if len(str(usercode)) > 4:
                _LOGGER.error(
                    'Invalid code provided: (%s)'
                    ' usercode must %s or less digits', usercode,
                    len(value.data))
            value.data = str(usercode)
            break

    def get_usercode(service):
        """Get a usercode at index X on the lock."""
        node_id = service.data.get(zwave.const.ATTR_NODE_ID)
        lock_node = zwave.NETWORK.nodes[node_id]
        code_slot = service.data.get(ATTR_CODE_SLOT)

        for value in lock_node.get_values(
                class_id=zwave.const.COMMAND_CLASS_USER_CODE).values():
            if value.index != code_slot:
                continue
            _LOGGER.info('Usercode at slot %s is: %s', value.index, value.data)
            break

    def clear_usercode(service):
        """Set usercode to slot X on the lock."""
        node_id = service.data.get(zwave.const.ATTR_NODE_ID)
        lock_node = zwave.NETWORK.nodes[node_id]
        code_slot = service.data.get(ATTR_CODE_SLOT)
        data = ''

        for value in lock_node.get_values(
                class_id=zwave.const.COMMAND_CLASS_USER_CODE).values():
            if value.index != code_slot:
                continue
            for i in range(len(value.data)):
                data += '\0'
                i += 1
            _LOGGER.debug('Data to clear lock: %s', data)
            value.data = data
            _LOGGER.info('Usercode at slot %s is cleared', value.index)
            break

    if node.has_command_class(zwave.const.COMMAND_CLASS_USER_CODE):
        hass.services.register(DOMAIN,
                               SERVICE_SET_USERCODE,
                               set_usercode,
                               descriptions.get(SERVICE_SET_USERCODE),
                               schema=SET_USERCODE_SCHEMA)
        hass.services.register(DOMAIN,
                               SERVICE_GET_USERCODE,
                               get_usercode,
                               descriptions.get(SERVICE_GET_USERCODE),
                               schema=GET_USERCODE_SCHEMA)
        hass.services.register(DOMAIN,
                               SERVICE_CLEAR_USERCODE,
                               clear_usercode,
                               descriptions.get(SERVICE_CLEAR_USERCODE),
                               schema=CLEAR_USERCODE_SCHEMA)
    return ZwaveLock(value)
예제 #42
0
def test_unhashable_key():
    """Test an unhashable key."""
    files = {YAML_CONFIG_FILE: "message:\n  {{ states.state }}"}
    with pytest.raises(HomeAssistantError), patch_yaml_files(files):
        load_yaml_config_file(YAML_CONFIG_FILE)
예제 #43
0
def setup(hass, config):
    """Setup Z-Wave.

    Will automatically load components to support devices found on the network.
    """
    descriptions = conf_util.load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    try:
        import libopenzwave
    except ImportError:
        _LOGGER.error("You are missing required dependency Python Open "
                      "Z-Wave. Please follow instructions at: "
                      "https://home-assistant.io/components/zwave/")
        return False
    from pydispatch import dispatcher
    # pylint: disable=import-error
    from openzwave.option import ZWaveOption
    from openzwave.network import ZWaveNetwork
    from openzwave.group import ZWaveGroup

    default_zwave_config_path = os.path.join(
        os.path.dirname(libopenzwave.__file__), 'config')

    # Load configuration
    use_debug = config[DOMAIN].get(CONF_DEBUG)
    autoheal = config[DOMAIN].get(CONF_AUTOHEAL)
    device_config = EntityValues(config[DOMAIN][CONF_DEVICE_CONFIG],
                                 config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN],
                                 config[DOMAIN][CONF_DEVICE_CONFIG_GLOB])

    # Setup options
    options = ZWaveOption(config[DOMAIN].get(CONF_USB_STICK_PATH),
                          user_path=hass.config.config_dir,
                          config_path=config[DOMAIN].get(
                              CONF_CONFIG_PATH, default_zwave_config_path))

    options.set_console_output(use_debug)
    options.lock()

    network = hass.data[ZWAVE_NETWORK] = ZWaveNetwork(options, autostart=False)
    hass.data[DATA_ZWAVE_DICT] = {}

    if use_debug:  # pragma: no cover

        def log_all(signal, value=None):
            """Log all the signals."""
            print("")
            print("SIGNAL *****", signal)
            if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED,
                                    ZWaveNetwork.SIGNAL_VALUE_ADDED,
                                    ZWaveNetwork.SIGNAL_SCENE_EVENT,
                                    ZWaveNetwork.SIGNAL_NODE_EVENT,
                                    ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED,
                                    ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED):
                pprint(_obj_to_dict(value))

            print("")

        dispatcher.connect(log_all, weak=False)

    discovered_values = []

    def value_added(node, value):
        """Called when a value is added to a node on the network."""
        # Check if this value should be tracked by an existing entity
        for values in discovered_values:
            values.check_value(value)

        for schema in DISCOVERY_SCHEMAS:
            if not check_node_schema(node, schema):
                continue
            if not check_value_schema(
                    value, schema[const.DISC_VALUES][const.DISC_PRIMARY]):
                continue

            values = ZWaveDeviceEntityValues(hass, schema, value, config,
                                             device_config)
            discovered_values.append(values)

    component = EntityComponent(_LOGGER, DOMAIN, hass)

    def node_added(node):
        """Called when a node is added on the network."""
        entity = ZWaveNodeEntity(node, network)
        node_config = device_config.get(entity.entity_id)
        if node_config.get(CONF_IGNORED):
            _LOGGER.info("Ignoring node entity %s due to device settings.",
                         entity.entity_id)
            return
        component.add_entities([entity])

    def scene_activated(node, scene_id):
        """Called when a scene is activated on any node in the network."""
        hass.bus.fire(
            const.EVENT_SCENE_ACTIVATED, {
                ATTR_ENTITY_ID: _node_object_id(node),
                const.ATTR_OBJECT_ID: _node_object_id(node),
                const.ATTR_SCENE_ID: scene_id
            })

    def node_event_activated(node, value):
        """Called when a nodeevent is activated on any node in the network."""
        hass.bus.fire(
            const.EVENT_NODE_EVENT, {
                const.ATTR_OBJECT_ID: _node_object_id(node),
                const.ATTR_BASIC_LEVEL: value
            })

    def network_ready():
        """Called when all awake nodes have been queried."""
        _LOGGER.info("Zwave network is ready for use. All awake nodes"
                     " have been queried. Sleeping nodes will be"
                     " queried when they awake.")
        hass.bus.fire(const.EVENT_NETWORK_READY)

    def network_complete():
        """Called when all nodes on network have been queried."""
        _LOGGER.info("Zwave network is complete. All nodes on the network"
                     " have been queried")
        hass.bus.fire(const.EVENT_NETWORK_COMPLETE)

    dispatcher.connect(value_added,
                       ZWaveNetwork.SIGNAL_VALUE_ADDED,
                       weak=False)
    dispatcher.connect(node_added, ZWaveNetwork.SIGNAL_NODE_ADDED, weak=False)
    dispatcher.connect(scene_activated,
                       ZWaveNetwork.SIGNAL_SCENE_EVENT,
                       weak=False)
    dispatcher.connect(node_event_activated,
                       ZWaveNetwork.SIGNAL_NODE_EVENT,
                       weak=False)
    dispatcher.connect(network_ready,
                       ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED,
                       weak=False)
    dispatcher.connect(network_complete,
                       ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED,
                       weak=False)

    def add_node(service):
        """Switch into inclusion mode."""
        _LOGGER.info("Zwave add_node have been initialized.")
        network.controller.add_node()

    def add_node_secure(service):
        """Switch into secure inclusion mode."""
        _LOGGER.info("Zwave add_node_secure have been initialized.")
        network.controller.add_node(True)

    def remove_node(service):
        """Switch into exclusion mode."""
        _LOGGER.info("Zwave remove_node have been initialized.")
        network.controller.remove_node()

    def cancel_command(service):
        """Cancel a running controller command."""
        _LOGGER.info("Cancel running ZWave command.")
        network.controller.cancel_command()

    def heal_network(service):
        """Heal the network."""
        _LOGGER.info("ZWave heal running.")
        network.heal()

    def soft_reset(service):
        """Soft reset the controller."""
        _LOGGER.info("Zwave soft_reset have been initialized.")
        network.controller.soft_reset()

    def test_network(service):
        """Test the network by sending commands to all the nodes."""
        _LOGGER.info("Zwave test_network have been initialized.")
        network.test()

    def stop_network(_service_or_event):
        """Stop Z-Wave network."""
        _LOGGER.info("Stopping ZWave network.")
        network.stop()
        if hass.state == CoreState.running:
            hass.bus.fire(const.EVENT_NETWORK_STOP)

    def rename_node(service):
        """Rename a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = hass.data[ZWAVE_NETWORK].nodes[node_id]
        name = service.data.get(const.ATTR_NAME)
        node.name = name
        _LOGGER.info("Renamed ZWave node %d to %s", node_id, name)

    def remove_failed_node(service):
        """Remove failed node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        _LOGGER.info('Trying to remove zwave node %d', node_id)
        network.controller.remove_failed_node(node_id)

    def replace_failed_node(service):
        """Replace failed node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        _LOGGER.info('Trying to replace zwave node %d', node_id)
        network.controller.replace_failed_node(node_id)

    def set_config_parameter(service):
        """Set a config parameter to a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        param = service.data.get(const.ATTR_CONFIG_PARAMETER)
        selection = service.data.get(const.ATTR_CONFIG_VALUE)
        size = service.data.get(const.ATTR_CONFIG_SIZE, 2)
        i = 0
        for value in (node.get_values(
                class_id=const.COMMAND_CLASS_CONFIGURATION).values()):
            if value.index == param and value.type == const.TYPE_LIST:
                _LOGGER.debug('Values for parameter %s: %s', param,
                              value.data_items)
                i = len(value.data_items) - 1
        if i == 0:
            node.set_config_param(param, selection, size)
        else:
            if selection > i:
                _LOGGER.info(
                    'Config parameter selection does not exist!'
                    ' Please check zwcfg_[home_id].xml in'
                    ' your homeassistant config directory. '
                    ' Available selections are 0 to %s', i)
                return
            node.set_config_param(param, selection, size)
            _LOGGER.info(
                'Setting config parameter %s on Node %s '
                'with selection %s and size=%s', param, node_id, selection,
                size)

    def print_config_parameter(service):
        """Print a config parameter from a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        param = service.data.get(const.ATTR_CONFIG_PARAMETER)
        _LOGGER.info("Config parameter %s on Node %s : %s", param, node_id,
                     get_config_value(node, param))

    def print_node(service):
        """Print all information about z-wave node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        nice_print_node(node)

    def set_wakeup(service):
        """Set wake-up interval of a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        value = service.data.get(const.ATTR_CONFIG_VALUE)
        if node.can_wake_up():
            for value_id in node.get_values(
                    class_id=const.COMMAND_CLASS_WAKE_UP):
                node.values[value_id].data = value
                _LOGGER.info("Node %s wake-up set to %d", node_id, value)
        else:
            _LOGGER.info("Node %s is not wakeable", node_id)

    def change_association(service):
        """Change an association in the zwave network."""
        association_type = service.data.get(const.ATTR_ASSOCIATION)
        node_id = service.data.get(const.ATTR_NODE_ID)
        target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID)
        group = service.data.get(const.ATTR_GROUP)
        instance = service.data.get(const.ATTR_INSTANCE)

        node = ZWaveGroup(group, network, node_id)
        if association_type == 'add':
            node.add_association(target_node_id, instance)
            _LOGGER.info(
                "Adding association for node:%s in group:%s "
                "target node:%s, instance=%s", node_id, group, target_node_id,
                instance)
        if association_type == 'remove':
            node.remove_association(target_node_id, instance)
            _LOGGER.info(
                "Removing association for node:%s in group:%s "
                "target node:%s, instance=%s", node_id, group, target_node_id,
                instance)

    @asyncio.coroutine
    def async_refresh_entity(service):
        """Refresh values that specific entity depends on."""
        entity_id = service.data.get(ATTR_ENTITY_ID)
        async_dispatcher_send(hass,
                              SIGNAL_REFRESH_ENTITY_FORMAT.format(entity_id))

    def refresh_node(service):
        """Refresh all node info."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        node.refresh_info()

    def start_zwave(_service_or_event):
        """Startup Z-Wave network."""
        _LOGGER.info("Starting ZWave network.")
        network.start()
        hass.bus.fire(const.EVENT_NETWORK_START)

        # Need to be in STATE_AWAKED before talking to nodes.
        # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network
        # to be ready.
        for i in range(const.NETWORK_READY_WAIT_SECS):
            _LOGGER.debug("network state: %d %s",
                          hass.data[ZWAVE_NETWORK].state, network.state_str)
            if network.state >= network.STATE_AWAKED:
                _LOGGER.info("zwave ready after %d seconds", i)
                break
            time.sleep(1)
        else:
            _LOGGER.warning(
                "zwave not ready after %d seconds, continuing anyway",
                const.NETWORK_READY_WAIT_SECS)
            _LOGGER.info("final network state: %d %s", network.state,
                         network.state_str)

        polling_interval = convert(config[DOMAIN].get(CONF_POLLING_INTERVAL),
                                   int)
        if polling_interval is not None:
            network.set_poll_interval(polling_interval, False)

        poll_interval = network.get_poll_interval()
        _LOGGER.info("zwave polling interval set to %d ms", poll_interval)

        hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network)

        # Register node services for Z-Wave network
        hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node,
                               descriptions[const.SERVICE_ADD_NODE])
        hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE,
                               add_node_secure,
                               descriptions[const.SERVICE_ADD_NODE_SECURE])
        hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node,
                               descriptions[const.SERVICE_REMOVE_NODE])
        hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND,
                               cancel_command,
                               descriptions[const.SERVICE_CANCEL_COMMAND])
        hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK,
                               heal_network,
                               descriptions[const.SERVICE_HEAL_NETWORK])
        hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset,
                               descriptions[const.SERVICE_SOFT_RESET])
        hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK,
                               test_network,
                               descriptions[const.SERVICE_TEST_NETWORK])
        hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK,
                               stop_network,
                               descriptions[const.SERVICE_STOP_NETWORK])
        hass.services.register(DOMAIN, const.SERVICE_START_NETWORK,
                               start_zwave,
                               descriptions[const.SERVICE_START_NETWORK])
        hass.services.register(DOMAIN,
                               const.SERVICE_RENAME_NODE,
                               rename_node,
                               descriptions[const.SERVICE_RENAME_NODE],
                               schema=RENAME_NODE_SCHEMA)
        hass.services.register(
            DOMAIN,
            const.SERVICE_SET_CONFIG_PARAMETER,
            set_config_parameter,
            descriptions[const.SERVICE_SET_CONFIG_PARAMETER],
            schema=SET_CONFIG_PARAMETER_SCHEMA)
        hass.services.register(
            DOMAIN,
            const.SERVICE_PRINT_CONFIG_PARAMETER,
            print_config_parameter,
            descriptions[const.SERVICE_PRINT_CONFIG_PARAMETER],
            schema=PRINT_CONFIG_PARAMETER_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REMOVE_FAILED_NODE,
                               remove_failed_node,
                               descriptions[const.SERVICE_REMOVE_FAILED_NODE],
                               schema=NODE_SERVICE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REPLACE_FAILED_NODE,
                               replace_failed_node,
                               descriptions[const.SERVICE_REPLACE_FAILED_NODE],
                               schema=NODE_SERVICE_SCHEMA)

        hass.services.register(DOMAIN,
                               const.SERVICE_CHANGE_ASSOCIATION,
                               change_association,
                               descriptions[const.SERVICE_CHANGE_ASSOCIATION],
                               schema=CHANGE_ASSOCIATION_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_SET_WAKEUP,
                               set_wakeup,
                               descriptions[const.SERVICE_SET_WAKEUP],
                               schema=SET_WAKEUP_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_PRINT_NODE,
                               print_node,
                               descriptions[const.SERVICE_PRINT_NODE],
                               schema=NODE_SERVICE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REFRESH_ENTITY,
                               async_refresh_entity,
                               descriptions[const.SERVICE_REFRESH_ENTITY],
                               schema=REFRESH_ENTITY_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REFRESH_NODE,
                               refresh_node,
                               descriptions[const.SERVICE_REFRESH_NODE],
                               schema=NODE_SERVICE_SCHEMA)

    # Setup autoheal
    if autoheal:
        _LOGGER.info("ZWave network autoheal is enabled.")
        track_time_change(hass, heal_network, hour=0, minute=0, second=0)

    hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave)

    if 'frontend' in hass.config.components:
        register_built_in_panel(hass, 'zwave', 'Z-Wave', 'mdi:nfc')

    return True
예제 #44
0
def setup(hass, config):
    """Setup thermostats."""
    component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL)
    component.setup(config)

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

    def away_mode_set_service(service):
        """Set away mode on target thermostats."""
        target_thermostats = component.extract_from_service(service)

        away_mode = service.data[ATTR_AWAY_MODE]

        for thermostat in target_thermostats:
            if away_mode:
                thermostat.turn_away_mode_on()
            else:
                thermostat.turn_away_mode_off()

            thermostat.update_ha_state(True)

    hass.services.register(DOMAIN,
                           SERVICE_SET_AWAY_MODE,
                           away_mode_set_service,
                           descriptions.get(SERVICE_SET_AWAY_MODE),
                           schema=SET_AWAY_MODE_SCHEMA)

    def temperature_set_service(service):
        """Set temperature on the target thermostats."""
        target_thermostats = component.extract_from_service(service)

        temperature = service.data[ATTR_TEMPERATURE]

        for thermostat in target_thermostats:
            thermostat.set_temperature(
                convert(temperature, hass.config.temperature_unit,
                        thermostat.unit_of_measurement))

            thermostat.update_ha_state(True)

    hass.services.register(DOMAIN,
                           SERVICE_SET_TEMPERATURE,
                           temperature_set_service,
                           descriptions.get(SERVICE_SET_TEMPERATURE),
                           schema=SET_TEMPERATURE_SCHEMA)

    def fan_mode_set_service(service):
        """Set fan mode on target thermostats."""
        target_thermostats = component.extract_from_service(service)

        fan_mode = service.data[ATTR_FAN]

        for thermostat in target_thermostats:
            if fan_mode:
                thermostat.turn_fan_on()
            else:
                thermostat.turn_fan_off()

            thermostat.update_ha_state(True)

    hass.services.register(DOMAIN,
                           SERVICE_SET_FAN_MODE,
                           fan_mode_set_service,
                           descriptions.get(SERVICE_SET_FAN_MODE),
                           schema=SET_FAN_MODE_SCHEMA)

    def hvac_mode_set_service(service):
        """Set hvac mode on target thermostats."""
        target_thermostats = component.extract_from_service(service)

        hvac_mode = service.data[ATTR_HVAC_MODE]

        for thermostat in target_thermostats:
            thermostat.set_hvac_mode(hvac_mode)

            thermostat.update_ha_state(True)

    hass.services.register(DOMAIN,
                           SERVICE_SET_HVAC_MODE,
                           hvac_mode_set_service,
                           descriptions.get(SERVICE_SET_HVAC_MODE),
                           schema=SET_HVAC_MODE_SCHEMA)

    return True
예제 #45
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Sonos platform."""
    import soco

    if DATA_SONOS not in hass.data:
        hass.data[DATA_SONOS] = []

    advertise_addr = config.get(CONF_ADVERTISE_ADDR, None)
    if advertise_addr:
        soco.config.EVENT_ADVERTISE_IP = advertise_addr

    if discovery_info:
        player = soco.SoCo(discovery_info.get('host'))

        # if device already exists by config
        if player.uid in [x.unique_id for x in hass.data[DATA_SONOS]]:
            return

        if player.is_visible:
            device = SonosDevice(player)
            add_devices([device], True)
            hass.data[DATA_SONOS].append(device)
            if len(hass.data[DATA_SONOS]) > 1:
                return
    else:
        players = None
        hosts = config.get(CONF_HOSTS, None)
        if hosts:
            # Support retro compatibility with comma separated list of hosts
            # from config
            hosts = hosts[0] if len(hosts) == 1 else hosts
            hosts = hosts.split(',') if isinstance(hosts, str) else hosts
            players = []
            for host in hosts:
                players.append(soco.SoCo(socket.gethostbyname(host)))

        if not players:
            players = soco.discover(
                interface_addr=config.get(CONF_INTERFACE_ADDR))

        if not players:
            _LOGGER.warning("No Sonos speakers found")
            return

        # Add coordinators first so they can be queried by slaves
        coordinators = [SonosDevice(p) for p in players if p.is_coordinator]
        slaves = [SonosDevice(p) for p in players if not p.is_coordinator]
        hass.data[DATA_SONOS] = coordinators + slaves
        if coordinators:
            add_devices(coordinators, True)
        if slaves:
            add_devices(slaves, True)
        _LOGGER.info("Added %s Sonos speakers", len(players))

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

    def service_handle(service):
        """Handle for services."""
        entity_ids = service.data.get('entity_id')

        if entity_ids:
            devices = [
                device for device in hass.data[DATA_SONOS]
                if device.entity_id in entity_ids
            ]
        else:
            devices = hass.data[DATA_SONOS]

        for device in devices:
            if service.service == SERVICE_JOIN:
                if device.entity_id != service.data[ATTR_MASTER]:
                    device.join(service.data[ATTR_MASTER])
            elif service.service == SERVICE_UNJOIN:
                device.unjoin()
            elif service.service == SERVICE_SNAPSHOT:
                device.snapshot(service.data[ATTR_WITH_GROUP])
            elif service.service == SERVICE_RESTORE:
                device.restore(service.data[ATTR_WITH_GROUP])
            elif service.service == SERVICE_SET_TIMER:
                device.set_sleep_timer(service.data[ATTR_SLEEP_TIME])
            elif service.service == SERVICE_CLEAR_TIMER:
                device.clear_sleep_timer()
            elif service.service == SERVICE_UPDATE_ALARM:
                device.update_alarm(**service.data)

            device.schedule_update_ha_state(True)

    hass.services.register(DOMAIN,
                           SERVICE_JOIN,
                           service_handle,
                           descriptions.get(SERVICE_JOIN),
                           schema=SONOS_JOIN_SCHEMA)

    hass.services.register(DOMAIN,
                           SERVICE_UNJOIN,
                           service_handle,
                           descriptions.get(SERVICE_UNJOIN),
                           schema=SONOS_SCHEMA)

    hass.services.register(DOMAIN,
                           SERVICE_SNAPSHOT,
                           service_handle,
                           descriptions.get(SERVICE_SNAPSHOT),
                           schema=SONOS_STATES_SCHEMA)

    hass.services.register(DOMAIN,
                           SERVICE_RESTORE,
                           service_handle,
                           descriptions.get(SERVICE_RESTORE),
                           schema=SONOS_STATES_SCHEMA)

    hass.services.register(DOMAIN,
                           SERVICE_SET_TIMER,
                           service_handle,
                           descriptions.get(SERVICE_SET_TIMER),
                           schema=SONOS_SET_TIMER_SCHEMA)

    hass.services.register(DOMAIN,
                           SERVICE_CLEAR_TIMER,
                           service_handle,
                           descriptions.get(SERVICE_CLEAR_TIMER),
                           schema=SONOS_SCHEMA)

    hass.services.register(DOMAIN,
                           SERVICE_UPDATE_ALARM,
                           service_handle,
                           descriptions.get(SERVICE_UPDATE_ALARM),
                           schema=SONOS_UPDATE_ALARM_SCHEMA)
예제 #46
0
 def test_duplicate_key(self):
     """Test duplicate dict keys."""
     files = {YAML_CONFIG_FILE: 'key: thing1\nkey: thing2'}
     with self.assertRaises(HomeAssistantError):
         with patch_yaml_files(files):
             load_yaml_config_file(YAML_CONFIG_FILE)
예제 #47
0
def setup(hass, config):
    """Start the MQTT protocol service."""
    # pylint: disable=too-many-locals
    conf = config.get(DOMAIN, {})

    client_id = conf.get(CONF_CLIENT_ID)
    keepalive = conf.get(CONF_KEEPALIVE)

    broker_config = _setup_server(hass, config)

    broker_in_conf = CONF_BROKER in conf

    # Only auto config if no server config was passed in
    if broker_config and CONF_EMBEDDED not in conf:
        broker, port, username, password, certificate, protocol = broker_config
        # Embedded broker doesn't have some ssl variables
        client_key, client_cert, tls_insecure = None, None, None
    elif not broker_config and not broker_in_conf:
        _LOGGER.error('Unable to start broker and auto-configure MQTT.')
        return False

    if broker_in_conf:
        broker = conf[CONF_BROKER]
        port = conf[CONF_PORT]
        username = conf.get(CONF_USERNAME)
        password = conf.get(CONF_PASSWORD)
        certificate = conf.get(CONF_CERTIFICATE)
        client_key = conf.get(CONF_CLIENT_KEY)
        client_cert = conf.get(CONF_CLIENT_CERT)
        tls_insecure = conf.get(CONF_TLS_INSECURE)
        protocol = conf[CONF_PROTOCOL]

    # For cloudmqtt.com, secured connection, auto fill in certificate
    if certificate is None and 19999 < port < 30000 and \
       broker.endswith('.cloudmqtt.com'):
        certificate = os.path.join(os.path.dirname(__file__),
                                   'addtrustexternalcaroot.crt')

    global MQTT_CLIENT
    try:
        MQTT_CLIENT = MQTT(hass, broker, port, client_id, keepalive, username,
                           password, certificate, client_key, client_cert,
                           tls_insecure, protocol)
    except socket.error:
        _LOGGER.exception("Can't connect to the broker. "
                          "Please check your settings and the broker "
                          "itself.")
        return False

    def stop_mqtt(event):
        """Stop MQTT component."""
        MQTT_CLIENT.stop()

    def start_mqtt(event):
        """Launch MQTT component when Home Assistant starts up."""
        MQTT_CLIENT.start()
        hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_mqtt)

    def publish_service(call):
        """Handle MQTT publish service calls."""
        msg_topic = call.data[ATTR_TOPIC]
        payload = call.data.get(ATTR_PAYLOAD)
        payload_template = call.data.get(ATTR_PAYLOAD_TEMPLATE)
        qos = call.data[ATTR_QOS]
        retain = call.data[ATTR_RETAIN]
        try:
            payload = (payload if payload_template is None else
                       template.render(hass, payload_template)) or ''
        except template.jinja2.TemplateError as exc:
            _LOGGER.error(
                "Unable to publish to '%s': rendering payload template of "
                "'%s' failed because %s.", msg_topic, payload_template, exc)
            return
        MQTT_CLIENT.publish(msg_topic, payload, qos, retain)

    hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_mqtt)

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

    hass.services.register(DOMAIN,
                           SERVICE_PUBLISH,
                           publish_service,
                           descriptions.get(SERVICE_PUBLISH),
                           schema=MQTT_PUBLISH_SCHEMA)

    return True
예제 #48
0
def check_ha_config_file(hass):
    """Check if Home Assistant configuration file is valid."""
    config_dir = hass.config.config_dir
    result = HomeAssistantConfig()

    def _pack_error(package, component, config, message):
        """Handle errors from packages: _log_pkg_error."""
        message = "Package {} setup failed. Component {} {}".format(
            package, component, message)
        domain = 'homeassistant.packages.{}.{}'.format(package, component)
        pack_config = core_config[CONF_PACKAGES].get(package, config)
        result.add_error(message, domain, pack_config)

    def _comp_error(ex, domain, config):
        """Handle errors from components: async_log_exception."""
        result.add_error(_format_config_error(ex, domain, config), domain,
                         config)

    # Load configuration.yaml
    try:
        config_path = find_config_file(config_dir)
        if not config_path:
            return result.add_error("File configuration.yaml not found.")
        config = load_yaml_config_file(config_path)
    except HomeAssistantError as err:
        return result.add_error("Error loading {}: {}".format(
            config_path, err))
    finally:
        yaml.clear_secret_cache()

    # Extract and validate core [homeassistant] config
    try:
        core_config = config.pop(CONF_CORE, {})
        core_config = CORE_CONFIG_SCHEMA(core_config)
        result[CONF_CORE] = core_config
    except vol.Invalid as err:
        result.add_error(err, CONF_CORE, core_config)
        core_config = {}

    # Merge packages
    merge_packages_config(hass, config, core_config.get(CONF_PACKAGES, {}),
                          _pack_error)
    del core_config[CONF_PACKAGES]

    # Ensure we have no None values after merge
    for key, value in config.items():
        if not value:
            config[key] = {}

    # Filter out repeating config sections
    components = set(key.split(' ')[0] for key in config.keys())

    # Process and validate config
    for domain in components:
        component = loader.get_component(hass, domain)
        if not component:
            result.add_error("Component not found: {}".format(domain))
            continue

        if hasattr(component, 'CONFIG_SCHEMA'):
            try:
                config = component.CONFIG_SCHEMA(config)
                result[domain] = config[domain]
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

        if not hasattr(component, 'PLATFORM_SCHEMA'):
            continue

        platforms = []
        for p_name, p_config in config_per_platform(config, domain):
            # Validate component specific platform schema
            try:
                p_validated = component.PLATFORM_SCHEMA(p_config)
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

            # Not all platform components follow same pattern for platforms
            # So if p_name is None we are not going to validate platform
            # (the automation component is one of them)
            if p_name is None:
                platforms.append(p_validated)
                continue

            platform = loader.get_platform(hass, domain, p_name)

            if platform is None:
                result.add_error("Platform not found: {}.{}".format(
                    domain, p_name))
                continue

            # Validate platform specific schema
            if hasattr(platform, 'PLATFORM_SCHEMA'):
                try:
                    p_validated = platform.PLATFORM_SCHEMA(p_validated)
                except vol.Invalid as ex:
                    _comp_error(ex, '{}.{}'.format(domain, p_name),
                                p_validated)
                    continue

            platforms.append(p_validated)

        # Remove config for current component and add validated config back in.
        for filter_comp in extract_domain_configs(config, domain):
            del config[filter_comp]
        result[domain] = platforms

    return result
예제 #49
0
                                    config)


def autosetup_ihc_products(hass: HomeAssistant, config, ihc_controller,
                           controller_id):
    """Auto setup of IHC products from the IHC project file."""
    if not (project_xml := ihc_controller.get_project()):
        _LOGGER.error("Unable to read project from IHC controller")
        return False
    project = ElementTree.fromstring(project_xml)

    # If an auto setup file exist in the configuration it will override
    yaml_path = hass.config.path(AUTO_SETUP_YAML)
    if not os.path.isfile(yaml_path):
        yaml_path = os.path.join(os.path.dirname(__file__), AUTO_SETUP_YAML)
    yaml = load_yaml_config_file(yaml_path)
    try:
        auto_setup_conf = AUTO_SETUP_SCHEMA(yaml)
    except vol.Invalid as exception:
        _LOGGER.error("Invalid IHC auto setup data: %s", exception)
        return False

    groups = project.findall(".//group")
    for platform in PLATFORMS:
        platform_setup = auto_setup_conf[platform]
        discovery_info = get_discovery_info(platform_setup, groups,
                                            controller_id)
        if discovery_info:
            discovery.load_platform(hass, platform, DOMAIN, discovery_info,
                                    config)
예제 #50
0
def test_representing_yaml_loaded_data():
    """Test we can represent YAML loaded data."""
    files = {YAML_CONFIG_FILE: 'key: [1, "2", 3]'}
    with patch_yaml_files(files):
        data = load_yaml_config_file(YAML_CONFIG_FILE)
    assert yaml.dump(data) == "key:\n- 1\n- '2'\n- 3\n"
예제 #51
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
예제 #52
0
def test_duplicate_key(caplog):
    """Test duplicate dict keys."""
    files = {YAML_CONFIG_FILE: 'key: thing1\nkey: thing2'}
    with patch_yaml_files(files):
        load_yaml_config_file(YAML_CONFIG_FILE)
    assert 'contains duplicate key' in caplog.text
예제 #53
0
def setup(hass: HomeAssistantType, config: ConfigType):
    """Setup device tracker."""
    yaml_path = hass.config.path(YAML_DEVICES)

    try:
        conf = _CONFIG_SCHEMA(config).get(DOMAIN, [])
    except vol.Invalid as ex:
        log_exception(ex, DOMAIN, config)
        return False
    else:
        conf = conf[0] if len(conf) > 0 else {}
        consider_home = conf.get(CONF_CONSIDER_HOME,
                                 timedelta(seconds=DEFAULT_CONSIDER_HOME))
        track_new = conf.get(CONF_TRACK_NEW, DEFAULT_TRACK_NEW)

    devices = load_config(yaml_path, hass, consider_home)

    tracker = DeviceTracker(hass, consider_home, track_new, devices)

    def setup_platform(p_type, p_config, disc_info=None):
        """Setup a device tracker platform."""
        platform = prepare_setup_platform(hass, config, DOMAIN, p_type)
        if platform is None:
            return

        try:
            if hasattr(platform, 'get_scanner'):
                scanner = platform.get_scanner(hass, {DOMAIN: p_config})

                if scanner is None:
                    _LOGGER.error('Error setting up platform %s', p_type)
                    return

                setup_scanner_platform(hass, p_config, scanner, tracker.see)
                return

            if not platform.setup_scanner(hass, p_config, tracker.see):
                _LOGGER.error('Error setting up platform %s', p_type)
        except Exception:  # pylint: disable=broad-except
            _LOGGER.exception('Error setting up platform %s', p_type)

    for p_type, p_config in config_per_platform(config, DOMAIN):
        setup_platform(p_type, p_config)

    def device_tracker_discovered(service, info):
        """Called when a device tracker platform is discovered."""
        setup_platform(DISCOVERY_PLATFORMS[service], {}, info)

    discovery.listen(hass, DISCOVERY_PLATFORMS.keys(),
                     device_tracker_discovered)

    def update_stale(now):
        """Clean up stale devices."""
        tracker.update_stale(now)

    track_utc_time_change(hass, update_stale, second=range(0, 60, 5))

    tracker.setup_group()

    def see_service(call):
        """Service to see a device."""
        args = {
            key: value
            for key, value in call.data.items()
            if key in (ATTR_MAC, ATTR_DEV_ID, ATTR_HOST_NAME,
                       ATTR_LOCATION_NAME, ATTR_GPS, ATTR_GPS_ACCURACY,
                       ATTR_BATTERY, ATTR_ATTRIBUTES)
        }
        tracker.see(**args)

    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))
    hass.services.register(DOMAIN, SERVICE_SEE, see_service,
                           descriptions.get(SERVICE_SEE))

    return True
예제 #54
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the Sonos platform."""
    import soco

    if discovery_info:
        player = soco.SoCo(discovery_info)
        if player.is_visible:
            add_devices([SonosDevice(hass, player)])
            return True
        return False

    players = None
    hosts = config.get('hosts', None)
    if hosts:
        # Support retro compatibility with comma separated list of hosts
        # from config
        hosts = hosts.split(',') if isinstance(hosts, str) else hosts
        players = []
        for host in hosts:
            players.append(soco.SoCo(socket.gethostbyname(host)))

    if not players:
        players = soco.discover(
            interface_addr=config.get('interface_addr', None))

    if not players:
        _LOGGER.warning('No Sonos speakers found.')
        return False

    devices = [SonosDevice(hass, p) for p in players]
    add_devices(devices)
    _LOGGER.info('Added %s Sonos speakers', len(players))

    def _apply_service(service, service_func, *service_func_args):
        """Internal func for applying a service."""
        entity_id = service.data.get('entity_id')

        if entity_id:
            _devices = [
                device for device in devices if device.entity_id == entity_id
            ]
        else:
            _devices = devices

        for device in _devices:
            service_func(device, *service_func_args)
            device.update_ha_state(True)

    def group_players_service(service):
        """Group media players, use player as coordinator."""
        _apply_service(service, SonosDevice.group_players)

    def unjoin_service(service):
        """Unjoin the player from a group."""
        _apply_service(service, SonosDevice.unjoin)

    def snapshot_service(service):
        """Take a snapshot."""
        _apply_service(service, SonosDevice.snapshot)

    def restore_service(service):
        """Restore a snapshot."""
        _apply_service(service, SonosDevice.restore)

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

    hass.services.register(DOMAIN, SERVICE_GROUP_PLAYERS,
                           group_players_service,
                           descriptions.get(SERVICE_GROUP_PLAYERS))

    hass.services.register(DOMAIN, SERVICE_UNJOIN, unjoin_service,
                           descriptions.get(SERVICE_UNJOIN))

    hass.services.register(DOMAIN, SERVICE_SNAPSHOT, snapshot_service,
                           descriptions.get(SERVICE_SNAPSHOT))

    hass.services.register(DOMAIN, SERVICE_RESTORE, restore_service,
                           descriptions.get(SERVICE_RESTORE))

    return True
예제 #55
0
def setup_bridge(host, hass, add_devices, filename, allow_unreachable,
                 allow_in_emulated_hue, allow_hue_groups):
    """Set up a phue bridge based on host parameter."""
    import phue

    try:
        bridge = phue.Bridge(host, config_file_path=hass.config.path(filename))
    except ConnectionRefusedError:  # Wrong host was given
        _LOGGER.error("Error connecting to the Hue bridge at %s", host)

        return

    except phue.PhueRegistrationException:
        _LOGGER.warning("Connected to Hue at %s but not registered.", host)

        request_configuration(host, hass, add_devices, filename,
                              allow_unreachable, allow_in_emulated_hue,
                              allow_hue_groups)

        return

    # If we came here and configuring this host, mark as done
    if host in _CONFIGURING:
        request_id = _CONFIGURING.pop(host)

        configurator = get_component('configurator')

        configurator.request_done(request_id)

    lights = {}
    lightgroups = {}
    skip_groups = not allow_hue_groups

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
    def update_lights():
        """Update the Hue light objects with latest info from the bridge."""
        nonlocal skip_groups

        try:
            api = bridge.get_api()
        except phue.PhueRequestTimeout:
            _LOGGER.warning("Timeout trying to reach the bridge")
            return
        except ConnectionRefusedError:
            _LOGGER.error("The bridge refused the connection")
            return
        except socket.error:
            # socket.error when we cannot reach Hue
            _LOGGER.exception("Cannot reach the bridge")
            return

        api_lights = api.get('lights')

        if not isinstance(api_lights, dict):
            _LOGGER.error("Got unexpected result from Hue API")
            return

        if skip_groups:
            api_groups = {}
        else:
            api_groups = api.get('groups')

        if not isinstance(api_groups, dict):
            _LOGGER.error("Got unexpected result from Hue API")
            return

        new_lights = []

        api_name = api.get('config').get('name')
        if api_name in ('RaspBee-GW', 'deCONZ-GW'):
            bridge_type = 'deconz'
        else:
            bridge_type = 'hue'

        for light_id, info in api_lights.items():
            if light_id not in lights:
                lights[light_id] = HueLight(int(light_id), info, bridge,
                                            update_lights, bridge_type,
                                            allow_unreachable,
                                            allow_in_emulated_hue)
                new_lights.append(lights[light_id])
            else:
                lights[light_id].info = info
                lights[light_id].schedule_update_ha_state()

        for lightgroup_id, info in api_groups.items():
            if 'state' not in info:
                _LOGGER.warning("Group info does not contain state. "
                                "Please update your hub.")
                skip_groups = True
                break

            if lightgroup_id not in lightgroups:
                lightgroups[lightgroup_id] = HueLight(int(lightgroup_id), info,
                                                      bridge, update_lights,
                                                      bridge_type,
                                                      allow_unreachable,
                                                      allow_in_emulated_hue,
                                                      True)
                new_lights.append(lightgroups[lightgroup_id])
            else:
                lightgroups[lightgroup_id].info = info
                lightgroups[lightgroup_id].schedule_update_ha_state()

        if new_lights:
            add_devices(new_lights)

    _CONFIGURED_BRIDGES[socket.gethostbyname(host)] = True

    # create a service for calling run_scene directly on the bridge,
    # used to simplify automation rules.
    def hue_activate_scene(call):
        """Service to call directly directly into bridge to set scenes."""
        group_name = call.data[ATTR_GROUP_NAME]
        scene_name = call.data[ATTR_SCENE_NAME]
        bridge.run_scene(group_name, scene_name)

    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))
    hass.services.register(DOMAIN,
                           SERVICE_HUE_SCENE,
                           hue_activate_scene,
                           descriptions.get(SERVICE_HUE_SCENE),
                           schema=SCENE_SCHEMA)

    update_lights()
예제 #56
0
def setup(hass, config):
    """Set up Z-Wave.

    Will automatically load components to support devices found on the network.
    """
    descriptions = conf_util.load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    from pydispatch import dispatcher
    # pylint: disable=import-error
    from openzwave.option import ZWaveOption
    from openzwave.network import ZWaveNetwork
    from openzwave.group import ZWaveGroup

    # Load configuration
    use_debug = config[DOMAIN].get(CONF_DEBUG)
    autoheal = config[DOMAIN].get(CONF_AUTOHEAL)
    device_config = EntityValues(config[DOMAIN][CONF_DEVICE_CONFIG],
                                 config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN],
                                 config[DOMAIN][CONF_DEVICE_CONFIG_GLOB])
    new_entity_ids = config[DOMAIN][CONF_NEW_ENTITY_IDS]
    if not new_entity_ids:
        _LOGGER.warning(
            "ZWave entity_ids will soon be changing. To opt in to new "
            "entity_ids now, set `new_entity_ids: true` under zwave in your "
            "configuration.yaml. See the following blog post for details: "
            "https://home-assistant.io/blog/2017/06/15/zwave-entity-ids/")

    # Setup options
    options = ZWaveOption(config[DOMAIN].get(CONF_USB_STICK_PATH),
                          user_path=hass.config.config_dir,
                          config_path=config[DOMAIN].get(CONF_CONFIG_PATH))

    options.set_console_output(use_debug)

    if CONF_NETWORK_KEY in config[DOMAIN]:
        options.addOption("NetworkKey", config[DOMAIN][CONF_NETWORK_KEY])

    options.lock()

    network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False)
    hass.data[DATA_DEVICES] = {}
    hass.data[DATA_ENTITY_VALUES] = []

    if use_debug:  # pragma: no cover

        def log_all(signal, value=None):
            """Log all the signals."""
            print("")
            print("SIGNAL *****", signal)
            if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED,
                                    ZWaveNetwork.SIGNAL_VALUE_ADDED,
                                    ZWaveNetwork.SIGNAL_SCENE_EVENT,
                                    ZWaveNetwork.SIGNAL_NODE_EVENT,
                                    ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED,
                                    ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED):
                pprint(_obj_to_dict(value))

            print("")

        dispatcher.connect(log_all, weak=False)

    def value_added(node, value):
        """Handle new added value to a node on the network."""
        # Check if this value should be tracked by an existing entity
        for values in hass.data[DATA_ENTITY_VALUES]:
            values.check_value(value)

        for schema in DISCOVERY_SCHEMAS:
            if not check_node_schema(node, schema):
                continue
            if not check_value_schema(
                    value, schema[const.DISC_VALUES][const.DISC_PRIMARY]):
                continue

            values = ZWaveDeviceEntityValues(hass, schema, value, config,
                                             device_config)

            # We create a new list and update the reference here so that
            # the list can be safely iterated over in the main thread
            new_values = hass.data[DATA_ENTITY_VALUES] + [values]
            hass.data[DATA_ENTITY_VALUES] = new_values

    component = EntityComponent(_LOGGER, DOMAIN, hass)

    def node_added(node):
        """Handle a new node on the network."""
        entity = ZWaveNodeEntity(node, network, new_entity_ids)
        name = node_name(node)
        if new_entity_ids:
            generated_id = generate_entity_id(DOMAIN + '.{}', name, [])
        else:
            generated_id = entity.entity_id
        node_config = device_config.get(generated_id)
        if node_config.get(CONF_IGNORED):
            _LOGGER.info("Ignoring node entity %s due to device settings",
                         generated_id)
            return
        component.add_entities([entity])

    def network_ready():
        """Handle the query of all awake nodes."""
        _LOGGER.info("Zwave network is ready for use. All awake nodes "
                     "have been queried. Sleeping nodes will be "
                     "queried when they awake.")
        hass.bus.fire(const.EVENT_NETWORK_READY)

    def network_complete():
        """Handle the querying of all nodes on network."""
        _LOGGER.info("Z-Wave network is complete. All nodes on the network "
                     "have been queried")
        hass.bus.fire(const.EVENT_NETWORK_COMPLETE)

    dispatcher.connect(value_added,
                       ZWaveNetwork.SIGNAL_VALUE_ADDED,
                       weak=False)
    dispatcher.connect(node_added, ZWaveNetwork.SIGNAL_NODE_ADDED, weak=False)
    dispatcher.connect(network_ready,
                       ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED,
                       weak=False)
    dispatcher.connect(network_complete,
                       ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED,
                       weak=False)

    def add_node(service):
        """Switch into inclusion mode."""
        _LOGGER.info("Z-Wave add_node have been initialized")
        network.controller.add_node()

    def add_node_secure(service):
        """Switch into secure inclusion mode."""
        _LOGGER.info("Z-Wave add_node_secure have been initialized")
        network.controller.add_node(True)

    def remove_node(service):
        """Switch into exclusion mode."""
        _LOGGER.info("Z-Wwave remove_node have been initialized")
        network.controller.remove_node()

    def cancel_command(service):
        """Cancel a running controller command."""
        _LOGGER.info("Cancel running Z-Wave command")
        network.controller.cancel_command()

    def heal_network(service):
        """Heal the network."""
        _LOGGER.info("Z-Wave heal running")
        network.heal()

    def soft_reset(service):
        """Soft reset the controller."""
        _LOGGER.info("Z-Wave soft_reset have been initialized")
        network.controller.soft_reset()

    def test_network(service):
        """Test the network by sending commands to all the nodes."""
        _LOGGER.info("Z-Wave test_network have been initialized")
        network.test()

    def stop_network(_service_or_event):
        """Stop Z-Wave network."""
        _LOGGER.info("Stopping Z-Wave network")
        network.stop()
        if hass.state == CoreState.running:
            hass.bus.fire(const.EVENT_NETWORK_STOP)

    def rename_node(service):
        """Rename a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        name = service.data.get(const.ATTR_NAME)
        node.name = name
        _LOGGER.info("Renamed Z-Wave node %d to %s", node_id, name)

    def rename_value(service):
        """Rename a node value."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        value_id = service.data.get(const.ATTR_VALUE_ID)
        node = network.nodes[node_id]
        value = node.values[value_id]
        name = service.data.get(const.ATTR_NAME)
        value.label = name
        _LOGGER.info("Renamed Z-Wave value (Node %d Value %d) to %s", node_id,
                     value_id, name)

    def set_poll_intensity(service):
        """Set the polling intensity of a node value."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        value_id = service.data.get(const.ATTR_VALUE_ID)
        node = network.nodes[node_id]
        value = node.values[value_id]
        intensity = service.data.get(const.ATTR_POLL_INTENSITY)
        if intensity == 0:
            if value.disable_poll():
                _LOGGER.info("Polling disabled (Node %d Value %d)", node_id,
                             value_id)
                return
            _LOGGER.info("Polling disabled failed (Node %d Value %d)", node_id,
                         value_id)
        else:
            if value.enable_poll(intensity):
                _LOGGER.info("Set polling intensity (Node %d Value %d) to %s",
                             node_id, value_id, intensity)
                return
            _LOGGER.info("Set polling intensity failed (Node %d Value %d)",
                         node_id, value_id)

    def remove_failed_node(service):
        """Remove failed node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        _LOGGER.info("Trying to remove zwave node %d", node_id)
        network.controller.remove_failed_node(node_id)

    def replace_failed_node(service):
        """Replace failed node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        _LOGGER.info("Trying to replace zwave node %d", node_id)
        network.controller.replace_failed_node(node_id)

    def set_config_parameter(service):
        """Set a config parameter to a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        param = service.data.get(const.ATTR_CONFIG_PARAMETER)
        selection = service.data.get(const.ATTR_CONFIG_VALUE)
        size = service.data.get(const.ATTR_CONFIG_SIZE)
        for value in (node.get_values(
                class_id=const.COMMAND_CLASS_CONFIGURATION).values()):
            if value.index != param:
                continue
            if value.type in [const.TYPE_LIST, const.TYPE_BOOL]:
                value.data = selection
                _LOGGER.info(
                    "Setting config list parameter %s on Node %s "
                    "with selection %s", param, node_id, selection)
                return
            value.data = int(selection)
            _LOGGER.info(
                "Setting config parameter %s on Node %s "
                "with selection %s", param, node_id, selection)
            return
        node.set_config_param(param, selection, size)
        _LOGGER.info(
            "Setting unknown config parameter %s on Node %s "
            "with selection %s", param, node_id, selection)

    def print_config_parameter(service):
        """Print a config parameter from a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        param = service.data.get(const.ATTR_CONFIG_PARAMETER)
        _LOGGER.info("Config parameter %s on Node %s: %s", param, node_id,
                     get_config_value(node, param))

    def print_node(service):
        """Print all information about z-wave node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        nice_print_node(node)

    def set_wakeup(service):
        """Set wake-up interval of a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        value = service.data.get(const.ATTR_CONFIG_VALUE)
        if node.can_wake_up():
            for value_id in node.get_values(
                    class_id=const.COMMAND_CLASS_WAKE_UP):
                node.values[value_id].data = value
                _LOGGER.info("Node %s wake-up set to %d", node_id, value)
        else:
            _LOGGER.info("Node %s is not wakeable", node_id)

    def change_association(service):
        """Change an association in the zwave network."""
        association_type = service.data.get(const.ATTR_ASSOCIATION)
        node_id = service.data.get(const.ATTR_NODE_ID)
        target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID)
        group = service.data.get(const.ATTR_GROUP)
        instance = service.data.get(const.ATTR_INSTANCE)

        node = ZWaveGroup(group, network, node_id)
        if association_type == 'add':
            node.add_association(target_node_id, instance)
            _LOGGER.info(
                "Adding association for node:%s in group:%s "
                "target node:%s, instance=%s", node_id, group, target_node_id,
                instance)
        if association_type == 'remove':
            node.remove_association(target_node_id, instance)
            _LOGGER.info(
                "Removing association for node:%s in group:%s "
                "target node:%s, instance=%s", node_id, group, target_node_id,
                instance)

    @asyncio.coroutine
    def async_refresh_entity(service):
        """Refresh values that specific entity depends on."""
        entity_id = service.data.get(ATTR_ENTITY_ID)
        async_dispatcher_send(hass,
                              SIGNAL_REFRESH_ENTITY_FORMAT.format(entity_id))

    def refresh_node(service):
        """Refresh all node info."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        node.refresh_info()

    def reset_node_meters(service):
        """Reset meter counters of a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        instance = service.data.get(const.ATTR_INSTANCE)
        node = network.nodes[node_id]
        for value in (node.get_values(
                class_id=const.COMMAND_CLASS_METER).values()):
            if value.index != const.INDEX_METER_RESET:
                continue
            if value.instance != instance:
                continue
            network.manager.pressButton(value.value_id)
            network.manager.releaseButton(value.value_id)
            _LOGGER.info("Resetting meters on node %s instance %s....",
                         node_id, instance)
            return
        _LOGGER.info(
            "Node %s on instance %s does not have resettable "
            "meters.", node_id, instance)

    def start_zwave(_service_or_event):
        """Startup Z-Wave network."""
        _LOGGER.info("Starting Z-Wave network...")
        network.start()
        hass.bus.fire(const.EVENT_NETWORK_START)

        # Need to be in STATE_AWAKED before talking to nodes.
        # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network
        # to be ready.
        for i in range(const.NETWORK_READY_WAIT_SECS):
            _LOGGER.debug("network state: %d %s", network.state,
                          network.state_str)
            if network.state >= network.STATE_AWAKED:
                _LOGGER.info("Z-Wave ready after %d seconds", i)
                break
            time.sleep(1)
        else:
            _LOGGER.warning(
                "zwave not ready after %d seconds, continuing anyway",
                const.NETWORK_READY_WAIT_SECS)
            _LOGGER.info("final network state: %d %s", network.state,
                         network.state_str)

        polling_interval = convert(config[DOMAIN].get(CONF_POLLING_INTERVAL),
                                   int)
        if polling_interval is not None:
            network.set_poll_interval(polling_interval, False)

        poll_interval = network.get_poll_interval()
        _LOGGER.info("Z-Wave polling interval set to %d ms", poll_interval)

        hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network)

        # Register node services for Z-Wave network
        hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node,
                               descriptions[const.SERVICE_ADD_NODE])
        hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE,
                               add_node_secure,
                               descriptions[const.SERVICE_ADD_NODE_SECURE])
        hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node,
                               descriptions[const.SERVICE_REMOVE_NODE])
        hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND,
                               cancel_command,
                               descriptions[const.SERVICE_CANCEL_COMMAND])
        hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK,
                               heal_network,
                               descriptions[const.SERVICE_HEAL_NETWORK])
        hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset,
                               descriptions[const.SERVICE_SOFT_RESET])
        hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK,
                               test_network,
                               descriptions[const.SERVICE_TEST_NETWORK])
        hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK,
                               stop_network,
                               descriptions[const.SERVICE_STOP_NETWORK])
        hass.services.register(DOMAIN, const.SERVICE_START_NETWORK,
                               start_zwave,
                               descriptions[const.SERVICE_START_NETWORK])
        hass.services.register(DOMAIN,
                               const.SERVICE_RENAME_NODE,
                               rename_node,
                               descriptions[const.SERVICE_RENAME_NODE],
                               schema=RENAME_NODE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_RENAME_VALUE,
                               rename_value,
                               descriptions[const.SERVICE_RENAME_VALUE],
                               schema=RENAME_VALUE_SCHEMA)
        hass.services.register(
            DOMAIN,
            const.SERVICE_SET_CONFIG_PARAMETER,
            set_config_parameter,
            descriptions[const.SERVICE_SET_CONFIG_PARAMETER],
            schema=SET_CONFIG_PARAMETER_SCHEMA)
        hass.services.register(
            DOMAIN,
            const.SERVICE_PRINT_CONFIG_PARAMETER,
            print_config_parameter,
            descriptions[const.SERVICE_PRINT_CONFIG_PARAMETER],
            schema=PRINT_CONFIG_PARAMETER_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REMOVE_FAILED_NODE,
                               remove_failed_node,
                               descriptions[const.SERVICE_REMOVE_FAILED_NODE],
                               schema=NODE_SERVICE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REPLACE_FAILED_NODE,
                               replace_failed_node,
                               descriptions[const.SERVICE_REPLACE_FAILED_NODE],
                               schema=NODE_SERVICE_SCHEMA)

        hass.services.register(DOMAIN,
                               const.SERVICE_CHANGE_ASSOCIATION,
                               change_association,
                               descriptions[const.SERVICE_CHANGE_ASSOCIATION],
                               schema=CHANGE_ASSOCIATION_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_SET_WAKEUP,
                               set_wakeup,
                               descriptions[const.SERVICE_SET_WAKEUP],
                               schema=SET_WAKEUP_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_PRINT_NODE,
                               print_node,
                               descriptions[const.SERVICE_PRINT_NODE],
                               schema=NODE_SERVICE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REFRESH_ENTITY,
                               async_refresh_entity,
                               descriptions[const.SERVICE_REFRESH_ENTITY],
                               schema=REFRESH_ENTITY_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REFRESH_NODE,
                               refresh_node,
                               descriptions[const.SERVICE_REFRESH_NODE],
                               schema=NODE_SERVICE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_RESET_NODE_METERS,
                               reset_node_meters,
                               descriptions[const.SERVICE_RESET_NODE_METERS],
                               schema=RESET_NODE_METERS_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_SET_POLL_INTENSITY,
                               set_poll_intensity,
                               descriptions[const.SERVICE_SET_POLL_INTENSITY],
                               schema=SET_POLL_INTENSITY_SCHEMA)

    # Setup autoheal
    if autoheal:
        _LOGGER.info("Z-Wave network autoheal is enabled")
        track_time_change(hass, heal_network, hour=0, minute=0, second=0)

    hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave)

    return True
예제 #57
0
def load_yaml(fname, string):
    """Write a string to file and return the parsed yaml."""
    FILES[fname] = string
    with patch_yaml_files(FILES):
        return load_yaml_config_file(fname)
예제 #58
0
def setup(hass, config):
    """ Track states and offer events for media_players. """
    component = EntityComponent(
        logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL,
        DISCOVERY_PLATFORMS)

    component.setup(config)

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

    def media_player_service_handler(service):
        """ Maps services to methods on MediaPlayerDevice. """
        target_players = component.extract_from_service(service)

        method = SERVICE_TO_METHOD[service.service]

        for player in target_players:
            getattr(player, method)()

            if player.should_poll:
                player.update_ha_state(True)

    for service in SERVICE_TO_METHOD:
        hass.services.register(DOMAIN, service, media_player_service_handler,
                               descriptions.get(service))

    def volume_set_service(service):
        """ Set specified volume on the media player. """
        target_players = component.extract_from_service(service)

        if ATTR_MEDIA_VOLUME_LEVEL not in service.data:
            return

        volume = service.data[ATTR_MEDIA_VOLUME_LEVEL]

        for player in target_players:
            player.set_volume_level(volume)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_VOLUME_SET, volume_set_service,
                           descriptions.get(SERVICE_VOLUME_SET))

    def volume_mute_service(service):
        """ Mute (true) or unmute (false) the media player. """
        target_players = component.extract_from_service(service)

        if ATTR_MEDIA_VOLUME_MUTED not in service.data:
            return

        mute = service.data[ATTR_MEDIA_VOLUME_MUTED]

        for player in target_players:
            player.mute_volume(mute)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE, volume_mute_service,
                           descriptions.get(SERVICE_VOLUME_MUTE))

    def media_seek_service(service):
        """ Seek to a position. """
        target_players = component.extract_from_service(service)

        if ATTR_MEDIA_SEEK_POSITION not in service.data:
            return

        position = service.data[ATTR_MEDIA_SEEK_POSITION]

        for player in target_players:
            player.seek(position)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK, media_seek_service,
                           descriptions.get(SERVICE_MEDIA_SEEK))

    def play_youtube_video_service(service, media_id=None):
        """ Plays specified media_id on the media player. """
        if media_id is None:
            service.data.get('video')

        if media_id is None:
            return

        for player in component.extract_from_service(service):
            player.play_youtube(media_id)

            if player.should_poll:
                player.update_ha_state(True)

    def play_media_service(service):
        """ Plays specified media_id on the media player. """
        media_type = service.data.get('media_type')
        media_id = service.data.get('media_id')

        if media_type is None:
            return

        if media_id is None:
            return

        for player in component.extract_from_service(service):
            player.play_media(media_type, media_id)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(
        DOMAIN, "start_fireplace",
        lambda service: play_youtube_video_service(service, "eyU3bRy2x44"),
        descriptions.get('start_fireplace'))

    hass.services.register(
        DOMAIN, "start_epic_sax",
        lambda service: play_youtube_video_service(service, "kxopViU98Xo"),
        descriptions.get('start_epic_sax'))

    hass.services.register(
        DOMAIN, SERVICE_YOUTUBE_VIDEO, play_youtube_video_service,
        descriptions.get(SERVICE_YOUTUBE_VIDEO))

    hass.services.register(
        DOMAIN, SERVICE_PLAY_MEDIA, play_media_service,
        descriptions.get(SERVICE_PLAY_MEDIA))

    return True
예제 #59
0
 def test_unhashable_key(self):
     """Test an unhasable key."""
     files = {YAML_CONFIG_FILE: 'message:\n  {{ states.state }}'}
     with self.assertRaises(HomeAssistantError), \
             patch_yaml_files(files):
         load_yaml_config_file(YAML_CONFIG_FILE)
예제 #60
0
def setup(hass, config):
    """ Exposes light control via statemachine and services. """

    component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL,
                                DISCOVERY_PLATFORMS, GROUP_NAME_ALL_LIGHTS)
    component.setup(config)

    # Load built-in profiles and custom profiles
    profile_paths = [
        os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE),
        hass.config.path(LIGHT_PROFILES_FILE)
    ]
    profiles = {}

    for profile_path in profile_paths:
        if not os.path.isfile(profile_path):
            continue
        with open(profile_path) as inp:
            reader = csv.reader(inp)

            # Skip the header
            next(reader, None)

            try:
                for profile_id, color_x, color_y, brightness in reader:
                    profiles[profile_id] = (float(color_x), float(color_y),
                                            int(brightness))
            except ValueError:
                # ValueError if not 4 values per row
                # ValueError if convert to float/int failed
                _LOGGER.error("Error parsing light profiles from %s",
                              profile_path)

                return False

    def handle_light_service(service):
        """ Hande a turn light on or off service call. """
        # Get and validate data
        dat = service.data

        # Convert the entity ids to valid light ids
        target_lights = component.extract_from_service(service)

        params = {}

        transition = util.convert(dat.get(ATTR_TRANSITION), int)

        if transition is not None:
            params[ATTR_TRANSITION] = transition

        service_fun = None
        if service.service == SERVICE_TURN_OFF:
            service_fun = 'turn_off'
        elif service.service == SERVICE_TOGGLE:
            service_fun = 'toggle'

        if service_fun:
            for light in target_lights:
                getattr(light, service_fun)(**params)

            for light in target_lights:
                if light.should_poll:
                    light.update_ha_state(True)
            return

        # Processing extra data for turn light on request

        # We process the profile first so that we get the desired
        # behavior that extra service data attributes overwrite
        # profile values
        profile = profiles.get(dat.get(ATTR_PROFILE))

        if profile:
            *params[ATTR_XY_COLOR], params[ATTR_BRIGHTNESS] = profile

        if ATTR_BRIGHTNESS in dat:
            # We pass in the old value as the default parameter if parsing
            # of the new one goes wrong.
            params[ATTR_BRIGHTNESS] = util.convert(dat.get(ATTR_BRIGHTNESS),
                                                   int,
                                                   params.get(ATTR_BRIGHTNESS))

        if ATTR_XY_COLOR in dat:
            try:
                # xy_color should be a list containing 2 floats
                xycolor = dat.get(ATTR_XY_COLOR)

                # Without this check, a xycolor with value '99' would work
                if not isinstance(xycolor, str):
                    params[ATTR_XY_COLOR] = [float(val) for val in xycolor]

            except (TypeError, ValueError):
                # TypeError if xy_color is not iterable
                # ValueError if value could not be converted to float
                pass

        if ATTR_COLOR_TEMP in dat:
            # color_temp should be an int of mirads value
            colortemp = dat.get(ATTR_COLOR_TEMP)

            # Without this check, a ctcolor with value '99' would work
            # These values are based on Philips Hue, may need ajustment later
            if isinstance(colortemp, int) and 154 <= colortemp <= 500:
                params[ATTR_COLOR_TEMP] = colortemp

        if ATTR_RGB_COLOR in dat:
            try:
                # rgb_color should be a list containing 3 ints
                rgb_color = dat.get(ATTR_RGB_COLOR)

                if len(rgb_color) == 3:
                    params[ATTR_RGB_COLOR] = [int(val) for val in rgb_color]

            except (TypeError, ValueError):
                # TypeError if rgb_color is not iterable
                # ValueError if not all values can be converted to int
                pass

        if dat.get(ATTR_FLASH) in (FLASH_SHORT, FLASH_LONG):
            params[ATTR_FLASH] = dat[ATTR_FLASH]

        if dat.get(ATTR_EFFECT) in (EFFECT_COLORLOOP, EFFECT_WHITE,
                                    EFFECT_RANDOM):
            params[ATTR_EFFECT] = dat[ATTR_EFFECT]

        for light in target_lights:
            light.turn_on(**params)

        for light in target_lights:
            if light.should_poll:
                light.update_ha_state(True)

    # Listen for light on and light off service calls
    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))
    hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_light_service,
                           descriptions.get(SERVICE_TURN_ON))

    hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_light_service,
                           descriptions.get(SERVICE_TURN_OFF))

    hass.services.register(DOMAIN, SERVICE_TOGGLE, handle_light_service,
                           descriptions.get(SERVICE_TOGGLE))

    return True