148 lines
4.9 KiB
Python
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))
|