Add missing sensors for Shelly Plus H&T (#76001)

* Add missing sensors for Shelly Plus H&T

* Cleanup

* Fix

* Add voltage to battery sensor

* Apply review comments
This commit is contained in:
Simone Chemelli 2022-08-01 09:52:51 +02:00 committed by GitHub
parent 5bb5920697
commit 0738f08215
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 7 deletions

View file

@ -190,9 +190,9 @@ def async_setup_entry_rpc(
] and not description.supported(wrapper.device.status[key]): ] and not description.supported(wrapper.device.status[key]):
continue continue
# Filter and remove entities that according to settings should not create an entity # Filter and remove entities that according to settings/status should not create an entity
if description.removal_condition and description.removal_condition( if description.removal_condition and description.removal_condition(
wrapper.device.config, key wrapper.device.config, wrapper.device.status, key
): ):
domain = sensor_class.__module__.split(".")[-1] domain = sensor_class.__module__.split(".")[-1]
unique_id = f"{wrapper.mac}-{key}-{sensor_id}" unique_id = f"{wrapper.mac}-{key}-{sensor_id}"
@ -268,7 +268,7 @@ class RpcEntityDescription(EntityDescription, RpcEntityRequiredKeysMixin):
value: Callable[[Any, Any], Any] | None = None value: Callable[[Any, Any], Any] | None = None
available: Callable[[dict], bool] | None = None available: Callable[[dict], bool] | None = None
removal_condition: Callable[[dict, str], bool] | None = None removal_condition: Callable[[dict, dict, str], bool] | None = None
extra_state_attributes: Callable[[dict, dict], dict | None] | None = None extra_state_attributes: Callable[[dict, dict], dict | None] | None = None
use_polling_wrapper: bool = False use_polling_wrapper: bool = False
supported: Callable = lambda _: False supported: Callable = lambda _: False

View file

@ -46,7 +46,12 @@ from .entity import (
async_setup_entry_rest, async_setup_entry_rest,
async_setup_entry_rpc, async_setup_entry_rpc,
) )
from .utils import get_device_entry_gen, get_device_uptime, temperature_unit from .utils import (
get_device_entry_gen,
get_device_uptime,
is_rpc_device_externally_powered,
temperature_unit,
)
@dataclass @dataclass
@ -352,6 +357,15 @@ RPC_SENSORS: Final = {
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
use_polling_wrapper=True, use_polling_wrapper=True,
), ),
"temperature_0": RpcSensorDescription(
key="temperature:0",
sub_key="tC",
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=True,
),
"rssi": RpcSensorDescription( "rssi": RpcSensorDescription(
key="wifi", key="wifi",
sub_key="rssi", sub_key="rssi",
@ -373,6 +387,27 @@ RPC_SENSORS: Final = {
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
use_polling_wrapper=True, use_polling_wrapper=True,
), ),
"humidity_0": RpcSensorDescription(
key="humidity:0",
sub_key="rh",
name="Humidity",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=True,
),
"battery": RpcSensorDescription(
key="devicepower:0",
sub_key="battery",
name="Battery",
native_unit_of_measurement=PERCENTAGE,
value=lambda status, _: status["percent"],
device_class=SensorDeviceClass.BATTERY,
state_class=SensorStateClass.MEASUREMENT,
removal_condition=is_rpc_device_externally_powered,
entity_registry_enabled_default=True,
entity_category=EntityCategory.DIAGNOSTIC,
),
} }

View file

@ -271,7 +271,9 @@ def get_rpc_channel_name(device: RpcDevice, key: str) -> str:
entity_name = device.config[key].get("name", device_name) entity_name = device.config[key].get("name", device_name)
if entity_name is None: if entity_name is None:
return f"{device_name} {key.replace(':', '_')}" if [k for k in key if k.startswith(("input", "switch"))]:
return f"{device_name} {key.replace(':', '_')}"
return device_name
return entity_name return entity_name
@ -325,7 +327,9 @@ def get_rpc_key_ids(keys_dict: dict[str, Any], key: str) -> list[int]:
return key_ids return key_ids
def is_rpc_momentary_input(config: dict[str, Any], key: str) -> bool: def is_rpc_momentary_input(
config: dict[str, Any], status: dict[str, Any], key: str
) -> bool:
"""Return true if rpc input button settings is set to a momentary type.""" """Return true if rpc input button settings is set to a momentary type."""
return cast(bool, config[key]["type"] == "button") return cast(bool, config[key]["type"] == "button")
@ -342,6 +346,13 @@ def is_rpc_channel_type_light(config: dict[str, Any], channel: int) -> bool:
return con_types is not None and con_types[channel].lower().startswith("light") return con_types is not None and con_types[channel].lower().startswith("light")
def is_rpc_device_externally_powered(
config: dict[str, Any], status: dict[str, Any], key: str
) -> bool:
"""Return true if device has external power instead of battery."""
return cast(bool, status[key]["external"]["present"])
def get_rpc_input_triggers(device: RpcDevice) -> list[tuple[str, str]]: def get_rpc_input_triggers(device: RpcDevice) -> list[tuple[str, str]]:
"""Return list of input triggers for RPC device.""" """Return list of input triggers for RPC device."""
triggers = [] triggers = []
@ -350,7 +361,7 @@ def get_rpc_input_triggers(device: RpcDevice) -> list[tuple[str, str]]:
for id_ in key_ids: for id_ in key_ids:
key = f"input:{id_}" key = f"input:{id_}"
if not is_rpc_momentary_input(device.config, key): if not is_rpc_momentary_input(device.config, device.status, key):
continue continue
for trigger_type in RPC_INPUTS_EVENTS_TYPES: for trigger_type in RPC_INPUTS_EVENTS_TYPES: