Skip to content

[pull] dev from home-assistant:dev #783

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/amazon_devices/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,5 @@
"iot_class": "cloud_polling",
"loggers": ["aioamazondevices"],
"quality_scale": "bronze",
"requirements": ["aioamazondevices==3.0.5"]
"requirements": ["aioamazondevices==3.0.6"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/environment_canada/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/environment_canada",
"iot_class": "cloud_polling",
"loggers": ["env_canada"],
"requirements": ["env-canada==0.10.2"]
"requirements": ["env-canada==0.11.2"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/hydrawise/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/hydrawise",
"iot_class": "cloud_polling",
"loggers": ["pydrawise"],
"requirements": ["pydrawise==2025.3.0"]
"requirements": ["pydrawise==2025.6.0"]
}
40 changes: 40 additions & 0 deletions homeassistant/components/imeon_inverter/entity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Imeon inverter base class for entities."""

from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .const import DOMAIN
from .coordinator import InverterCoordinator

type InverterConfigEntry = ConfigEntry[InverterCoordinator]


class InverterEntity(CoordinatorEntity[InverterCoordinator]):
"""Common elements for all entities."""

_attr_has_entity_name = True

def __init__(
self,
coordinator: InverterCoordinator,
entry: InverterConfigEntry,
entity_description: EntityDescription,
) -> None:
"""Pass coordinator to CoordinatorEntity."""
super().__init__(coordinator)
self.entity_description = entity_description
self._inverter = coordinator.api.inverter
self.data_key = entity_description.key
assert entry.unique_id
self._attr_unique_id = f"{entry.unique_id}_{self.data_key}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, entry.unique_id)},
name="Imeon inverter",
manufacturer="Imeon Energy",
model=self._inverter.get("inverter"),
sw_version=self._inverter.get("software"),
serial_number=self._inverter.get("serial"),
configuration_url=self._inverter.get("url"),
)
38 changes: 6 additions & 32 deletions homeassistant/components/imeon_inverter/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,18 @@
UnitOfTime,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .const import DOMAIN
from .coordinator import InverterCoordinator
from .entity import InverterEntity

type InverterConfigEntry = ConfigEntry[InverterCoordinator]

_LOGGER = logging.getLogger(__name__)


ENTITY_DESCRIPTIONS = (
SENSOR_DESCRIPTIONS = (
# Battery
SensorEntityDescription(
key="battery_autonomy",
Expand Down Expand Up @@ -423,42 +421,18 @@ async def async_setup_entry(
"""Create each sensor for a given config entry."""

coordinator = entry.runtime_data

# Init sensor entities
async_add_entities(
InverterSensor(coordinator, entry, description)
for description in ENTITY_DESCRIPTIONS
for description in SENSOR_DESCRIPTIONS
)


class InverterSensor(CoordinatorEntity[InverterCoordinator], SensorEntity):
"""A sensor that returns numerical values with units."""
class InverterSensor(InverterEntity, SensorEntity):
"""Representation of an Imeon inverter sensor."""

_attr_has_entity_name = True
_attr_entity_category = EntityCategory.DIAGNOSTIC

def __init__(
self,
coordinator: InverterCoordinator,
entry: InverterConfigEntry,
description: SensorEntityDescription,
) -> None:
"""Pass coordinator to CoordinatorEntity."""
super().__init__(coordinator)
self.entity_description = description
self._inverter = coordinator.api.inverter
self.data_key = description.key
assert entry.unique_id
self._attr_unique_id = f"{entry.unique_id}_{self.data_key}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, entry.unique_id)},
name="Imeon inverter",
manufacturer="Imeon Energy",
model=self._inverter.get("inverter"),
sw_version=self._inverter.get("software"),
)

@property
def native_value(self) -> StateType | None:
"""Value of the sensor."""
"""Return the state of the entity."""
return self.coordinator.data.get(self.data_key)
6 changes: 3 additions & 3 deletions homeassistant/components/jellyfin/media_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,8 @@ async def _build_movies(self, library_id: str) -> list[BrowseMediaSource]:
movies = await self._get_children(library_id, ITEM_TYPE_MOVIE)
movies = sorted(
movies,
# Sort by whether a movies has an name first, then by name
# This allows for sorting moveis with, without and with missing names
# Sort by whether a movie has a name first, then by name
# This allows for sorting movies with, without and with missing names
key=lambda k: (
ITEM_KEY_NAME not in k,
k.get(ITEM_KEY_NAME),
Expand Down Expand Up @@ -388,7 +388,7 @@ async def _build_tvshow(self, library_id: str) -> list[BrowseMediaSource]:
series = await self._get_children(library_id, ITEM_TYPE_SERIES)
series = sorted(
series,
# Sort by whether a seroes has an name first, then by name
# Sort by whether a series has a name first, then by name
# This allows for sorting series with, without and with missing names
key=lambda k: (
ITEM_KEY_NAME not in k,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/nordpool/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
"iot_class": "cloud_polling",
"loggers": ["pynordpool"],
"quality_scale": "platinum",
"requirements": ["pynordpool==0.2.4"],
"requirements": ["pynordpool==0.3.0"],
"single_config_entry": true
}
3 changes: 1 addition & 2 deletions homeassistant/components/openweathermap/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
)
from homeassistant.const import (
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_MILLION,
DEGREE,
PERCENTAGE,
UV_INDEX,
Expand Down Expand Up @@ -170,7 +169,7 @@
),
SensorEntityDescription(
key=ATTR_API_AIRPOLLUTION_CO,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.CO,
state_class=SensorStateClass.MEASUREMENT,
),
Expand Down
16 changes: 7 additions & 9 deletions homeassistant/components/telegram_bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ def __init__(
self._parse_mode = self._parsers.get(parser)
self.bot = bot
self.hass = hass
self._last_message_id: dict[int, int] = {}

def _get_allowed_chat_ids(self) -> list[int]:
allowed_chat_ids: list[int] = [
Expand All @@ -260,9 +261,6 @@ def _get_allowed_chat_ids(self) -> list[int]:

return allowed_chat_ids

def _get_last_message_id(self):
return dict.fromkeys(self._get_allowed_chat_ids())

def _get_msg_ids(self, msg_data, chat_id):
"""Get the message id to edit.

Expand All @@ -277,9 +275,9 @@ def _get_msg_ids(self, msg_data, chat_id):
if (
isinstance(message_id, str)
and (message_id == "last")
and (self._get_last_message_id()[chat_id] is not None)
and (chat_id in self._last_message_id)
):
message_id = self._get_last_message_id()[chat_id]
message_id = self._last_message_id[chat_id]
else:
inline_message_id = msg_data["inline_message_id"]
return message_id, inline_message_id
Expand Down Expand Up @@ -408,10 +406,10 @@ async def _send_msg(
if not isinstance(out, bool) and hasattr(out, ATTR_MESSAGEID):
chat_id = out.chat_id
message_id = out[ATTR_MESSAGEID]
self._get_last_message_id()[chat_id] = message_id
self._last_message_id[chat_id] = message_id
_LOGGER.debug(
"Last message ID: %s (from chat_id %s)",
self._get_last_message_id(),
self._last_message_id,
chat_id,
)

Expand Down Expand Up @@ -480,9 +478,9 @@ async def delete_message(self, chat_id=None, context=None, **kwargs):
context=context,
)
# reduce message_id anyway:
if self._get_last_message_id()[chat_id] is not None:
if chat_id in self._last_message_id:
# change last msg_id for deque(n_msgs)?
self._get_last_message_id()[chat_id] -= 1
self._last_message_id[chat_id] -= 1
return deleted

async def edit_message(self, type_edit, chat_id=None, context=None, **kwargs):
Expand Down
8 changes: 4 additions & 4 deletions requirements_all.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions requirements_test_all.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion tests/components/imeon_inverter/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ def mock_imeon_inverter() -> Generator[MagicMock]:
inverter.__aenter__.return_value = inverter
inverter.login.return_value = True
inverter.get_serial.return_value = TEST_SERIAL
inverter.inverter.get.return_value = {"inverter": "blah", "software": "1.0"}
inverter.inverter = {
"inverter": "3.6",
"software": "1.0",
"serial": TEST_SERIAL,
"url": f"http://{TEST_USER_INPUT[CONF_HOST]}",
}
inverter.storage = load_json_object_fixture("sensor_data.json", DOMAIN)
yield inverter

Expand Down
7 changes: 2 additions & 5 deletions tests/components/imeon_inverter/test_sensor.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Test the Imeon Inverter sensors."""

from unittest.mock import MagicMock, patch
from unittest.mock import patch

from syrupy.assertion import SnapshotAssertion

Expand All @@ -15,15 +15,12 @@

async def test_sensors(
hass: HomeAssistant,
mock_imeon_inverter: MagicMock,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test the Imeon Inverter sensors."""
with patch(
"homeassistant.components.imeon_inverter.const.PLATFORMS", [Platform.SENSOR]
):
with patch("homeassistant.components.imeon_inverter.PLATFORMS", [Platform.SENSOR]):
await setup_integration(hass, mock_config_entry)

await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
4 changes: 2 additions & 2 deletions tests/components/openweathermap/snapshots/test_sensor.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
'supported_features': 0,
'translation_key': None,
'unique_id': '12.34-56.78-co',
'unit_of_measurement': 'ppm',
'unit_of_measurement': 'µg/m³',
})
# ---
# name: test_sensor_states[air_pollution][sensor.openweathermap_carbon_monoxide-state]
Expand All @@ -96,7 +96,7 @@
'device_class': 'carbon_monoxide',
'friendly_name': 'openweathermap Carbon monoxide',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': 'ppm',
'unit_of_measurement': 'µg/m³',
}),
'context': <ANY>,
'entity_id': 'sensor.openweathermap_carbon_monoxide',
Expand Down
4 changes: 2 additions & 2 deletions tests/components/telegram_bot/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,8 @@ def mock_broadcast_config_entry() -> MockConfigEntry:
options={ATTR_PARSER: PARSER_MD},
subentries_data=[
ConfigSubentryData(
unique_id="1234567890",
data={CONF_CHAT_ID: 1234567890},
unique_id="123456",
data={CONF_CHAT_ID: 123456},
subentry_id="mock_id",
subentry_type=CONF_ALLOWED_CHAT_IDS,
title="mock chat",
Expand Down
4 changes: 2 additions & 2 deletions tests/components/telegram_bot/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ async def test_subentry_flow_chat_error(
with patch(
"homeassistant.components.telegram_bot.config_flow.Bot.get_chat",
return_value=ChatFullInfo(
id=1234567890,
id=123456,
title="mock title",
first_name="mock first_name",
type="PRIVATE",
Expand All @@ -423,7 +423,7 @@ async def test_subentry_flow_chat_error(
):
result = await hass.config_entries.subentries.async_configure(
result["flow_id"],
user_input={CONF_CHAT_ID: 1234567890},
user_input={CONF_CHAT_ID: 123456},
)
await hass.async_block_till_done()

Expand Down
Loading