home-assistant / core

:house_with_garden: Open source home automation that puts local control and privacy first.
https://www.home-assistant.io
Apache License 2.0
73.27k stars 30.6k forks source link

Error: 'str' object has no attribute 'tzinfo' #67455

Closed rgerbranda closed 2 years ago

rgerbranda commented 2 years ago

The problem

After installing the latest beta of Home Assistant, integration delijn will not run

What version of Home Assistant Core has the issue?

core-2022.3.0b5

What was the last working version of Home Assistant Core?

No response

What type of installation are you running?

Home Assistant Container

Integration causing the issue

delijn

Link to integration documentation on our website

https://www.home-assistant.io/integrations/delijn/

Diagnostics information

No response

Example YAML snippet

No response

Anything in the logs that might be useful for us?

2022-03-01 20:29:01 ERROR (MainThread) [homeassistant.components.sensor] Error adding entities for domain sensor with platform delijn
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 381, in state
    if value.tzinfo is None:
AttributeError: 'str' object has no attribute 'tzinfo'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 382, in async_add_entities
    await asyncio.gather(*tasks)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 614, in _async_add_entity
    await entity.add_to_platform_finish()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 783, in add_to_platform_finish
    self.async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 539, in async_write_ha_state
    self._async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 572, in _async_write_ha_state
    state = self._stringify_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 545, in _stringify_state
    if (state := self.state) is None:
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 392, in state
    raise ValueError(
ValueError: Invalid datetime: sensor.meir_metro_antwerpen has a timestamp device class but does not provide a datetime state but <class 'str'>
2022-03-01 20:29:01 ERROR (MainThread) [homeassistant.components.sensor] Error while setting up delijn platform for sensor
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 381, in state
    if value.tzinfo is None:
AttributeError: 'str' object has no attribute 'tzinfo'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 257, in _async_setup_platform
    await asyncio.gather(*pending)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 382, in async_add_entities
    await asyncio.gather(*tasks)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 614, in _async_add_entity
    await entity.add_to_platform_finish()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 783, in add_to_platform_finish
    self.async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 539, in async_write_ha_state
    self._async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 572, in _async_write_ha_state
    state = self._stringify_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 545, in _stringify_state
    if (state := self.state) is None:
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 392, in state
    raise ValueError(
ValueError: Invalid datetime: sensor.meir_metro_antwerpen has a timestamp device class but does not provide a datetime state but <class 'str'>

Additional information

bash-5.1# pip show pydelijn
Name: pydelijn
Version: 1.0.0
Summary: Get realtime info on stop passages of De Lijn (api.delijn.be)
Home-page: https://github.com/bollewolle/pydelijn
Author: bollewolle
Author-email: dev@bollewolle.be
License: MIT
Location: /usr/local/lib/python3.9/site-packages
Requires: aiohttp, async-timeout, pytz
Required-by:
probot-home-assistant[bot] commented 2 years ago

delijn documentation delijn source (message by IssueLinks)

probot-home-assistant[bot] commented 2 years ago

Hey there @bollewolle, @emilv2, mind taking a look at this issue as it has been labeled with an integration (delijn) you are listed as a code owner for? Thanks! (message by CodeOwnersMention)

rgerbranda commented 2 years ago

I fixed it for myself by adding the strptime method to line 114: This comes from the datetime module, which should be imported.

"""Support for De Lijn (Flemish public transport) information."""
from __future__ import annotations

import logging

""" >>>>> add the following"""
from datetime import datetime

from pydelijn.api import Passages
from pydelijn.common import HttpException
import voluptuous as vol

from homeassistant.components.sensor import (
    PLATFORM_SCHEMA,
    SensorDeviceClass,
    SensorEntity,
)
from homeassistant.const import CONF_API_KEY
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType

_LOGGER = logging.getLogger(__name__)

ATTRIBUTION = "Data provided by data.delijn.be"

CONF_NEXT_DEPARTURE = "next_departure"
CONF_STOP_ID = "stop_id"
CONF_NUMBER_OF_DEPARTURES = "number_of_departures"

DEFAULT_NAME = "De Lijn"

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
    {
        vol.Required(CONF_API_KEY): cv.string,
        vol.Required(CONF_NEXT_DEPARTURE): [
            {
                vol.Required(CONF_STOP_ID): cv.string,
                vol.Optional(CONF_NUMBER_OF_DEPARTURES, default=5): cv.positive_int,
            }
        ],
    }
)

AUTO_ATTRIBUTES = (
    "line_number_public",
    "line_transport_type",
    "final_destination",
    "due_at_schedule",
    "due_at_realtime",
    "is_realtime",
)

async def async_setup_platform(
    hass: HomeAssistant,
    config: ConfigType,
    async_add_entities: AddEntitiesCallback,
    discovery_info: DiscoveryInfoType | None = None,
) -> None:
    """Create the sensor."""
    api_key = config[CONF_API_KEY]

    session = async_get_clientsession(hass)

    sensors = []
    for nextpassage in config[CONF_NEXT_DEPARTURE]:
        sensors.append(
            DeLijnPublicTransportSensor(
                Passages(
                    nextpassage[CONF_STOP_ID],
                    nextpassage[CONF_NUMBER_OF_DEPARTURES],
                    api_key,
                    session,
                    True,
                )
            )
        )

    async_add_entities(sensors, True)

class DeLijnPublicTransportSensor(SensorEntity):
    """Representation of a Ruter sensor."""

    _attr_attribution = ATTRIBUTION
    _attr_device_class = SensorDeviceClass.TIMESTAMP
    _attr_icon = "mdi:bus"

    def __init__(self, line):
        """Initialize the sensor."""
        self.line = line
        self._attr_extra_state_attributes = {}

    async def async_update(self):
        """Get the latest data from the De Lijn API."""
        try:
            await self.line.get_passages()
            self._attr_name = await self.line.get_stopname()
        except HttpException:
            self._attr_available = False
            _LOGGER.error("De Lijn http error")
            return

        self._attr_extra_state_attributes["stopname"] = self._attr_name

        if not self.line.passages:
            self._attr_available = False
            return

        try:
            first = self.line.passages[0]
            if (first_passage := first["due_at_realtime"]) is None:
                first_passage = first["due_at_schedule"]
""" >>>>>> change the following line """
            self._attr_native_value = datetime.strptime(first_passage, '%Y-%m-%dT%H:%M:%S%z')

            for key in AUTO_ATTRIBUTES:
                self._attr_extra_state_attributes[key] = first[key]
            self._attr_extra_state_attributes["next_passages"] = self.line.passages

            self._attr_available = True
        except (KeyError) as error:
            _LOGGER.error("Invalid data received from De Lijn: %s", error)
            self._attr_available = False
bollewolle commented 2 years ago

For what it's worth, I can confirm that copying the code into a custom_component and updating the 2 lines of code described by @rgerbranda also fixes it for me.

ericvb commented 2 years ago

Hi @bollewolle, will the correction also be made available through normal update code workflow in HA? Or is this integration De Lijn not maintained anymore?