Skip to content

Commit

Permalink
Add partial mobile app sensor validation (#36433)
Browse files Browse the repository at this point in the history
  • Loading branch information
balloob committed Jun 5, 2020
1 parent 7194b74 commit 0a779ac
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 5 deletions.
1 change: 1 addition & 0 deletions homeassistant/components/mobile_app/const.py
Expand Up @@ -57,6 +57,7 @@
ERR_ENCRYPTION_REQUIRED = "encryption_required"
ERR_SENSOR_NOT_REGISTERED = "not_registered"
ERR_SENSOR_DUPLICATE_UNIQUE_ID = "duplicate_unique_id"
ERR_INVALID_FORMAT = "invalid_format"


ATTR_SENSOR_ATTRIBUTES = "attributes"
Expand Down
33 changes: 29 additions & 4 deletions homeassistant/components/mobile_app/webhook.py
Expand Up @@ -76,6 +76,7 @@
ERR_ENCRYPTION_ALREADY_ENABLED,
ERR_ENCRYPTION_NOT_AVAILABLE,
ERR_ENCRYPTION_REQUIRED,
ERR_INVALID_FORMAT,
ERR_SENSOR_DUPLICATE_UNIQUE_ID,
ERR_SENSOR_NOT_REGISTERED,
SIGNAL_LOCATION_UPDATE,
Expand Down Expand Up @@ -394,20 +395,31 @@ async def webhook_register_sensor(hass, config_entry, data):
vol.All(
cv.ensure_list,
[
# Partial schema, enough to identify schema.
# We don't validate everything because otherwise 1 invalid sensor
# will invalidate all sensors.
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(bool, str, int, float),
vol.Required(ATTR_SENSOR_TYPE): vol.In(SENSOR_TYPES),
vol.Required(ATTR_SENSOR_UNIQUE_ID): cv.string,
}
},
extra=vol.ALLOW_EXTRA,
)
],
)
)
async def webhook_update_sensor_states(hass, config_entry, data):
"""Handle an update sensor states webhook."""
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(bool, str, int, float),
vol.Required(ATTR_SENSOR_TYPE): vol.In(SENSOR_TYPES),
vol.Required(ATTR_SENSOR_UNIQUE_ID): cv.string,
}
)

resp = {}
for sensor in data:
entity_type = sensor[ATTR_SENSOR_TYPE]
Expand All @@ -429,6 +441,19 @@ async def webhook_update_sensor_states(hass, config_entry, data):

entry = hass.data[DOMAIN][entity_type][unique_store_key]

try:
sensor = sensor_schema_full(sensor)
except vol.Invalid as err:
err_msg = vol.humanize.humanize_error(sensor, err)
_LOGGER.error(
"Received invalid sensor payload for %s: %s", unique_id, err_msg
)
resp[unique_id] = {
"success": False,
"error": {"code": ERR_INVALID_FORMAT, "message": err_msg},
}
continue

new_state = {**entry, **sensor}

hass.data[DOMAIN][entity_type][unique_store_key] = new_state
Expand Down
7 changes: 6 additions & 1 deletion tests/components/mobile_app/test_entity.py
Expand Up @@ -57,13 +57,18 @@ async def test_sensor(hass, create_registrations, webhook_client):
"state": 123,
"type": "sensor",
"unique_id": "battery_state",
}
},
# This invalid data should not invalidate whole request
{"type": "sensor", "unique_id": "invalid_state", "invalid": "data"},
],
},
)

assert update_resp.status == 200

json = await update_resp.json()
assert json["invalid_state"]["success"] is False

updated_entity = hass.states.get("sensor.test_1_battery_state")
assert updated_entity.state == "123"

Expand Down

0 comments on commit 0a779ac

Please sign in to comment.