core/homeassistant/components/octoprint/coordinator.py

95 lines
3.2 KiB
Python

"""The data update coordinator for OctoPrint."""
from __future__ import annotations
from datetime import timedelta
import logging
from typing import cast
from pyoctoprintapi import ApiError, OctoprintClient, PrinterOffline
from pyoctoprintapi.exceptions import UnauthorizedException
from yarl import URL
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PATH, CONF_PORT, CONF_SSL
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
import homeassistant.util.dt as dt_util
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
class OctoprintDataUpdateCoordinator(DataUpdateCoordinator):
"""Class to manage fetching Octoprint data."""
config_entry: ConfigEntry
def __init__(
self,
hass: HomeAssistant,
octoprint: OctoprintClient,
config_entry: ConfigEntry,
interval: int,
) -> None:
"""Initialize."""
super().__init__(
hass,
_LOGGER,
name=f"octoprint-{config_entry.entry_id}",
update_interval=timedelta(seconds=interval),
)
self.config_entry = config_entry
self._octoprint = octoprint
self._printer_offline = False
self.data = {"printer": None, "job": None, "last_read_time": None}
async def _async_update_data(self):
"""Update data via API."""
printer = None
try:
job = await self._octoprint.get_job_info()
except UnauthorizedException as err:
raise ConfigEntryAuthFailed from err
except ApiError as err:
raise UpdateFailed(err) from err
# If octoprint is on, but the printer is disconnected
# printer will return a 409, so continue using the last
# reading if there is one
try:
printer = await self._octoprint.get_printer_info()
except PrinterOffline:
if not self._printer_offline:
_LOGGER.debug("Unable to retrieve printer information: Printer offline")
self._printer_offline = True
except UnauthorizedException as err:
raise ConfigEntryAuthFailed from err
except ApiError as err:
raise UpdateFailed(err) from err
else:
self._printer_offline = False
return {"job": job, "printer": printer, "last_read_time": dt_util.utcnow()}
@property
def device_info(self) -> DeviceInfo:
"""Device info."""
unique_id = cast(str, self.config_entry.unique_id)
configuration_url = URL.build(
scheme=self.config_entry.data[CONF_SSL] and "https" or "http",
host=self.config_entry.data[CONF_HOST],
port=self.config_entry.data[CONF_PORT],
path=self.config_entry.data[CONF_PATH],
)
return DeviceInfo(
identifiers={(DOMAIN, unique_id)},
manufacturer="OctoPrint",
name="OctoPrint",
configuration_url=str(configuration_url),
)