def test_async_parse_datetime(caplog): """Test async_parse_date_datetime.""" entity_id = "sensor.timestamp" device_class = SensorDeviceClass.TIMESTAMP assert (async_parse_date_datetime( "2021-12-12 12:12Z", entity_id, device_class).isoformat() == "2021-12-12T12:12:00+00:00") assert not caplog.text # No timezone assert (async_parse_date_datetime("2021-12-12 12:12", entity_id, device_class) is None) assert "sensor.timestamp rendered timestamp without timezone" in caplog.text # Invalid timestamp assert async_parse_date_datetime("12 past 12", entity_id, device_class) is None assert "sensor.timestamp rendered invalid timestamp: 12 past 12" in caplog.text device_class = SensorDeviceClass.DATE caplog.clear() assert (async_parse_date_datetime( "2021-12-12", entity_id, device_class).isoformat() == "2021-12-12") assert not caplog.text # Invalid date assert async_parse_date_datetime("December 12th", entity_id, device_class) is None assert "sensor.timestamp rendered invalid date December 12th" in caplog.text
class TriggerSensorEntity(TriggerEntity, SensorEntity): """Sensor entity based on trigger data.""" domain = SENSOR_DOMAIN extra_template_keys = (CONF_STATE, ) @property def native_value(self) -> str | datetime | date | None: """Return state of the sensor.""" return self._rendered.get(CONF_STATE) @property def state_class(self) -> str | None: """Sensor state class.""" return self._config.get(CONF_STATE_CLASS) @callback def _process_data(self) -> None: """Process new data.""" super()._process_data() if (state := self._rendered.get(CONF_STATE) ) is None or self.device_class not in ( SensorDeviceClass.DATE, SensorDeviceClass.TIMESTAMP, ): return self._rendered[CONF_STATE] = async_parse_date_datetime( state, self.entity_id, self.device_class)
def _update_state(self, result): super()._update_state(result) if isinstance(result, TemplateError): self._attr_native_value = None return if result is None or self.device_class not in ( SensorDeviceClass.DATE, SensorDeviceClass.TIMESTAMP, ): self._attr_native_value = result return self._attr_native_value = async_parse_date_datetime( result, self.entity_id, self.device_class)
def _update_from_rest_data(self): """Update state from the rest data.""" value = self.rest.data _LOGGER.debug("[%s] Data fetched from resource: %s", self._name, value) if self.rest.headers is not None: # If the http request failed, headers will be None content_type = self.rest.headers.get("content-type") if content_type and ( content_type.startswith("text/xml") or content_type.startswith("application/xml") or content_type.startswith("application/xhtml+xml")): try: value = json.dumps(xmltodict.parse(value)) _LOGGER.debug("[%s] JSON converted from XML: %s", self._name, value) except ExpatError: _LOGGER.warning( "[%s] REST xml result could not be parsed and converted to JSON", self._name) _LOGGER.debug("[%s] Erroneous XML: %s", self._name, value) if self._json_attrs: self._attributes = {} if value: try: json_dict = json.loads(value) if self._json_attrs_path is not None: json_dict = jsonpath(json_dict, self._json_attrs_path) # jsonpath will always store the result in json_dict[0] # so the next line happens to work exactly as needed to # find the result if isinstance(json_dict, list): json_dict = json_dict[0] if isinstance(json_dict, dict): attrs = { k: json_dict[k] for k in self._json_attrs if k in json_dict } self._attributes = attrs else: _LOGGER.warning( "[%s] JSON result was not a dictionary" " or list with 0th element a dictionary", self._name) except ValueError: _LOGGER.warning( "[%s] REST result could not be parsed as JSON", self._name) _LOGGER.debug("[%s] Erroneous JSON: %s", self._name, value) else: _LOGGER.warning( "[%s] Empty reply found when expecting JSON data", self._name) if value is not None and self._value_template is not None: value = self._value_template.async_render_with_possible_json_value( value, None) if value is None or self.device_class not in ( SensorDeviceClass.DATE, SensorDeviceClass.TIMESTAMP, ): self._state = value return self._state = async_parse_date_datetime(value, self.entity_id, self.device_class)
@property def native_value(self) -> str | datetime | date | None: """Return state of the sensor.""" return self._rendered.get(CONF_STATE) @property def state_class(self) -> str | None: """Sensor state class.""" return self._config.get(CONF_STATE_CLASS) @property def native_unit_of_measurement(self) -> str | None: """Return the unit of measurement of the sensor, if any.""" return self._config.get(CONF_UNIT_OF_MEASUREMENT) @callback def _process_data(self) -> None: """Process new data.""" super()._process_data() if (state := self._rendered.get(CONF_STATE) ) is None or self.device_class not in ( SensorDeviceClass.DATE, SensorDeviceClass.TIMESTAMP, ): return self._rendered[CONF_STATE] = async_parse_date_datetime( state, self.entity_id, self.device_class)