Fix mobile_app sensor re-registration handling (#36567)

This commit is contained in:
Franck Nijhof 2020-06-08 21:11:37 +02:00 committed by Paulus Schoutsen
parent a84378bb79
commit b3d5717df8
3 changed files with 45 additions and 19 deletions

View File

@ -56,7 +56,6 @@ ERR_ENCRYPTION_ALREADY_ENABLED = "encryption_already_enabled"
ERR_ENCRYPTION_NOT_AVAILABLE = "encryption_not_available"
ERR_ENCRYPTION_REQUIRED = "encryption_required"
ERR_SENSOR_NOT_REGISTERED = "not_registered"
ERR_SENSOR_DUPLICATE_UNIQUE_ID = "duplicate_unique_id"
ERR_INVALID_FORMAT = "invalid_format"

View File

@ -78,7 +78,6 @@ from .const import (
ERR_ENCRYPTION_NOT_AVAILABLE,
ERR_ENCRYPTION_REQUIRED,
ERR_INVALID_FORMAT,
ERR_SENSOR_DUPLICATE_UNIQUE_ID,
ERR_SENSOR_NOT_REGISTERED,
SIGNAL_LOCATION_UPDATE,
SIGNAL_SENSOR_UPDATE,
@ -364,29 +363,30 @@ async def webhook_enable_encryption(hass, config_entry, data):
async def webhook_register_sensor(hass, config_entry, data):
"""Handle a register sensor webhook."""
entity_type = data[ATTR_SENSOR_TYPE]
unique_id = data[ATTR_SENSOR_UNIQUE_ID]
unique_store_key = f"{config_entry.data[CONF_WEBHOOK_ID]}_{unique_id}"
if unique_store_key in hass.data[DOMAIN][entity_type]:
_LOGGER.error("Refusing to re-register existing sensor %s!", unique_id)
return error_response(
ERR_SENSOR_DUPLICATE_UNIQUE_ID,
f"{entity_type} {unique_id} already exists!",
status=409,
)
existing_sensor = unique_store_key in hass.data[DOMAIN][entity_type]
data[CONF_WEBHOOK_ID] = config_entry.data[CONF_WEBHOOK_ID]
# If sensor already is registered, update current state instead
if existing_sensor:
_LOGGER.debug("Re-register existing sensor %s", unique_id)
entry = hass.data[DOMAIN][entity_type][unique_store_key]
data = {**entry, **data}
hass.data[DOMAIN][entity_type][unique_store_key] = data
hass.data[DOMAIN][DATA_STORE].async_delay_save(
lambda: savable_state(hass), DELAY_SAVE
)
register_signal = f"{DOMAIN}_{data[ATTR_SENSOR_TYPE]}_register"
async_dispatcher_send(hass, register_signal, data)
if existing_sensor:
async_dispatcher_send(hass, SIGNAL_SENSOR_UPDATE, data)
else:
register_signal = f"{DOMAIN}_{data[ATTR_SENSOR_TYPE]}_register"
async_dispatcher_send(hass, register_signal, data)
return webhook_response(
{"success": True}, registration=config_entry.data, status=HTTP_CREATED,

View File

@ -95,8 +95,8 @@ async def test_sensor_must_register(hass, create_registrations, webhook_client):
assert json["battery_state"]["error"]["code"] == "not_registered"
async def test_sensor_id_no_dupes(hass, create_registrations, webhook_client):
"""Test that sensors must have a unique ID."""
async def test_sensor_id_no_dupes(hass, create_registrations, webhook_client, caplog):
"""Test that a duplicate unique ID in registration updates the sensor."""
webhook_id = create_registrations[1]["webhook_id"]
webhook_url = f"/api/webhook/{webhook_id}"
@ -120,14 +120,41 @@ async def test_sensor_id_no_dupes(hass, create_registrations, webhook_client):
reg_json = await reg_resp.json()
assert reg_json == {"success": True}
await hass.async_block_till_done()
assert "Re-register existing sensor" not in caplog.text
entity = hass.states.get("sensor.test_1_battery_state")
assert entity is not None
assert entity.attributes["device_class"] == "battery"
assert entity.attributes["icon"] == "mdi:battery"
assert entity.attributes["unit_of_measurement"] == UNIT_PERCENTAGE
assert entity.attributes["foo"] == "bar"
assert entity.domain == "sensor"
assert entity.name == "Test 1 Battery State"
assert entity.state == "100"
payload["data"]["state"] = 99
dupe_resp = await webhook_client.post(webhook_url, json=payload)
assert dupe_resp.status == 409
assert dupe_resp.status == 201
dupe_reg_json = await dupe_resp.json()
assert dupe_reg_json == {"success": True}
await hass.async_block_till_done()
dupe_json = await dupe_resp.json()
assert dupe_json["success"] is False
assert dupe_json["error"]["code"] == "duplicate_unique_id"
assert "Re-register existing sensor" in caplog.text
entity = hass.states.get("sensor.test_1_battery_state")
assert entity is not None
assert entity.attributes["device_class"] == "battery"
assert entity.attributes["icon"] == "mdi:battery"
assert entity.attributes["unit_of_measurement"] == UNIT_PERCENTAGE
assert entity.attributes["foo"] == "bar"
assert entity.domain == "sensor"
assert entity.name == "Test 1 Battery State"
assert entity.state == "99"
async def test_register_sensor_no_state(hass, create_registrations, webhook_client):