From d587f134ca7d57bf2948c711fc9bd330aa48aa0c Mon Sep 17 00:00:00 2001
From: Daniel Shokouhi <dshokouhi@gmail.com>
Date: Fri, 28 Aug 2020 13:13:43 -0700
Subject: [PATCH] Reload mobile app notify service upon device name change, add
 device name to all webhook logs (#39364)

* Add device name to all webhook logs to help with multiple devices

* Reload notifications when we update the registration, update from rebase

* Make hassfest happy

* Adjust caplog test to accomodate log message change

Co-authored-by: J. Nick Koston <nick@koston.org>
---
 .../components/mobile_app/manifest.json       |  2 +-
 .../components/mobile_app/webhook.py          | 35 +++++++++++++------
 tests/components/mobile_app/test_entity.py    |  4 +--
 3 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/homeassistant/components/mobile_app/manifest.json b/homeassistant/components/mobile_app/manifest.json
index 732a2495311..758df70c3d0 100644
--- a/homeassistant/components/mobile_app/manifest.json
+++ b/homeassistant/components/mobile_app/manifest.json
@@ -5,7 +5,7 @@
   "documentation": "https://www.home-assistant.io/integrations/mobile_app",
   "requirements": ["PyNaCl==1.3.0", "emoji==0.5.4"],
   "dependencies": ["http", "webhook", "person", "tag"],
-  "after_dependencies": ["cloud", "camera"],
+  "after_dependencies": ["cloud", "camera", "notify"],
   "codeowners": ["@robbiet480"],
   "quality_scale": "internal"
 }
diff --git a/homeassistant/components/mobile_app/webhook.py b/homeassistant/components/mobile_app/webhook.py
index 9d614664a62..2f5e69fd02b 100644
--- a/homeassistant/components/mobile_app/webhook.py
+++ b/homeassistant/components/mobile_app/webhook.py
@@ -8,7 +8,7 @@ from aiohttp.web import HTTPBadRequest, Request, Response, json_response
 from nacl.secret import SecretBox
 import voluptuous as vol
 
-from homeassistant.components import tag
+from homeassistant.components import notify as hass_notify, tag
 from homeassistant.components.binary_sensor import (
     DEVICE_CLASSES as BINARY_SENSOR_CLASSES,
 )
@@ -149,10 +149,12 @@ async def handle_webhook(
 
     config_entry = hass.data[DOMAIN][DATA_CONFIG_ENTRIES][webhook_id]
 
+    device_name = config_entry.data[ATTR_DEVICE_NAME]
+
     try:
         req_data = await request.json()
     except ValueError:
-        _LOGGER.warning("Received invalid JSON from mobile_app")
+        _LOGGER.warning("Received invalid JSON from mobile_app device: %s", device_name)
         return empty_okay_response(status=HTTP_BAD_REQUEST)
 
     if (
@@ -161,7 +163,7 @@ async def handle_webhook(
     ):
         _LOGGER.warning(
             "Refusing to accept unencrypted webhook from %s",
-            config_entry.data[ATTR_DEVICE_NAME],
+            device_name,
         )
         return error_response(ERR_ENCRYPTION_REQUIRED, "Encryption required")
 
@@ -169,7 +171,9 @@ async def handle_webhook(
         req_data = WEBHOOK_PAYLOAD_SCHEMA(req_data)
     except vol.Invalid as ex:
         err = vol.humanize.humanize_error(req_data, ex)
-        _LOGGER.error("Received invalid webhook payload: %s", err)
+        _LOGGER.error(
+            "Received invalid webhook from %s with payload: %s", device_name, err
+        )
         return empty_okay_response()
 
     webhook_type = req_data[ATTR_WEBHOOK_TYPE]
@@ -181,11 +185,11 @@ async def handle_webhook(
         webhook_payload = _decrypt_payload(config_entry.data[CONF_SECRET], enc_data)
 
     if webhook_type not in WEBHOOK_COMMANDS:
-        _LOGGER.error("Received invalid webhook type: %s", webhook_type)
+        _LOGGER.error(
+            "Received invalid webhook from %s of type: %s", device_name, webhook_type
+        )
         return empty_okay_response()
 
-    device_name = config_entry.data[ATTR_DEVICE_NAME]
-
     _LOGGER.debug(
         "Received webhook payload from %s for type %s: %s",
         device_name,
@@ -348,6 +352,8 @@ async def webhook_update_registration(hass, config_entry, data):
 
     hass.config_entries.async_update_entry(config_entry, data=new_registration)
 
+    await hass_notify.async_reload(hass, DOMAIN)
+
     return webhook_response(
         safe_registration(new_registration),
         registration=new_registration,
@@ -403,6 +409,7 @@ 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]
+    device_name = config_entry.data[ATTR_DEVICE_NAME]
 
     unique_store_key = f"{config_entry.data[CONF_WEBHOOK_ID]}_{unique_id}"
     existing_sensor = unique_store_key in hass.data[DOMAIN][entity_type]
@@ -411,7 +418,9 @@ async def webhook_register_sensor(hass, config_entry, data):
 
     # If sensor already is registered, update current state instead
     if existing_sensor:
-        _LOGGER.debug("Re-register existing sensor %s", unique_id)
+        _LOGGER.debug(
+            "Re-register for %s of existing sensor %s", device_name, unique_id
+        )
         entry = hass.data[DOMAIN][entity_type][unique_store_key]
         data = {**entry, **data}
 
@@ -464,6 +473,7 @@ async def webhook_update_sensor_states(hass, config_entry, data):
         }
     )
 
+    device_name = config_entry.data[ATTR_DEVICE_NAME]
     resp = {}
     for sensor in data:
         entity_type = sensor[ATTR_SENSOR_TYPE]
@@ -474,7 +484,9 @@ async def webhook_update_sensor_states(hass, config_entry, data):
 
         if unique_store_key not in hass.data[DOMAIN][entity_type]:
             _LOGGER.error(
-                "Refusing to update non-registered sensor: %s", unique_store_key
+                "Refusing to update %s non-registered sensor: %s",
+                device_name,
+                unique_store_key,
             )
             err_msg = f"{entity_type} {unique_id} is not registered"
             resp[unique_id] = {
@@ -490,7 +502,10 @@ async def webhook_update_sensor_states(hass, config_entry, data):
         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
+                "Received invalid sensor payload from %s for %s: %s",
+                device_name,
+                unique_id,
+                err_msg,
             )
             resp[unique_id] = {
                 "success": False,
diff --git a/tests/components/mobile_app/test_entity.py b/tests/components/mobile_app/test_entity.py
index fd5baf50beb..df1493c084e 100644
--- a/tests/components/mobile_app/test_entity.py
+++ b/tests/components/mobile_app/test_entity.py
@@ -122,7 +122,7 @@ async def test_sensor_id_no_dupes(hass, create_registrations, webhook_client, ca
     assert reg_json == {"success": True}
     await hass.async_block_till_done()
 
-    assert "Re-register existing sensor" not in caplog.text
+    assert "Re-register" not in caplog.text
 
     entity = hass.states.get("sensor.test_1_battery_state")
     assert entity is not None
@@ -143,7 +143,7 @@ async def test_sensor_id_no_dupes(hass, create_registrations, webhook_client, ca
     assert dupe_reg_json == {"success": True}
     await hass.async_block_till_done()
 
-    assert "Re-register existing sensor" in caplog.text
+    assert "Re-register" in caplog.text
 
     entity = hass.states.get("sensor.test_1_battery_state")
     assert entity is not None