def valid_subscribe_topic(value, invalid_chars='\0'): """Validate that we can subscribe using this MQTT topic.""" value = cv.string(value) if all(c not in value for c in invalid_chars): return vol.Length(min=1, max=65535)(value) raise vol.Invalid('Invalid MQTT topic name')
from homeassistant.const import CONF_DEVICES, CONF_EMAIL, CONF_PASSWORD from homeassistant.helpers.entity import Entity REQUIREMENTS = ["tank_utility==1.4.0"] _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = datetime.timedelta(hours=1) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_EMAIL): cv.string, vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_DEVICES): vol.All(cv.ensure_list, vol.Length(min=1)) }) SENSOR_TYPE = "tank" SENSOR_ROUNDING_PRECISION = 1 SENSOR_UNIT_OF_MEASUREMENT = "%" SENSOR_ATTRS = [ "name", "address", "capacity", "fuelType", "orientation", "status", "time", "time_iso" ] def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tank Utility sensor.""" from tank_utility import auth email = config.get(CONF_EMAIL)
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity from homeassistant.const import CONF_DEVICES, CONF_EMAIL, CONF_PASSWORD, PERCENTAGE from homeassistant.core import HomeAssistant import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = datetime.timedelta(hours=1) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Required(CONF_EMAIL): cv.string, vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_DEVICES): vol.All(cv.ensure_list, vol.Length(min=1)), } ) SENSOR_TYPE = "tank" SENSOR_ROUNDING_PRECISION = 1 SENSOR_ATTRS = [ "name", "address", "capacity", "fuelType", "orientation", "status", "time", "time_iso", ]
raise vol.Invalid("All RCSwitch codes must be in quotes ('')") for c in value: if c not in ('0', '1'): raise vol.Invalid( u"Invalid RCSwitch code character '{}'. Only '0' and '1' are allowed" u"".format(c)) if len(value) > 32: raise vol.Invalid( "Maximum length for RCSwitch codes is 32, code '{}' has length {}" "".format(value, len(value))) if not value: raise vol.Invalid("RCSwitch code must not be empty") return value RC_SWITCH_TIMING_SCHEMA = vol.All([cv.uint8_t], vol.Length(min=2, max=2)) RC_SWITCH_PROTOCOL_SCHEMA = vol.Any( vol.All(vol.Coerce(int), vol.Range(min=1, max=7)), vol.Schema({ vol.Required(CONF_PULSE_LENGTH): cv.uint32_t, vol.Optional(CONF_SYNC, default=[1, 31]): RC_SWITCH_TIMING_SCHEMA, vol.Optional(CONF_ZERO, default=[1, 3]): RC_SWITCH_TIMING_SCHEMA, vol.Optional(CONF_ONE, default=[3, 1]): RC_SWITCH_TIMING_SCHEMA, vol.Optional(CONF_INVERTED, default=False): cv.boolean, })) RC_SWITCH_RAW_SCHEMA = vol.Schema({ vol.Required(CONF_CODE): validate_rc_switch_code, vol.Optional(CONF_PROTOCOL, default=1):
from .device import BroadlinkDevice _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(minutes=2) CODE_STORAGE_VERSION = 1 FLAG_STORAGE_VERSION = 1 FLAG_SAVE_DELAY = 15 DEVICE_TYPES = RM_TYPES + RM4_TYPES MINIMUM_SERVICE_SCHEMA = vol.Schema( { vol.Required(ATTR_COMMAND): vol.All(cv.ensure_list, [vol.All(cv.string, vol.Length(min=1))], vol.Length(min=1)), vol.Required(ATTR_DEVICE): vol.All(cv.string, vol.Length(min=1)), }, extra=vol.ALLOW_EXTRA, ) SERVICE_SEND_SCHEMA = MINIMUM_SERVICE_SCHEMA.extend({ vol.Optional(ATTR_DELAY_SECS, default=DEFAULT_DELAY_SECS): vol.Coerce(float) }) SERVICE_LEARN_SCHEMA = MINIMUM_SERVICE_SCHEMA.extend({ vol.Optional(ATTR_ALTERNATIVE, default=False): cv.boolean,
async_get_data_manager, async_remove_data_manager, get_data_manager_by_webhook_id, json_message_response, ) DOMAIN = const.DOMAIN PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR] CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.All( cv.deprecated(const.CONF_PROFILES), vol.Schema( { vol.Required(CONF_CLIENT_ID): vol.All(cv.string, vol.Length(min=1)), vol.Required(CONF_CLIENT_SECRET): vol.All( cv.string, vol.Length(min=1) ), vol.Optional(const.CONF_USE_WEBHOOK, default=False): cv.boolean, vol.Optional(const.CONF_PROFILES): vol.All( cv.ensure_list, vol.Unique(), vol.Length(min=1), [vol.All(cv.string, vol.Length(min=1))], ), } ), ) }, extra=vol.ALLOW_EXTRA,
from homeassistant.exceptions import PlatformNotReady import homeassistant.helpers.config_validation as cv from homeassistant.util import color, dt REQUIREMENTS = ['python-miio==0.4.4', 'construct==2.9.45'] _LOGGER = logging.getLogger(__name__) DEFAULT_NAME = 'Xiaomi Philips Light' DATA_KEY = 'light.xiaomi_miio' CONF_MODEL = 'model' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Required(CONF_TOKEN): vol.All(cv.string, vol.Length(min=32, max=32)), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_MODEL): vol.In( ['philips.light.sread1', 'philips.light.ceiling', 'philips.light.zyceiling', 'philips.light.moonlight', 'philips.light.bulb', 'philips.light.candle', 'philips.light.candle2', 'philips.light.mono1', 'philips.light.downlight', ]), }) # The light does not accept cct values < 1
from homeassistant.helpers import config_validation as cv from homeassistant.components.camera import PLATFORM_SCHEMA, Camera _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(seconds=5) DEFAULT_TRIMS = { CONF_LEFT: 0, CONF_RIGHT: 0, CONF_TOP: 0, CONF_BOTTOM: 0 } 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.Required(CONF_COUNTRY): vol.In(CONF_AVAILABLE_COUNTRIES), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_COLORS, default={}): vol.Schema({ vol.In(CONF_AVAILABLE_COLORS): COLOR_SCHEMA
vol.Optional("config_flow"): bool, vol.Optional("mqtt"): [str], vol.Optional("zeroconf"): [ vol.Any( str, vol.Schema( { vol.Required("type"): str, vol.Optional("macaddress"): vol.All(str, verify_uppercase), vol.Optional("name"): vol.All(str, verify_lowercase), } ), ) ], vol.Optional("ssdp"): vol.Schema( vol.All([vol.All(vol.Schema({}, extra=vol.ALLOW_EXTRA), vol.Length(min=1))]) ), vol.Optional("homekit"): vol.Schema({vol.Optional("models"): [str]}), vol.Required("documentation"): vol.All( vol.Url(), documentation_url # pylint: disable=no-value-for-parameter ), vol.Optional( "issue_tracker" ): vol.Url(), # pylint: disable=no-value-for-parameter vol.Optional("quality_scale"): vol.In(SUPPORTED_QUALITY_SCALES), vol.Optional("requirements"): [str], vol.Optional("dependencies"): [str], vol.Optional("after_dependencies"): [str], vol.Required("codeowners"): [str], vol.Optional("disabled"): str, }
# Valid sensors for configuration VALID_SENSORS = ['%s_%s' % (typ, var) for typ in SENSOR_TYPES for var in SENSOR_VARIANTS] ICON = 'mdi:flash' MIN_TIME_BETWEEN_DAILY_UPDATES = timedelta(seconds=300) MIN_TIME_BETWEEN_ACTIVE_UPDATES = timedelta(seconds=60) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_EMAIL): cv.string, vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_MONITORED_CONDITIONS): vol.All(cv.ensure_list, vol.Length(min=1), [vol.In(VALID_SENSORS)]), }) def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Sense sensor.""" from sense_energy import Senseable username = config.get(CONF_EMAIL) password = config.get(CONF_PASSWORD) data = Senseable(username, password) @Throttle(MIN_TIME_BETWEEN_DAILY_UPDATES) def update_trends(): """Update the daily power usage."""
SUPPORT_TURN_ON = 1 SUPPORT_TURN_OFF = 2 SUPPORT_LOAD_URL = 4 SUPPORT_SET_BRIGHTNESS = 8 DISPLAY_DEVICE_SCHEMA = vol.Schema({ ATTR_ENTITY_ID: cv.entity_ids, }) DISPLAY_DEVICE_LOAD_URL_SCHEMA = DISPLAY_DEVICE_SCHEMA.extend({ vol.Required(ATTR_URL): cv.string, }) DISPLAY_DEVICE_SET_BRIGHTNESS_SCHEMA = DISPLAY_DEVICE_SCHEMA.extend({ vol.Optional(ATTR_BRIGHTNESS, default=None): vol.Any( vol.All(str, vol.Length(min=0, max=3)), vol.All(int, vol.Range(min=0, max=255)) ) }) @bind_hass def is_on(hass, entity_id=None): entity_id = entity_id or ENTITY_ID_ALL_DISPLAYS return hass.states.is_state(entity_id, STATE_ON) async def async_setup(hass, config): component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_DISPLAYS)
json_message_response, ) DOMAIN = const.DOMAIN PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR] CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.All( cv.deprecated(const.CONF_PROFILES), cv.deprecated(CONF_CLIENT_ID), cv.deprecated(CONF_CLIENT_SECRET), vol.Schema({ vol.Optional(CONF_CLIENT_ID): vol.All(cv.string, vol.Length(min=1)), vol.Optional(CONF_CLIENT_SECRET): vol.All(cv.string, vol.Length(min=1)), vol.Optional(const.CONF_USE_WEBHOOK, default=False): cv.boolean, vol.Optional(const.CONF_PROFILES): vol.All( cv.ensure_list, vol.Unique(), vol.Length(min=1), [vol.All(cv.string, vol.Length(min=1))], ), }), ) }, extra=vol.ALLOW_EXTRA,
# 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)),
DEFAULT_NAME = 'LG TV Remote' MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(seconds=1) MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) SUPPORT_LGTV = SUPPORT_PAUSE | SUPPORT_VOLUME_STEP | \ SUPPORT_VOLUME_MUTE | SUPPORT_PREVIOUS_TRACK | \ SUPPORT_NEXT_TRACK | SUPPORT_TURN_OFF | \ SUPPORT_SELECT_SOURCE | SUPPORT_PLAY PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_ACCESS_TOKEN): vol.All(cv.string, vol.Length(max=6)), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the LG TV platform.""" from pylgnetcast import LgNetCastClient host = config.get(CONF_HOST) access_token = config.get(CONF_ACCESS_TOKEN) name = config.get(CONF_NAME) client = LgNetCastClient(host, access_token)
}) SERVICE_SELECT_PREVIOUS = 'select_previous' SERVICE_SELECT_PREVIOUS_SCHEMA = vol.Schema({ vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, }) SERVICE_SET_OPTIONS = 'set_options' SERVICE_SET_OPTIONS_SCHEMA = vol.Schema({ vol.Required(ATTR_ENTITY_ID): cv.entity_ids, vol.Required(ATTR_OPTIONS): vol.All(cv.ensure_list, vol.Length(min=1), [cv.string]), }) def _cv_input_select(cfg): """Configure validation helper for input select (voluptuous).""" options = cfg[CONF_OPTIONS] initial = cfg.get(CONF_INITIAL) if initial is not None and initial not in options: raise vol.Invalid( 'initial state "{}" is not part of the options: {}'.format( initial, ','.join(options))) return cfg CONFIG_SCHEMA = vol.Schema(
def post(self, title, body, author, permlink=None, reply_identifier=None, json_metadata=None, comment_options=None, community=None, tags=None, beneficiaries=None, self_vote=False): """ Create a new post. If this post is intended as a reply/comment, `reply_identifier` needs to be set with the identifier of the parent post/comment (eg. `author/permlink`). Optionally you can also set json_metadata, comment_options and upvote the newly created post as an author. Setting category, tags or community will override the values provided in json_metadata and/or comment_options where appropriate. Args: title (str): Title of the post body (str): Body of the post/comment author (str): Account are you posting from permlink (str): Manually set the permlink (defaults to None). If left empty, it will be derived from title automatically. reply_identifier (str): Identifier of the parent post/comment (only if this post is a reply/comment). json_metadata (str, dict): JSON meta object that can be attached to the post. comment_options (str, dict): JSON options object that can be attached to the post. Example:: comment_options = { 'max_accepted_payout': '1000000.000 SMOKE', 'allow_votes': True, 'allow_curation_rewards': True, 'extensions': [[0, { 'beneficiaries': [ {'account': 'account1', 'weight': 5000}, {'account': 'account2', 'weight': 5000}, ]} ]] } community (str): (Optional) Name of the community we are posting into. This will also override the community specified in `json_metadata`. tags (str, list): (Optional) A list of tags (5 max) to go with the post. This will also override the tags specified in `json_metadata`. The first tag will be used as a 'category'. If provided as a string, it should be space separated. beneficiaries (list of dicts): (Optional) A list of beneficiaries for posting reward distribution. This argument overrides beneficiaries as specified in `comment_options`. For example, if we would like to split rewards between account1 and account2:: beneficiaries = [ {'account': 'account1', 'weight': 5000}, {'account': 'account2', 'weight': 5000} ] self_vote (bool): (Optional) Upvote the post as author, right after posting. """ # prepare json_metadata json_metadata = json_metadata or {} if isinstance(json_metadata, str): json_metadata = silent(json.loads)(json_metadata) or {} # override the community if community: json_metadata.update({'community': community}) # deal with the category and tags if isinstance(tags, str): tags = list(set(filter(None, (re.split("[\W_]", tags))))) category = None tags = tags or json_metadata.get('tags', []) if tags: if len(tags) > 5: raise ValueError('Can only specify up to 5 tags per post.') # first tag should be a category category = tags[0] json_metadata.update({"tags": tags}) # can't provide a category while replying to a post if reply_identifier and category: category = None # deal with replies/categories if reply_identifier: parent_author, parent_permlink = resolve_identifier( reply_identifier) if not permlink: permlink = derive_permlink(title, parent_permlink) elif category: parent_permlink = derive_permlink(category) parent_author = "" if not permlink: permlink = derive_permlink(title) else: parent_author = "" parent_permlink = "" if not permlink: permlink = derive_permlink(title) post_op = operations.Comment( **{ "parent_author": parent_author, "parent_permlink": parent_permlink, "author": author, "permlink": permlink, "title": title, "body": body, "json_metadata": json_metadata }) ops = [post_op] # if comment_options are used, add a new op to the transaction if comment_options or beneficiaries: options = keep_in_dict(comment_options or {}, [ 'max_accepted_payout', 'percent_steem_dollars', 'allow_votes', 'allow_curation_rewards', 'extensions' ]) # override beneficiaries extension if beneficiaries: # validate schema # or just simply vo.Schema([{'account': str, 'weight': int}]) schema = vo.Schema([{ vo.Required('account'): vo.All(str, vo.Length(max=16)), vo.Required('weight', default=10000): vo.All(int, vo.Range(min=1, max=10000)) }]) schema(beneficiaries) options['beneficiaries'] = beneficiaries default_max_payout = "1000000.000 SMOKE" comment_op = operations.CommentOptions( **{ "author": author, "permlink": permlink, "max_accepted_payout": options.get("max_accepted_payout", default_max_payout), "percent_steem_dollars": int(options.get("percent_steem_dollars", 10000)), "allow_votes": options.get("allow_votes", True), "allow_curation_rewards": options.get("allow_curation_rewards", True), "extensions": options.get("extensions", []), "beneficiaries": options.get("beneficiaries"), }) ops.append(comment_op) if self_vote: vote_op = operations.Vote( **{ 'voter': author, 'author': author, 'permlink': permlink, 'weight': 10000, }) ops.append(vote_op) return self.finalizeOp(ops, author, "posting")
def validate_fingerprint(value): value = cv.string(value) if re.match(r'^[0-9a-f]{40}$', value) is None: raise vol.Invalid(u"fingerprint must be valid SHA1 hash") return value CONFIG_SCHEMA = vol.Schema({ cv.GenerateID(): cv.declare_variable_id(MQTTClientComponent), vol.Required(CONF_BROKER): validate_broker, vol.Optional(CONF_PORT, default=1883): cv.port, vol.Optional(CONF_USERNAME, default=''): cv.string, vol.Optional(CONF_PASSWORD, default=''): cv.string, vol.Optional(CONF_CLIENT_ID): vol.All(cv.string, vol.Length(max=23)), vol.Optional(CONF_DISCOVERY): cv.boolean, vol.Optional(CONF_DISCOVERY_RETAIN): cv.boolean, vol.Optional(CONF_DISCOVERY_PREFIX): cv.publish_topic, vol.Optional(CONF_BIRTH_MESSAGE): MQTT_MESSAGE_SCHEMA, vol.Optional(CONF_WILL_MESSAGE): MQTT_MESSAGE_SCHEMA, vol.Optional(CONF_TOPIC_PREFIX): cv.publish_topic, vol.Optional(CONF_LOG_TOPIC): MQTT_MESSAGE_TEMPLATE_SCHEMA, vol.Optional(CONF_SSL_FINGERPRINTS): vol.All(cv.only_on_esp8266, cv.ensure_list, [validate_fingerprint]), vol.Optional(CONF_KEEPALIVE): cv.positive_time_period_seconds, vol.Optional(CONF_ON_MESSAGE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(MQTTMessageTrigger), vol.Required(CONF_TOPIC): cv.publish_topic, vol.Optional(CONF_QOS, default=0): cv.mqtt_qos, })])
"gust": ["gust", SPEED_METERS_PER_SECOND, None, "38", "2", "10"], "rain": ["rain", LENGTH_MILLIMETERS, None, "41", "4", "10"], "rain_day": ["rain day", LENGTH_MILLIMETERS, None, "46", "4", "10"], "rain_week": ["rain week", LENGTH_MILLIMETERS, None, "51", "4", "10"], "rain_month": ["rain month", LENGTH_MILLIMETERS, None, "56", "4", "10"], "rain_year": ["rain year", LENGTH_MILLIMETERS, None, "61", "4", "10"], "rain_total": ["rain total", LENGTH_MILLIMETERS, None, "66", "4", "10"], "light": ["light", ILLUMINANCE, None, "71", "4", "10"], "uv_value": ["uv value", UV_VALUE, None, "76", "2", "10"], "uv_index": ["uv index", UV_INDEX, None, "79", "1", "1"], } PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Optional(CONF_MONITORED_CONDITIONS, default=["inside_temperature"]): vol.All( cv.ensure_list, vol.Length(min=1), [vol.In(SENSOR_PROPERTIES)] ), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int } ) async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the sensor platform.""" name = config.get(CONF_NAME) sensors = [] for sensor_property in config[CONF_MONITORED_CONDITIONS]: sensors.append(WeatherSensor(name, sensor_property))
"YI", ] PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_API_KEY): cv.string, vol.Optional(CONF_PWS_ID): cv.string, vol.Optional(CONF_LANG, default=DEFAULT_LANG): vol.All(vol.In(LANG_CODES)), vol.Inclusive(CONF_LATITUDE, "coordinates", "Latitude and longitude must exist together"): cv.latitude, vol.Inclusive(CONF_LONGITUDE, "coordinates", "Latitude and longitude must exist together"): cv.longitude, vol.Required(CONF_MONITORED_CONDITIONS): vol.All(cv.ensure_list, vol.Length(min=1), [vol.In(SENSOR_TYPES)]), }) async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, async_add_entities, discovery_info=None): """Set up the WUnderground sensor.""" latitude = config.get(CONF_LATITUDE, hass.config.latitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude) pws_id = config.get(CONF_PWS_ID) rest = WUndergroundData( hass, config.get(CONF_API_KEY),
EFFECT_WHITE_STROBE: 0x37, EFFECT_COLORJUMP: 0x38, } 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,
async def async_setup_entry(hass, config_entry, async_add_entities): """Set up an LMS Server from a config entry.""" config = config_entry.data _LOGGER.debug("Reached async_setup_entry for host=%s", config[CONF_HOST]) username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) host = config[CONF_HOST] port = config[CONF_PORT] hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN].setdefault(config_entry.entry_id, {}) known_players = hass.data[DOMAIN].setdefault(KNOWN_PLAYERS, []) session = async_get_clientsession(hass) _LOGGER.debug("Creating LMS object for %s", host) lms = Server(session, host, port, username, password) async def _discovery(now=None): """Discover squeezebox players by polling server.""" async def _discovered_player(player): """Handle a (re)discovered player.""" entity = next( (known for known in known_players if known.unique_id == player.player_id), None, ) if entity: await player.async_update() async_dispatcher_send(hass, SIGNAL_PLAYER_REDISCOVERED, player.player_id, player.connected) if not entity: _LOGGER.debug("Adding new entity: %s", player) entity = SqueezeBoxEntity(player) known_players.append(entity) async_add_entities([entity]) players = await lms.async_get_players() if players: for player in players: hass.async_create_task(_discovered_player(player)) hass.data[DOMAIN][config_entry.entry_id][ PLAYER_DISCOVERY_UNSUB] = hass.helpers.event.async_call_later( DISCOVERY_INTERVAL, _discovery) _LOGGER.debug("Adding player discovery job for LMS server: %s", host) asyncio.create_task(_discovery()) # Register entity services platform = entity_platform.current_platform.get() platform.async_register_entity_service( SERVICE_CALL_METHOD, { vol.Required(ATTR_COMMAND): cv.string, vol.Optional(ATTR_PARAMETERS): vol.All(cv.ensure_list, vol.Length(min=1), [cv.string]), }, "async_call_method", ) platform.async_register_entity_service( SERVICE_CALL_QUERY, { vol.Required(ATTR_COMMAND): cv.string, vol.Optional(ATTR_PARAMETERS): vol.All(cv.ensure_list, vol.Length(min=1), [cv.string]), }, "async_call_query", ) platform.async_register_entity_service( SERVICE_SYNC, {vol.Required(ATTR_OTHER_PLAYER): cv.string}, "async_sync", ) platform.async_register_entity_service(SERVICE_UNSYNC, None, "async_unsync") # Start server discovery task if not already running if hass.is_running: asyncio.create_task(start_server_discovery(hass)) else: hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, start_server_discovery(hass)) return True
# pylint: disable=unused-import from .const import DOMAIN from .gateway import ConnectXiaomiGateway _LOGGER = logging.getLogger(__name__) CONF_FLOW_TYPE = "config_flow_device" CONF_GATEWAY = "gateway" DEFAULT_GATEWAY_NAME = "Xiaomi Gateway" GATEWAY_CONFIG = vol.Schema({ vol.Required(CONF_HOST): str, vol.Required(CONF_TOKEN): vol.All(str, vol.Length(min=32, max=32)), vol.Optional(CONF_NAME, default=DEFAULT_GATEWAY_NAME): str, }) CONFIG_SCHEMA = vol.Schema({vol.Optional(CONF_GATEWAY, default=False): bool}) class XiaomiMiioFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Handle a Xiaomi Miio config flow.""" VERSION = 1 CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL async def async_step_user(self, user_input=None): """Handle a flow initialized by the user."""
def validate_device_has_at_least_one_identifier( value: ConfigType) -> ConfigType: """Validate that a device info entry has at least one identifying value.""" if value.get(CONF_IDENTIFIERS) or value.get(CONF_CONNECTIONS): return value raise vol.Invalid("Device must have at least one identifying value in " "'identifiers' and/or 'connections'") MQTT_ENTITY_DEVICE_INFO_SCHEMA = vol.All( cv.deprecated(CONF_DEPRECATED_VIA_HUB, CONF_VIA_DEVICE), vol.Schema({ vol.Optional(CONF_IDENTIFIERS, default=list): vol.All(cv.ensure_list, [cv.string]), vol.Optional(CONF_CONNECTIONS, default=list): vol.All(cv.ensure_list, [vol.All(vol.Length(2), [cv.string])]), vol.Optional(CONF_MANUFACTURER): cv.string, vol.Optional(CONF_MODEL): cv.string, vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_SW_VERSION): cv.string, vol.Optional(CONF_VIA_DEVICE): cv.string, }), validate_device_has_at_least_one_identifier, ) MQTT_JSON_ATTRS_SCHEMA = vol.Schema({
"""Define sensor commands.""" from typing import Any, Awaitable, Callable, Dict, cast import voluptuous as vol from aioguardian.errors import CommandError from aioguardian.helpers.command import Command import aioguardian.helpers.config_validation as cv PARAM_UID = "uid" PAIRED_SENSOR_UID_SCHEMA: vol.Schema = vol.Schema( {vol.Required(PARAM_UID): vol.All(cv.alphanumeric, vol.Length(max=12))}) class SensorCommands: """Define an object to manage sensor commands. Note that this class shouldn't be instantiated directly; an instance of it will automatically be added to the :meth:`Client <aioguardian.Client>` (as ``client.sensor``). """ def __init__(self, execute_command: Callable[..., Awaitable]) -> None: """Initialize.""" self._execute_command = execute_command async def pair_dump(self, *, silent: bool = True) -> Dict[str, Any]: """Dump information on all paired sensors. :param silent: If ``True``, silence "beep" tones associated with this command :type silent: ``bool``
COMMAND_SCHEMA = vol.Schema( {vol.Required(CONF_COMMAND): vol.All(cv.ensure_list, [cv.string])} ) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Optional(CONF_NAME): cv.string, vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): vol.All( int, vol.Range(min=0) ), vol.Optional(CONF_SLOT, default=DEFAULT_SLOT): vol.All( int, vol.Range(min=1, max=1000000) ), vol.Required(CONF_TOKEN): vol.All(str, vol.Length(min=32, max=32)), vol.Optional(CONF_COMMANDS, default={}): cv.schema_with_slug_keys( COMMAND_SCHEMA ), }, extra=vol.ALLOW_EXTRA, ) async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Xiaomi IR Remote (Chuangmi IR) platform.""" host = config[CONF_HOST] token = config[CONF_TOKEN] # Create handler _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5])
CONF_KEY = 'key' CONF_DISABLE = 'disable' DOMAIN = 'xiaomi_aqara' PY_XIAOMI_GATEWAY = "xiaomi_gw" TIME_TILL_UNAVAILABLE = timedelta(minutes=150) SERVICE_PLAY_RINGTONE = 'play_ringtone' SERVICE_STOP_RINGTONE = 'stop_ringtone' SERVICE_ADD_DEVICE = 'add_device' SERVICE_REMOVE_DEVICE = 'remove_device' GW_MAC = vol.All(cv.string, lambda value: value.replace(':', '').lower(), vol.Length(min=12, max=12)) SERVICE_SCHEMA_PLAY_RINGTONE = vol.Schema({ vol.Required(ATTR_RINGTONE_ID): vol.All(vol.Coerce(int), vol.NotIn([9, 14, 15, 16, 17, 18, 19])), vol.Optional(ATTR_RINGTONE_VOL): vol.All(vol.Coerce(int), vol.Clamp(min=0, max=100)) }) SERVICE_SCHEMA_REMOVE_DEVICE = vol.Schema({ vol.Required(ATTR_DEVICE_ID): vol.All(cv.string, vol.Length(min=14, max=14)) }) GATEWAY_CONFIG = vol.Schema({ vol.Optional(CONF_MAC, default=None):
continue device_trackers = person[CONF_DEVICE_TRACKERS] if device_tracker_entity_id in device_trackers: return await coll.async_update_item( person[collection.CONF_ID], {CONF_DEVICE_TRACKERS: device_trackers + [device_tracker_entity_id]}, ) break CREATE_FIELDS = { vol.Required(CONF_NAME): vol.All(str, vol.Length(min=1)), vol.Optional(CONF_USER_ID): vol.Any(str, None), vol.Optional(CONF_DEVICE_TRACKERS, default=list): vol.All( cv.ensure_list, cv.entities_domain(DEVICE_TRACKER_DOMAIN) ), vol.Optional(CONF_PICTURE): vol.Any(str, None), } UPDATE_FIELDS = { vol.Optional(CONF_NAME): vol.All(str, vol.Length(min=1)), vol.Optional(CONF_USER_ID): vol.Any(str, None), vol.Optional(CONF_DEVICE_TRACKERS, default=list): vol.All( cv.ensure_list, cv.entities_domain(DEVICE_TRACKER_DOMAIN) ), vol.Optional(CONF_PICTURE): vol.Any(str, None),
from homeassistant.const import ( CONF_NAME, CONF_HOST, CONF_TOKEN, ) from homeassistant.exceptions import PlatformNotReady _LOGGER = logging.getLogger(__name__) DEFAULT_NAME = 'Xiaomi Miio Switch' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Required(CONF_TOKEN): vol.All(cv.string, vol.Length(min=32, max=32)), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) REQUIREMENTS = ['python-miio==0.3.3'] ATTR_POWER = 'power' ATTR_TEMPERATURE = 'temperature' ATTR_LOAD_POWER = 'load_power' ATTR_MODEL = 'model' SUCCESS = ['ok'] # pylint: disable=unused-argument @asyncio.coroutine
customs = list(conf[CONF_CUSTOM]) for sensor in conf[CONF_SENSORS]: if sensor in customs: _LOGGER.warning( "All custom sensors will be added automatically, no need to include them in sensors: %s", sensor, ) elif sensor not in valid: raise vol.Invalid(f"{sensor} does not exist") return conf CUSTOM_SCHEMA = vol.Any( { vol.Required(CONF_KEY): vol.All(cv.string, vol.Length(min=13, max=15)), vol.Required(CONF_UNIT): cv.string, vol.Optional(CONF_FACTOR, default=1): vol.Coerce(float), vol.Optional(CONF_PATH): vol.All(cv.ensure_list, [cv.string]), } ) PLATFORM_SCHEMA = vol.All( PLATFORM_SCHEMA.extend( { vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_SSL, default=False): cv.boolean, vol.Optional(CONF_VERIFY_SSL, default=True): cv.boolean, vol.Required(CONF_PASSWORD): cv.string, vol.Optional(CONF_GROUP, default=GROUPS[0]): vol.In(GROUPS), vol.Optional(CONF_SENSORS, default=[]): vol.Any(
vol.Range(1, 48), vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_NET_METERING, default=False): cv.boolean, }) CHANNELS_SCHEMA = vol.All(cv.ensure_list, [CHANNEL_SCHEMA]) MONITOR_SCHEMA = vol.Schema({ vol.Required(CONF_SERIAL_NUMBER): vol.All( cv.string, vol.Length( min=8, max=8, msg="GEM serial number must be specified as an 8-character " "string (including leading zeroes).", ), vol.Coerce(int), ), vol.Optional(CONF_CHANNELS, default=[]): CHANNELS_SCHEMA, vol.Optional( CONF_TEMPERATURE_SENSORS, default={ CONF_TEMPERATURE_UNIT: TEMPERATURE_UNIT_CELSIUS, CONF_SENSORS: [] }, ): TEMPERATURE_SENSORS_SCHEMA, vol.Optional(CONF_PULSE_COUNTERS, default=[]):