def test_rounding_value_get_original_value_on_error(self): """.""" self.assertEqual('None', template.render(self.hass, '{{ None | round }}')) self.assertEqual( 'no_number', template.render(self.hass, '{{ "no_number" | round }}'))
def test_states_function(self): """.""" self.hass.states.set('test.object', 'available') self.assertEqual( 'available', template.render(self.hass, '{{ states("test.object") }}')) self.assertEqual( 'unknown', template.render(self.hass, '{{ states("test.object2") }}'))
def test_states_function(self): """.""" self.hass.states.set('test.object', 'available') self.assertEqual( 'available', template.render(self.hass, '{{ states("test.object") }}')) self.assertEqual( 'unknown', template.render(self.hass, '{{ states("test.object2") }}'))
def notify_message(notify_service, call): """Handle sending notification message service calls.""" message = call.data[ATTR_MESSAGE] title = template.render( hass, call.data.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)) target = call.data.get(ATTR_TARGET) message = template.render(hass, message) data = call.data.get(ATTR_DATA) notify_service.send_message(message, title=title, target=target, data=data)
def test_float(self): """.""" self.hass.states.set('sensor.temperature', '12') self.assertEqual( '12.0', template.render(self.hass, '{{ float(states.sensor.temperature.state) }}')) self.assertEqual( 'True', template.render( self.hass, '{{ float(states.sensor.temperature.state) > 11 }}'))
def notify_message(notify_service, call): """Handle sending notification message service calls.""" message = call.data[ATTR_MESSAGE] title = template.render( hass, call.data.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)) target = call.data.get(ATTR_TARGET) message = template.render(hass, message) data = call.data.get(ATTR_DATA) notify_service.send_message(message, title=title, target=target, data=data)
def test_rounding_value_get_original_value_on_error(self): """.""" self.assertEqual( 'None', template.render( self.hass, '{{ None | round }}' )) self.assertEqual( 'no_number', template.render( self.hass, '{{ "no_number" | round }}' ))
def test_float(self): """.""" self.hass.states.set('sensor.temperature', '12') self.assertEqual( '12.0', template.render( self.hass, '{{ float(states.sensor.temperature.state) }}')) self.assertEqual( 'True', template.render( self.hass, '{{ float(states.sensor.temperature.state) > 11 }}'))
def test_rounding_value(self): """.""" self.hass.states.set('sensor.temperature', 12.78) self.assertEqual( '12.8', template.render( self.hass, '{{ states.sensor.temperature.state | round(1) }}')) self.assertEqual( '128', template.render( self.hass, '{{ states.sensor.temperature.state | multiply(10) | round }}') )
def test_rounding_value(self): """.""" self.hass.states.set('sensor.temperature', 12.78) self.assertEqual( '12.8', template.render( self.hass, '{{ states.sensor.temperature.state | round(1) }}')) self.assertEqual( '128', template.render( self.hass, '{{ states.sensor.temperature.state | multiply(10) | round }}' ))
def numeric_state(hass, entity, below=None, above=None, value_template=None, variables=None): """Test a numeric state condition.""" if isinstance(entity, str): entity = hass.states.get(entity) if entity is None: return False if value_template is None: value = entity.state else: variables = dict(variables or {}) variables['state'] = entity try: value = render(hass, value_template, variables) except TemplateError as ex: _LOGGER.error(ex) return False try: value = float(value) except ValueError: _LOGGER.warning("Value cannot be processed as a number: %s", value) return False if below is not None and value > below: return False if above is not None and value < above: return False return True
def test_closest_function_to_state(self): """.""" self.hass.states.set( 'test_domain.closest_home', 'happy', { 'latitude': self.hass.config.latitude + 0.1, 'longitude': self.hass.config.longitude + 0.1, }) self.hass.states.set( 'test_domain.closest_zone', 'happy', { 'latitude': self.hass.config.latitude + 0.2, 'longitude': self.hass.config.longitude + 0.2, }) self.hass.states.set( 'zone.far_away', 'zoning', { 'latitude': self.hass.config.latitude + 0.3, 'longitude': self.hass.config.longitude + 0.3, }) self.assertEqual( 'test_domain.closest_zone', template.render( self.hass, '{{ closest(states.zone.far_away, ' 'states.test_domain).entity_id }}'))
def test_closest_function_to_coord(self): """.""" self.hass.states.set('test_domain.closest_home', 'happy', { 'latitude': self.hass.config.latitude + 0.1, 'longitude': self.hass.config.longitude + 0.1, }) self.hass.states.set('test_domain.closest_zone', 'happy', { 'latitude': self.hass.config.latitude + 0.2, 'longitude': self.hass.config.longitude + 0.2, }) self.hass.states.set('zone.far_away', 'zoning', { 'latitude': self.hass.config.latitude + 0.3, 'longitude': self.hass.config.longitude + 0.3, }) self.assertEqual( 'test_domain.closest_zone', template.render( self.hass, '{{ closest("%s", %s, states.test_domain).entity_id }}' % (self.hass.config.latitude + 0.3, self.hass.config.longitude + 0.3)) )
def test_distance_function_with_2_coords(self): """.""" self.assertEqual( '187', template.render( self.hass, '{{ distance("32.87336", "-117.22943", %s, %s) | round }}' % (self.hass.config.latitude, self.hass.config.longitude)))
def post(self, request): """Render a template.""" try: return template.render(self.hass, request.json['template'], request.json.get('variables')) except TemplateError as ex: return self.json_message('Error rendering template: {}'.format(ex), HTTP_BAD_REQUEST)
def post(self, request): """Render a template.""" try: return template.render(self.hass, request.json['template'], request.json.get('variables')) except TemplateError as ex: return self.json_message('Error rendering template: {}'.format(ex), HTTP_BAD_REQUEST)
def test_distance_function_with_2_coords(self): """.""" self.assertEqual( '187', template.render( self.hass, '{{ distance("32.87336", "-117.22943", %s, %s) | round }}' % (self.hass.config.latitude, self.hass.config.longitude)))
def log_message(service): """Handle sending notification message service calls.""" message = service.data[ATTR_MESSAGE] name = service.data[ATTR_NAME] domain = service.data.get(ATTR_DOMAIN) entity_id = service.data.get(ATTR_ENTITY_ID) message = template.render(hass, message) log_entry(hass, name, message, domain, entity_id)
def template(hass, value_template, variables=None): """Test if template condition matches.""" try: value = render(hass, value_template, variables) except TemplateError as ex: _LOGGER.error('Error duriong template condition: %s', ex) return False return value.lower() == 'true'
def template(hass, value_template, variables=None): """Test if template condition matches.""" try: value = render(hass, value_template, variables) except TemplateError as ex: _LOGGER.error('Error duriong template condition: %s', ex) return False return value.lower() == 'true'
def test_distance_function_return_None_if_invalid_coord(self): """.""" self.assertEqual( 'None', template.render(self.hass, '{{ distance("123", "abc") }}')) self.assertEqual('None', template.render(self.hass, '{{ distance("123") }}')) self.hass.states.set( 'test.object_2', 'happy', { 'latitude': self.hass.config.latitude, 'longitude': self.hass.config.longitude, }) self.assertEqual( 'None', template.render(self.hass, '{{ distance("123", states.test_object_2) }}'))
def test_if_state_exists(self): """.""" self.hass.states.set('test.object', 'available') self.assertEqual( 'exists', template.render( self.hass, """ {% if states.test.object %}exists{% else %}not exists{% endif %} """))
def test_is_state(self): """.""" self.hass.states.set('test.object', 'available') self.assertEqual( 'yes', template.render( self.hass, """ {% if is_state("test.object", "available") %}yes{% else %}no{% endif %} """))
def test_is_state_attr(self): """.""" self.hass.states.set('test.object', 'available', {'mode': 'on'}) self.assertEqual( 'yes', template.render( self.hass, """ {% if is_state_attr("test.object", "mode", "on") %}yes{% else %}no{% endif %} """))
def test_multiply(self): """.""" tests = {None: 'None', 10: '100', '"abcd"': 'abcd'} for inp, out in tests.items(): self.assertEqual( out, template.render(self.hass, '{{ %s | multiply(10) | round }}' % inp))
def log_message(service): """Handle sending notification message service calls.""" message = service.data[ATTR_MESSAGE] name = service.data[ATTR_NAME] domain = service.data.get(ATTR_DOMAIN) entity_id = service.data.get(ATTR_ENTITY_ID) message = template.render(hass, message) log_entry(hass, name, message, domain, entity_id)
def test_distance_function_return_None_if_invalid_state(self): """.""" self.hass.states.set('test.object_2', 'happy', { 'latitude': 10, }) self.assertEqual( 'None', template.render(self.hass, '{{ distance(states.test.object_2) | round }}'))
def test_iterating_all_states(self): """.""" self.hass.states.set('test.object', 'happy') self.hass.states.set('sensor.temperature', 10) self.assertEqual( '10happy', template.render( self.hass, '{% for state in states %}{{ state.state }}{% endfor %}'))
def test_if_state_exists(self): """.""" self.hass.states.set('test.object', 'available') self.assertEqual( 'exists', template.render( self.hass, """ {% if states.test.object %}exists{% else %}not exists{% endif %} """))
def test_is_state(self): """.""" self.hass.states.set('test.object', 'available') self.assertEqual( 'yes', template.render( self.hass, """ {% if is_state("test.object", "available") %}yes{% else %}no{% endif %} """))
def test_is_state_attr(self): """.""" self.hass.states.set('test.object', 'available', {'mode': 'on'}) self.assertEqual( 'yes', template.render( self.hass, """ {% if is_state_attr("test.object", "mode", "on") %}yes{% else %}no{% endif %} """))
def test_iterating_all_states(self): """.""" self.hass.states.set('test.object', 'happy') self.hass.states.set('sensor.temperature', 10) self.assertEqual( '10happy', template.render( self.hass, '{% for state in states %}{{ state.state }}{% endfor %}'))
def test_distance_function_with_1_state(self): """.""" self.hass.states.set('test.object', 'happy', { 'latitude': 32.87336, 'longitude': -117.22943, }) self.assertEqual( '187', template.render(self.hass, '{{ distance(states.test.object) | round }}'))
def test_distance_function_with_1_state(self): """.""" self.hass.states.set('test.object', 'happy', { 'latitude': 32.87336, 'longitude': -117.22943, }) self.assertEqual( '187', template.render( self.hass, '{{ distance(states.test.object) | round }}'))
def test_closest_function_invalid_coordinates(self): """.""" self.hass.states.set('test_domain.closest_home', 'happy', { 'latitude': self.hass.config.latitude + 0.1, 'longitude': self.hass.config.longitude + 0.1, }) self.assertEqual( 'None', template.render(self.hass, '{{ closest("invalid", "coord", states) }}'))
def test_distance_function_with_1_state_1_coord(self): """.""" self.hass.states.set('test.object_2', 'happy', { 'latitude': self.hass.config.latitude, 'longitude': self.hass.config.longitude, }) self.assertEqual( '187', template.render( self.hass, '{{ distance("32.87336", "-117.22943", states.test.object_2) ' '| round }}')) self.assertEqual( '187', template.render( self.hass, '{{ distance(states.test.object_2, "32.87336", "-117.22943") ' '| round }}'))
def test_distance_function_return_None_if_invalid_state(self): """.""" self.hass.states.set('test.object_2', 'happy', { 'latitude': 10, }) self.assertEqual( 'None', template.render( self.hass, '{{ distance(states.test.object_2) | round }}'))
def test_distance_function_with_1_state_1_coord(self): """.""" self.hass.states.set( 'test.object_2', 'happy', { 'latitude': self.hass.config.latitude, 'longitude': self.hass.config.longitude, }) self.assertEqual( '187', template.render( self.hass, '{{ distance("32.87336", "-117.22943", states.test.object_2) ' '| round }}')) self.assertEqual( '187', template.render( self.hass, '{{ distance(states.test.object_2, "32.87336", "-117.22943") ' '| round }}'))
def test_iterating_domain_states(self): """.""" self.hass.states.set('test.object', 'happy') self.hass.states.set('sensor.back_door', 'open') self.hass.states.set('sensor.temperature', 10) self.assertEqual( 'open10', template.render( self.hass, """ {% for state in states.sensor %}{{ state.state }}{% endfor %} """))
def update(self): """Get the latest data and update the states.""" try: self._state = template.render(self.hass, self._template) except TemplateError as ex: if ex.args and ex.args[0].startswith( "UndefinedError: 'None' has no attribute"): # Common during HA startup - so just a warning _LOGGER.warning(ex) return self._state = None _LOGGER.error(ex)
def test_closest_function_invalid_state(self): """.""" self.hass.states.set('test_domain.closest_home', 'happy', { 'latitude': self.hass.config.latitude + 0.1, 'longitude': self.hass.config.longitude + 0.1, }) for state in ('states.zone.non_existing', '"zone.non_existing"'): self.assertEqual( 'None', template.render( self.hass, '{{ closest(%s, states) }}' % state))
def update(self): """Get the latest data and update the states.""" try: self._state = template.render(self.hass, self._template) except TemplateError as ex: if ex.args and ex.args[0].startswith( "UndefinedError: 'None' has no attribute"): # Common during HA startup - so just a warning _LOGGER.warning(ex) return self._state = None _LOGGER.error(ex)
def test_closest_function_invalid_coordinates(self): """.""" self.hass.states.set( 'test_domain.closest_home', 'happy', { 'latitude': self.hass.config.latitude + 0.1, 'longitude': self.hass.config.longitude + 0.1, }) self.assertEqual( 'None', template.render(self.hass, '{{ closest("invalid", "coord", states) }}'))
def call_from_config(hass, config, blocking=False, variables=None, validate_config=True): """Call a service based on a config hash.""" if validate_config: try: config = cv.SERVICE_SCHEMA(config) except vol.Invalid as ex: _LOGGER.error("Invalid config for calling service: %s", ex) return if CONF_SERVICE in config: domain_service = config[CONF_SERVICE] else: try: domain_service = template.render(hass, config[CONF_SERVICE_TEMPLATE], variables) domain_service = cv.service(domain_service) except TemplateError as ex: _LOGGER.error('Error rendering service name template: %s', ex) return except vol.Invalid as ex: _LOGGER.error('Template rendered invalid service: %s', domain_service) return domain, service_name = domain_service.split('.', 1) service_data = dict(config.get(CONF_SERVICE_DATA, {})) if CONF_SERVICE_DATA_TEMPLATE in config: for key, value in config[CONF_SERVICE_DATA_TEMPLATE].items(): service_data[key] = template.render(hass, value, variables) if CONF_SERVICE_ENTITY_ID in config: service_data[ATTR_ENTITY_ID] = config[CONF_SERVICE_ENTITY_ID] hass.services.call(domain, service_name, service_data, blocking)
def test_closest_function_invalid_state(self): """.""" self.hass.states.set( 'test_domain.closest_home', 'happy', { 'latitude': self.hass.config.latitude + 0.1, 'longitude': self.hass.config.longitude + 0.1, }) for state in ('states.zone.non_existing', '"zone.non_existing"'): self.assertEqual( 'None', template.render(self.hass, '{{ closest(%s, states) }}' % state))
def test_closest_function_state_with_invalid_location(self): """.""" self.hass.states.set( 'test_domain.closest_home', 'happy', { 'latitude': 'invalid latitude', 'longitude': self.hass.config.longitude + 0.1, }) self.assertEqual( 'None', template.render( self.hass, '{{ closest(states.test_domain.closest_home, ' 'states) }}'))
def test_multiply(self): """.""" tests = { None: 'None', 10: '100', '"abcd"': 'abcd' } for inp, out in tests.items(): self.assertEqual( out, template.render(self.hass, '{{ %s | multiply(10) | round }}' % inp))
def test_iterating_domain_states(self): """.""" self.hass.states.set('test.object', 'happy') self.hass.states.set('sensor.back_door', 'open') self.hass.states.set('sensor.temperature', 10) self.assertEqual( 'open10', template.render( self.hass, """ {% for state in states.sensor %}{{ state.state }}{% endfor %} """))
def test_closest_function_state_with_invalid_location(self): """.""" self.hass.states.set('test_domain.closest_home', 'happy', { 'latitude': 'invalid latitude', 'longitude': self.hass.config.longitude + 0.1, }) self.assertEqual( 'None', template.render( self.hass, '{{ closest(states.test_domain.closest_home, ' 'states) }}'))
def test_distance_function_return_None_if_invalid_coord(self): """.""" self.assertEqual( 'None', template.render( self.hass, '{{ distance("123", "abc") }}')) self.assertEqual( 'None', template.render( self.hass, '{{ distance("123") }}')) self.hass.states.set('test.object_2', 'happy', { 'latitude': self.hass.config.latitude, 'longitude': self.hass.config.longitude, }) self.assertEqual( 'None', template.render( self.hass, '{{ distance("123", states.test_object_2) }}'))
def call_from_config(hass, config, blocking=False, variables=None, validate_config=True): """Call a service based on a config hash.""" if validate_config: try: config = cv.SERVICE_SCHEMA(config) except vol.Invalid as ex: _LOGGER.error("Invalid config for calling service: %s", ex) return if CONF_SERVICE in config: domain_service = config[CONF_SERVICE] else: try: domain_service = template.render( hass, config[CONF_SERVICE_TEMPLATE], variables) domain_service = cv.service(domain_service) except TemplateError as ex: _LOGGER.error('Error rendering service name template: %s', ex) return except vol.Invalid as ex: _LOGGER.error('Template rendered invalid service: %s', domain_service) return domain, service_name = domain_service.split('.', 1) service_data = dict(config.get(CONF_SERVICE_DATA, {})) if CONF_SERVICE_DATA_TEMPLATE in config: for key, value in config[CONF_SERVICE_DATA_TEMPLATE].items(): service_data[key] = template.render(hass, value, variables) if CONF_SERVICE_ENTITY_ID in config: service_data[ATTR_ENTITY_ID] = config[CONF_SERVICE_ENTITY_ID] hass.services.call(domain, service_name, service_data, blocking)
def update(self): """Get the latest value for this sensor.""" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.settimeout(self._config[CONF_TIMEOUT]) try: sock.connect( (self._config[CONF_HOST], self._config[CONF_PORT])) except socket.error as err: _LOGGER.error( "Unable to connect to %s on port %s: %s", self._config[CONF_HOST], self._config[CONF_PORT], err) return try: sock.send(self._config[CONF_PAYLOAD].encode()) except socket.error as err: _LOGGER.error( "Unable to send payload %r to %s on port %s: %s", self._config[CONF_PAYLOAD], self._config[CONF_HOST], self._config[CONF_PORT], err) return readable, _, _ = select.select( [sock], [], [], self._config[CONF_TIMEOUT]) if not readable: _LOGGER.warning( "Timeout (%s second(s)) waiting for a response after " "sending %r to %s on port %s.", self._config[CONF_TIMEOUT], self._config[CONF_PAYLOAD], self._config[CONF_HOST], self._config[CONF_PORT]) return value = sock.recv(self._config[CONF_BUFFER_SIZE]).decode() if self._config[CONF_VALUE_TEMPLATE] is not None: try: self._state = template.render( self._hass, self._config[CONF_VALUE_TEMPLATE], value=value) return except TemplateError as err: _LOGGER.error( "Unable to render template of %r with value: %r", self._config[CONF_VALUE_TEMPLATE], value) return self._state = value
def test_closest_function_home_vs_all_states(self): """.""" self.hass.states.set('test_domain.object', 'happy', { 'latitude': self.hass.config.latitude + 0.1, 'longitude': self.hass.config.longitude + 0.1, }) self.hass.states.set('test_domain_2.and_closer', 'happy', { 'latitude': self.hass.config.latitude, 'longitude': self.hass.config.longitude, }) self.assertEqual( 'test_domain_2.and_closer', template.render(self.hass, '{{ closest(states).entity_id }}'))
def update(self): """Update the state from the template.""" try: state = template.render(self.hass, self._template).lower() if state in _VALID_STATES: self._state = state in ('true', STATE_ON) else: _LOGGER.error( 'Received invalid switch is_on state: %s. Expected: %s', state, ', '.join(_VALID_STATES)) self._state = None except TemplateError as ex: _LOGGER.error(ex) self._state = None
def publish_service(call): """Handle MQTT publish service calls.""" msg_topic = call.data[ATTR_TOPIC] payload = call.data.get(ATTR_PAYLOAD) payload_template = call.data.get(ATTR_PAYLOAD_TEMPLATE) qos = call.data[ATTR_QOS] retain = call.data[ATTR_RETAIN] try: payload = (payload if payload_template is None else template.render(hass, payload_template)) or '' except template.jinja2.TemplateError as exc: _LOGGER.error( "Unable to publish to '%s': rendering payload template of " "'%s' failed because %s.", msg_topic, payload_template, exc) return MQTT_CLIENT.publish(msg_topic, payload, qos, retain)
def test_closest_function_home_vs_all_states(self): """.""" self.hass.states.set( 'test_domain.object', 'happy', { 'latitude': self.hass.config.latitude + 0.1, 'longitude': self.hass.config.longitude + 0.1, }) self.hass.states.set( 'test_domain_2.and_closer', 'happy', { 'latitude': self.hass.config.latitude, 'longitude': self.hass.config.longitude, }) self.assertEqual( 'test_domain_2.and_closer', template.render(self.hass, '{{ closest(states).entity_id }}'))
def update(self): """Get the latest value for this sensor.""" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.settimeout(self._config[CONF_TIMEOUT]) try: sock.connect( (self._config[CONF_HOST], self._config[CONF_PORT])) except socket.error as err: _LOGGER.error("Unable to connect to %s on port %s: %s", self._config[CONF_HOST], self._config[CONF_PORT], err) return try: sock.send(self._config[CONF_PAYLOAD].encode()) except socket.error as err: _LOGGER.error("Unable to send payload %r to %s on port %s: %s", self._config[CONF_PAYLOAD], self._config[CONF_HOST], self._config[CONF_PORT], err) return readable, _, _ = select.select([sock], [], [], self._config[CONF_TIMEOUT]) if not readable: _LOGGER.warning( "Timeout (%s second(s)) waiting for a response after " "sending %r to %s on port %s.", self._config[CONF_TIMEOUT], self._config[CONF_PAYLOAD], self._config[CONF_HOST], self._config[CONF_PORT]) return value = sock.recv(self._config[CONF_BUFFER_SIZE]).decode() if self._config[CONF_VALUE_TEMPLATE] is not None: try: self._state = template.render( self._hass, self._config[CONF_VALUE_TEMPLATE], value=value) return except TemplateError as err: _LOGGER.error("Unable to render template of %r with value: %r", self._config[CONF_VALUE_TEMPLATE], value) return self._state = value
def test_closest_function_home_vs_group_entity_id(self): """.""" self.hass.states.set( 'test_domain.object', 'happy', { 'latitude': self.hass.config.latitude + 0.1, 'longitude': self.hass.config.longitude + 0.1, }) self.hass.states.set( 'not_in_group.but_closer', 'happy', { 'latitude': self.hass.config.latitude, 'longitude': self.hass.config.longitude, }) group.Group(self.hass, 'location group', ['test_domain.object']) self.assertEqual( 'test_domain.object', template.render(self.hass, '{{ closest("group.location_group").entity_id }}'))