Fix some mobile app sensor registration/update issues (#86965)
Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
parent
f7fdaadde0
commit
e0f8b5bbd1
3 changed files with 107 additions and 21 deletions
|
@ -1,6 +1,7 @@
|
|||
"""Sensor platform for mobile_app."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date, datetime
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.sensor import RestoreSensor, SensorDeviceClass
|
||||
|
@ -10,6 +11,7 @@ from homeassistant.core import HomeAssistant, callback
|
|||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import (
|
||||
|
@ -99,7 +101,7 @@ class MobileAppSensor(MobileAppEntity, RestoreSensor):
|
|||
self._config[ATTR_SENSOR_UOM] = last_sensor_data.native_unit_of_measurement
|
||||
|
||||
@property
|
||||
def native_value(self):
|
||||
def native_value(self) -> StateType | date | datetime:
|
||||
"""Return the state of the sensor."""
|
||||
if (state := self._config[ATTR_SENSOR_STATE]) in (None, STATE_UNKNOWN):
|
||||
return None
|
||||
|
@ -122,7 +124,7 @@ class MobileAppSensor(MobileAppEntity, RestoreSensor):
|
|||
return state
|
||||
|
||||
@property
|
||||
def native_unit_of_measurement(self):
|
||||
def native_unit_of_measurement(self) -> str | None:
|
||||
"""Return the unit of measurement this sensor expresses itself in."""
|
||||
return self._config.get(ATTR_SENSOR_UOM)
|
||||
|
||||
|
|
|
@ -22,9 +22,7 @@ from homeassistant.components import (
|
|||
notify as hass_notify,
|
||||
tag,
|
||||
)
|
||||
from homeassistant.components.binary_sensor import (
|
||||
DEVICE_CLASSES as BINARY_SENSOR_CLASSES,
|
||||
)
|
||||
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
||||
from homeassistant.components.camera import CameraEntityFeature
|
||||
from homeassistant.components.device_tracker import (
|
||||
ATTR_BATTERY,
|
||||
|
@ -33,10 +31,7 @@ from homeassistant.components.device_tracker import (
|
|||
ATTR_LOCATION_NAME,
|
||||
)
|
||||
from homeassistant.components.frontend import MANIFEST_JSON
|
||||
from homeassistant.components.sensor import (
|
||||
DEVICE_CLASSES as SENSOR_CLASSES,
|
||||
STATE_CLASSES as SENSOSR_STATE_CLASSES,
|
||||
)
|
||||
from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass
|
||||
from homeassistant.components.zone import DOMAIN as ZONE_DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
|
@ -58,7 +53,7 @@ from homeassistant.helpers import (
|
|||
template,
|
||||
)
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.entity import ENTITY_CATEGORIES_SCHEMA
|
||||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.util.decorator import Registry
|
||||
|
||||
from .const import (
|
||||
|
@ -131,8 +126,7 @@ WEBHOOK_COMMANDS: Registry[
|
|||
str, Callable[[HomeAssistant, ConfigEntry, Any], Coroutine[Any, Any, Response]]
|
||||
] = Registry()
|
||||
|
||||
COMBINED_CLASSES = set(BINARY_SENSOR_CLASSES + SENSOR_CLASSES)
|
||||
SENSOR_TYPES = [ATTR_SENSOR_TYPE_BINARY_SENSOR, ATTR_SENSOR_TYPE_SENSOR]
|
||||
SENSOR_TYPES = (ATTR_SENSOR_TYPE_BINARY_SENSOR, ATTR_SENSOR_TYPE_SENSOR)
|
||||
|
||||
WEBHOOK_PAYLOAD_SCHEMA = vol.Schema(
|
||||
{
|
||||
|
@ -507,19 +501,27 @@ def _extract_sensor_unique_id(webhook_id: str, unique_id: str) -> str:
|
|||
vol.All(
|
||||
{
|
||||
vol.Optional(ATTR_SENSOR_ATTRIBUTES, default={}): dict,
|
||||
vol.Optional(ATTR_SENSOR_DEVICE_CLASS): vol.All(
|
||||
vol.Lower, vol.In(COMBINED_CLASSES)
|
||||
vol.Optional(ATTR_SENSOR_DEVICE_CLASS): vol.Any(
|
||||
None,
|
||||
vol.All(vol.Lower, vol.Coerce(BinarySensorDeviceClass)),
|
||||
vol.All(vol.Lower, vol.Coerce(SensorDeviceClass)),
|
||||
),
|
||||
vol.Required(ATTR_SENSOR_NAME): cv.string,
|
||||
vol.Required(ATTR_SENSOR_TYPE): vol.In(SENSOR_TYPES),
|
||||
vol.Required(ATTR_SENSOR_UNIQUE_ID): cv.string,
|
||||
vol.Optional(ATTR_SENSOR_UOM): cv.string,
|
||||
vol.Optional(ATTR_SENSOR_UOM): vol.Any(None, cv.string),
|
||||
vol.Optional(ATTR_SENSOR_STATE, default=None): vol.Any(
|
||||
None, bool, str, int, float
|
||||
None, bool, int, float, str
|
||||
),
|
||||
vol.Optional(ATTR_SENSOR_ENTITY_CATEGORY): vol.Any(
|
||||
None, vol.Coerce(EntityCategory)
|
||||
),
|
||||
vol.Optional(ATTR_SENSOR_ICON, default="mdi:cellphone"): vol.Any(
|
||||
None, cv.icon
|
||||
),
|
||||
vol.Optional(ATTR_SENSOR_STATE_CLASS): vol.Any(
|
||||
None, vol.Coerce(SensorStateClass)
|
||||
),
|
||||
vol.Optional(ATTR_SENSOR_ENTITY_CATEGORY): ENTITY_CATEGORIES_SCHEMA,
|
||||
vol.Optional(ATTR_SENSOR_ICON, default="mdi:cellphone"): cv.icon,
|
||||
vol.Optional(ATTR_SENSOR_STATE_CLASS): vol.In(SENSOSR_STATE_CLASSES),
|
||||
vol.Optional(ATTR_SENSOR_DISABLED): bool,
|
||||
},
|
||||
_validate_state_class_sensor,
|
||||
|
@ -619,8 +621,10 @@ async def webhook_update_sensor_states(
|
|||
sensor_schema_full = vol.Schema(
|
||||
{
|
||||
vol.Optional(ATTR_SENSOR_ATTRIBUTES, default={}): dict,
|
||||
vol.Optional(ATTR_SENSOR_ICON, default="mdi:cellphone"): cv.icon,
|
||||
vol.Required(ATTR_SENSOR_STATE): vol.Any(None, bool, str, int, float),
|
||||
vol.Optional(ATTR_SENSOR_ICON, default="mdi:cellphone"): vol.Any(
|
||||
None, cv.icon
|
||||
),
|
||||
vol.Required(ATTR_SENSOR_STATE): vol.Any(None, bool, int, float, str),
|
||||
vol.Required(ATTR_SENSOR_TYPE): vol.In(SENSOR_TYPES),
|
||||
vol.Required(ATTR_SENSOR_UNIQUE_ID): cv.string,
|
||||
}
|
||||
|
|
|
@ -979,6 +979,32 @@ async def test_reregister_sensor(hass, create_registrations, webhook_client):
|
|||
entry = ent_reg.async_get("sensor.test_1_battery_state")
|
||||
assert entry.disabled_by is None
|
||||
|
||||
reg_resp = await webhook_client.post(
|
||||
webhook_url,
|
||||
json={
|
||||
"type": "register_sensor",
|
||||
"data": {
|
||||
"name": "New Name 2",
|
||||
"state": 100,
|
||||
"type": "sensor",
|
||||
"unique_id": "abcd",
|
||||
"state_class": None,
|
||||
"device_class": None,
|
||||
"entity_category": None,
|
||||
"icon": None,
|
||||
"unit_of_measurement": None,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert reg_resp.status == HTTPStatus.CREATED
|
||||
entry = ent_reg.async_get("sensor.test_1_battery_state")
|
||||
assert entry.original_name == "Test 1 New Name 2"
|
||||
assert entry.device_class is None
|
||||
assert entry.unit_of_measurement is None
|
||||
assert entry.entity_category is None
|
||||
assert entry.original_icon is None
|
||||
|
||||
|
||||
async def test_webhook_handle_conversation_process(
|
||||
hass, create_registrations, webhook_client, mock_agent
|
||||
|
@ -1017,3 +1043,57 @@ async def test_webhook_handle_conversation_process(
|
|||
},
|
||||
"conversation_id": None,
|
||||
}
|
||||
|
||||
|
||||
async def test_sending_sensor_state(hass, create_registrations, webhook_client, caplog):
|
||||
"""Test that we can register and send sensor state as number and None."""
|
||||
webhook_id = create_registrations[1]["webhook_id"]
|
||||
webhook_url = f"/api/webhook/{webhook_id}"
|
||||
|
||||
reg_resp = await webhook_client.post(
|
||||
webhook_url,
|
||||
json={
|
||||
"type": "register_sensor",
|
||||
"data": {
|
||||
"name": "Battery State",
|
||||
"state": 100,
|
||||
"type": "sensor",
|
||||
"unique_id": "abcd",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert reg_resp.status == HTTPStatus.CREATED
|
||||
|
||||
ent_reg = er.async_get(hass)
|
||||
entry = ent_reg.async_get("sensor.test_1_battery_state")
|
||||
assert entry.original_name == "Test 1 Battery State"
|
||||
assert entry.device_class is None
|
||||
assert entry.unit_of_measurement is None
|
||||
assert entry.entity_category is None
|
||||
assert entry.original_icon == "mdi:cellphone"
|
||||
assert entry.disabled_by is None
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("sensor.test_1_battery_state")
|
||||
assert state is not None
|
||||
assert state.state == "100"
|
||||
|
||||
reg_resp = await webhook_client.post(
|
||||
webhook_url,
|
||||
json={
|
||||
"type": "update_sensor_states",
|
||||
"data": {
|
||||
"state": 50.0000,
|
||||
"type": "sensor",
|
||||
"unique_id": "abcd",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("sensor.test_1_battery_state")
|
||||
assert state is not None
|
||||
assert state.state == "50.0"
|
||||
|
|
Loading…
Add table
Reference in a new issue