def async_stop_program_service(call): for program in conf.get(ATTR_PROGRAMS): y_irrigation_id = cv.slugify(program.get(ATTR_IRRIG_ID)) entity_id = ENTITY_ID_FORMAT.format(y_irrigation_id) entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [ irrigation.async_stop_program() for irrigation in target_irrigation ] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation program not found: %s', entity_id) for zone in conf.get(ATTR_ZONES): y_irrigation_id = cv.slugify(zone.get(ATTR_IRRIG_ID)) entity_id = ZONE_ENTITY_ID_FORMAT.format(y_irrigation_id) entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [ irrigation_zone.async_stop_zone() for irrigation_zone in target_irrigation ] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation_zone not found: %s', entity_id)
async def async_step_init(self, info=None): """Handle config flow initiation.""" if info: name = info[CONF_NAME] device = info[CONF_DEVICE] gw_id = cv.slugify(info.get(CONF_ID, name)) entries = [ e.data for e in self.hass.config_entries.async_entries(DOMAIN) ] if gw_id in [e[CONF_ID] for e in entries]: return self._show_form({"base": "id_exists"}) if device in [e[CONF_DEVICE] for e in entries]: return self._show_form({"base": "already_configured"}) async def test_connection(): """Try to connect to the OpenTherm Gateway.""" otgw = pyotgw.pyotgw() status = await otgw.connect(self.hass.loop, device) await otgw.disconnect() return status.get(pyotgw.OTGW_ABOUT) try: res = await asyncio.wait_for(test_connection(), timeout=10) except asyncio.TimeoutError: return self._show_form({"base": "timeout"}) except SerialException: return self._show_form({"base": "serial_error"}) if res: return self._create_entry(gw_id, name, device) return self._show_form()
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 []
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 []
async def do_enable(name): """Enable the named Pi-Hole.""" slug = cv.slugify(name) pi_hole = hass.data[DOMAIN][slug] LOGGER.debug("Enabling Pi-hole '%s' (%s)", name, pi_hole.api.host) await pi_hole.api.enable()
def __init__(self, hass, name, config): """Initialize the Plant component.""" self._config = config self._sensors = dict() self._readings = dict() self._unit_of_measurement = dict() self._state = None self._name = name self._problems = PROBLEM_NONE self._sensor_basename = "{}.{}{}_".format( SENSOR_DOMAIN, (self._config[CONF_DISCOVERY_PREFIX] + "_" if self._config[CONF_DISCOVERY_PREFIX] else ""), cv.slugify(self._name).lower()) _LOGGER.debug("Sensors starting with %s will be added to %s", self._sensor_basename, self._name) for reading, entity_id in self._config.get("sensors", {}).items(): _LOGGER.debug( "Adding statically defined sensor %s for reading %s on %s", entity_id, reading, self._name) self._sensors[entity_id] = reading self._add_reading(reading, entity_id) self._conf_check_days = self._config[CONF_CHECK_DAYS] self._brightness_history = DailyHistory(self._conf_check_days)
def _update_members(self, members, members_updated): for member in members: member_id = member['id'] if member_id in members_updated: continue members_updated.append(member_id) err_key = 'Member data' try: first = member.get('firstName') last = member.get('lastName') if first and last: full_name = ' '.join([first, last]) else: full_name = first or last slug_name = cv.slugify(full_name) include_member = _include_name(self._members_filter, slug_name) dev_id = self._dev_id(slug_name) if member_id not in self._members_logged: self._members_logged.add(member_id) _LOGGER.debug('%s -> %s: will%s be tracked, id=%s', full_name, dev_id, '' if include_member else ' NOT', member_id) sharing = bool(int(member['features']['shareLocation'])) except (KeyError, TypeError, ValueError, vol.Invalid): self._err(err_key, member) continue self._ok(err_key) if include_member and sharing: self._update_member(member, dev_id)
def _update_members(self, members, members_updated): for member in members: member_id = member["id"] if member_id in members_updated: continue err_key = "Member data" try: first = member.get("firstName") last = member.get("lastName") if first and last: full_name = " ".join([first, last]) else: full_name = first or last slug_name = cv.slugify(full_name) include_member = _include_name(self._members_filter, slug_name) dev_id = self._dev_id(slug_name) if member_id not in self._members_logged: self._members_logged.add(member_id) _LOGGER.debug( "%s -> %s: will%s be tracked, id=%s", full_name, dev_id, "" if include_member else " NOT", member_id, ) sharing = bool(int(member["features"]["shareLocation"])) except (KeyError, TypeError, ValueError, vol.Invalid): self._err(err_key, member) continue self._ok(err_key) if include_member and sharing: members_updated.append(member_id) self._update_member(member, dev_id)
async def async_load_config(path: str, hass: HomeAssistantType, config: ConfigType, async_add_entities): """Load devices from YAML configuration file. This method is a coroutine. """ dev_schema = vol.Schema({ vol.Required('dev_id'): cv.string, vol.Optional(CONF_NAME, default=''): cv.string, vol.Optional(CONF_DEVICE_CLASS, default='motion'): DEVICE_CLASSES_SCHEMA # vol.Optional(CONF_ICON, default=None): vol.Any(None, cv.icon), # vol.Optional('track', default=False): cv.boolean, # vol.Optional(CONF_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), }) result = [] try: _LOGGER.debug("async_load_config(): reading config file %s", path) devices = await hass.async_add_job(load_yaml_config_file, path) _LOGGER.debug( 'async_load_config(): devices loaded from config file: %s', devices) except HomeAssistantError as err: _LOGGER.error("async_load_config(): unable to load %s: %s", path, str(err)) return [] except FileNotFoundError as err: _LOGGER.debug("async_load_config(): file %s could not be found: %s", path, str(err)) return [] for dev_id, device in devices.items(): # Deprecated option. We just ignore it to avoid breaking change # device.pop('vendor', None) try: device = dev_schema(device) device['dev_id'] = cv.slugify(dev_id) except vol.Invalid as exp: async_log_exception(exp, dev_id, devices, hass) else: _LOGGER.debug('device: %s', device) dev = JablotronSensor(hass, **device) result.append(dev) """ Create sensors for each device in devices """ # device = JablotronSensor(hass, dev_id) async_add_entities([dev]) return result
async def do_disable(name): """Disable the named Pi-Hole.""" slug = cv.slugify(name) pi_hole = hass.data[DOMAIN][slug] LOGGER.debug( "Disabling Pi-hole '%s' (%s) for %d seconds", name, pi_hole.api.host, duration, ) await pi_hole.api.disable(duration)
def async_stop_switches(call): _LOGGER.info('async_stop_switches') for zone in conf.get(ATTR_ZONES): irrigation_id = cv.slugify(zone.get(ATTR_IRRIG_ID)) entity_id = ZONE_ENTITY_ID_FORMAT.format(irrigation_id) entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [irrigation_zone.async_stop_switch() for irrigation_zone in target_irrigation] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation_zone not found: %s', entity_id)
def async_load_config(path: str, hass: HomeAssistantType, consider_home: timedelta): """Load devices from YAML configuration file. This method is a coroutine. """ dev_schema = vol.Schema({ vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_ICON, default=None): vol.Any(None, cv.icon), vol.Optional('track', default=False): cv.boolean, vol.Optional(CONF_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 = [] try: devices = yield from hass.async_add_job(load_yaml_config_file, path) except HomeAssistantError as err: _LOGGER.error("Unable to load %s: %s", path, str(err)) return [] for dev_id, device in devices.items(): # Deprecated option. We just ignore it to avoid breaking change device.pop('vendor', None) try: device = dev_schema(device) device['dev_id'] = cv.slugify(dev_id) except vol.Invalid as exp: async_log_exception(exp, dev_id, devices, hass) else: result.append(Device(hass, **device)) return result except (HomeAssistantError, FileNotFoundError): # When YAML file could not be loaded/did not contain a dict return []
def __init__(self, config): """Assumes config confirms to const.MOTION_SCHEMA""" self._url = config[CONF_URL] if self._url.endswith('/'): self._url = self._url[0:-1] self._unique_id = cv.slugify(self._url) self._username = config[CONF_USERNAME] self._password = config[CONF_PASSWORD] self._auth = config[CONF_AUTHENTICATION] self._pwhash = hashlib.sha1(self._password.encode('utf-8')).hexdigest() self._session = requests.Session() self._cameras = {} o = urlparse.urlparse(self._url) self._host = o.scheme + '://' + o.hostname self._path = o.path _LOGGER.info( f"step motion created API {self.unique_id} -> {self._host} {self._path}" )
def async_load_config(path: str, hass: HomeAssistantType, consider_home: timedelta): """Load devices from YAML configuration file. This method is a coroutine. """ 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), vol.Optional('vendor', default=None): vol.Any(None, cv.string), }) try: result = [] try: devices = yield from hass.loop.run_in_executor( None, load_yaml_config_file, path) except HomeAssistantError as err: _LOGGER.error('Unable to load %s: %s', path, str(err)) return [] for dev_id, device in list(devices.items()): try: device = dev_schema(device) device['dev_id'] = cv.slugify(dev_id) except vol.Invalid as exp: async_log_exception(exp, dev_id, devices, hass) else: result.append(Device(hass, **device)) return result except (HomeAssistantError, FileNotFoundError): # When YAML file could not be loaded/did not contain a dict return []
def ensure_api_token(call_data): """Ensure the Pi-Hole to be enabled/disabled has a api_token configured.""" data = get_data() if SERVICE_DISABLE_ATTR_NAME not in call_data: for slug in data: call_data[SERVICE_DISABLE_ATTR_NAME] = data[slug].name ensure_api_token(call_data) call_data[SERVICE_DISABLE_ATTR_NAME] = None else: slug = cv.slugify(call_data[SERVICE_DISABLE_ATTR_NAME]) if (data[slug]).api.api_token is None: raise vol.Invalid( "Pi-hole '{}' must have an api_key provided in configuration to be enabled." .format(pi_hole.name)) return call_data
async def async_load_config(path: str, hass: HomeAssistant, consider_home: timedelta) -> list[Device]: """Load devices from YAML configuration file. This method is a coroutine. """ dev_schema = vol.Schema({ vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_ICON, default=None): vol.Any(None, cv.icon), vol.Optional("track", default=False): cv.boolean, vol.Optional(CONF_MAC, default=None): vol.Any(None, vol.All(cv.string, vol.Upper)), 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), }) result: list[Device] = [] try: devices = await hass.async_add_executor_job(load_yaml_config_file, path) except HomeAssistantError as err: LOGGER.error("Unable to load %s: %s", path, str(err)) return [] except FileNotFoundError: return [] for dev_id, device in devices.items(): # Deprecated option. We just ignore it to avoid breaking change device.pop("vendor", None) device.pop("hide_if_away", None) try: device = dev_schema(device) device["dev_id"] = cv.slugify(dev_id) except vol.Invalid as exp: async_log_exception(exp, dev_id, devices, hass) else: result.append(Device(hass, **device)) return result
async def _get_legacy_devices(hass: HomeAssistant) -> dict: legacy_devices = {} try: devices = await hass.async_add_executor_job(load_yaml_config_file, hass.config.path(LEGACY_YAML_DEVICES)) except HomeAssistantError: return {} except FileNotFoundError: return {} for dev_id, device in devices.items(): try: device = legacy_schema(device) device["dev_id"] = cv.slugify(dev_id) except vol.Invalid: continue else: legacy_devices[device["mac"]] = dict(device) return legacy_devices
async def async_load_config(path: str, hass: HomeAssistantType, consider_home: timedelta): """Load devices from YAML configuration file. This method is a coroutine. """ dev_schema = vol.Schema({ vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_ICON, default=None): vol.Any(None, cv.icon), vol.Optional('track', default=False): cv.boolean, vol.Optional(CONF_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 = [] try: devices = await hass.async_add_job( load_yaml_config_file, path) except HomeAssistantError as err: _LOGGER.error("Unable to load %s: %s", path, str(err)) return [] for dev_id, device in devices.items(): # Deprecated option. We just ignore it to avoid breaking change device.pop('vendor', None) try: device = dev_schema(device) device['dev_id'] = cv.slugify(dev_id) except vol.Invalid as exp: async_log_exception(exp, dev_id, devices, hass) else: result.append(Device(hass, **device)) return result except (HomeAssistantError, FileNotFoundError): # When YAML file could not be loaded/did not contain a dict return []
def async_load_config(path: str, hass: HomeAssistantType, consider_home: timedelta): """Load devices from YAML configuration file. This method is a coroutine. """ 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), vol.Optional('vendor', default=None): vol.Any(None, cv.string), }) try: result = [] try: devices = yield from hass.loop.run_in_executor( None, load_yaml_config_file, path) except HomeAssistantError as err: _LOGGER.error('Unable to load %s: %s', path, str(err)) return [] for dev_id, device in devices.items(): try: device = dev_schema(device) device['dev_id'] = cv.slugify(dev_id) except vol.Invalid as exp: async_log_exception(exp, dev_id, devices, hass) else: result.append(Device(hass, **device)) return result except (HomeAssistantError, FileNotFoundError): # When YAML file could not be loaded/did not contain a dict return []
def coerce_slug(config): """Coerce the name of the Pi-Hole into a slug.""" config[CONF_SLUG] = cv.slugify(config[CONF_NAME]) return config
async def async_setup(hass, config): @asyncio.coroutine def async_run_program_service(call): _LOGGER.info('async_run_program_service') entity_id = call.data.get(CONST_ENTITY) """ stop any running zones before starting a new program""" hass.services.async_call(DOMAIN, 'stop_programs', {}) DATA = {} entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [irrigation.async_run_program(DATA) for irrigation in target_irrigation] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation program not found: %s', entity_id) """ END async_run_program_service """ @asyncio.coroutine def async_stop_program_service(call): _LOGGER.info('async_stop_program_service') entity_id = call.data.get(CONST_ENTITY) entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [irrigation.async_stop_program() for irrigation in target_irrigation] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation program not found: %s', entity_id) """ END async_stop_program_service """ @asyncio.coroutine def async_run_zone_service(call): _LOGGER.info('async_run_zone_service') entity_id = call.data.get(CONST_ENTITY) duration = call.data.get(ATTR_DURATION, 0) DATA = {ATTR_DURATION: duration} entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [irrigation_zone.async_run_zone(DATA) for irrigation_zone in target_irrigation] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation_zone not found: %s', entity_id) """ END async_run_zone_service """ @asyncio.coroutine def async_stop_zone_service(call): _LOGGER.info('async_stop_zone_service') entity_id = call.data.get(CONST_ENTITY) entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [irrigation_zone.async_stop_zone() for irrigation_zone in target_irrigation] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation_zone not found: %s', entity_id) """ END async_stop_zone_service """ @asyncio.coroutine def async_stop_programs_service(call): _LOGGER.info('async_stop_programs_service') for program in conf.get(ATTR_PROGRAMS): irrigation_id = cv.slugify(program.get(ATTR_IRRIG_ID)) entity_id = ENTITY_ID_FORMAT.format(irrigation_id) entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [irrigation.async_stop_program() for irrigation in target_irrigation] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation program not found: %s', entity_id) for zone in conf.get(ATTR_ZONES): irrigation_id = cv.slugify(zone.get(ATTR_IRRIG_ID)) entity_id = ZONE_ENTITY_ID_FORMAT.format(irrigation_id) entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [irrigation_zone.async_stop_zone() for irrigation_zone in target_irrigation] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation_zone not found: %s', entity_id) """ END async_stop_programs_service """ @asyncio.coroutine def async_stop_switches(call): _LOGGER.info('async_stop_switches') for zone in conf.get(ATTR_ZONES): irrigation_id = cv.slugify(zone.get(ATTR_IRRIG_ID)) entity_id = ZONE_ENTITY_ID_FORMAT.format(irrigation_id) entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [irrigation_zone.async_stop_switch() for irrigation_zone in target_irrigation] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation_zone not found: %s', entity_id) """ END async_stop_switches """ """ create the entities and time tracking on setup of the component """ conf = config[DOMAIN] component = EntityComponent(_LOGGER, DOMAIN, hass) """ parse progams """ programentities = [] for program in conf.get(ATTR_PROGRAMS): irrigation_id = cv.slugify(program.get(ATTR_IRRIG_ID)) template = program.get(ATTR_TEMPLATE) if template is not None: template.hass = hass p_entity = ENTITY_ID_FORMAT.format(irrigation_id) programentities.append(Irrigation(p_entity, program, component)) _LOGGER.info('Irrigation %s added', irrigation_id) if(not program.get(ATTR_ENABLED)): _LOGGER.warn('Irrigation %s disabled', irrigation_id) await component.async_add_entities(programentities) """ parse zones """ zoneentities = [] for zone in conf.get(ATTR_ZONES): irrigation_id = cv.slugify(zone.get(ATTR_IRRIG_ID)) p_entity = ZONE_ENTITY_ID_FORMAT.format(irrigation_id) zoneentities.append(IrrigationZone(p_entity, zone)) _LOGGER.info('Zone %s added', p_entity) await component.async_add_entities(zoneentities) """ define services """ hass.services.async_register(DOMAIN, 'run_program', async_run_program_service) hass.services.async_register(DOMAIN, 'stop_program', async_stop_program_service) hass.services.async_register(DOMAIN, 'run_zone', async_run_zone_service) hass.services.async_register(DOMAIN, 'stop_zone', async_stop_zone_service) hass.services.async_register(DOMAIN, 'stop_programs', async_stop_programs_service) return True
async def async_setup(hass, config): @asyncio.coroutine def async_run_program_service(call): try: perform_eval = call.data.get(ATTR_EVAL, False) entity_id = call.data.get(CONST_ENTITY) except: perform_eval = call.get(ATTR_EVAL, False) entity_id = call.get(CONST_ENTITY) """ stop any running zones before starting a new program""" hass.services.async_call(DOMAIN, 'stop_programs', {ATTR_EVAL: True}) entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [ irrigation.async_run_program(perform_eval) for irrigation in target_irrigation ] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation program not found: %s', entity_id) """ END async_run_program_service """ @asyncio.coroutine def async_run_zone_service(call): """ called from manually service """ entity_id = call.data.get(CONST_ENTITY) y_water = call.data.get(ATTR_WATER, 0) y_wait = call.data.get(ATTR_WAIT, 0) y_repeat = call.data.get(ATTR_REPEAT, 0) y_ignore = call.data.get(ATTR_EVAL, False) DATA = { ATTR_WATER: y_water, ATTR_WAIT: y_wait, ATTR_REPEAT: y_repeat, ATTR_EVAL: y_ignore } entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [ irrigation_zone.async_run_zone(DATA) for irrigation_zone in target_irrigation ] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation_zone not found: %s', entity_id) """ END async_run_zone_service """ @asyncio.coroutine def async_stop_program_service(call): for program in conf.get(ATTR_PROGRAMS): y_irrigation_id = cv.slugify(program.get(ATTR_IRRIG_ID)) entity_id = ENTITY_ID_FORMAT.format(y_irrigation_id) entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [ irrigation.async_stop_program() for irrigation in target_irrigation ] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation program not found: %s', entity_id) for zone in conf.get(ATTR_ZONES): y_irrigation_id = cv.slugify(zone.get(ATTR_IRRIG_ID)) entity_id = ZONE_ENTITY_ID_FORMAT.format(y_irrigation_id) entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [ irrigation_zone.async_stop_zone() for irrigation_zone in target_irrigation ] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation_zone not found: %s', entity_id) """ END async_stop_program_service """ @asyncio.coroutine def async_stop_switches(call): for zone in conf.get(ATTR_ZONES): y_irrigation_id = cv.slugify(zone.get(ATTR_IRRIG_ID)) entity_id = ZONE_ENTITY_ID_FORMAT.format(y_irrigation_id) entity = component.get_entity(entity_id) if entity: target_irrigation = [entity] tasks = [ irrigation_zone.async_stop_switch() for irrigation_zone in target_irrigation ] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) else: _LOGGER.error('irrigation_zone not found: %s', entity_id) """ END async_stop_switches """ """ create the entities and time tracking on setup of the component """ conf = config[DOMAIN] component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] zoneentities = [] for program in conf.get(ATTR_PROGRAMS): y_irrigation_id = cv.slugify(program.get(ATTR_IRRIG_ID)) """ Used same model as Template Sensor """ entity_ids = set() invalid_templates = [] template = program.get(ATTR_TEMPLATE) if template is None: continue template.hass = hass template_entity_ids = template.extract_entities() if template_entity_ids == MATCH_ALL: entity_ids = MATCH_ALL # Cut off _template from name invalid_templates.append(tpl_name[:-9]) elif entity_ids != MATCH_ALL: entity_ids |= set(template_entity_ids) if invalid_templates: _LOGGER.warning( 'Irrigation %s has no entity ids configured to track nor' ' were we able to extract the entities to track from the %s ' 'template.' 'manually.', device, ', '.join(invalid_templates)) entity_ids = list(entity_ids) p_entity = ENTITY_ID_FORMAT.format(y_irrigation_id) entities.append(Irrigation(p_entity, program, entity_ids, component)) for zone in conf.get(ATTR_ZONES): y_irrigation_id = cv.slugify(zone.get(ATTR_IRRIG_ID)) p_entity = ZONE_ENTITY_ID_FORMAT.format(y_irrigation_id) zoneentities.append(IrrigationZone(p_entity, zone)) await component.async_add_entities(entities) await component.async_add_entities(zoneentities) """ define services """ hass.services.async_register(DOMAIN, 'run_program', async_run_program_service) hass.services.async_register(DOMAIN, 'run_zone', async_run_zone_service) hass.services.async_register(DOMAIN, 'stop_programs', async_stop_program_service) return True