def setup(hass, config): """Setup zone.""" entities = set() for key in extract_domain_configs(config, DOMAIN): entries = config[key] if not isinstance(entries, list): entries = entries, for entry in entries: name = entry.get(CONF_NAME, DEFAULT_NAME) latitude = convert(entry.get(ATTR_LATITUDE), float) longitude = convert(entry.get(ATTR_LONGITUDE), float) radius = convert(entry.get(ATTR_RADIUS, DEFAULT_RADIUS), float) icon = entry.get(ATTR_ICON) passive = entry.get(ATTR_PASSIVE, DEFAULT_PASSIVE) if None in (latitude, longitude): logging.getLogger(__name__).error( 'Each zone needs a latitude and longitude.') continue zone = Zone(hass, name, latitude, longitude, radius, icon, passive, False) add_zone(hass, name, zone, entities) entities.add(zone.entity_id) if ENTITY_ID_HOME not in entities: zone = Zone(hass, hass.config.location_name, hass.config.latitude, hass.config.longitude, DEFAULT_RADIUS, ICON_HOME, False, False) add_zone(hass, hass.config.location_name, zone, entities) zone.entity_id = ENTITY_ID_HOME zone.update_ha_state() return True
def test_convert(self): """ Test convert. """ self.assertEqual(5, util.convert("5", int)) self.assertEqual(5.0, util.convert("5", float)) self.assertEqual(True, util.convert("True", bool)) self.assertEqual(1, util.convert("NOT A NUMBER", int, 1)) self.assertEqual(1, util.convert(None, int, 1))
def setup_platform(hass, config, add_devices_callback, discovery_info=None): """Read in all of our configuration, and initialize the loopback switch.""" if config.get('sink_name') is None: _LOGGER.error("Missing required variable: sink_name") return False if config.get('source_name') is None: _LOGGER.error("Missing required variable: source_name") return False name = convert(config.get('name'), str, DEFAULT_NAME) sink_name = config.get('sink_name') source_name = config.get('source_name') host = convert(config.get('host'), str, DEFAULT_HOST) port = convert(config.get('port'), int, DEFAULT_PORT) buffer_size = convert(config.get('buffer_size'), int, DEFAULT_BUFFER_SIZE) tcp_timeout = convert(config.get('tcp_timeout'), int, DEFAULT_TCP_TIMEOUT) server_id = str.format("{0}:{1}", host, port) if server_id in _PULSEAUDIO_SERVERS: server = _PULSEAUDIO_SERVERS[server_id] else: server = PAServer(host, port, buffer_size, tcp_timeout) _PULSEAUDIO_SERVERS[server_id] = server add_devices_callback([PALoopbackSwitch( hass, name, server, sink_name, source_name )])
def closest(self, *args): """Find closest entity. Closest to home: closest(states) closest(states.device_tracker) closest('group.children') closest(states.group.children) Closest to a point: closest(23.456, 23.456, 'group.children') closest('zone.school', 'group.children') closest(states.zone.school, 'group.children') """ if len(args) == 1: latitude = self._hass.config.latitude longitude = self._hass.config.longitude entities = args[0] elif len(args) == 2: point_state = self._resolve_state(args[0]) if point_state is None: _LOGGER.warning('Closest:Unable to find state %s', args[0]) return None elif not loc_helper.has_location(point_state): _LOGGER.warning( 'Closest:State does not contain valid location: %s', point_state) return None latitude = point_state.attributes.get(ATTR_LATITUDE) longitude = point_state.attributes.get(ATTR_LONGITUDE) entities = args[1] else: latitude = convert(args[0], float) longitude = convert(args[1], float) if latitude is None or longitude is None: _LOGGER.warning( 'Closest:Received invalid coordinates: %s, %s', args[0], args[1]) return None entities = args[2] if isinstance(entities, (AllStates, DomainStates)): states = list(entities) else: if isinstance(entities, State): gr_entity_id = entities.entity_id else: gr_entity_id = str(entities) states = [self._hass.states.get(entity_id) for entity_id in group.expand_entity_ids(self._hass, [gr_entity_id])] return loc_helper.closest(latitude, longitude, states)
def device_state_attributes(self): """Return the state attributes of the device.""" attr = {} if self.vera_device.has_battery: attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level if self.vera_device.is_armable: armed = self.vera_device.is_armed attr[ATTR_ARMED] = 'True' if armed else 'False' if self.vera_device.is_trippable: last_tripped = self.vera_device.last_trip if last_tripped is not None: utc_time = utc_from_timestamp(int(last_tripped)) attr[ATTR_LAST_TRIP_TIME] = utc_time.isoformat() else: attr[ATTR_LAST_TRIP_TIME] = None tripped = self.vera_device.is_tripped attr[ATTR_TRIPPED] = 'True' if tripped else 'False' power = self.vera_device.power if power: attr[ATTR_CURRENT_POWER_W] = convert(power, float, 0.0) energy = self.vera_device.energy if energy: attr[ATTR_CURRENT_ENERGY_KWH] = convert(energy, float, 0.0) attr['Vera Device Id'] = self.vera_device.vera_device_id return attr
def trigger(hass, config, action): """ Listen for state changes based on `config`. """ if CONF_AFTER in config: after = dt_util.parse_time_str(config[CONF_AFTER]) if after is None: _error_time(config[CONF_AFTER], CONF_AFTER) return False hours, minutes, seconds = after.hour, after.minute, after.second elif (CONF_HOURS in config or CONF_MINUTES in config or CONF_SECONDS in config): hours = convert(config.get(CONF_HOURS), int) minutes = convert(config.get(CONF_MINUTES), int) seconds = convert(config.get(CONF_SECONDS), int) else: _LOGGER.error('One of %s, %s, %s OR %s needs to be specified', CONF_HOURS, CONF_MINUTES, CONF_SECONDS, CONF_AFTER) return False def time_automation_listener(now): """ Listens for time changes and calls action. """ action() track_time_change(hass, time_automation_listener, hour=hours, minute=minutes, second=seconds) return True
def __init__(self, hass, config, logger): self.logger = logger self.hass = hass self.heater_entity_id = config.get("heater") self.name_device = config.get("name") self.target_sensor_entity_id = config.get("target_sensor") self.time_temp = [] if config.get("time_temp"): for time_temp in list(config.get("time_temp").split(",")): time, temp = time_temp.split(':') time_start, time_end = time.split('-') start_time = datetime.datetime.time( datetime.datetime.strptime(time_start, '%H%M')) end_time = datetime.datetime.time( datetime.datetime.strptime(time_end, '%H%M')) self.time_temp.append((start_time, end_time, float(temp))) self._min_temp = util.convert(config.get("min_temp"), float, 0) self._max_temp = util.convert(config.get("max_temp"), float, 100) self._manual_sat_temp = None self._away = False self._heater_manual_changed = True track_state_change(hass, self.heater_entity_id, self._heater_turned_on, STATE_OFF, STATE_ON) track_state_change(hass, self.heater_entity_id, self._heater_turned_off, STATE_ON, STATE_OFF)
def validate_payload(payload, data_type): """Validate OwnTracks payload.""" try: data = json.loads(payload) except ValueError: # If invalid JSON _LOGGER.error('Unable to parse payload as JSON: %s', payload) return None if not isinstance(data, dict) or data.get('_type') != data_type: _LOGGER.debug('Skipping %s update for following data ' 'because of missing or malformatted data: %s', data_type, data) return None if data_type == VALIDATE_TRANSITION or data_type == VALIDATE_WAYPOINTS: return data if max_gps_accuracy is not None and \ convert(data.get('acc'), float, 0.0) > max_gps_accuracy: _LOGGER.warning('Ignoring %s update because expected GPS ' 'accuracy %s is not met: %s', data_type, max_gps_accuracy, payload) return None if convert(data.get('acc'), float, 1.0) == 0.0: _LOGGER.warning('Ignoring %s update because GPS accuracy' 'is zero: %s', data_type, payload) return None return data
def setup_platform(hass, config, add_devices, discovery_info=None): """Setup Tellstick sensors.""" import tellcore.telldus as telldus import tellcore.constants as tellcore_constants sensor_value_descriptions = { tellcore_constants.TELLSTICK_TEMPERATURE: DatatypeDescription( 'temperature', config.get('temperature_scale', TEMP_CELSIUS)), tellcore_constants.TELLSTICK_HUMIDITY: DatatypeDescription('humidity', '%'), tellcore_constants.TELLSTICK_RAINRATE: DatatypeDescription('rain rate', ''), tellcore_constants.TELLSTICK_RAINTOTAL: DatatypeDescription('rain total', ''), tellcore_constants.TELLSTICK_WINDDIRECTION: DatatypeDescription('wind direction', ''), tellcore_constants.TELLSTICK_WINDAVERAGE: DatatypeDescription('wind average', ''), tellcore_constants.TELLSTICK_WINDGUST: DatatypeDescription('wind gust', '') } try: core = telldus.TelldusCore() except OSError: logging.getLogger(__name__).exception( 'Could not initialize Tellstick.') return sensors = [] datatype_mask = util.convert(config.get('datatype_mask'), int, 127) for ts_sensor in core.sensors(): try: sensor_name = config[ts_sensor.id] except KeyError: if util.convert(config.get('only_named'), bool, False): continue sensor_name = str(ts_sensor.id) for datatype in sensor_value_descriptions: if datatype & datatype_mask and ts_sensor.has_value(datatype): sensor_info = sensor_value_descriptions[datatype] sensors.append( TellstickSensor( sensor_name, ts_sensor, datatype, sensor_info)) add_devices(sensors)
def setup(hass, config): """Setup the StatsD component.""" import statsd conf = config[DOMAIN] host = conf[CONF_HOST] port = util.convert(conf.get(CONF_PORT), int, DEFAULT_PORT) sample_rate = util.convert(conf.get(CONF_RATE), int, DEFAULT_RATE) prefix = util.convert(conf.get(CONF_PREFIX), str, DEFAULT_PREFIX) show_attribute_flag = conf.get(CONF_ATTR, False) statsd_client = statsd.StatsClient( host=host, port=port, prefix=prefix ) def statsd_event_listener(event): """Listen for new messages on the bus and sends them to StatsD.""" state = event.data.get('new_state') if state is None: return try: _state = state_helper.state_as_number(state) except ValueError: return states = dict(state.attributes) _LOGGER.debug('Sending %s.%s', state.entity_id, _state) if show_attribute_flag is True: statsd_client.gauge( "%s.state" % state.entity_id, _state, sample_rate ) # Send attribute values for key, value in states.items(): if isinstance(value, (float, int)): stat = "%s.%s" % (state.entity_id, key.replace(' ', '_')) statsd_client.gauge(stat, value, sample_rate) else: statsd_client.gauge(state.entity_id, _state, sample_rate) # Increment the count statsd_client.incr(state.entity_id, rate=sample_rate) hass.bus.listen(EVENT_STATE_CHANGED, statsd_event_listener) return True
def setup(hass, config): """ Setup the Splunk component. """ if not validate_config(config, {DOMAIN: ['token']}, _LOGGER): _LOGGER.error("You must include the token for your HTTP " "Event Collector input in Splunk.") return False conf = config[DOMAIN] host = conf[CONF_HOST] port = util.convert(conf.get(CONF_PORT), int, DEFAULT_PORT) token = util.convert(conf.get(CONF_TOKEN), str) use_ssl = util.convert(conf.get(CONF_SSL), bool, DEFAULT_SSL) if use_ssl: uri_scheme = "https://" else: uri_scheme = "http://" event_collector = uri_scheme + host + ":" + str(port) + \ "/services/collector/event" headers = {'Authorization': 'Splunk ' + token} def splunk_event_listener(event): """ Listen for new messages on the bus and sends them to Splunk. """ state = event.data.get('new_state') if state is None: return try: _state = state_helper.state_as_number(state) except ValueError: _state = state.state json_body = [ { 'domain': state.domain, 'entity_id': state.object_id, 'attributes': state.attributes, 'time': str(event.time_fired), 'value': _state, } ] try: payload = {"host": event_collector, "event": json_body} requests.post(event_collector, data=json.dumps(payload), headers=headers) except requests.exceptions.RequestException as error: _LOGGER.exception('Error saving event to Splunk: %s', error) hass.bus.listen(EVENT_STATE_CHANGED, splunk_event_listener) return True
def distance(self, *args): """Calculate distance. Will calculate distance from home to a point or between points. Points can be passed in using state objects or lat/lng coordinates. """ locations = [] to_process = list(args) while to_process: value = to_process.pop(0) point_state = self._resolve_state(value) if point_state is None: # We expect this and next value to be lat&lng if not to_process: _LOGGER.warning( "Distance:Expected latitude and longitude, got %s", value) return None value_2 = to_process.pop(0) latitude = convert(value, float) longitude = convert(value_2, float) if latitude is None or longitude is None: _LOGGER.warning("Distance:Unable to process latitude and " "longitude: %s, %s", value, value_2) return None else: if not loc_helper.has_location(point_state): _LOGGER.warning( "distance:State does not contain valid location: %s", point_state) return None latitude = point_state.attributes.get(ATTR_LATITUDE) longitude = point_state.attributes.get(ATTR_LONGITUDE) if latitude is None or longitude is None: _LOGGER.warning( "Distance:State does not contains a location: %s", value) return None locations.append((latitude, longitude)) if len(locations) == 1: return self._hass.config.distance(*locations[0]) return self._hass.config.units.length( loc_util.distance(*locations[0] + locations[1]), 'm')
def register(hass, config, action): """ Listen for state changes based on `config`. """ hours = convert(config.get(CONF_HOURS), int) minutes = convert(config.get(CONF_MINUTES), int) seconds = convert(config.get(CONF_SECONDS), int) def time_automation_listener(now): """ Listens for time changes and calls action. """ action() track_time_change(hass, time_automation_listener, hour=hours, minute=minutes, second=seconds) return True
def setup(hass, config): """ Get the MQTT protocol service. """ if not validate_config(config, {DOMAIN: ['broker']}, _LOGGER): return False conf = config[DOMAIN] broker = conf[CONF_BROKER] port = util.convert(conf.get(CONF_PORT), int, DEFAULT_PORT) client_id = util.convert(conf.get(CONF_CLIENT_ID), str) keepalive = util.convert(conf.get(CONF_KEEPALIVE), int, DEFAULT_KEEPALIVE) username = util.convert(conf.get(CONF_USERNAME), str) password = util.convert(conf.get(CONF_PASSWORD), str) global MQTT_CLIENT try: MQTT_CLIENT = MQTT(hass, broker, port, client_id, keepalive, username, password) except socket.error: _LOGGER.exception("Can't connect to the broker. " "Please check your settings and the broker " "itself.") return False def stop_mqtt(event): """ Stop MQTT component. """ MQTT_CLIENT.stop() def start_mqtt(event): """ Launch MQTT component when Home Assistant starts up. """ MQTT_CLIENT.start() hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_mqtt) def publish_service(call): """ Handle MQTT publish service calls. """ msg_topic = call.data.get(ATTR_TOPIC) payload = call.data.get(ATTR_PAYLOAD) qos = call.data.get(ATTR_QOS, DEFAULT_QOS) if msg_topic is None or payload is None: return MQTT_CLIENT.publish(msg_topic, payload, qos) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_mqtt) hass.services.register(DOMAIN, SERVICE_PUBLISH, publish_service) return True
def update(self): """Update the state.""" import pyvera as veraApi if self.vera_device.category == veraApi.CATEGORY_TEMPERATURE_SENSOR: self.current_value = self.vera_device.temperature vera_temp_units = ( self.vera_device.vera_controller.temperature_units) if vera_temp_units == 'F': self._temperature_units = TEMP_FAHRENHEIT else: self._temperature_units = TEMP_CELSIUS elif self.vera_device.category == veraApi.CATEGORY_LIGHT_SENSOR: self.current_value = self.vera_device.light elif self.vera_device.category == veraApi.CATEGORY_HUMIDITY_SENSOR: self.current_value = self.vera_device.humidity elif self.vera_device.category == veraApi.CATEGORY_SCENE_CONTROLLER: value = self.vera_device.get_last_scene_id(True) time = self.vera_device.get_last_scene_time(True) if time == self.last_changed_time: self.current_value = None else: self.current_value = value self.last_changed_time = time elif self.vera_device.category == veraApi.CATEGORY_POWER_METER: power = convert(self.vera_device.power, float, 0) self.current_value = int(round(power, 0)) elif self.vera_device.is_trippable: tripped = self.vera_device.is_tripped self.current_value = 'Tripped' if tripped else 'Not Tripped' else: self.current_value = 'Unknown'
def owntracks_location_update(topic, payload, qos): """MQTT message received.""" # Docs on available data: # http://owntracks.org/booklet/tech/json/#_typelocation try: data = json.loads(payload) except ValueError: # If invalid JSON _LOGGER.error( 'Unable to parse payload as JSON: %s', payload) return if (not isinstance(data, dict) or data.get('_type') != 'location') or ( max_gps_accuracy is not None and convert(data.get('acc'), float, 0.0) > max_gps_accuracy): return dev_id, kwargs = _parse_see_args(topic, data) # Block updates if we're in a region with LOCK: if REGIONS_ENTERED[dev_id]: _LOGGER.debug( "location update ignored - inside region %s", REGIONS_ENTERED[-1]) return see(**kwargs) see_beacons(dev_id, kwargs)
def _update_temp_sensor(state): """Parse temperature sensor value.""" _LOGGER.debug("Updating temp sensor with value %s", state.state) # Return an error if the sensor change its state to Unknown. if state.state == STATE_UNKNOWN: _LOGGER.error("Unable to parse temperature sensor %s with state:" " %s", state.entity_id, state.state) return None unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) temp = util.convert(state.state, float) if temp is None: _LOGGER.error("Unable to parse temperature sensor %s with state:" " %s", state.entity_id, state.state) return None # convert to celsius if necessary if unit == TEMP_FAHRENHEIT: return util.temperature.fahrenheit_to_celsius(temp) if unit == TEMP_CELSIUS: return temp _LOGGER.error("Temp sensor %s has unsupported unit: %s (allowed: %s, " "%s)", state.entity_id, unit, TEMP_CELSIUS, TEMP_FAHRENHEIT) return None
def _update_hum_sensor(state): """Parse humidity sensor value.""" _LOGGER.debug("Updating humidity sensor with value %s", state.state) # Return an error if the sensor change its state to Unknown. if state.state == STATE_UNKNOWN: _LOGGER.error('Unable to parse humidity sensor %s, state: %s', state.entity_id, state.state) return None unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) hum = util.convert(state.state, float) if hum is None: _LOGGER.error("Unable to parse humidity sensor %s, state: %s", state.entity_id, state.state) return None if unit != '%': _LOGGER.error("Humidity sensor %s has unsupported unit: %s %s", state.entity_id, unit, " (allowed: %)") return None if hum > 100 or hum < 0: _LOGGER.error("Humidity sensor %s is out of range: %s %s", state.entity_id, hum, "(allowed: 0-100%)") return None return hum
def thermostat_service(service): """ Handles calls to the services. """ # Convert the entity ids to valid light ids target_thermostats = [thermostats[entity_id] for entity_id in extract_entity_ids(hass, service) if entity_id in thermostats] if not target_thermostats: target_thermostats = thermostats.values() if service.service == SERVICE_TURN_AWAY_MODE_ON: for thermostat in target_thermostats: thermostat.turn_away_mode_on() elif service.service == SERVICE_TURN_AWAY_MODE_OFF: for thermostat in target_thermostats: thermostat.turn_away_mode_off() elif service.service == SERVICE_SET_TEMPERATURE: temperature = util.convert( service.data.get(ATTR_TEMPERATURE), float) if temperature is None: return for thermostat in target_thermostats: thermostat.nest.set_temperature(temperature) for thermostat in target_thermostats: thermostat.update_ha_state(hass, True)
def value_added(node, value): """Called when a value is added to a node on the network.""" for (component, generic_device_class, specific_device_class, command_class, value_type, value_genre) in DISCOVERY_COMPONENTS: _LOGGER.debug("Component=%s Node_id=%s query start", component, node.node_id) if node.generic not in generic_device_class and \ None not in generic_device_class: _LOGGER.debug("node.generic %s not None and in \ generic_device_class %s", node.generic, generic_device_class) continue if node.specific not in specific_device_class and \ None not in specific_device_class: _LOGGER.debug("node.specific %s is not None and in \ specific_device_class %s", node.specific, specific_device_class) continue if value.command_class not in command_class and \ None not in command_class: _LOGGER.debug("value.command_class %s is not None \ and in command_class %s", value.command_class, command_class) continue if value_type != value.type and value_type is not None: _LOGGER.debug("value.type %s != value_type %s", value.type, value_type) continue if value_genre != value.genre and value_genre is not None: _LOGGER.debug("value.genre %s != value_genre %s", value.genre, value_genre) continue # Configure node _LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, \ Specific_command_class=%s, \ Command_class=%s, Value type=%s, \ Genre=%s", node.node_id, node.generic, node.specific, value.command_class, value.type, value.genre) name = "{}.{}".format(component, _object_id(value)) node_config = customize.get(name, {}) polling_intensity = convert( node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: value.enable_poll(polling_intensity) else: value.disable_poll() discovery.load_platform(hass, component, DOMAIN, { ATTR_NODE_ID: node.node_id, ATTR_VALUE_ID: value.value_id, }, config)
def value_added(node, value): """Called when a value is added to a node on the network.""" for (component, command_ids, value_type, value_genre) in DISCOVERY_COMPONENTS: if value.command_class not in command_ids: continue if value_type is not None and value_type != value.type: continue if value_genre is not None and value_genre != value.genre: continue # Configure node name = "{}.{}".format(component, _object_id(value)) node_config = customize.get(name, {}) polling_intensity = convert( node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: value.enable_poll(polling_intensity) else: value.disable_poll() discovery.load_platform(hass, component, DOMAIN, { ATTR_NODE_ID: node.node_id, ATTR_VALUE_ID: value.value_id, }, config)
def update(self): """Update the state.""" if self.vera_device.category == "Temperature Sensor": self.current_value = self.vera_device.temperature vera_temp_units = ( self.vera_device.vera_controller.temperature_units) if vera_temp_units == 'F': self._temperature_units = TEMP_FAHRENHEIT else: self._temperature_units = TEMP_CELSIUS elif self.vera_device.category == "Light Sensor": self.current_value = self.vera_device.light elif self.vera_device.category == "Humidity Sensor": self.current_value = self.vera_device.humidity elif self.vera_device.category == "Scene Controller": value = self.vera_device.get_last_scene_id(True) time = self.vera_device.get_last_scene_time(True) if time == self.last_changed_time: self.current_value = None else: self.current_value = value self.last_changed_time = time elif self.vera_device.category == "Power meter": power = convert(self.vera_device.power, float, 0) self.current_value = int(round(power, 0)) elif self.vera_device.category == "Sensor": tripped = self.vera_device.is_tripped self.current_value = 'Tripped' if tripped else 'Not Tripped' else: self.current_value = 'Unknown'
def start_zwave(_service_or_event): """Startup Z-Wave network.""" _LOGGER.info("Starting ZWave network.") NETWORK.start() hass.bus.fire(const.EVENT_NETWORK_START) # Need to be in STATE_AWAKED before talking to nodes. # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network # to be ready. for i in range(const.NETWORK_READY_WAIT_SECS): _LOGGER.debug( "network state: %d %s", NETWORK.state, NETWORK.state_str) if NETWORK.state >= NETWORK.STATE_AWAKED: _LOGGER.info("zwave ready after %d seconds", i) break time.sleep(1) else: _LOGGER.warning( "zwave not ready after %d seconds, continuing anyway", const.NETWORK_READY_WAIT_SECS) _LOGGER.info( "final network state: %d %s", NETWORK.state, NETWORK.state_str) polling_interval = convert( config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: NETWORK.set_poll_interval(polling_interval, False) poll_interval = NETWORK.get_poll_interval() _LOGGER.info("zwave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zwave) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node, descriptions[const.SERVICE_ADD_NODE]) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure, descriptions[const.SERVICE_ADD_NODE_SECURE]) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node, descriptions[const.SERVICE_REMOVE_NODE]) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command, descriptions[const.SERVICE_CANCEL_COMMAND]) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network, descriptions[const.SERVICE_HEAL_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset, descriptions[const.SERVICE_SOFT_RESET]) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network, descriptions[const.SERVICE_TEST_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_zwave, descriptions[const.SERVICE_STOP_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_START_NETWORK, start_zwave, descriptions[const.SERVICE_START_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, descriptions[const.SERVICE_RENAME_NODE], schema=RENAME_NODE_SCHEMA)
def setup(hass, config): """Set up the HTTP API and debug interface.""" conf = config.get(DOMAIN, {}) api_password = util.convert(conf.get(CONF_API_PASSWORD), str) # If no server host is given, accept all incoming requests server_host = conf.get(CONF_SERVER_HOST, '0.0.0.0') server_port = conf.get(CONF_SERVER_PORT, SERVER_PORT) development = str(conf.get(CONF_DEVELOPMENT, "")) == "1" ssl_certificate = conf.get(CONF_SSL_CERTIFICATE) ssl_key = conf.get(CONF_SSL_KEY) try: server = HomeAssistantHTTPServer( (server_host, server_port), RequestHandler, hass, api_password, development, ssl_certificate, ssl_key) except OSError: # If address already in use _LOGGER.exception("Error setting up HTTP server") return False hass.bus.listen_once( ha.EVENT_HOMEASSISTANT_START, lambda event: threading.Thread(target=server.start, daemon=True, name='HTTP-server').start()) hass.http = server hass.config.api = rem.API(server_host if server_host != '0.0.0.0' else util.get_local_ip(), api_password, server_port, ssl_certificate is not None) return True
def setup(hass, config=None): """ Sets up the HTTP API and debug interface. """ if config is None or DOMAIN not in config: config = {DOMAIN: {}} api_password = util.convert(config[DOMAIN].get(CONF_API_PASSWORD), str) no_password_set = api_password is None if no_password_set: api_password = util.get_random_string() # If no server host is given, accept all incoming requests server_host = config[DOMAIN].get(CONF_SERVER_HOST, '0.0.0.0') server_port = config[DOMAIN].get(CONF_SERVER_PORT, SERVER_PORT) development = str(config[DOMAIN].get(CONF_DEVELOPMENT, "")) == "1" sessions_enabled = config[DOMAIN].get(CONF_SESSIONS_ENABLED, True) server = HomeAssistantHTTPServer( (server_host, server_port), RequestHandler, hass, api_password, development, no_password_set, sessions_enabled) hass.bus.listen_once( ha.EVENT_HOMEASSISTANT_START, lambda event: threading.Thread(target=server.start, daemon=True).start()) hass.http = server hass.config.api = rem.API(util.get_local_ip(), api_password, server_port) return True
def thermostat_service(service): """ Handles calls to the services. """ # Convert the entity ids to valid light ids target_thermostats = component.extract_from_service(service) if service.service == SERVICE_SET_AWAY_MODE: away_mode = service.data.get(ATTR_AWAY_MODE) if away_mode is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_AWAY_MODE, ATTR_AWAY_MODE) elif away_mode: for thermostat in target_thermostats: thermostat.turn_away_mode_on() else: for thermostat in target_thermostats: thermostat.turn_away_mode_off() elif service.service == SERVICE_SET_TEMPERATURE: temperature = util.convert( service.data.get(ATTR_TEMPERATURE), float) if temperature is None: return for thermostat in target_thermostats: thermostat.set_temperature(convert( temperature, hass.config.temperature_unit, thermostat.unit_of_measurement)) for thermostat in target_thermostats: thermostat.update_ha_state(True)
def setup(hass, config): """ Sets up the device tracker. """ if not validate_config(config, {DOMAIN: [CONF_PLATFORM]}, _LOGGER): return False tracker_type = config[DOMAIN].get(CONF_PLATFORM) tracker_implementation = get_component( 'device_tracker.{}'.format(tracker_type)) if tracker_implementation is None: _LOGGER.error("Unknown device_tracker type specified.") return False device_scanner = tracker_implementation.get_scanner(hass, config) if device_scanner is None: _LOGGER.error("Failed to initialize device scanner for %s", tracker_type) return False seconds = util.convert(config[DOMAIN].get(CONF_SECONDS), int, DEFAULT_CONF_SECONDS) track_new_devices = config[DOMAIN].get(TRACK_NEW_DEVICES) or False _LOGGER.info("Tracking new devices: %s", track_new_devices) tracker = DeviceTracker(hass, device_scanner, seconds, track_new_devices) # We only succeeded if we got to parse the known devices file return not tracker.invalid_known_devices_file
def setup_platform(hass, config, add_devices, discovery_info=None): """ Sets up the heat control thermostat. """ name = config.get(CONF_NAME, DEFAULT_NAME) heater_entity_id = config.get(CONF_HEATER) sensor_entity_id = config.get(CONF_SENSOR) min_temp = util.convert(config.get(CONF_MIN_TEMP), float, None) max_temp = util.convert(config.get(CONF_MAX_TEMP), float, None) target_temp = util.convert(config.get(CONF_TARGET_TEMP), float, None) if None in (heater_entity_id, sensor_entity_id): _LOGGER.error('Missing required key %s or %s', CONF_HEATER, CONF_SENSOR) return False add_devices([HeatControl(hass, name, heater_entity_id, sensor_entity_id, min_temp, max_temp, target_temp)])
def value_added(node, value): """Called when a value is added to a node on the network.""" for (component, discovery_service, command_ids, value_type, value_genre) in DISCOVERY_COMPONENTS: if value.command_class not in command_ids: continue if value_type is not None and value_type != value.type: continue if value_genre is not None and value_genre != value.genre: continue # Ensure component is loaded bootstrap.setup_component(hass, component, config) # Configure node name = "{}.{}".format(component, _object_id(value)) node_config = customize.get(name, {}) polling_intensity = convert( node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity is not None: value.enable_poll(polling_intensity) # Fire discovery event hass.bus.fire(EVENT_PLATFORM_DISCOVERED, { ATTR_SERVICE: discovery_service, ATTR_DISCOVERED: { ATTR_NODE_ID: node.node_id, ATTR_VALUE_ID: value.value_id, } })
def _update_hum_sensor(state): """Parse humidity sensor value.""" unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) hum = util.convert(state.state, float) if hum is None: _LOGGER.error('Unable to parse sensor humidity: %s', state.state) return None # check unit if unit != "%": _LOGGER.error( "Humidity sensor has unsupported unit: %s %s", unit, " (allowed: %)") # check range if hum > 100 or hum < 0: _LOGGER.error( "Humidity sensor out of range: %s %s", hum, " (allowed: 0-100%)") return hum
def setup_platform(hass, config, add_entities, discovery_info=None): """Display the current season.""" if None in (hass.config.latitude, hass.config.longitude): _LOGGER.error("Latitude or longitude not set in Safegate Pro config") return False latitude = util.convert(hass.config.latitude, float) _type = config.get(CONF_TYPE) name = config.get(CONF_NAME) if latitude < 0: hemisphere = SOUTHERN elif latitude > 0: hemisphere = NORTHERN else: hemisphere = EQUATOR _LOGGER.debug(_type) add_entities([Season(hass, hemisphere, _type, name)], True) return True
def do_setup(hass, hass_config, config): """Run the setup after we have everything configured.""" # Load calendars the user has configured hass.data[DATA_INDEX] = load_config(hass.config.path(YAML_DEVICES)) calendar_service = GoogleCalendarService(hass.config.path(TOKEN_FILE)) track_new_found_calendars = convert(config.get(CONF_TRACK_NEW), bool, DEFAULT_CONF_TRACK_NEW) setup_services(hass, hass_config, track_new_found_calendars, calendar_service) # Ensure component is loaded setup_component(hass, "calendar", config) for calendar in hass.data[DATA_INDEX].values(): discovery.load_platform(hass, "calendar", DOMAIN, calendar, hass_config) # Look for any new calendars hass.services.call(DOMAIN, SERVICE_SCAN_CALENDARS, None) return True
def setup(hass, config): """ Sets up the device tracker. """ # CONF_TYPE is deprecated for CONF_PLATOFRM. We keep supporting it for now. if not (validate_config(config, {DOMAIN: [CONF_PLATFORM]}, _LOGGER) or validate_config(config, {DOMAIN: [CONF_TYPE]}, _LOGGER)): return False tracker_type = config[DOMAIN].get(CONF_PLATFORM) if tracker_type is None: tracker_type = config[DOMAIN][CONF_TYPE] _LOGGER.warning(("Please update your config for %s to use 'platform' " "instead of 'type'"), tracker_type) tracker_implementation = get_component( 'device_tracker.{}'.format(tracker_type)) if tracker_implementation is None: _LOGGER.error("Unknown device_tracker type specified.") return False device_scanner = tracker_implementation.get_scanner(hass, config) if device_scanner is None: _LOGGER.error("Failed to initialize device scanner for %s", tracker_type) return False seconds = util.convert(config[DOMAIN].get(CONF_SECONDS), int, DEFAULT_CONF_SECONDS) tracker = DeviceTracker(hass, device_scanner, seconds) # We only succeeded if we got to parse the known devices file return not tracker.invalid_known_devices_file
def setup_scanner_platform(hass, config, scanner, see_device): """ Helper method to connect scanner-based platform to device tracker. """ interval = util.convert(config.get(CONF_SCAN_INTERVAL), int, DEFAULT_SCAN_INTERVAL) # Initial scan of each mac we also tell about host name for config seen = set() def device_tracker_scan(now): """ Called when interval matches. """ for mac in scanner.scan_devices(): if mac in seen: host_name = None else: host_name = scanner.get_device_name(mac) seen.add(mac) see_device(mac=mac, host_name=host_name) track_utc_time_change(hass, device_tracker_scan, second=range(0, 60, interval)) device_tracker_scan(None)
def setup(hass, config=None): """ Sets up the HTTP API and debug interface. """ if config is None or DOMAIN not in config: config = {DOMAIN: {}} api_password = util.convert(config[DOMAIN].get(CONF_API_PASSWORD), str) no_password_set = api_password is None if no_password_set: api_password = util.get_random_string() # If no server host is given, accept all incoming requests server_host = config[DOMAIN].get(CONF_SERVER_HOST, '0.0.0.0') server_port = config[DOMAIN].get(CONF_SERVER_PORT, SERVER_PORT) development = str(config[DOMAIN].get(CONF_DEVELOPMENT, "")) == "1" sessions_enabled = config[DOMAIN].get(CONF_SESSIONS_ENABLED, True) try: server = HomeAssistantHTTPServer( (server_host, server_port), RequestHandler, hass, api_password, development, no_password_set, sessions_enabled) except OSError: # Happens if address already in use _LOGGER.exception("Error setting up HTTP server") return False hass.bus.listen_once( ha.EVENT_HOMEASSISTANT_START, lambda event: threading.Thread(target=server.start, daemon=True).start()) hass.http = server hass.config.api = rem.API(util.get_local_ip(), api_password, server_port) return True
def extra_state_attributes(self): """Return the state attributes of the device.""" attr = {} if isinstance(self.wemo, Maker): # Is the maker sensor on or off. if self.wemo.maker_params["hassensor"]: # Note a state of 1 matches the WeMo app 'not triggered'! if self.wemo.maker_params["sensorstate"]: attr[ATTR_SENSOR_STATE] = STATE_OFF else: attr[ATTR_SENSOR_STATE] = STATE_ON # Is the maker switch configured as toggle(0) or momentary (1). if self.wemo.maker_params["switchmode"]: attr[ATTR_SWITCH_MODE] = MAKER_SWITCH_MOMENTARY else: attr[ATTR_SWITCH_MODE] = MAKER_SWITCH_TOGGLE if isinstance(self.wemo, (Insight, CoffeeMaker)): attr[ATTR_CURRENT_STATE_DETAIL] = self.detail_state if isinstance(self.wemo, Insight): attr["on_latest_time"] = WemoSwitch.as_uptime( self.wemo.insight_params["onfor"] ) attr["on_today_time"] = WemoSwitch.as_uptime( self.wemo.insight_params["ontoday"] ) attr["on_total_time"] = WemoSwitch.as_uptime( self.wemo.insight_params["ontotal"] ) attr["power_threshold_w"] = ( convert(self.wemo.insight_params["powerthreshold"], float, 0.0) / 1000.0 ) if isinstance(self.wemo, CoffeeMaker): attr[ATTR_COFFEMAKER_MODE] = self.wemo.mode return attr
def _update_temp(self, state): """Update thermostat with latest state from sensor.""" unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) if unit not in (TEMP_CELCIUS, TEMP_FAHRENHEIT): self._cur_temp = None self._unit = None _LOGGER.error('Sensor has unsupported unit: %s (allowed: %s, %s)', unit, TEMP_CELCIUS, TEMP_FAHRENHEIT) return temp = util.convert(state.state, float) if temp is None: self._cur_temp = None self._unit = None _LOGGER.error('Unable to parse sensor temperature: %s', state.state) return self._cur_temp = temp self._unit = unit
def setup_platform(hass, config, add_devices_callback, discovery_info=None): """Add MQTT Light.""" if config.get('command_topic') is None: _LOGGER.error("Missing required variable: command_topic") return False add_devices_callback([ MqttLight( hass, convert(config.get('name'), str, DEFAULT_NAME), { key: convert(config.get(key), str) for key in (typ + topic for typ in ('', 'brightness_', 'rgb_') for topic in ('state_topic', 'command_topic')) }, { key: convert(config.get(key + '_value_template'), str) for key in ('state', 'brightness', 'rgb') }, convert(config.get('qos'), int, DEFAULT_QOS), { 'on': convert(config.get('payload_on'), str, DEFAULT_PAYLOAD_ON), 'off': convert(config.get('payload_off'), str, DEFAULT_PAYLOAD_OFF) }, convert(config.get('optimistic'), bool, DEFAULT_OPTIMISTIC), convert(config.get('brightness_scale'), int, DEFAULT_BRIGHTNESS_SCALE)) ])
def start_zwave(event): """Startup Z-Wave.""" NETWORK.start() # Need to be in STATE_AWAKED before talking to nodes. # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network # to be ready. for i in range(NETWORK_READY_WAIT_SECS): _LOGGER.debug( "network state: %d %s", NETWORK.state, NETWORK.state_str) if NETWORK.state >= NETWORK.STATE_AWAKED: _LOGGER.info("zwave ready after %d seconds", i) break time.sleep(1) else: _LOGGER.warning( "zwave not ready after %d seconds, continuing anyway", NETWORK_READY_WAIT_SECS) _LOGGER.info( "final network state: %d %s", NETWORK.state, NETWORK.state_str) polling_interval = convert( config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: NETWORK.set_poll_interval(polling_interval, False) poll_interval = NETWORK.get_poll_interval() _LOGGER.info("zwave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zwave) # Register add / remove node services for Z-Wave sticks without # hardware inclusion button hass.services.register(DOMAIN, SERVICE_ADD_NODE, add_node) hass.services.register(DOMAIN, SERVICE_REMOVE_NODE, remove_node) hass.services.register(DOMAIN, SERVICE_HEAL_NETWORK, heal_network) hass.services.register(DOMAIN, SERVICE_SOFT_RESET, soft_reset) hass.services.register(DOMAIN, SERVICE_TEST_NETWORK, test_network)
def setup(hass, config): """Set up the HTTP API and debug interface.""" _LOGGER.addFilter(HideSensitiveFilter(hass)) conf = config.get(DOMAIN, {}) api_password = util.convert(conf.get(CONF_API_PASSWORD), str) server_host = conf.get(CONF_SERVER_HOST, '0.0.0.0') server_port = conf.get(CONF_SERVER_PORT, SERVER_PORT) development = str(conf.get(CONF_DEVELOPMENT, "")) == "1" ssl_certificate = conf.get(CONF_SSL_CERTIFICATE) ssl_key = conf.get(CONF_SSL_KEY) cors_origins = conf.get(CONF_CORS_ORIGINS, []) server = HomeAssistantWSGI( hass, development=development, server_host=server_host, server_port=server_port, api_password=api_password, ssl_certificate=ssl_certificate, ssl_key=ssl_key, cors_origins=cors_origins ) hass.bus.listen_once( ha.EVENT_HOMEASSISTANT_START, lambda event: threading.Thread(target=server.start, daemon=True, name='WSGI-server').start()) hass.wsgi = server hass.config.api = rem.API(server_host if server_host != '0.0.0.0' else util.get_local_ip(), api_password, server_port, ssl_certificate is not None) return True
def _update_temp_sensor(state): """Parse temperature sensor value.""" _LOGGER.debug("Updating temp sensor with value %s", state.state) # Return an error if the sensor change its state to Unknown. if state.state == STATE_UNKNOWN: _LOGGER.error( "Unable to parse temperature sensor %s with state: %s", state.entity_id, state.state, ) return None unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) temp = util.convert(state.state, float) if temp is None: _LOGGER.error( "Unable to parse temperature sensor %s with state: %s", state.entity_id, state.state, ) return None # convert to celsius if necessary if unit == TEMP_FAHRENHEIT: return util.temperature.fahrenheit_to_celsius(temp) if unit == TEMP_CELSIUS: return temp _LOGGER.error( "Temp sensor %s has unsupported unit: %s (allowed: %s, %s)", state.entity_id, unit, TEMP_CELSIUS, TEMP_FAHRENHEIT, ) return None
def thermostat_service(service): """ Handles calls to the services. """ # Convert the entity ids to valid light ids target_thermostats = [thermostats[entity_id] for entity_id in extract_entity_ids(hass, service) if entity_id in thermostats] if not target_thermostats: target_thermostats = thermostats.values() if service.service == SERVICE_SET_AWAY_MODE: away_mode = service.data.get(ATTR_AWAY_MODE) if away_mode is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_AWAY_MODE, ATTR_AWAY_MODE) elif away_mode: for thermostat in target_thermostats: thermostat.turn_away_mode_on() else: for thermostat in target_thermostats: thermostat.turn_away_mode_off() elif service.service == SERVICE_SET_TEMPERATURE: temperature = util.convert( service.data.get(ATTR_TEMPERATURE), float) if temperature is None: return for thermostat in target_thermostats: thermostat.set_temperature(temperature) for thermostat in target_thermostats: thermostat.update_ha_state(True)
def device_state_attributes(self): """Return the state attributes of the device.""" attr = {} if self.maker_params: # Is the maker sensor on or off. if self.maker_params['hassensor']: # Note a state of 1 matches the WeMo app 'not triggered'! if self.maker_params['sensorstate']: attr[ATTR_SENSOR_STATE] = STATE_OFF else: attr[ATTR_SENSOR_STATE] = STATE_ON # Is the maker switch configured as toggle(0) or momentary (1). if self.maker_params['switchmode']: attr[ATTR_SWITCH_MODE] = MAKER_SWITCH_MOMENTARY else: attr[ATTR_SWITCH_MODE] = MAKER_SWITCH_TOGGLE if self.insight_params or (self.coffeemaker_mode is not None): attr[ATTR_CURRENT_STATE_DETAIL] = self.detail_state if self.insight_params: attr['on_latest_time'] = \ WemoSwitch.as_uptime(self.insight_params['onfor']) attr['on_today_time'] = \ WemoSwitch.as_uptime(self.insight_params['ontoday']) attr['on_total_time'] = \ WemoSwitch.as_uptime(self.insight_params['ontotal']) attr['power_threshold_w'] = \ convert( self.insight_params['powerthreshold'], float, 0.0 ) / 1000.0 if self.coffeemaker_mode is not None: attr[ATTR_COFFEMAKER_MODE] = self.coffeemaker_mode return attr
def setup(hass, config): """Setup the Logentries component.""" if not validate_config(config, {DOMAIN: ['token']}, _LOGGER): _LOGGER.error("Logentries token not present") return False conf = config[DOMAIN] token = util.convert(conf.get(CONF_TOKEN), str) le_wh = DEFAULT_HOST + token def logentries_event_listener(event): """Listen for new messages on the bus and sends them to Logentries.""" state = event.data.get('new_state') if state is None: return try: _state = state_helper.state_as_number(state) except ValueError: _state = state.state json_body = [ { 'domain': state.domain, 'entity_id': state.object_id, 'attributes': dict(state.attributes), 'time': str(event.time_fired), 'value': _state, } ] try: payload = {"host": le_wh, "event": json_body} requests.post(le_wh, data=json.dumps(payload), timeout=10) except requests.exceptions.RequestException as error: _LOGGER.exception('Error sending to Logentries: %s', error) hass.bus.listen(EVENT_STATE_CHANGED, logentries_event_listener) return True
def value_added(node, value): """Called when a value is added to a node on the network.""" for (component, discovery_service, command_ids, value_type, value_genre) in DISCOVERY_COMPONENTS: if value.command_class not in command_ids: continue if value_type is not None and value_type != value.type: continue if value_genre is not None and value_genre != value.genre: continue # Ensure component is loaded bootstrap.setup_component(hass, component, config) # Configure node name = "{}.{}".format(component, _object_id(value)) node_config = customize.get(name, {}) polling_intensity = convert( node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: value.enable_poll(polling_intensity) else: value.disable_poll() # Fire discovery event hass.bus.fire(EVENT_PLATFORM_DISCOVERED, { ATTR_SERVICE: discovery_service, ATTR_DISCOVERED: { ATTR_NODE_ID: node.node_id, ATTR_VALUE_ID: value.value_id, } })
def update(self): """Update the state.""" import pyvera as veraApi if self.vera_device.category == veraApi.CATEGORY_TEMPERATURE_SENSOR: self.current_value = self.vera_device.temperature vera_temp_units = ( self.vera_device.vera_controller.temperature_units) if vera_temp_units == 'F': self._temperature_units = TEMP_FAHRENHEIT else: self._temperature_units = TEMP_CELSIUS elif self.vera_device.category == veraApi.CATEGORY_LIGHT_SENSOR: self.current_value = self.vera_device.light elif self.vera_device.category == veraApi.CATEGORY_UV_SENSOR: self.current_value = self.vera_device.light elif self.vera_device.category == veraApi.CATEGORY_HUMIDITY_SENSOR: self.current_value = self.vera_device.humidity elif self.vera_device.category == veraApi.CATEGORY_SCENE_CONTROLLER: value = self.vera_device.get_last_scene_id(True) time = self.vera_device.get_last_scene_time(True) if time == self.last_changed_time: self.current_value = None else: self.current_value = value self.last_changed_time = time elif self.vera_device.category == veraApi.CATEGORY_POWER_METER: power = convert(self.vera_device.power, float, 0) self.current_value = int(round(power, 0)) elif self.vera_device.is_trippable: tripped = self.vera_device.is_tripped self.current_value = 'Tripped' if tripped else 'Not Tripped' else: self.current_value = 'Unknown'
def update(self) -> None: """Update the state.""" super().update() if self.vera_device.category == veraApi.CATEGORY_TEMPERATURE_SENSOR: self.current_value = self.vera_device.temperature vera_temp_units = self.vera_device.vera_controller.temperature_units if vera_temp_units == "F": self._temperature_units = TEMP_FAHRENHEIT else: self._temperature_units = TEMP_CELSIUS elif self.vera_device.category == veraApi.CATEGORY_LIGHT_SENSOR: self.current_value = self.vera_device.light elif self.vera_device.category == veraApi.CATEGORY_UV_SENSOR: self.current_value = self.vera_device.light elif self.vera_device.category == veraApi.CATEGORY_HUMIDITY_SENSOR: self.current_value = self.vera_device.humidity elif self.vera_device.category == veraApi.CATEGORY_SCENE_CONTROLLER: controller = cast(veraApi.VeraSceneController, self.vera_device) value = controller.get_last_scene_id(True) time = controller.get_last_scene_time(True) if time == self.last_changed_time: self.current_value = None else: self.current_value = value self.last_changed_time = time elif self.vera_device.category == veraApi.CATEGORY_POWER_METER: power = convert(self.vera_device.power, float, 0) self.current_value = int(round(power, 0)) elif self.vera_device.is_trippable: tripped = self.vera_device.is_tripped self.current_value = "Tripped" if tripped else "Not Tripped" else: self.current_value = "Unknown"
def _check_entity_ready(self): """Check if all required values are discovered and create entity.""" if self._workaround_ignore: return if self._entity is not None: return for name in self._schema[const.DISC_VALUES]: if self._values[name] is None and not self._schema[ const.DISC_VALUES][name].get(const.DISC_OPTIONAL): return component = self._schema[const.DISC_COMPONENT] workaround_component = workaround.get_device_component_mapping( self.primary) if workaround_component and workaround_component != component: if workaround_component == workaround.WORKAROUND_IGNORE: _LOGGER.info( "Ignoring Node %d Value %d due to workaround.", self.primary.node.node_id, self.primary.value_id, ) # No entity will be created for this value self._workaround_ignore = True return _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component entity_id = self._registry.async_get_entity_id( component, DOMAIN, compute_value_unique_id(self._node, self.primary)) if entity_id is None: value_name = _value_name(self.primary) entity_id = generate_entity_id(component + ".{}", value_name, []) node_config = self._device_config.get(entity_id) # Configure node _LOGGER.debug( "Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s as %s", self._node.node_id, self._node.generic, self._node.specific, self.primary.command_class, self.primary.type, self.primary.genre, component, ) if node_config.get(CONF_IGNORED): _LOGGER.info("Ignoring entity %s due to device settings", entity_id) # No entity will be created for this value self._workaround_ignore = True return polling_intensity = convert(node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: self.primary.enable_poll(polling_intensity) platform = import_module(f".{component}", __name__) device = platform.get_device(node=self._node, values=self, node_config=node_config, hass=self._hass) if device is None: # No entity will be created for this value self._workaround_ignore = True return self._entity = device @callback def _on_ready(sec): _LOGGER.info( "Z-Wave entity %s (node_id: %d) ready after %d seconds", device.name, self._node.node_id, sec, ) self._hass.async_add_job(discover_device, component, device) @callback def _on_timeout(sec): _LOGGER.warning( "Z-Wave entity %s (node_id: %d) not ready after %d seconds, " "continuing anyway", device.name, self._node.node_id, sec, ) self._hass.async_add_job(discover_device, component, device) async def discover_device(component, device): """Put device in a dictionary and call discovery on it.""" if self._hass.data[DATA_DEVICES].get(device.unique_id): return self._hass.data[DATA_DEVICES][device.unique_id] = device if component in SUPPORTED_PLATFORMS: async_dispatcher_send(self._hass, f"zwave_new_{component}", device) else: await discovery.async_load_platform( self._hass, component, DOMAIN, {const.DISCOVERY_DEVICE: device.unique_id}, self._zwave_config, ) if device.unique_id: self._hass.add_job(discover_device, component, device) else: self._hass.add_job(check_has_unique_id, device, _on_ready, _on_timeout)
def closest(hass, *args): """Find closest entity. Closest to home: closest(states) closest(states.device_tracker) closest('group.children') closest(states.group.children) Closest to a point: closest(23.456, 23.456, 'group.children') closest('zone.school', 'group.children') closest(states.zone.school, 'group.children') As a filter: states | closest states.device_tracker | closest ['group.children', states.device_tracker] | closest 'group.children' | closest(23.456, 23.456) states.device_tracker | closest('zone.school') 'group.children' | closest(states.zone.school) """ if len(args) == 1: latitude = hass.config.latitude longitude = hass.config.longitude entities = args[0] elif len(args) == 2: point_state = _resolve_state(hass, args[0]) if point_state is None: _LOGGER.warning("Closest:Unable to find state %s", args[0]) return None if not loc_helper.has_location(point_state): _LOGGER.warning( "Closest:State does not contain valid location: %s", point_state ) return None latitude = point_state.attributes.get(ATTR_LATITUDE) longitude = point_state.attributes.get(ATTR_LONGITUDE) entities = args[1] else: latitude = convert(args[0], float) longitude = convert(args[1], float) if latitude is None or longitude is None: _LOGGER.warning( "Closest:Received invalid coordinates: %s, %s", args[0], args[1] ) return None entities = args[2] states = expand(hass, entities) # state will already be wrapped here return loc_helper.closest(latitude, longitude, states)
def _check_entity_ready(self): """Check if all required values are discovered and create entity.""" if self._workaround_ignore: return if self._entity is not None: return for name in self._schema[const.DISC_VALUES]: if self._values[name] is None and \ not self._schema[const.DISC_VALUES][name].get( const.DISC_OPTIONAL): return component = self._schema[const.DISC_COMPONENT] workaround_component = workaround.get_device_component_mapping( self.primary) if workaround_component and workaround_component != component: if workaround_component == workaround.WORKAROUND_IGNORE: _LOGGER.info("Ignoring Node %d Value %d due to workaround.", self.primary.node.node_id, self.primary.value_id) # No entity will be created for this value self._workaround_ignore = True return _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component value_name = _value_name(self.primary) if self._zwave_config[DOMAIN][CONF_NEW_ENTITY_IDS]: generated_id = generate_entity_id(component + '.{}', value_name, []) else: generated_id = "{}.{}".format(component, object_id(self.primary)) node_config = self._device_config.get(generated_id) # Configure node _LOGGER.debug( "Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s as %s", self._node.node_id, self._node.generic, self._node.specific, self.primary.command_class, self.primary.type, self.primary.genre, component) if node_config.get(CONF_IGNORED): _LOGGER.info("Ignoring entity %s due to device settings", generated_id) # No entity will be created for this value self._workaround_ignore = True return polling_intensity = convert(node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: self.primary.enable_poll(polling_intensity) platform = get_platform(component, DOMAIN) device = platform.get_device(node=self._node, values=self, node_config=node_config, hass=self._hass) if device is None: # No entity will be created for this value self._workaround_ignore = True return device.old_entity_id = "{}.{}".format(component, object_id(self.primary)) device.new_entity_id = "{}.{}".format(component, slugify(device.name)) if not self._zwave_config[DOMAIN][CONF_NEW_ENTITY_IDS]: device.entity_id = device.old_entity_id self._entity = device dict_id = id(self) @asyncio.coroutine def discover_device(component, device, dict_id): """Put device in a dictionary and call discovery on it.""" self._hass.data[DATA_DEVICES][dict_id] = device yield from discovery.async_load_platform( self._hass, component, DOMAIN, {const.DISCOVERY_DEVICE: dict_id}, self._zwave_config) self._hass.add_job(discover_device, component, device, dict_id)
def start_zwave(_service_or_event): """Startup Z-Wave network.""" _LOGGER.info("Starting Z-Wave network...") network.start() hass.bus.fire(const.EVENT_NETWORK_START) # Need to be in STATE_AWAKED before talking to nodes. # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network # to be ready. for i in range(const.NETWORK_READY_WAIT_SECS): _LOGGER.debug("network state: %d %s", network.state, network.state_str) if network.state >= network.STATE_AWAKED: _LOGGER.info("Z-Wave ready after %d seconds", i) break time.sleep(1) else: _LOGGER.warning( "zwave not ready after %d seconds, continuing anyway", const.NETWORK_READY_WAIT_SECS) _LOGGER.info("final network state: %d %s", network.state, network.state_str) polling_interval = convert(config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: network.set_poll_interval(polling_interval, False) poll_interval = network.get_poll_interval() _LOGGER.info("Z-Wave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node, descriptions[const.SERVICE_ADD_NODE]) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure, descriptions[const.SERVICE_ADD_NODE_SECURE]) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node, descriptions[const.SERVICE_REMOVE_NODE]) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command, descriptions[const.SERVICE_CANCEL_COMMAND]) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network, descriptions[const.SERVICE_HEAL_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset, descriptions[const.SERVICE_SOFT_RESET]) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network, descriptions[const.SERVICE_TEST_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_network, descriptions[const.SERVICE_STOP_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_START_NETWORK, start_zwave, descriptions[const.SERVICE_START_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, descriptions[const.SERVICE_RENAME_NODE], schema=RENAME_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RENAME_VALUE, rename_value, descriptions[const.SERVICE_RENAME_VALUE], schema=RENAME_VALUE_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER, set_config_parameter, descriptions[const.SERVICE_SET_CONFIG_PARAMETER], schema=SET_CONFIG_PARAMETER_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_PRINT_CONFIG_PARAMETER, print_config_parameter, descriptions[const.SERVICE_PRINT_CONFIG_PARAMETER], schema=PRINT_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REMOVE_FAILED_NODE, remove_failed_node, descriptions[const.SERVICE_REMOVE_FAILED_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REPLACE_FAILED_NODE, replace_failed_node, descriptions[const.SERVICE_REPLACE_FAILED_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_CHANGE_ASSOCIATION, change_association, descriptions[const.SERVICE_CHANGE_ASSOCIATION], schema=CHANGE_ASSOCIATION_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_WAKEUP, set_wakeup, descriptions[const.SERVICE_SET_WAKEUP], schema=SET_WAKEUP_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_NODE, print_node, descriptions[const.SERVICE_PRINT_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_ENTITY, async_refresh_entity, descriptions[const.SERVICE_REFRESH_ENTITY], schema=REFRESH_ENTITY_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_NODE, refresh_node, descriptions[const.SERVICE_REFRESH_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RESET_NODE_METERS, reset_node_meters, descriptions[const.SERVICE_RESET_NODE_METERS], schema=RESET_NODE_METERS_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_POLL_INTENSITY, set_poll_intensity, descriptions[const.SERVICE_SET_POLL_INTENSITY], schema=SET_POLL_INTENSITY_SCHEMA)
def closest(self, *args): """Find closest entity. Closest to home: closest(states) closest(states.device_tracker) closest('group.children') closest(states.group.children) Closest to a point: closest(23.456, 23.456, 'group.children') closest('zone.school', 'group.children') closest(states.zone.school, 'group.children') """ if len(args) == 1: latitude = self._hass.config.latitude longitude = self._hass.config.longitude entities = args[0] elif len(args) == 2: point_state = self._resolve_state(args[0]) if point_state is None: _LOGGER.warning('Closest:Unable to find state %s', args[0]) return None elif not loc_helper.has_location(point_state): _LOGGER.warning( 'Closest:State does not contain valid location: %s', point_state) return None latitude = point_state.attributes.get(ATTR_LATITUDE) longitude = point_state.attributes.get(ATTR_LONGITUDE) entities = args[1] else: latitude = convert(args[0], float) longitude = convert(args[1], float) if latitude is None or longitude is None: _LOGGER.warning('Closest:Received invalid coordinates: %s, %s', args[0], args[1]) return None entities = args[2] if isinstance(entities, (AllStates, DomainStates)): states = list(entities) else: if isinstance(entities, State): gr_entity_id = entities.entity_id else: gr_entity_id = str(entities) group = get_component('group') states = [ self._hass.states.get(entity_id) for entity_id in group.expand_entity_ids( self._hass, [gr_entity_id]) ] return loc_helper.closest(latitude, longitude, states)
def current_power_mwh(self): """Current power usage in mWh.""" power = self.vera_device.power if power: return convert(power, float, 0.0) * 1000
def current_power_w(self) -> Optional[float]: """Return the current power usage in W.""" power = self.vera_device.power if power: return convert(power, float, 0.0)
def current_power_w(self): """Return the current power usage in W.""" if "power" in self.fibaro_device.properties and ( power := self.fibaro_device.properties.power): return convert(power, float, 0.0)
def _finalize_start(): """Perform final initializations after Z-Wave network is awaked.""" polling_interval = convert(config.get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: network.set_poll_interval(polling_interval, False) poll_interval = network.get_poll_interval() _LOGGER.info("Z-Wave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_network) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, schema=RENAME_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RENAME_VALUE, rename_value, schema=RENAME_VALUE_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER, set_config_parameter, schema=SET_CONFIG_PARAMETER_SCHEMA, ) hass.services.register( DOMAIN, const.SERVICE_SET_NODE_VALUE, set_node_value, schema=SET_NODE_VALUE_SCHEMA, ) hass.services.register( DOMAIN, const.SERVICE_REFRESH_NODE_VALUE, refresh_node_value, schema=REFRESH_NODE_VALUE_SCHEMA, ) hass.services.register( DOMAIN, const.SERVICE_PRINT_CONFIG_PARAMETER, print_config_parameter, schema=PRINT_CONFIG_PARAMETER_SCHEMA, ) hass.services.register( DOMAIN, const.SERVICE_REMOVE_FAILED_NODE, remove_failed_node, schema=NODE_SERVICE_SCHEMA, ) hass.services.register( DOMAIN, const.SERVICE_REPLACE_FAILED_NODE, replace_failed_node, schema=NODE_SERVICE_SCHEMA, ) hass.services.register( DOMAIN, const.SERVICE_CHANGE_ASSOCIATION, change_association, schema=CHANGE_ASSOCIATION_SCHEMA, ) hass.services.register(DOMAIN, const.SERVICE_SET_WAKEUP, set_wakeup, schema=SET_WAKEUP_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_NODE, print_node, schema=NODE_SERVICE_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_REFRESH_ENTITY, async_refresh_entity, schema=REFRESH_ENTITY_SCHEMA, ) hass.services.register(DOMAIN, const.SERVICE_REFRESH_NODE, refresh_node, schema=NODE_SERVICE_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_RESET_NODE_METERS, reset_node_meters, schema=RESET_NODE_METERS_SCHEMA, ) hass.services.register( DOMAIN, const.SERVICE_SET_POLL_INTENSITY, set_poll_intensity, schema=SET_POLL_INTENSITY_SCHEMA, ) hass.services.register(DOMAIN, const.SERVICE_HEAL_NODE, heal_node, schema=HEAL_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_TEST_NODE, test_node, schema=TEST_NODE_SCHEMA)
def setup(hass, config): """Setup the InfluxDB component.""" from influxdb import InfluxDBClient, exceptions if not validate_config( config, {DOMAIN: ['host', CONF_USERNAME, CONF_PASSWORD]}, _LOGGER): return False conf = config[DOMAIN] host = conf[CONF_HOST] port = util.convert(conf.get(CONF_PORT), int, DEFAULT_PORT) database = util.convert(conf.get(CONF_DB_NAME), str, DEFAULT_DATABASE) username = util.convert(conf.get(CONF_USERNAME), str) password = util.convert(conf.get(CONF_PASSWORD), str) ssl = util.convert(conf.get(CONF_SSL), bool, DEFAULT_SSL) verify_ssl = util.convert(conf.get(CONF_VERIFY_SSL), bool, DEFAULT_VERIFY_SSL) try: influx = InfluxDBClient(host=host, port=port, username=username, password=password, database=database, ssl=ssl, verify_ssl=verify_ssl) influx.query("select * from /.*/ LIMIT 1;") except exceptions.InfluxDBClientError as exc: _LOGGER.error( "Database host is not accessible due to '%s', please " "check your entries in the configuration file and that " "the database exists and is READ/WRITE.", exc) return False def influx_event_listener(event): """Listen for new messages on the bus and sends them to Influx.""" state = event.data.get('new_state') if state is None or state.state in (STATE_UNKNOWN, ''): return try: _state = state_helper.state_as_number(state) except ValueError: _state = state.state measurement = state.attributes.get('unit_of_measurement') if measurement in (None, ''): measurement = state.entity_id json_body = [{ 'measurement': measurement, 'tags': { 'domain': state.domain, 'entity_id': state.object_id, }, 'time': event.time_fired, 'fields': { 'value': _state, } }] try: influx.write_points(json_body) except exceptions.InfluxDBClientError: _LOGGER.exception('Error saving event "%s" to InfluxDB', json_body) hass.bus.listen(EVENT_STATE_CHANGED, influx_event_listener) return True
def update(self): """Update the state.""" with suppress(KeyError, ValueError): self._attr_native_value = convert( self.fibaro_device.properties.power, float )
def native_value(self) -> StateType: """Return the current energy use today.""" miliwatts = convert( self.wemo.insight_params.get(self.entity_description.key), float, 0.0 ) return round(miliwatts / (1000.0 * 1000.0 * 60), 2)
def today_energy_kwh(self): """Today total energy usage in kWh.""" if self.insight_params: miliwatts = convert(self.insight_params['todaymw'], float, 0.0) return round(miliwatts / (1000.0 * 1000.0 * 60), 2)