1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-21 03:20:01 +00:00
Files
core/homeassistant/components/octoprint/number.py
2025-10-24 18:01:27 +02:00

147 lines
4.9 KiB
Python

"""Support for OctoPrint number entities."""
from __future__ import annotations
import logging
from pyoctoprintapi import OctoprintClient
from homeassistant.components.number import NumberDeviceClass, NumberEntity, NumberMode
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import UnitOfTemperature
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import OctoprintDataUpdateCoordinator
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
def is_bed(tool_name: str) -> bool:
"""Return True if the tool name indicates a bed."""
return tool_name == "bed"
def is_extruder(tool_name: str) -> bool:
"""Return True if the tool name indicates an extruder."""
return tool_name.startswith("tool") and tool_name[4:].isdigit()
def is_first_extruder(tool_name: str) -> bool:
"""Return True if the tool name indicates the first extruder."""
return tool_name == "tool0"
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the OctoPrint number entities."""
coordinator: OctoprintDataUpdateCoordinator = hass.data[DOMAIN][
config_entry.entry_id
]["coordinator"]
client: OctoprintClient = hass.data[DOMAIN][config_entry.entry_id]["client"]
device_id = config_entry.unique_id
assert device_id is not None
known_tools = set()
@callback
def async_add_tool_numbers() -> None:
if not coordinator.data["printer"]:
return
new_numbers: list[OctoPrintTemperatureNumber] = []
for tool in coordinator.data["printer"].temperatures:
if (
is_extruder(tool.name) or is_bed(tool.name)
) and tool.name not in known_tools:
assert device_id is not None
known_tools.add(tool.name)
new_numbers.append(
OctoPrintTemperatureNumber(
coordinator,
client,
tool.name,
device_id,
)
)
async_add_entities(new_numbers)
config_entry.async_on_unload(coordinator.async_add_listener(async_add_tool_numbers))
if coordinator.data["printer"]:
async_add_tool_numbers()
class OctoPrintTemperatureNumber(
CoordinatorEntity[OctoprintDataUpdateCoordinator], NumberEntity
):
"""Representation of an OctoPrint temperature setter entity."""
_attr_has_entity_name = True
_attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS
_attr_native_min_value = 0
_attr_native_max_value = 300
_attr_native_step = 1
_attr_mode = NumberMode.BOX
_attr_device_class = NumberDeviceClass.TEMPERATURE
def __init__(
self,
coordinator: OctoprintDataUpdateCoordinator,
client: OctoprintClient,
tool: str,
device_id: str,
) -> None:
"""Initialize a new OctoPrint temperature number entity."""
super().__init__(coordinator)
self._api_tool = tool
self._attr_device_info = coordinator.device_info
self._attr_unique_id = f"{device_id}_{tool}_temperature"
self._client = client
self._device_id = device_id
if is_bed(tool):
self._attr_translation_key = "bed_temperature"
elif is_first_extruder(tool):
self._attr_translation_key = "extruder_temperature"
else:
self._attr_translation_key = "extruder_n_temperature"
self._attr_translation_placeholders = {"n": tool[4:]}
@property
def native_value(self) -> float | None:
"""Return the current target temperature."""
if not self.coordinator.data["printer"]:
return None
for tool in self.coordinator.data["printer"].temperatures:
if tool.name == self._api_tool and tool.target_temp is not None:
return tool.target_temp
return None
async def async_set_native_value(self, value: float) -> None:
"""Set the target temperature."""
try:
if is_bed(self._api_tool):
await self._client.set_bed_temperature(int(value))
elif is_extruder(self._api_tool):
await self._client.set_tool_temperature(self._api_tool, int(value))
except Exception as err:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="error_setting_temperature",
translation_placeholders={
"tool": self._api_tool,
},
) from err
# Request coordinator update to reflect the change
await self.coordinator.async_request_refresh()