# Constant color temp values for 2 flux_led special modes
# Warm-white and Cool-white modes
COLOR_TEMP_WARM_VS_COLD_WHITE_CUT_OFF: Final = 285

EFFECT_CUSTOM: Final = "custom"

SERVICE_CUSTOM_EFFECT: Final = "set_custom_effect"

CUSTOM_EFFECT_DICT: Final = {
    vol.Required(CONF_COLORS):
    vol.All(
        cv.ensure_list,
        vol.Length(min=1, max=16),
        [
            vol.All(vol.Coerce(tuple),
                    vol.ExactSequence((cv.byte, cv.byte, cv.byte)))
        ],
    ),
    vol.Optional(CONF_SPEED_PCT, default=50):
    vol.All(vol.Range(min=0, max=100), vol.Coerce(int)),
    vol.Optional(CONF_TRANSITION, default=TRANSITION_GRADUAL):
    vol.All(cv.string,
            vol.In([TRANSITION_GRADUAL, TRANSITION_JUMP, TRANSITION_STROBE])),
}

CUSTOM_EFFECT_SCHEMA: Final = vol.Schema(CUSTOM_EFFECT_DICT)

DEVICE_SCHEMA: Final = vol.Schema({
    vol.Optional(CONF_NAME):
    cv.string,
    vol.Optional(ATTR_MODE, default=MODE_AUTO):
Beispiel #2
0
LIGHT_PROFILES_FILE = "light_profiles.csv"

# Service call validation schemas
VALID_TRANSITION = vol.All(vol.Coerce(float), vol.Clamp(min=0, max=6553))
VALID_BRIGHTNESS = vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255))
VALID_BRIGHTNESS_PCT = vol.All(vol.Coerce(float), vol.Range(min=0, max=100))

LIGHT_TURN_ON_SCHEMA = vol.Schema({
    ATTR_ENTITY_ID: cv.entity_ids,
    vol.Exclusive(ATTR_PROFILE, COLOR_GROUP): cv.string,
    ATTR_TRANSITION: VALID_TRANSITION,
    ATTR_BRIGHTNESS: VALID_BRIGHTNESS,
    ATTR_BRIGHTNESS_PCT: VALID_BRIGHTNESS_PCT,
    vol.Exclusive(ATTR_COLOR_NAME, COLOR_GROUP): cv.string,
    vol.Exclusive(ATTR_RGB_COLOR, COLOR_GROUP):
        vol.All(vol.ExactSequence((cv.byte, cv.byte, cv.byte)),
                vol.Coerce(tuple)),
    vol.Exclusive(ATTR_XY_COLOR, COLOR_GROUP):
        vol.All(vol.ExactSequence((cv.small_float, cv.small_float)),
                vol.Coerce(tuple)),
    vol.Exclusive(ATTR_HS_COLOR, COLOR_GROUP):
        vol.All(vol.ExactSequence(
            (vol.All(vol.Coerce(float), vol.Range(min=0, max=360)),
             vol.All(vol.Coerce(float), vol.Range(min=0, max=100)))),
                vol.Coerce(tuple)),
    vol.Exclusive(ATTR_COLOR_TEMP, COLOR_GROUP):
        vol.All(vol.Coerce(int), vol.Range(min=1)),
    vol.Exclusive(ATTR_KELVIN, COLOR_GROUP):
        vol.All(vol.Coerce(int), vol.Range(min=0)),
    ATTR_WHITE_VALUE: vol.All(vol.Coerce(int), vol.Range(min=0, max=255)),
    ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]),
Beispiel #3
0
    EFFECT_SLOWDOWN: yee_transitions.slowdown,
}

VALID_BRIGHTNESS = vol.All(vol.Coerce(int), vol.Range(min=1, max=100))

SERVICE_SCHEMA_SET_MODE = YEELIGHT_SERVICE_SCHEMA.extend({
    vol.Required(ATTR_MODE):
    vol.In([mode.name.lower() for mode in PowerMode])
})

SERVICE_SCHEMA_START_FLOW = YEELIGHT_SERVICE_SCHEMA.extend(
    YEELIGHT_FLOW_TRANSITION_SCHEMA)

SERVICE_SCHEMA_SET_COLOR_SCENE = YEELIGHT_SERVICE_SCHEMA.extend({
    vol.Required(ATTR_RGB_COLOR):
    vol.All(vol.ExactSequence((cv.byte, cv.byte, cv.byte)), vol.Coerce(tuple)),
    vol.Required(ATTR_BRIGHTNESS):
    VALID_BRIGHTNESS,
})

SERVICE_SCHEMA_SET_HSV_SCENE = YEELIGHT_SERVICE_SCHEMA.extend({
    vol.Required(ATTR_HS_COLOR):
    vol.All(
        vol.ExactSequence((
            vol.All(vol.Coerce(float), vol.Range(min=0, max=359)),
            vol.All(vol.Coerce(float), vol.Range(min=0, max=100)),
        )),
        vol.Coerce(tuple),
    ),
    vol.Required(ATTR_BRIGHTNESS):
    VALID_BRIGHTNESS,
Beispiel #4
0
# Constant color temp values for 2 flux_led special modes
# Warm-white and Cool-white modes
COLOR_TEMP_WARM_VS_COLD_WHITE_CUT_OFF: Final = 285

EFFECT_CUSTOM: Final = "custom"

SERVICE_CUSTOM_EFFECT: Final = "set_custom_effect"
SERVICE_SET_ZONES: Final = "set_zones"
SERVICE_SET_MUSIC_MODE: Final = "set_music_mode"

CUSTOM_EFFECT_DICT: Final = {
    vol.Required(CONF_COLORS): vol.All(
        cv.ensure_list,
        vol.Length(min=1, max=16),
        [vol.All(vol.Coerce(tuple), vol.ExactSequence((cv.byte, cv.byte, cv.byte)))],
    ),
    vol.Optional(CONF_SPEED_PCT, default=50): vol.All(
        vol.Coerce(int), vol.Range(min=0, max=100)
    ),
    vol.Optional(CONF_TRANSITION, default=TRANSITION_GRADUAL): vol.All(
        cv.string, vol.In([TRANSITION_GRADUAL, TRANSITION_JUMP, TRANSITION_STROBE])
    ),
}

SET_MUSIC_MODE_DICT: Final = {
    vol.Optional(ATTR_SENSITIVITY, default=100): vol.All(
        vol.Coerce(int), vol.Range(min=0, max=100)
    ),
    vol.Optional(ATTR_BRIGHTNESS, default=100): vol.All(
        vol.Coerce(int), vol.Range(min=0, max=100)
    extra=vol.ALLOW_EXTRA,
)

VACUUM_SERVICE_SCHEMA = vol.Schema({vol.Optional(ATTR_ENTITY_ID): cv.comp_entity_ids})
SERVICE_CLEAN_ZONE = "xiaomi_clean_zone"
SERVICE_CLEAN_POINT = "xiaomi_clean_point"
ATTR_ZONE_ARRAY = "zone"
ATTR_ZONE_REPEATER = "repeats"
ATTR_POINT = "point"
SERVICE_SCHEMA_CLEAN_ZONE = VACUUM_SERVICE_SCHEMA.extend(
    {
        vol.Required(ATTR_ZONE_ARRAY): vol.All(
            list,
            [
                vol.ExactSequence(
                    [vol.Coerce(float), vol.Coerce(float), vol.Coerce(float), vol.Coerce(float)]
                )
            ],
        ),
        vol.Required(ATTR_ZONE_REPEATER): vol.All(
            vol.Coerce(int), vol.Clamp(min=1, max=3)
        ),
    }
)
SERVICE_SCHEMA_CLEAN_POINT = VACUUM_SERVICE_SCHEMA.extend(
    {
        vol.Required(ATTR_POINT): vol.All(
            vol.ExactSequence(
                [vol.Coerce(float), vol.Coerce(float)]
            )
        )
}
EFFECT_CUSTOM_CODE = 0x60

TRANSITION_GRADUAL = "gradual"
TRANSITION_JUMP = "jump"
TRANSITION_STROBE = "strobe"

FLUX_EFFECT_LIST = sorted(list(EFFECT_MAP)) + [EFFECT_RANDOM]

CUSTOM_EFFECT_SCHEMA = vol.Schema({
    vol.Required(CONF_COLORS):
    vol.All(
        cv.ensure_list,
        vol.Length(min=1, max=16),
        [
            vol.All(vol.ExactSequence(
                (cv.byte, cv.byte, cv.byte)), vol.Coerce(tuple))
        ],
    ),
    vol.Optional(CONF_SPEED_PCT, default=50):
    vol.All(vol.Range(min=0, max=100), vol.Coerce(int)),
    vol.Optional(CONF_TRANSITION, default=TRANSITION_GRADUAL):
    vol.All(cv.string,
            vol.In([TRANSITION_GRADUAL, TRANSITION_JUMP, TRANSITION_STROBE])),
})

DEVICE_SCHEMA = vol.Schema({
    vol.Optional(CONF_NAME):
    cv.string,
    vol.Optional(ATTR_MODE, default=MODE_RGBW):
    vol.All(cv.string, vol.In([MODE_RGBW, MODE_RGB, MODE_WHITE])),
    vol.Optional(CONF_PROTOCOL):
Beispiel #7
0
 vol.Exclusive(ATTR_BRIGHTNESS_PCT, ATTR_BRIGHTNESS):
 VALID_BRIGHTNESS_PCT,
 vol.Exclusive(ATTR_BRIGHTNESS_STEP, ATTR_BRIGHTNESS):
 VALID_BRIGHTNESS_STEP,
 vol.Exclusive(ATTR_BRIGHTNESS_STEP_PCT, ATTR_BRIGHTNESS):
 VALID_BRIGHTNESS_STEP_PCT,
 vol.Exclusive(ATTR_COLOR_NAME, COLOR_GROUP):
 cv.string,
 vol.Exclusive(ATTR_COLOR_TEMP, COLOR_GROUP):
 vol.All(vol.Coerce(int), vol.Range(min=1)),
 vol.Exclusive(ATTR_KELVIN, COLOR_GROUP):
 cv.positive_int,
 vol.Exclusive(ATTR_HS_COLOR, COLOR_GROUP):
 vol.All(
     vol.ExactSequence((
         vol.All(vol.Coerce(float), vol.Range(min=0, max=360)),
         vol.All(vol.Coerce(float), vol.Range(min=0, max=100)),
     )),
     vol.Coerce(tuple),
 ),
 vol.Exclusive(ATTR_RGB_COLOR, COLOR_GROUP):
 vol.All(vol.ExactSequence((cv.byte, ) * 3), vol.Coerce(tuple)),
 vol.Exclusive(ATTR_RGBW_COLOR, COLOR_GROUP):
 vol.All(vol.ExactSequence((cv.byte, ) * 4), vol.Coerce(tuple)),
 vol.Exclusive(ATTR_RGBWW_COLOR, COLOR_GROUP):
 vol.All(vol.ExactSequence((cv.byte, ) * 5), vol.Coerce(tuple)),
 vol.Exclusive(ATTR_XY_COLOR, COLOR_GROUP):
 vol.All(vol.ExactSequence((cv.small_float, cv.small_float)),
         vol.Coerce(tuple)),
 vol.Exclusive(ATTR_WHITE, COLOR_GROUP):
 VALID_BRIGHTNESS,
 ATTR_WHITE_VALUE:
Beispiel #8
0
 def __call__(self, data: Any) -> list[int]:
     """Validate the passed selection."""
     value: list[int] = vol.All(list, vol.ExactSequence((cv.byte,) * 3))(data)
     return value
async def async_setup_platform(hass,
                               config,
                               async_add_entities,
                               discovery_info=None):
    """Set up the Xiaomi vacuum cleaner robot platform."""
    if DATA_KEY not in hass.data:
        hass.data[DATA_KEY] = {}

    host = config[CONF_HOST]
    token = config[CONF_TOKEN]
    name = config[CONF_NAME]

    # Create handler
    _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5])
    vacuum = Vacuum(host, token)

    mirobo = MiroboVacuum(name, vacuum)
    hass.data[DATA_KEY][host] = mirobo

    async_add_entities([mirobo], update_before_add=True)

    platform = entity_platform.current_platform.get()

    platform.async_register_entity_service(
        SERVICE_START_REMOTE_CONTROL,
        {},
        MiroboVacuum.async_remote_control_start.__name__,
    )

    platform.async_register_entity_service(
        SERVICE_STOP_REMOTE_CONTROL,
        {},
        MiroboVacuum.async_remote_control_stop.__name__,
    )

    platform.async_register_entity_service(
        SERVICE_MOVE_REMOTE_CONTROL,
        {
            vol.Optional(ATTR_RC_VELOCITY):
            vol.All(vol.Coerce(float), vol.Clamp(min=-0.29, max=0.29)),
            vol.Optional(ATTR_RC_ROTATION):
            vol.All(vol.Coerce(int), vol.Clamp(min=-179, max=179)),
            vol.Optional(ATTR_RC_DURATION):
            cv.positive_int,
        },
        MiroboVacuum.async_remote_control_move.__name__,
    )

    platform.async_register_entity_service(
        SERVICE_MOVE_REMOTE_CONTROL_STEP,
        {
            vol.Optional(ATTR_RC_VELOCITY):
            vol.All(vol.Coerce(float), vol.Clamp(min=-0.29, max=0.29)),
            vol.Optional(ATTR_RC_ROTATION):
            vol.All(vol.Coerce(int), vol.Clamp(min=-179, max=179)),
            vol.Optional(ATTR_RC_DURATION):
            cv.positive_int,
        },
        MiroboVacuum.async_remote_control_move_step.__name__,
    )

    platform.async_register_entity_service(
        SERVICE_CLEAN_ZONE,
        {
            vol.Required(ATTR_ZONE_ARRAY):
            vol.All(
                list,
                [
                    vol.ExactSequence([
                        vol.Coerce(int),
                        vol.Coerce(int),
                        vol.Coerce(int),
                        vol.Coerce(int),
                    ])
                ],
            ),
            vol.Required(ATTR_ZONE_REPEATER):
            vol.All(vol.Coerce(int), vol.Clamp(min=1, max=3)),
        },
        MiroboVacuum.async_clean_zone.__name__,
    )

    platform.async_register_entity_service(
        SERVICE_GOTO,
        {
            vol.Required("x_coord"): vol.Coerce(int),
            vol.Required("y_coord"): vol.Coerce(int),
        },
        MiroboVacuum.async_goto.__name__,
    )
    platform.async_register_entity_service(
        SERVICE_CLEAN_SEGMENT,
        {
            vol.Required("segments"): vol.Any(vol.Coerce(int),
                                              [vol.Coerce(int)])
        },
        MiroboVacuum.async_clean_segment.__name__,
    )
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Optional(CONF_CLASSIFIER): {
        cv.string:
        vol.Any(
            cv.isfile,
            vol.Schema({
                vol.Required(CONF_FILE):
                cv.isfile,
                vol.Optional(CONF_SCALE, DEFAULT_SCALE):
                float,
                vol.Optional(CONF_NEIGHBORS, DEFAULT_NEIGHBORS):
                cv.positive_int,
                vol.Optional(CONF_MIN_SIZE, DEFAULT_MIN_SIZE):
                vol.Schema(
                    vol.All(vol.Coerce(tuple), vol.ExactSequence([int, int]))),
            }),
        )
    }
})


def _create_processor_from_config(hass, camera_entity, config):
    """Create an OpenCV processor from configuration."""
    classifier_config = config.get(CONF_CLASSIFIER)
    name = f"{config[CONF_NAME]} {split_entity_id(camera_entity)[1].replace('_', ' ')}"

    processor = OpenCVImageProcessor(hass, camera_entity, name,
                                     classifier_config)

    return processor
Beispiel #11
0
    vol.Optional(ATTR_CONTINUOUS_DURATION, default=0):
    cv.small_float,
    vol.Optional(ATTR_DISTANCE, default=0.1):
    cv.small_float,
    vol.Optional(ATTR_SPEED, default=0.5):
    cv.small_float,
})

SERVICE_PTZ_ADVANCED_MOVE_SCHEMA = vol.Schema({
    ATTR_ENTITY_ID:
    cv.entity_ids,
    ATTR_MOVE_MODE:
    vol.In([CONTINUOUS_MOVE, RELATIVE_MOVE, ABSOLUTE_MOVE, STOP_MOVE]),
    vol.Required(ATTR_PTZ_VECTOR):
    vol.All(
        vol.ExactSequence((cv.small_float, cv.small_float, cv.small_float)),
        vol.Coerce(tuple)),
    vol.Optional(ATTR_SPEED_VECTOR, default=(1.0, 1.0, 1.0)):
    vol.All(
        vol.ExactSequence((cv.small_float, cv.small_float, cv.small_float)),
        vol.Coerce(tuple)),
    vol.Optional(ATTR_CONTINUOUS_DURATION, default=0):
    cv.small_float
})

SERVICE_PTZ_PRESET_SCHEMA = vol.Schema({
    ATTR_ENTITY_ID:
    cv.entity_ids,
    ATTR_PRESET_OPERATION:
    vol.In([GET_PRESETS, SET_PRESET, GOTO_PRESET, GOTO_HOME, SET_HOME]),
    vol.Optional(ATTR_PRESET_NAME, default=""):
Beispiel #12
0
async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up the Xiaomi vacuum cleaner robot from a config entry."""
    entities = []

    if config_entry.data[CONF_FLOW_TYPE] == CONF_DEVICE:
        unique_id = config_entry.unique_id

        mirobo = MiroboVacuum(
            hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE],
            config_entry,
            unique_id,
            hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR],
        )
        entities.append(mirobo)

        platform = entity_platform.async_get_current_platform()

        platform.async_register_entity_service(
            SERVICE_START_REMOTE_CONTROL,
            {},
            MiroboVacuum.async_remote_control_start.__name__,
        )

        platform.async_register_entity_service(
            SERVICE_STOP_REMOTE_CONTROL,
            {},
            MiroboVacuum.async_remote_control_stop.__name__,
        )

        platform.async_register_entity_service(
            SERVICE_MOVE_REMOTE_CONTROL,
            {
                vol.Optional(ATTR_RC_VELOCITY):
                vol.All(vol.Coerce(float), vol.Clamp(min=-0.29, max=0.29)),
                vol.Optional(ATTR_RC_ROTATION):
                vol.All(vol.Coerce(int), vol.Clamp(min=-179, max=179)),
                vol.Optional(ATTR_RC_DURATION):
                cv.positive_int,
            },
            MiroboVacuum.async_remote_control_move.__name__,
        )

        platform.async_register_entity_service(
            SERVICE_MOVE_REMOTE_CONTROL_STEP,
            {
                vol.Optional(ATTR_RC_VELOCITY):
                vol.All(vol.Coerce(float), vol.Clamp(min=-0.29, max=0.29)),
                vol.Optional(ATTR_RC_ROTATION):
                vol.All(vol.Coerce(int), vol.Clamp(min=-179, max=179)),
                vol.Optional(ATTR_RC_DURATION):
                cv.positive_int,
            },
            MiroboVacuum.async_remote_control_move_step.__name__,
        )

        platform.async_register_entity_service(
            SERVICE_CLEAN_ZONE,
            {
                vol.Required(ATTR_ZONE_ARRAY):
                vol.All(
                    list,
                    [
                        vol.ExactSequence([
                            vol.Coerce(int),
                            vol.Coerce(int),
                            vol.Coerce(int),
                            vol.Coerce(int),
                        ])
                    ],
                ),
                vol.Required(ATTR_ZONE_REPEATER):
                vol.All(vol.Coerce(int), vol.Clamp(min=1, max=3)),
            },
            MiroboVacuum.async_clean_zone.__name__,
        )

        platform.async_register_entity_service(
            SERVICE_GOTO,
            {
                vol.Required("x_coord"): vol.Coerce(int),
                vol.Required("y_coord"): vol.Coerce(int),
            },
            MiroboVacuum.async_goto.__name__,
        )
        platform.async_register_entity_service(
            SERVICE_CLEAN_SEGMENT,
            {
                vol.Required("segments"):
                vol.Any(vol.Coerce(int), [vol.Coerce(int)])
            },
            MiroboVacuum.async_clean_segment.__name__,
        )

    async_add_entities(entities, update_before_add=True)
    CONF_RIGHT: 0,
    CONF_TOP: 0,
    CONF_BOTTOM: 0
}

DEFAULT_SIZES = {
    CONF_SIZE_VACUUM_RADIUS: 4,
    CONF_SIZE_IGNORED_OBSTACLE_RADIUS: 3,
    CONF_SIZE_IGNORED_OBSTACLE_WITH_PHOTO_RADIUS: 3,
    CONF_SIZE_OBSTACLE_RADIUS: 3,
    CONF_SIZE_OBSTACLE_WITH_PHOTO_RADIUS: 3,
    CONF_SIZE_CHARGER_RADIUS: 4
}

COLOR_SCHEMA = vol.Or(
    vol.All(vol.Length(min=3, max=3), vol.ExactSequence((cv.byte, cv.byte, cv.byte)), vol.Coerce(tuple)),
    vol.All(vol.Length(min=4, max=4), vol.ExactSequence((cv.byte, cv.byte, cv.byte, cv.byte)), vol.Coerce(tuple))
)

PERCENT_SCHEMA = vol.All(vol.Coerce(float), vol.Range(min=0, max=100))

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
    {
        vol.Required(CONF_HOST): cv.string,
        vol.Required(CONF_TOKEN): vol.All(str, vol.Length(min=32, max=32)),
        vol.Required(CONF_USERNAME): cv.string,
        vol.Required(CONF_PASSWORD): cv.string,
        vol.Optional(CONF_COUNTRY, default=None): vol.Or(vol.In(CONF_AVAILABLE_COUNTRIES), vol.Equal(None)),
        vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
        vol.Optional(CONF_AUTO_UPDATE, default=True): cv.boolean,
        vol.Optional(CONF_COLORS, default={}): vol.Schema({
class Profiles:
    """Representation of available color profiles."""

    SCHEMA = vol.Schema(
        vol.Any(
            vol.ExactSequence((str, cv.small_float, cv.small_float, cv.byte)),
            vol.ExactSequence((str, cv.small_float, cv.small_float, cv.byte,
                               cv.positive_int)),
        ))

    def __init__(self, hass):
        """Initialize profiles."""
        self.hass = hass
        self.data = None

    def _load_profile_data(self):
        """Load built-in profiles and custom profiles."""
        profile_paths = [
            os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE),
            self.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,
                            *transition,
                        ) = Profiles.SCHEMA(rec)

                        transition = transition[0] if transition else 0

                        profiles[profile] = color_util.color_xy_to_hs(
                            color_x, color_y) + (
                                brightness,
                                transition,
                            )
                except vol.MultipleInvalid as ex:
                    _LOGGER.error("Error parsing light profile from %s: %s",
                                  profile_path, ex)
                    continue
        return profiles

    async def async_initialize(self):
        """Load and cache profiles."""
        self.data = await self.hass.async_add_executor_job(
            self._load_profile_data)

    @callback
    def apply_default(self, entity_id, params):
        """Return the default turn-on profile for the given light."""
        name = f"{entity_id}.default"
        if name in self.data:
            self.apply_profile(name, params)
            return

        name = "group.all_lights.default"
        if name in self.data:
            self.apply_profile(name, params)

    @callback
    def apply_profile(self, name, params):
        """Apply a profile."""
        profile = self.data.get(name)

        if profile is None:
            return

        params.setdefault(ATTR_HS_COLOR, profile[:2])
        params.setdefault(ATTR_BRIGHTNESS, profile[2])
        params.setdefault(ATTR_TRANSITION, profile[3])
Beispiel #15
0
    'effect_list': ATTR_EFFECT_LIST,
    'effect': ATTR_EFFECT,
    'supported_features': ATTR_SUPPORTED_FEATURES,
}

# Service call validation schemas
VALID_TRANSITION = vol.All(vol.Coerce(int), vol.Clamp(min=0, max=900))
VALID_BRIGHTNESS = vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255))

LIGHT_TURN_ON_SCHEMA = vol.Schema({
    ATTR_ENTITY_ID: cv.entity_ids,
    ATTR_PROFILE: cv.string,
    ATTR_TRANSITION: VALID_TRANSITION,
    ATTR_BRIGHTNESS: VALID_BRIGHTNESS,
    ATTR_COLOR_NAME: cv.string,
    ATTR_RGB_COLOR: vol.All(vol.ExactSequence((cv.byte, cv.byte, cv.byte)),
                            vol.Coerce(tuple)),
    ATTR_XY_COLOR: vol.All(vol.ExactSequence((cv.small_float, cv.small_float)),
                           vol.Coerce(tuple)),
    ATTR_COLOR_TEMP: vol.All(vol.Coerce(int),
                             vol.Range(min=color_util.HASS_COLOR_MIN,
                                       max=color_util.HASS_COLOR_MAX)),
    ATTR_WHITE_VALUE: vol.All(vol.Coerce(int), vol.Range(min=0, max=255)),
    ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]),
    ATTR_EFFECT: cv.string,
})

LIGHT_TURN_OFF_SCHEMA = vol.Schema({
    ATTR_ENTITY_ID: cv.entity_ids,
    ATTR_TRANSITION: VALID_TRANSITION,
    ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]),
Beispiel #16
0
from . import legacy_device_id
from .const import DOMAIN
from .coordinator import TPLinkDataUpdateCoordinator
from .entity import CoordinatedTPLinkEntity, async_refresh_after

_LOGGER = logging.getLogger(__name__)

SERVICE_RANDOM_EFFECT = "random_effect"
SERVICE_SEQUENCE_EFFECT = "sequence_effect"

HUE = vol.Range(min=0, max=360)
SAT = vol.Range(min=0, max=100)
VAL = vol.Range(min=0, max=100)
TRANSITION = vol.Range(min=0, max=6000)
HSV_SEQUENCE = vol.ExactSequence((HUE, SAT, VAL))

BASE_EFFECT_DICT: Final = {
    vol.Optional("brightness", default=100): vol.All(
        vol.Coerce(int), vol.Range(min=0, max=100)
    ),
    vol.Optional("duration", default=0): vol.All(
        vol.Coerce(int), vol.Range(min=0, max=5000)
    ),
    vol.Optional("transition", default=0): vol.All(vol.Coerce(int), TRANSITION),
    vol.Optional("segments", default=[0]): vol.All(
        cv.ensure_list_csv,
        vol.Length(min=1, max=80),
        [vol.All(vol.Coerce(int), vol.Range(min=0, max=80))],
    ),
}
Beispiel #17
0
ATTR_STATUS = 'status'
ATTR_ZONE_ARRAY = 'zone'
ATTR_ZONE_REPEATER = 'repeats'

SERVICE_SCHEMA_REMOTE_CONTROL = VACUUM_SERVICE_SCHEMA.extend({
    vol.Optional(ATTR_RC_VELOCITY):
        vol.All(vol.Coerce(float), vol.Clamp(min=-0.29, max=0.29)),
    vol.Optional(ATTR_RC_ROTATION):
        vol.All(vol.Coerce(int), vol.Clamp(min=-179, max=179)),
    vol.Optional(ATTR_RC_DURATION): cv.positive_int,
})

SERVICE_SCHEMA_CLEAN_ZONE = VACUUM_SERVICE_SCHEMA.extend({
    vol.Required(ATTR_ZONE_ARRAY):
        vol.All(list, [vol.ExactSequence(
            [vol.Coerce(int), vol.Coerce(int),
             vol.Coerce(int), vol.Coerce(int)])]),
    vol.Required(ATTR_ZONE_REPEATER):
        vol.All(vol.Coerce(int), vol.Clamp(min=1, max=3)),
})

SERVICE_SCHEMA_CLEAN_ZONE = VACUUM_SERVICE_SCHEMA.extend({
    vol.Required(ATTR_ZONE_ARRAY):
        vol.All(list, [vol.ExactSequence(
            [vol.Coerce(int), vol.Coerce(int),
             vol.Coerce(int), vol.Coerce(int)])]),
    vol.Required(ATTR_ZONE_REPEATER):
        vol.All(vol.Coerce(int), vol.Clamp(min=1, max=3)),
})

SERVICE_TO_METHOD = {
OLD_SLUG_VALIDATION = r'^[a-z0-9_]+$'
OLD_ENTITY_ID_VALIDATION = r"^(\w+)\.(\w+)$"
# Keep track of invalid slugs and entity ids found so we can create a
# persistent notification. Rare temporary exception to use a global.
INVALID_SLUGS_FOUND = {}
INVALID_ENTITY_IDS_FOUND = {}

# Home Assistant types
byte = vol.All(vol.Coerce(int), vol.Range(min=0, max=255))
small_float = vol.All(vol.Coerce(float), vol.Range(min=0, max=1))
positive_int = vol.All(vol.Coerce(int), vol.Range(min=0))
latitude = vol.All(vol.Coerce(float), vol.Range(min=-90, max=90),
                   msg='invalid latitude')
longitude = vol.All(vol.Coerce(float), vol.Range(min=-180, max=180),
                    msg='invalid longitude')
gps = vol.ExactSequence([latitude, longitude])
sun_event = vol.All(vol.Lower, vol.Any(SUN_EVENT_SUNSET, SUN_EVENT_SUNRISE))
port = vol.All(vol.Coerce(int), vol.Range(min=1, max=65535))
color_rgb = vol.All(vol.ExactSequence((byte, byte, byte)), vol.Coerce(tuple))


def color_name(given_color_name):
    """Convert color name to RGB hex value."""
    # COLORS map has no spaces in it, so make the color_name have no
    # spaces in it as well for matching purposes
    rgb_value = COLORS.get(given_color_name.replace(" ", "").lower())
    if not rgb_value:
        raise vol.Invalid("Unknown color {0}".format(given_color_name))

    return rgb_value
Beispiel #19
0
ATTR_STATUS = 'status'
ATTR_ZONE_ARRAY = 'zone'
ATTR_ZONE_REPEATER = 'repeats'
ATTR_ZONE_REPEATER_TEMPLATE = 'repeats_template'

SERVICE_SCHEMA_REMOTE_CONTROL = VACUUM_SERVICE_SCHEMA.extend({
    vol.Optional(ATTR_RC_VELOCITY):
    vol.All(vol.Coerce(float), vol.Clamp(min=-0.29, max=0.29)),
    vol.Optional(ATTR_RC_ROTATION):
    vol.All(vol.Coerce(int), vol.Clamp(min=-179, max=179)),
    vol.Optional(ATTR_RC_DURATION):
    cv.positive_int,
})
SERVICE_SCHEMA_CLEAN_ZONE = VACUUM_SERVICE_SCHEMA.extend({
    vol.Required(ATTR_ZONE_ARRAY):
    vol.All(list, [vol.ExactSequence([int, int, int, int])]),
    vol.Exclusive(ATTR_ZONE_REPEATER, 'TimeToRepeats'):
    vol.All(vol.Coerce(int), vol.Clamp(min=1, max=3)),
    vol.Exclusive(ATTR_ZONE_REPEATER_TEMPLATE, 'TimeToRepeats'):
    cv.template,
})

SERVICE_TO_METHOD = {
    SERVICE_START_REMOTE_CONTROL: {
        'method': 'async_remote_control_start'
    },
    SERVICE_STOP_REMOTE_CONTROL: {
        'method': 'async_remote_control_stop'
    },
    SERVICE_MOVE_REMOTE_CONTROL: {
        'method': 'async_remote_control_move',
# persistent notification. Rare temporary exception to use a global.
INVALID_SLUGS_FOUND = {}
INVALID_ENTITY_IDS_FOUND = {}
INVALID_EXTRA_KEYS_FOUND = []

# Home Assistant types
byte = vol.All(vol.Coerce(int), vol.Range(min=0, max=255))
small_float = vol.All(vol.Coerce(float), vol.Range(min=0, max=1))
positive_int = vol.All(vol.Coerce(int), vol.Range(min=0))
latitude = vol.All(vol.Coerce(float),
                   vol.Range(min=-90, max=90),
                   msg='invalid latitude')
longitude = vol.All(vol.Coerce(float),
                    vol.Range(min=-180, max=180),
                    msg='invalid longitude')
gps = vol.ExactSequence([latitude, longitude])
sun_event = vol.All(vol.Lower, vol.Any(SUN_EVENT_SUNSET, SUN_EVENT_SUNRISE))
port = vol.All(vol.Coerce(int), vol.Range(min=1, max=65535))

# typing typevar
T = TypeVar('T')


# Adapted from:
# https://github.com/alecthomas/voluptuous/issues/115#issuecomment-144464666
def has_at_least_one_key(*keys: str) -> Callable:
    """Validate that at least one key exists."""
    def validate(obj: Dict) -> Dict:
        """Test keys exist in dict."""
        if not isinstance(obj, dict):
            raise vol.Invalid('expected dictionary')
Beispiel #21
0
async def async_setup_entry(hass, config_entry, async_add_entities):
    """Set up the Xiaomi vacuum cleaner robot from a config entry."""
    entities = []

    if config_entry.data[CONF_FLOW_TYPE] == CONF_DEVICE:
        host = config_entry.data[CONF_HOST]
        token = config_entry.data[CONF_TOKEN]
        name = config_entry.title
        unique_id = config_entry.unique_id

        # Create handler
        _LOGGER.debug("Initializing with host %s (token %s...)", host,
                      token[:5])
        vacuum = Vacuum(host, token)

        mirobo = MiroboVacuum(name, vacuum, config_entry, unique_id)
        entities.append(mirobo)

        platform = entity_platform.current_platform.get()

        platform.async_register_entity_service(
            SERVICE_START_REMOTE_CONTROL,
            {},
            MiroboVacuum.async_remote_control_start.__name__,
        )

        platform.async_register_entity_service(
            SERVICE_STOP_REMOTE_CONTROL,
            {},
            MiroboVacuum.async_remote_control_stop.__name__,
        )

        platform.async_register_entity_service(
            SERVICE_MOVE_REMOTE_CONTROL,
            {
                vol.Optional(ATTR_RC_VELOCITY):
                vol.All(vol.Coerce(float), vol.Clamp(min=-0.29, max=0.29)),
                vol.Optional(ATTR_RC_ROTATION):
                vol.All(vol.Coerce(int), vol.Clamp(min=-179, max=179)),
                vol.Optional(ATTR_RC_DURATION):
                cv.positive_int,
            },
            MiroboVacuum.async_remote_control_move.__name__,
        )

        platform.async_register_entity_service(
            SERVICE_MOVE_REMOTE_CONTROL_STEP,
            {
                vol.Optional(ATTR_RC_VELOCITY):
                vol.All(vol.Coerce(float), vol.Clamp(min=-0.29, max=0.29)),
                vol.Optional(ATTR_RC_ROTATION):
                vol.All(vol.Coerce(int), vol.Clamp(min=-179, max=179)),
                vol.Optional(ATTR_RC_DURATION):
                cv.positive_int,
            },
            MiroboVacuum.async_remote_control_move_step.__name__,
        )

        platform.async_register_entity_service(
            SERVICE_CLEAN_ZONE,
            {
                vol.Required(ATTR_ZONE_ARRAY):
                vol.All(
                    list,
                    [
                        vol.ExactSequence([
                            vol.Coerce(int),
                            vol.Coerce(int),
                            vol.Coerce(int),
                            vol.Coerce(int),
                        ])
                    ],
                ),
                vol.Required(ATTR_ZONE_REPEATER):
                vol.All(vol.Coerce(int), vol.Clamp(min=1, max=3)),
            },
            MiroboVacuum.async_clean_zone.__name__,
        )

        platform.async_register_entity_service(
            SERVICE_GOTO,
            {
                vol.Required("x_coord"): vol.Coerce(int),
                vol.Required("y_coord"): vol.Coerce(int),
            },
            MiroboVacuum.async_goto.__name__,
        )
        platform.async_register_entity_service(
            SERVICE_CLEAN_SEGMENT,
            {
                vol.Required("segments"):
                vol.Any(vol.Coerce(int), [vol.Coerce(int)])
            },
            MiroboVacuum.async_clean_segment.__name__,
        )

    async_add_entities(entities, update_before_add=True)
Beispiel #22
0
        # message even if it's an other operation that invalid.
        raise voluptuous.Invalid("'%s' operation invalid" % v[0])

    return [u"metric"] + voluptuous.Schema(voluptuous.Any(
        voluptuous.ExactSequence([six.text_type, six.text_type]),
        voluptuous.All(
            voluptuous.Length(min=1),
            [voluptuous.ExactSequence([six.text_type, six.text_type])],
        )),
                                           required=True)(v[1:])


OperationsSchemaBase = [
    MetricSchema,
    voluptuous.ExactSequence([
        voluptuous.Any(*list(agg_operations.binary_operators.keys())),
        _OperationsSubNodeSchema, _OperationsSubNodeSchema
    ]),
    voluptuous.ExactSequence([
        voluptuous.Any(*list(agg_operations.unary_operators.keys())),
        _OperationsSubNodeSchema
    ]),
    voluptuous.ExactSequence([
        u"aggregate",
        voluptuous.Any(*list(agg_operations.AGG_MAP.keys())),
        _OperationsSubNodeSchema
    ]),
    voluptuous.ExactSequence([
        u"resample",
        voluptuous.Any(*list(agg_operations.AGG_MAP.keys())),
        utils.to_timespan, _OperationsSubNodeSchema
    ]),
Beispiel #23
0
SERVICE_SCHEMA_REMOTE_CONTROL = VACUUM_SERVICE_SCHEMA.extend({
    vol.Optional(ATTR_RC_VELOCITY):
    vol.All(vol.Coerce(float), vol.Clamp(min=-0.29, max=0.29)),
    vol.Optional(ATTR_RC_ROTATION):
    vol.All(vol.Coerce(int), vol.Clamp(min=-179, max=179)),
    vol.Optional(ATTR_RC_DURATION):
    cv.positive_int,
})

SERVICE_SCHEMA_CLEAN_ZONE = VACUUM_SERVICE_SCHEMA.extend({
    vol.Required(ATTR_ZONE_ARRAY):
    vol.All(list, [
        vol.ExactSequence([
            vol.Coerce(int),
            vol.Coerce(int),
            vol.Coerce(int),
            vol.Coerce(int)
        ])
    ]),
    vol.Required(ATTR_ZONE_REPEATER):
    vol.All(vol.Coerce(int), vol.Clamp(min=1, max=3)),
})

SERVICE_SCHEMA_CLEAN_ZONE = VACUUM_SERVICE_SCHEMA.extend({
    vol.Required(ATTR_ZONE_ARRAY):
    vol.All(list, [
        vol.ExactSequence([
            vol.Coerce(int),
            vol.Coerce(int),
            vol.Coerce(int),
            vol.Coerce(int)
Beispiel #24
0
LIGHT_TURN_ON_SCHEMA = vol.Schema({
    ATTR_ENTITY_ID:
    cv.entity_ids,
    ATTR_PROFILE:
    cv.string,
    ATTR_TRANSITION:
    VALID_TRANSITION,
    ATTR_BRIGHTNESS:
    VALID_BRIGHTNESS,
    ATTR_BRIGHTNESS_PCT:
    VALID_BRIGHTNESS_PCT,
    ATTR_COLOR_NAME:
    cv.string,
    ATTR_RGB_COLOR:
    vol.All(vol.ExactSequence((cv.byte, cv.byte, cv.byte)), vol.Coerce(tuple)),
    ATTR_XY_COLOR:
    vol.All(vol.ExactSequence((cv.small_float, cv.small_float)),
            vol.Coerce(tuple)),
    ATTR_COLOR_TEMP:
    vol.All(vol.Coerce(int), vol.Range(min=1)),
    ATTR_KELVIN:
    vol.All(vol.Coerce(int), vol.Range(min=0)),
    ATTR_WHITE_VALUE:
    vol.All(vol.Coerce(int), vol.Range(min=0, max=255)),
    ATTR_FLASH:
    vol.In([FLASH_SHORT, FLASH_LONG]),
    ATTR_EFFECT:
    cv.string,
})
Beispiel #25
0
 vol.Exclusive(ATTR_PROFILE, COLOR_GROUP):
 cv.string,
 ATTR_TRANSITION:
 VALID_TRANSITION,
 vol.Exclusive(ATTR_BRIGHTNESS, ATTR_BRIGHTNESS):
 VALID_BRIGHTNESS,
 vol.Exclusive(ATTR_BRIGHTNESS_PCT, ATTR_BRIGHTNESS):
 VALID_BRIGHTNESS_PCT,
 vol.Exclusive(ATTR_BRIGHTNESS_STEP, ATTR_BRIGHTNESS):
 VALID_BRIGHTNESS_STEP,
 vol.Exclusive(ATTR_BRIGHTNESS_STEP_PCT, ATTR_BRIGHTNESS):
 VALID_BRIGHTNESS_STEP_PCT,
 vol.Exclusive(ATTR_COLOR_NAME, COLOR_GROUP):
 cv.string,
 vol.Exclusive(ATTR_RGB_COLOR, COLOR_GROUP):
 vol.All(vol.ExactSequence((cv.byte, cv.byte, cv.byte)), vol.Coerce(tuple)),
 vol.Exclusive(ATTR_XY_COLOR, COLOR_GROUP):
 vol.All(vol.ExactSequence((cv.small_float, cv.small_float)),
         vol.Coerce(tuple)),
 vol.Exclusive(ATTR_HS_COLOR, COLOR_GROUP):
 vol.All(
     vol.ExactSequence((
         vol.All(vol.Coerce(float), vol.Range(min=0, max=360)),
         vol.All(vol.Coerce(float), vol.Range(min=0, max=100)),
     )),
     vol.Coerce(tuple),
 ),
 vol.Exclusive(ATTR_COLOR_TEMP, COLOR_GROUP):
 vol.All(vol.Coerce(int), vol.Range(min=1)),
 vol.Exclusive(ATTR_KELVIN, COLOR_GROUP):
 vol.All(vol.Coerce(int), vol.Range(min=0)),