Files
homeassistant/config/custom_components/nodered/text.py
T
2026-08-24 21:55:33 +08:00

148 lines
4.9 KiB
Python

"""Sensor platform for nodered."""
import logging
from typing import Any
from homeassistant.components.text import RestoreText, TextMode
from homeassistant.components.websocket_api.connection import ActiveConnection
from homeassistant.components.websocket_api.messages import event_message
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ICON, CONF_ID, CONF_TYPE
from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import (
CONF_TEXT,
EVENT_VALUE_CHANGE,
HA_MAX_STATE_LENGTH,
NODERED_DISCOVERY_NEW,
TEXT_ICON,
)
from .entity import NodeRedEntity
from .number import CONF_VALUE
CONF_MAX_LENGTH = "max_length"
CONF_MIN_LENGTH = "min_length"
CONF_MODE = "mode"
CONF_PATTERN = "pattern"
CONF_STATE = "state"
DEFAULT_MODE = "text"
DEFAULT_MAX_LENGTH = 100
DEFAULT_MIN_LENGTH = 0
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the text platform."""
async def async_discover(
config: dict[str, Any], connection: ActiveConnection
) -> None:
await _async_setup_entity(hass, config, async_add_entities, connection)
config_entry.async_on_unload(
async_dispatcher_connect(
hass,
NODERED_DISCOVERY_NEW.format(CONF_TEXT),
async_discover,
)
)
async def _async_setup_entity(
hass: HomeAssistant,
config: dict[str, Any],
async_add_entities: AddEntitiesCallback,
connection: ActiveConnection,
) -> None:
"""Set up the Node-RED text."""
async_add_entities([NodeRedText(hass, config, connection)])
class NodeRedText(NodeRedEntity, RestoreText):
"""Node-RED text class."""
_bidirectional = True
component = CONF_TEXT
def __init__(
self,
hass: HomeAssistant,
config: dict[str, Any],
connection: ActiveConnection,
) -> None:
"""Initialize the number."""
super().__init__(hass, config)
self._message_id = config[CONF_ID]
self._connection = connection
async def async_added_to_hass(self) -> None:
"""Restore native_*."""
await super().async_added_to_hass()
if (last_text_data := await self.async_get_last_text_data()) is None:
return
self._attr_native_max = last_text_data.native_max
self._attr_native_min = last_text_data.native_min
self._attr_native_value = last_text_data.native_value
async def async_set_value(self, value: str) -> None:
"""Set new value."""
self._connection.send_message(
event_message(
self._message_id, {CONF_TYPE: EVENT_VALUE_CHANGE, CONF_VALUE: value}
)
)
def update_entity_state_attributes(self, msg: dict[str, Any]) -> None:
"""Update the entity state attributes."""
super().update_entity_state_attributes(msg)
# Ensure native value is a string for Text entity to avoid type
# errors in Home Assistant when measuring value length.
state = msg.get(CONF_STATE)
value = str(state) if state is not None else None
if value is not None:
# Determine max length to enforce. Prefer the attribute if set,
# otherwise fall back to the configured value or default.
max_len = getattr(self, "_attr_native_max", None)
if max_len is None:
max_len = self._config.get(CONF_MAX_LENGTH, DEFAULT_MAX_LENGTH)
# Enforce Home Assistant's maximum state length
if isinstance(max_len, int) and max_len >= 0:
effective_max = min(max_len, HA_MAX_STATE_LENGTH)
else:
effective_max = HA_MAX_STATE_LENGTH
if len(value) > effective_max:
_LOGGER.warning(
"Truncating text entity %s (node ID: %s) value to max length %s",
self.entity_id,
self._node_id,
effective_max,
)
value = value[:effective_max]
self._attr_native_value = value
def update_discovery_config(self, msg: dict[str, Any]) -> None:
"""Update the entity config."""
super().update_discovery_config(msg)
self._attr_icon = self._config.get(CONF_ICON, TEXT_ICON)
self._attr_native_min = self._config.get(CONF_MIN_LENGTH, DEFAULT_MIN_LENGTH)
cfg_max = self._config.get(CONF_MAX_LENGTH, DEFAULT_MAX_LENGTH)
if isinstance(cfg_max, int) and cfg_max >= 0:
self._attr_native_max = min(cfg_max, HA_MAX_STATE_LENGTH)
else:
self._attr_native_max = DEFAULT_MAX_LENGTH
self._attr_pattern = self._config.get(CONF_PATTERN, None)
self._attr_mode = TextMode(self._config.get(CONF_MODE, DEFAULT_MODE))