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
Example #2
0
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)
Example #3
0
    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)
Example #4
0
    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)
Example #5
0
    @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)