Skip to content
Closed
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
6 changes: 2 additions & 4 deletions custom_components/grocy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
"""
Custom integration to integrate Grocy with Home Assistant.
"""Custom integration to integrate Grocy with Home Assistant.

For more details about this integration, please refer to
https://github.com/custom-components/grocy
"""
from __future__ import annotations

import logging
from typing import List

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
Expand Down Expand Up @@ -67,7 +65,7 @@ async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
return unloaded


async def _async_get_available_entities(grocy_data: GrocyData) -> List[str]:
async def _async_get_available_entities(grocy_data: GrocyData) -> list[str]:
"""Return a list of available entities based on enabled Grocy features."""
available_entities = []
grocy_config = await grocy_data.async_get_config()
Expand Down
10 changes: 5 additions & 5 deletions custom_components/grocy/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""Binary sensor platform for Grocy."""
from __future__ import annotations

import logging
from collections.abc import Callable, Mapping
from dataclasses import dataclass
from typing import Any, List
import logging
from typing import Any

from homeassistant.components.binary_sensor import (
BinarySensorEntity,
Expand Down Expand Up @@ -35,7 +35,7 @@ async def async_setup_entry(
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
):
"""Setup binary sensor platform."""
"""Initialize binary sensor platform."""
coordinator: GrocyDataUpdateCoordinator = hass.data[DOMAIN]
entities = []
for description in BINARY_SENSORS:
Expand All @@ -56,8 +56,8 @@ async def async_setup_entry(
class GrocyBinarySensorEntityDescription(BinarySensorEntityDescription):
"""Grocy binary sensor entity description."""

attributes_fn: Callable[[List[Any]], Mapping[str, Any] | None] = lambda _: None
exists_fn: Callable[[List[str]], bool] = lambda _: True
attributes_fn: Callable[[list[Any]], Mapping[str, Any] | None] = lambda _: None
exists_fn: Callable[[list[str]], bool] = lambda _: True
entity_registry_enabled_default: bool = False


Expand Down
5 changes: 3 additions & 2 deletions custom_components/grocy/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""Adds config flow for Grocy."""
import logging
from collections import OrderedDict
import logging

from pygrocy import Grocy
import voluptuous as vol

from homeassistant import config_entries
from pygrocy import Grocy

from .const import (
CONF_API_KEY,
Expand Down
13 changes: 7 additions & 6 deletions custom_components/grocy/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
from __future__ import annotations

import logging
from typing import Any, Dict, List
from typing import Any

from pygrocy import Grocy

from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from pygrocy import Grocy

from .const import (
CONF_API_KEY,
Expand All @@ -23,7 +24,7 @@
_LOGGER = logging.getLogger(__name__)


class GrocyDataUpdateCoordinator(DataUpdateCoordinator[Dict[str, Any]]):
class GrocyDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""Grocy data update coordinator."""

def __init__(
Expand All @@ -50,16 +51,16 @@ def __init__(
)
self.grocy_data = GrocyData(hass, self.grocy_api)

self.available_entities: List[str] = []
self.entities: List[Entity] = []
self.available_entities: list[str] = []
self.entities: list[Entity] = []

async def _async_update_data(self) -> dict[str, Any]:
"""Fetch data."""
data: dict[str, Any] = {}

for entity in self.entities:
if not entity.enabled:
_LOGGER.debug("Entity %s is disabled.", entity.entity_id)
_LOGGER.debug("Entity %s is disabled", entity.entity_id)
continue

try:
Expand Down
2 changes: 1 addition & 1 deletion custom_components/grocy/entity.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""Entity for Grocy."""
from __future__ import annotations

import json
from collections.abc import Mapping
import json
from typing import Any

from homeassistant.config_entries import ConfigEntry
Expand Down
16 changes: 8 additions & 8 deletions custom_components/grocy/grocy_data.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
"""Communication with Grocy API."""
from __future__ import annotations

import logging
from datetime import datetime, timedelta
from typing import List
import logging

from aiohttp import hdrs, web
from pygrocy.data_models.battery import Battery

from homeassistant.components.http import HomeAssistantView
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from pygrocy.data_models.battery import Battery

from .const import (
ATTR_BATTERIES,
Expand Down Expand Up @@ -38,7 +38,7 @@
class GrocyData:
"""Handles communication and gets the data."""

def __init__(self, hass, api):
def __init__(self, hass: HomeAssistant, api) -> None: # noqa: D107
"""Initialize Grocy data."""
self.hass = hass
self.api = api
Expand Down Expand Up @@ -166,15 +166,15 @@ def wrapper():

return await self.hass.async_add_executor_job(wrapper)

async def async_update_batteries(self) -> List[Battery]:
async def async_update_batteries(self) -> list[Battery]:
"""Update batteries."""

def wrapper():
return self.api.batteries(get_details=True)

return await self.hass.async_add_executor_job(wrapper)

async def async_update_overdue_batteries(self) -> List[Battery]:
async def async_update_overdue_batteries(self) -> list[Battery]:
"""Update overdue batteries."""

def wrapper():
Expand All @@ -187,7 +187,7 @@ def wrapper():
async def async_setup_endpoint_for_image_proxy(
hass: HomeAssistant, config_entry: ConfigEntry
):
"""Setup and register the image api for grocy images with HA."""
"""Do setup and register the image api for grocy images with HA."""
session = async_get_clientsession(hass)

url = config_entry.get(CONF_URL)
Expand All @@ -210,7 +210,7 @@ class GrocyPictureView(HomeAssistantView):
url = "/api/grocy/{picture_type}/{filename}"
name = "api:grocy:picture"

def __init__(self, session, base_url, api_key):
def __init__(self, session, base_url, api_key) -> None: # noqa: D107
self._session = session
self._base_url = base_url
self._api_key = api_key
Expand Down
8 changes: 4 additions & 4 deletions custom_components/grocy/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
from __future__ import annotations

import base64
from typing import Any, Dict, Tuple
from typing import Any
from urllib.parse import urlparse

from pygrocy.data_models.meal_items import MealPlanItem


def extract_base_url_and_path(url: str) -> Tuple[str, str]:
def extract_base_url_and_path(url: str) -> tuple[str, str]:
"""Extract the base url and path from a given URL."""
parsed_url = urlparse(url)

Expand All @@ -18,7 +18,7 @@ def extract_base_url_and_path(url: str) -> Tuple[str, str]:
class MealPlanItemWrapper:
"""Wrapper around the pygrocy MealPlanItem."""

def __init__(self, meal_plan: MealPlanItem):
def __init__(self, meal_plan: MealPlanItem) -> None: # noqa: D107
self._meal_plan = meal_plan

@property
Expand All @@ -35,7 +35,7 @@ def picture_url(self) -> str | None:
return f"/api/grocy/recipepictures/{str(b64name, 'utf-8')}"
return None

def as_dict(self) -> Dict[str, Any]:
def as_dict(self) -> dict[str, Any]:
"""Return attributes for the pygrocy MealPlanItem object including picture URL."""
props = self.meal_plan.as_dict()
props["picture_url"] = self.picture_url
Expand Down
12 changes: 6 additions & 6 deletions custom_components/grocy/sensor.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""Sensor platform for Grocy."""
from __future__ import annotations

import logging
from collections.abc import Callable, Mapping
from dataclasses import dataclass
from typing import Any, List
import logging
from typing import Any

from homeassistant.components.sensor import (
SensorEntity,
Expand Down Expand Up @@ -41,7 +41,7 @@ async def async_setup_entry(
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
):
"""Setup sensor platform."""
"""Do setup sensor platform."""
coordinator: GrocyDataUpdateCoordinator = hass.data[DOMAIN]
entities = []
for description in SENSORS:
Expand All @@ -51,7 +51,7 @@ async def async_setup_entry(
entities.append(entity)
else:
_LOGGER.debug(
"Entity description '%s' is not available.",
"Entity description '%s' is not available",
description.key,
)

Expand All @@ -62,8 +62,8 @@ async def async_setup_entry(
class GrocySensorEntityDescription(SensorEntityDescription):
"""Grocy sensor entity description."""

attributes_fn: Callable[[List[Any]], Mapping[str, Any] | None] = lambda _: None
exists_fn: Callable[[List[str]], bool] = lambda _: True
attributes_fn: Callable[[list[Any]], Mapping[str, Any] | None] = lambda _: None
exists_fn: Callable[[list[str]], bool] = lambda _: True
entity_registry_enabled_default: bool = False


Expand Down
37 changes: 20 additions & 17 deletions custom_components/grocy/services.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""Grocy services."""
from __future__ import annotations

from pygrocy import EntityType, TransactionType
import voluptuous as vol

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, ServiceCall
from pygrocy import EntityType, TransactionType

from .const import ATTR_CHORES, ATTR_TASKS, DOMAIN
from .coordinator import GrocyDataUpdateCoordinator
Expand Down Expand Up @@ -145,7 +146,8 @@


async def async_setup_services(
hass: HomeAssistant, config_entry: ConfigEntry # pylint: disable=unused-argument
hass: HomeAssistant,
config_entry: ConfigEntry, # pylint: disable=unused-argument
) -> None:
"""Set up services for Grocy integration."""
coordinator: GrocyDataUpdateCoordinator = hass.data[DOMAIN]
Expand Down Expand Up @@ -200,7 +202,7 @@ async def async_unload_services(hass: HomeAssistant) -> None:
hass.services.async_remove(DOMAIN, service)


async def async_add_product_service(hass, coordinator, data):
async def async_add_product_service(hass: HomeAssistant, coordinator, data):
"""Add a product in Grocy."""
product_id = data[SERVICE_PRODUCT_ID]
amount = data[SERVICE_AMOUNT]
Expand All @@ -212,7 +214,7 @@ def wrapper():
await hass.async_add_executor_job(wrapper)


async def async_open_product_service(hass, coordinator, data):
async def async_open_product_service(hass: HomeAssistant, coordinator, data):
"""Open a product in Grocy."""
product_id = data[SERVICE_PRODUCT_ID]
amount = data[SERVICE_AMOUNT]
Expand All @@ -226,7 +228,7 @@ def wrapper():
await hass.async_add_executor_job(wrapper)


async def async_consume_product_service(hass, coordinator, data):
async def async_consume_product_service(hass: HomeAssistant, coordinator, data):
"""Consume a product in Grocy."""
product_id = data[SERVICE_PRODUCT_ID]
amount = data[SERVICE_AMOUNT]
Expand All @@ -251,7 +253,7 @@ def wrapper():
await hass.async_add_executor_job(wrapper)


async def async_execute_chore_service(hass, coordinator, data):
async def async_execute_chore_service(hass: HomeAssistant, coordinator, data):
"""Execute a chore in Grocy."""
chore_id = data[SERVICE_CHORE_ID]
done_by = data.get(SERVICE_DONE_BY, "")
Expand All @@ -264,7 +266,7 @@ def wrapper():
await _async_force_update_entity(coordinator, ATTR_CHORES)


async def async_complete_task_service(hass, coordinator, data):
async def async_complete_task_service(hass: HomeAssistant, coordinator, data):
"""Complete a task in Grocy."""
task_id = data[SERVICE_TASK_ID]

Expand All @@ -275,7 +277,7 @@ def wrapper():
await _async_force_update_entity(coordinator, ATTR_TASKS)


async def async_add_generic_service(hass, coordinator, data):
async def async_add_generic_service(hass: HomeAssistant, coordinator, data):
"""Add a generic entity in Grocy."""
entity_type_raw = data.get(SERVICE_ENTITY_TYPE, None)
entity_type = EntityType.TASKS
Expand All @@ -289,10 +291,10 @@ def wrapper():
coordinator.grocy_api.add_generic(entity_type, data)

await hass.async_add_executor_job(wrapper)
await post_generic_refresh(coordinator, entity_type);
await _post_generic_refresh(coordinator, entity_type)


async def async_update_generic_service(hass, coordinator, data):
async def async_update_generic_service(hass: HomeAssistant, coordinator, data):
"""Update a generic entity in Grocy."""
entity_type_raw = data.get(SERVICE_ENTITY_TYPE, None)
entity_type = EntityType.TASKS
Expand All @@ -308,10 +310,10 @@ def wrapper():
coordinator.grocy_api.update_generic(entity_type, object_id, data)

await hass.async_add_executor_job(wrapper)
await post_generic_refresh(coordinator, entity_type);
await _post_generic_refresh(coordinator, entity_type)


async def async_delete_generic_service(hass, coordinator, data):
async def async_delete_generic_service(hass: HomeAssistant, coordinator, data):
"""Delete a generic entity in Grocy."""
entity_type_raw = data.get(SERVICE_ENTITY_TYPE, None)
entity_type = EntityType.TASKS
Expand All @@ -325,14 +327,15 @@ def wrapper():
coordinator.grocy_api.delete_generic(entity_type, object_id)

await hass.async_add_executor_job(wrapper)
await post_generic_refresh(coordinator, entity_type);
await _post_generic_refresh(coordinator, entity_type)


async def post_generic_refresh(coordinator, entity_type):
if entity_type == "tasks" or entity_type == "chores":
async def _post_generic_refresh(coordinator, entity_type):
if entity_type in ("tasks", "chores"):
await _async_force_update_entity(coordinator, entity_type)

async def async_consume_recipe_service(hass, coordinator, data):

async def async_consume_recipe_service(hass: HomeAssistant, coordinator, data):
"""Consume a recipe in Grocy."""
recipe_id = data[SERVICE_RECIPE_ID]

Expand All @@ -342,7 +345,7 @@ def wrapper():
await hass.async_add_executor_job(wrapper)


async def async_track_battery_service(hass, coordinator, data):
async def async_track_battery_service(hass: HomeAssistant, coordinator, data):
"""Track a battery in Grocy."""
battery_id = data[SERVICE_BATTERY_ID]

Expand Down