b52b25973e
Adds a Select entity with four options (Normal / Charge Disabled / Discharge Disabled / Both Disabled) that sends the 0xE1 write command to the BMS and immediately refreshes sensor state. Current option is derived from the mos_charge_enabled / mos_discharge_enabled bits already parsed on every poll. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
74 lines
2.4 KiB
Python
74 lines
2.4 KiB
Python
"""Select entity for Xiaoxiang Smart BMS MOS gate control."""
|
|
from __future__ import annotations
|
|
|
|
from homeassistant.components.select import SelectEntity
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
|
|
|
from .const import (
|
|
DOMAIN,
|
|
MOS_BOTH_OFF,
|
|
MOS_CHARGE_OFF,
|
|
MOS_DISCHARGE_OFF,
|
|
MOS_NORMAL,
|
|
)
|
|
from .coordinator import BmsCoordinator
|
|
|
|
# Maps the human-readable option to the XX byte value in the write command
|
|
_OPTION_TO_VALUE: dict[str, int] = {
|
|
"Normal": MOS_NORMAL,
|
|
"Charge Disabled": MOS_CHARGE_OFF,
|
|
"Discharge Disabled": MOS_DISCHARGE_OFF,
|
|
"Both Disabled": MOS_BOTH_OFF,
|
|
}
|
|
_OPTIONS = list(_OPTION_TO_VALUE)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
entry: ConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
) -> None:
|
|
coordinator: BmsCoordinator = hass.data[DOMAIN][entry.entry_id]
|
|
async_add_entities([BmsMosSelect(coordinator)])
|
|
|
|
|
|
class BmsMosSelect(CoordinatorEntity[BmsCoordinator], SelectEntity):
|
|
"""Dropdown to control the BMS charge/discharge MOSFET gates.
|
|
|
|
Current state is derived from the MOS status bits returned by the BMS
|
|
on every poll. Selecting an option sends the write command (0xE1)
|
|
immediately and triggers a coordinator refresh so sensors update.
|
|
"""
|
|
|
|
_attr_has_entity_name = True
|
|
_attr_name = "MOS Control"
|
|
_attr_options = _OPTIONS
|
|
_attr_icon = "mdi:electric-switch"
|
|
|
|
def __init__(self, coordinator: BmsCoordinator) -> None:
|
|
super().__init__(coordinator)
|
|
self._attr_unique_id = f"{coordinator.address}_mos_control"
|
|
self._attr_device_info = coordinator.device_info
|
|
|
|
@property
|
|
def current_option(self) -> str | None:
|
|
data = self.coordinator.data
|
|
if not data:
|
|
return None
|
|
charge = data.get("mos_charge_enabled", True)
|
|
discharge = data.get("mos_discharge_enabled", True)
|
|
if charge and discharge:
|
|
return "Normal"
|
|
if not charge and discharge:
|
|
return "Charge Disabled"
|
|
if charge and not discharge:
|
|
return "Discharge Disabled"
|
|
return "Both Disabled"
|
|
|
|
async def async_select_option(self, option: str) -> None:
|
|
value = _OPTION_TO_VALUE[option]
|
|
await self.coordinator.async_write_mos(value)
|