From ac6dcf0765f4659b01f05df160d8d5c0782e067d Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Fri, 20 Mar 2020 00:18:18 +0100 Subject: [PATCH 01/18] Update translations --- ...e5b64-20e4-42bd-b86b-989b84afc22a-en_US.ts | 6 +- ...61c33-d44e-461e-8ec1-68803cb73f12-de_DE.ts | 2 +- ...61c33-d44e-461e-8ec1-68803cb73f12-en_US.ts | 2 +- ...7b796-4872-4eab-a7af-94ca9ddd8199-de_DE.ts | 2 +- ...7b796-4872-4eab-a7af-94ca9ddd8199-en_US.ts | 2 +- ...d63a7-fc39-4a50-a459-457fa7653089-en_US.ts | 10 +- ...58269-dbbb-4ef0-80ab-48bd9a8a2765-de_DE.ts | 2 +- ...58269-dbbb-4ef0-80ab-48bd9a8a2765-en_US.ts | 2 +- ...4c43c-9680-48d8-852a-93b2227139b9-de_DE.ts | 16 +-- ...4c43c-9680-48d8-852a-93b2227139b9-en_US.ts | 16 +-- ...74e2106a-3407-4e89-a27a-1c890d78bee7-de.ts | 8 +- ...2106a-3407-4e89-a27a-1c890d78bee7-en_US.ts | 2 +- ...ead55-996a-44ac-ba82-fc3c634e018a-de_DE.ts | 100 +++++++++--------- ...ead55-996a-44ac-ba82-fc3c634e018a-en_US.ts | 100 +++++++++--------- ...2670c-6268-4487-8dff-cccca498731a-en_US.ts | 16 +-- ...8d934-0397-42c1-ad63-9141bcac8563-de_DE.ts | 2 +- ...8d934-0397-42c1-ad63-9141bcac8563-en_US.ts | 2 +- ...2b09f-30a9-43d0-9ede-2f8debe075ac-en_US.ts | 2 +- ...86890-99fa-4c5b-8247-09c6d450d490-de_DE.ts | 2 +- ...86890-99fa-4c5b-8247-09c6d450d490-en_US.ts | 2 +- ...d23e6-fad8-4203-aeab-2e6e5c756990-de_DE.ts | 2 +- ...d23e6-fad8-4203-aeab-2e6e5c756990-en_US.ts | 2 +- ...7a68b-9da0-4c62-b9ac-f478dc6f9f52-de_DE.ts | 2 +- ...7a68b-9da0-4c62-b9ac-f478dc6f9f52-en_US.ts | 2 +- ...35df1-1b51-4c93-94fa-3febc77e0318-de_DE.ts | 2 +- ...35df1-1b51-4c93-94fa-3febc77e0318-en_US.ts | 2 +- ...867ec-1594-498d-8182-fbab1fe17489-en_US.ts | 2 +- ...69d14951-0c02-4877-bcef-dffdf48b7ccb-cs.ts | 2 +- ...69d14951-0c02-4877-bcef-dffdf48b7ccb-da.ts | 2 +- ...14951-0c02-4877-bcef-dffdf48b7ccb-de_DE.ts | 2 +- ...14951-0c02-4877-bcef-dffdf48b7ccb-en_US.ts | 2 +- ...69d14951-0c02-4877-bcef-dffdf48b7ccb-es.ts | 2 +- ...69d14951-0c02-4877-bcef-dffdf48b7ccb-fr.ts | 2 +- ...69d14951-0c02-4877-bcef-dffdf48b7ccb-it.ts | 2 +- ...69d14951-0c02-4877-bcef-dffdf48b7ccb-nl.ts | 2 +- ...69d14951-0c02-4877-bcef-dffdf48b7ccb-pt.ts | 2 +- ...e5806d75-a40e-4766-a272-5a3a8d3ed625-cs.ts | 10 +- ...e5806d75-a40e-4766-a272-5a3a8d3ed625-da.ts | 10 +- ...e5806d75-a40e-4766-a272-5a3a8d3ed625-de.ts | 10 +- ...06d75-a40e-4766-a272-5a3a8d3ed625-en_US.ts | 6 +- ...e5806d75-a40e-4766-a272-5a3a8d3ed625-es.ts | 10 +- ...e5806d75-a40e-4766-a272-5a3a8d3ed625-fr.ts | 10 +- ...e5806d75-a40e-4766-a272-5a3a8d3ed625-it.ts | 10 +- ...e5806d75-a40e-4766-a272-5a3a8d3ed625-nl.ts | 10 +- ...e5806d75-a40e-4766-a272-5a3a8d3ed625-pt.ts | 10 +- ...97fb7-0645-466d-9cb9-aa1922c85bee-en_US.ts | 2 +- ...d9cc8-77df-4197-a6fc-8a365747a3b1-en_US.ts | 2 +- ...af567-2338-41d5-aac1-462dec6e4783-de_DE.ts | 2 +- ...af567-2338-41d5-aac1-462dec6e4783-en_US.ts | 2 +- ...27596-e266-4a23-8634-7311b2c5fe32-de_DE.ts | 2 +- ...27596-e266-4a23-8634-7311b2c5fe32-en_US.ts | 2 +- ...5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-cs.ts | 2 +- ...5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-da.ts | 2 +- ...e634b-b7f3-48ee-976a-b5ae22aa5c55-de_DE.ts | 20 ++-- ...e634b-b7f3-48ee-976a-b5ae22aa5c55-en_US.ts | 2 +- ...5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-es.ts | 2 +- ...5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-fr.ts | 2 +- ...5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-it.ts | 2 +- ...5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-nl.ts | 2 +- ...5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-pt.ts | 2 +- ...46986575-0e62-483d-b5a8-76ac356fcce7-cs.ts | 18 ++-- ...46986575-0e62-483d-b5a8-76ac356fcce7-da.ts | 18 ++-- ...86575-0e62-483d-b5a8-76ac356fcce7-de_DE.ts | 18 ++-- ...86575-0e62-483d-b5a8-76ac356fcce7-en_US.ts | 18 ++-- ...46986575-0e62-483d-b5a8-76ac356fcce7-es.ts | 18 ++-- ...46986575-0e62-483d-b5a8-76ac356fcce7-fr.ts | 18 ++-- ...46986575-0e62-483d-b5a8-76ac356fcce7-it.ts | 18 ++-- ...46986575-0e62-483d-b5a8-76ac356fcce7-nl.ts | 18 ++-- ...46986575-0e62-483d-b5a8-76ac356fcce7-pt.ts | 18 ++-- ...413e9d77-335f-4ecf-abbc-8f2a8a399c39-cs.ts | 2 +- ...413e9d77-335f-4ecf-abbc-8f2a8a399c39-da.ts | 2 +- ...e9d77-335f-4ecf-abbc-8f2a8a399c39-de_DE.ts | 2 +- ...e9d77-335f-4ecf-abbc-8f2a8a399c39-en_US.ts | 2 +- ...413e9d77-335f-4ecf-abbc-8f2a8a399c39-es.ts | 2 +- ...413e9d77-335f-4ecf-abbc-8f2a8a399c39-fr.ts | 2 +- ...413e9d77-335f-4ecf-abbc-8f2a8a399c39-it.ts | 2 +- ...413e9d77-335f-4ecf-abbc-8f2a8a399c39-nl.ts | 2 +- ...413e9d77-335f-4ecf-abbc-8f2a8a399c39-pt.ts | 2 +- ...3a12e-36f4-4015-8019-26b659817773-en_US.ts | 2 +- ...2773b-0435-408c-a4f8-7860d38031a9-en_US.ts | 2 +- ...68429-e312-4c82-9eab-e1cd996e43d6-en_US.ts | 2 +- ...07719-c445-4fa5-9c7a-564ee02a4412-en_US.ts | 2 +- ...2d2ee-50bb-4786-b7f5-261fed204fa5-en_US.ts | 2 +- ...6e0c0-0cbf-4731-aabb-b2201088d6cb-en_US.ts | 2 +- ...b7b0a-0c9c-4c93-be99-0d0bcf5a4643-de_DE.ts | 2 +- ...b7b0a-0c9c-4c93-be99-0d0bcf5a4643-en_US.ts | 2 +- ...50a91-e734-4331-9d71-9f37df0b0fa6-en_US.ts | 2 +- ...024ff2e3-30df-44a1-9c8d-63cc416f1fb8-de.ts | 10 +- ...ff2e3-30df-44a1-9c8d-63cc416f1fb8-en_US.ts | 2 +- ...643b3-22ec-4a36-9808-e8b1405b01c9-en_US.ts | 2 +- ...8474c-1d86-499e-a76e-9cbfbf48dd72-de_DE.ts | 2 +- ...8474c-1d86-499e-a76e-9cbfbf48dd72-en_US.ts | 2 +- ...c00c7-9ea8-4aa6-8aec-831639e8fccc-en_US.ts | 2 +- ...ca391-f8bf-4f6c-a205-6764de3c2c3c-de_DE.ts | 2 +- ...ca391-f8bf-4f6c-a205-6764de3c2c3c-en_US.ts | 2 +- ...035d3-561c-498e-bdb2-2b574cbd0a2f-en_US.ts | 2 +- ...b5ce0-ecf1-43de-98f0-07df4068a583-de_DE.ts | 2 +- ...b5ce0-ecf1-43de-98f0-07df4068a583-en_US.ts | 2 +- ...c8ca5-4ef7-47a3-bf3f-c257b9f11ef0-en_US.ts | 2 +- 99 files changed, 346 insertions(+), 346 deletions(-) diff --git a/anel/translations/7a3e5b64-20e4-42bd-b86b-989b84afc22a-en_US.ts b/anel/translations/7a3e5b64-20e4-42bd-b86b-989b84afc22a-en_US.ts index a42bddbb..f138d009 100644 --- a/anel/translations/7a3e5b64-20e4-42bd-b86b-989b84afc22a-en_US.ts +++ b/anel/translations/7a3e5b64-20e4-42bd-b86b-989b84afc22a-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginAnel + IntegrationPluginAnel Error sending data to the network. Error discovering devices @@ -18,12 +18,12 @@ - Unexpected data received from NET-PWRCTL device. Perhaps it's running an old firmware? + The thing rejected our connection. Please check the configured network ports. Error setting up thing - The thing rejected our connection. Please check the configured network ports. + Unexpected data received from NET-PWRCTL device. Perhaps it's running an old firmware? Error setting up thing diff --git a/awattar/translations/9c261c33-d44e-461e-8ec1-68803cb73f12-de_DE.ts b/awattar/translations/9c261c33-d44e-461e-8ec1-68803cb73f12-de_DE.ts index dced9e6e..bc35467e 100644 --- a/awattar/translations/9c261c33-d44e-461e-8ec1-68803cb73f12-de_DE.ts +++ b/awattar/translations/9c261c33-d44e-461e-8ec1-68803cb73f12-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginAwattar + IntegrationPluginAwattar Please enter your token for awattar.com diff --git a/awattar/translations/9c261c33-d44e-461e-8ec1-68803cb73f12-en_US.ts b/awattar/translations/9c261c33-d44e-461e-8ec1-68803cb73f12-en_US.ts index db700ee2..a5166a58 100644 --- a/awattar/translations/9c261c33-d44e-461e-8ec1-68803cb73f12-en_US.ts +++ b/awattar/translations/9c261c33-d44e-461e-8ec1-68803cb73f12-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginAwattar + IntegrationPluginAwattar Please enter your token for awattar.com diff --git a/commandlauncher/translations/5d37b796-4872-4eab-a7af-94ca9ddd8199-de_DE.ts b/commandlauncher/translations/5d37b796-4872-4eab-a7af-94ca9ddd8199-de_DE.ts index fb499ebc..f52b3a9c 100644 --- a/commandlauncher/translations/5d37b796-4872-4eab-a7af-94ca9ddd8199-de_DE.ts +++ b/commandlauncher/translations/5d37b796-4872-4eab-a7af-94ca9ddd8199-de_DE.ts @@ -86,7 +86,7 @@ The name of the StateType ({f52eb984-432c-43b6-88f1-15edb026725f}) of ThingClass - DevicePluginCommandLauncher + IntegrattionPluginCommandLauncher The script "%1" does not exist. diff --git a/commandlauncher/translations/5d37b796-4872-4eab-a7af-94ca9ddd8199-en_US.ts b/commandlauncher/translations/5d37b796-4872-4eab-a7af-94ca9ddd8199-en_US.ts index 90ee537f..993aaf87 100644 --- a/commandlauncher/translations/5d37b796-4872-4eab-a7af-94ca9ddd8199-en_US.ts +++ b/commandlauncher/translations/5d37b796-4872-4eab-a7af-94ca9ddd8199-en_US.ts @@ -86,7 +86,7 @@ The name of the StateType ({f52eb984-432c-43b6-88f1-15edb026725f}) of ThingClass - DevicePluginCommandLauncher + IntegrattionPluginCommandLauncher The script "%1" does not exist. diff --git a/daylightsensor/translations/4b7d63a7-fc39-4a50-a459-457fa7653089-en_US.ts b/daylightsensor/translations/4b7d63a7-fc39-4a50-a459-457fa7653089-en_US.ts index de438e32..99ae216e 100644 --- a/daylightsensor/translations/4b7d63a7-fc39-4a50-a459-457fa7653089-en_US.ts +++ b/daylightsensor/translations/4b7d63a7-fc39-4a50-a459-457fa7653089-en_US.ts @@ -2,11 +2,7 @@ - DevicePluginDaylightSensor - - Daylight sensor - - + IntegrationPluginDaylightSensor Failed to fetch data from the internet. @@ -15,6 +11,10 @@ The server returned unexpected data. + + Daylight sensor + + daylightSensor diff --git a/denon/translations/cd758269-dbbb-4ef0-80ab-48bd9a8a2765-de_DE.ts b/denon/translations/cd758269-dbbb-4ef0-80ab-48bd9a8a2765-de_DE.ts index cc15324b..5ff05f4e 100644 --- a/denon/translations/cd758269-dbbb-4ef0-80ab-48bd9a8a2765-de_DE.ts +++ b/denon/translations/cd758269-dbbb-4ef0-80ab-48bd9a8a2765-de_DE.ts @@ -482,7 +482,7 @@ The name of the ActionType ({773636b9-304d-463a-8755-fc7488dc0ff3}) of ThingClas - DevicePluginDenon + IntegrationPluginDenon Device discovery is not available. diff --git a/denon/translations/cd758269-dbbb-4ef0-80ab-48bd9a8a2765-en_US.ts b/denon/translations/cd758269-dbbb-4ef0-80ab-48bd9a8a2765-en_US.ts index f92eb3b5..11b8a151 100644 --- a/denon/translations/cd758269-dbbb-4ef0-80ab-48bd9a8a2765-en_US.ts +++ b/denon/translations/cd758269-dbbb-4ef0-80ab-48bd9a8a2765-en_US.ts @@ -482,7 +482,7 @@ The name of the ActionType ({773636b9-304d-463a-8755-fc7488dc0ff3}) of ThingClas - DevicePluginDenon + IntegrationPluginDenon Device discovery is not available. diff --git a/eq-3/translations/f324c43c-9680-48d8-852a-93b2227139b9-de_DE.ts b/eq-3/translations/f324c43c-9680-48d8-852a-93b2227139b9-de_DE.ts index df03cb8c..d8963c5e 100644 --- a/eq-3/translations/f324c43c-9680-48d8-852a-93b2227139b9-de_DE.ts +++ b/eq-3/translations/f324c43c-9680-48d8-852a-93b2227139b9-de_DE.ts @@ -1,14 +1,6 @@ - - DevicePluginEQ3 - - - Bluetooth discovery failed. Is Bluetooth available and enabled? - - - EQ3 @@ -912,4 +904,12 @@ The name of the StateType ({ffaff87b-b741-4db8-9875-3380af4f1885}) of ThingClass + + IntegrationPluginEQ3 + + + Bluetooth discovery failed. Is Bluetooth available and enabled? + + + diff --git a/eq-3/translations/f324c43c-9680-48d8-852a-93b2227139b9-en_US.ts b/eq-3/translations/f324c43c-9680-48d8-852a-93b2227139b9-en_US.ts index 62db54c0..49c7e209 100644 --- a/eq-3/translations/f324c43c-9680-48d8-852a-93b2227139b9-en_US.ts +++ b/eq-3/translations/f324c43c-9680-48d8-852a-93b2227139b9-en_US.ts @@ -1,14 +1,6 @@ - - DevicePluginEQ3 - - - Bluetooth discovery failed. Is Bluetooth available and enabled? - - - EQ3 @@ -912,4 +904,12 @@ The name of the StateType ({ffaff87b-b741-4db8-9875-3380af4f1885}) of ThingClass + + IntegrationPluginEQ3 + + + Bluetooth discovery failed. Is Bluetooth available and enabled? + + + diff --git a/flowercare/translations/74e2106a-3407-4e89-a27a-1c890d78bee7-de.ts b/flowercare/translations/74e2106a-3407-4e89-a27a-1c890d78bee7-de.ts index 681613e7..5da37331 100644 --- a/flowercare/translations/74e2106a-3407-4e89-a27a-1c890d78bee7-de.ts +++ b/flowercare/translations/74e2106a-3407-4e89-a27a-1c890d78bee7-de.ts @@ -2,18 +2,18 @@ - DevicePluginFlowercare + IntegrationPluginFlowercare Cannot discover Bluetooth devices. Bluetooth is not available on this system. - Es kann nicht nach Bluetooth Geräten gesucht werden. Bluetooth ist auf diesem System nicht verfügbar. + Es kann nicht nach Bluetooth Geräten gesucht werden. Bluetooth ist auf diesem System nicht verfügbar. Cannot discover Bluetooth devices. Bluetooth is disabled. - Es kann nicht nach Bluetooth Geräten gesucht werden. Bluetooth ist deaktiviert. + Es kann nicht nach Bluetooth Geräten gesucht werden. Bluetooth ist deaktiviert. An error happened during Bluetooth discovery. - Beim Suchen von Bluetooth Geräten ist ein Fehler aufgetreten. + Beim Suchen von Bluetooth Geräten ist ein Fehler aufgetreten. diff --git a/flowercare/translations/74e2106a-3407-4e89-a27a-1c890d78bee7-en_US.ts b/flowercare/translations/74e2106a-3407-4e89-a27a-1c890d78bee7-en_US.ts index a67e6adf..fb6f6e58 100644 --- a/flowercare/translations/74e2106a-3407-4e89-a27a-1c890d78bee7-en_US.ts +++ b/flowercare/translations/74e2106a-3407-4e89-a27a-1c890d78bee7-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginFlowercare + IntegrationPluginFlowercare Cannot discover Bluetooth devices. Bluetooth is not available on this system. diff --git a/gpio/translations/127ead55-996a-44ac-ba82-fc3c634e018a-de_DE.ts b/gpio/translations/127ead55-996a-44ac-ba82-fc3c634e018a-de_DE.ts index 875ac2c2..23c1532c 100644 --- a/gpio/translations/127ead55-996a-44ac-ba82-fc3c634e018a-de_DE.ts +++ b/gpio/translations/127ead55-996a-44ac-ba82-fc3c634e018a-de_DE.ts @@ -1,56 +1,6 @@ - - DevicePluginGpio - - - No GPIOs found on this system. - Error setting up GPIO thing - - - - - Exporting GPIO failed. - Error setting up GPIO thing - - - - - Configuring output GPIO failed. - Error setting up GPIO thing - - - - - - - Setting GPIO value failed. - Error setting up GPIO thing ----------- -Error executing GPIO action - - - - - - Enabling GPIO monitor failed. - Error setting up GPIO thing - - - - - No GPIOs available on this system. - Error discovering GPIO devices - - - - - GPIO not found - Error executing GPIO action - - - GpioController @@ -261,4 +211,54 @@ The name of the StateType ({57f1b7cc-26c8-434b-ba04-d3077dc886c8}) of ThingClass + + IntegrationPluginGpio + + + No GPIOs found on this system. + Error setting up GPIO thing + + + + + Exporting GPIO failed. + Error setting up GPIO thing + + + + + Configuring output GPIO failed. + Error setting up GPIO thing + + + + + + + Setting GPIO value failed. + Error setting up GPIO thing +---------- +Error executing GPIO action + + + + + + Enabling GPIO monitor failed. + Error setting up GPIO thing + + + + + No GPIOs available on this system. + Error discovering GPIO devices + + + + + GPIO not found + Error executing GPIO action + + + diff --git a/gpio/translations/127ead55-996a-44ac-ba82-fc3c634e018a-en_US.ts b/gpio/translations/127ead55-996a-44ac-ba82-fc3c634e018a-en_US.ts index 3532afea..09294fde 100644 --- a/gpio/translations/127ead55-996a-44ac-ba82-fc3c634e018a-en_US.ts +++ b/gpio/translations/127ead55-996a-44ac-ba82-fc3c634e018a-en_US.ts @@ -1,56 +1,6 @@ - - DevicePluginGpio - - - No GPIOs found on this system. - Error setting up GPIO thing - - - - - Exporting GPIO failed. - Error setting up GPIO thing - - - - - Configuring output GPIO failed. - Error setting up GPIO thing - - - - - - - Setting GPIO value failed. - Error setting up GPIO thing ----------- -Error executing GPIO action - - - - - - Enabling GPIO monitor failed. - Error setting up GPIO thing - - - - - No GPIOs available on this system. - Error discovering GPIO devices - - - - - GPIO not found - Error executing GPIO action - - - GpioController @@ -261,4 +211,54 @@ The name of the StateType ({57f1b7cc-26c8-434b-ba04-d3077dc886c8}) of ThingClass + + IntegrationPluginGpio + + + No GPIOs found on this system. + Error setting up GPIO thing + + + + + Exporting GPIO failed. + Error setting up GPIO thing + + + + + Configuring output GPIO failed. + Error setting up GPIO thing + + + + + + + Setting GPIO value failed. + Error setting up GPIO thing +---------- +Error executing GPIO action + + + + + + Enabling GPIO monitor failed. + Error setting up GPIO thing + + + + + No GPIOs available on this system. + Error discovering GPIO devices + + + + + GPIO not found + Error executing GPIO action + + + diff --git a/httpcommander/translations/4e62670c-6268-4487-8dff-cccca498731a-en_US.ts b/httpcommander/translations/4e62670c-6268-4487-8dff-cccca498731a-en_US.ts index 1fdcde87..3e88f433 100644 --- a/httpcommander/translations/4e62670c-6268-4487-8dff-cccca498731a-en_US.ts +++ b/httpcommander/translations/4e62670c-6268-4487-8dff-cccca498731a-en_US.ts @@ -1,14 +1,6 @@ - - DevicePluginHttpCommander - - The given url is not valid. - Error setting up thing - - - HttpCommander @@ -100,4 +92,12 @@ The name of the ParamType (ThingClass: httpRequest, ActionType: request, ID: {36 + + IntegrationPluginHttpCommander + + The given url is not valid. + Error setting up thing + + + diff --git a/intertechno/translations/e998d934-0397-42c1-ad63-9141bcac8563-de_DE.ts b/intertechno/translations/e998d934-0397-42c1-ad63-9141bcac8563-de_DE.ts index 638e5b5a..9a5f7847 100644 --- a/intertechno/translations/e998d934-0397-42c1-ad63-9141bcac8563-de_DE.ts +++ b/intertechno/translations/e998d934-0397-42c1-ad63-9141bcac8563-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginIntertechno + IntegrationPluginIntertechno No 433MHz radio available on this system. diff --git a/intertechno/translations/e998d934-0397-42c1-ad63-9141bcac8563-en_US.ts b/intertechno/translations/e998d934-0397-42c1-ad63-9141bcac8563-en_US.ts index 7e68562b..c5cda6e0 100644 --- a/intertechno/translations/e998d934-0397-42c1-ad63-9141bcac8563-en_US.ts +++ b/intertechno/translations/e998d934-0397-42c1-ad63-9141bcac8563-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginIntertechno + IntegrationPluginIntertechno No 433MHz radio available on this system. diff --git a/keba/translations/9142b09f-30a9-43d0-9ede-2f8debe075ac-en_US.ts b/keba/translations/9142b09f-30a9-43d0-9ede-2f8debe075ac-en_US.ts index 8391b14b..2614c172 100644 --- a/keba/translations/9142b09f-30a9-43d0-9ede-2f8debe075ac-en_US.ts +++ b/keba/translations/9142b09f-30a9-43d0-9ede-2f8debe075ac-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginKeba + IntegrationPluginKeba Error opening network port. diff --git a/kodi/translations/e7186890-99fa-4c5b-8247-09c6d450d490-de_DE.ts b/kodi/translations/e7186890-99fa-4c5b-8247-09c6d450d490-de_DE.ts index 3de0343e..f260924b 100644 --- a/kodi/translations/e7186890-99fa-4c5b-8247-09c6d450d490-de_DE.ts +++ b/kodi/translations/e7186890-99fa-4c5b-8247-09c6d450d490-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginKodi + IntegrationPluginKodi This installation of Kodi is too old. Please upgrade your Kodi system. diff --git a/kodi/translations/e7186890-99fa-4c5b-8247-09c6d450d490-en_US.ts b/kodi/translations/e7186890-99fa-4c5b-8247-09c6d450d490-en_US.ts index 99ccf351..0c86ff42 100644 --- a/kodi/translations/e7186890-99fa-4c5b-8247-09c6d450d490-en_US.ts +++ b/kodi/translations/e7186890-99fa-4c5b-8247-09c6d450d490-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginKodi + IntegrationPluginKodi This installation of Kodi is too old. Please upgrade your Kodi system. diff --git a/leynew/translations/9a6d23e6-fad8-4203-aeab-2e6e5c756990-de_DE.ts b/leynew/translations/9a6d23e6-fad8-4203-aeab-2e6e5c756990-de_DE.ts index 33f178bd..74c58f91 100644 --- a/leynew/translations/9a6d23e6-fad8-4203-aeab-2e6e5c756990-de_DE.ts +++ b/leynew/translations/9a6d23e6-fad8-4203-aeab-2e6e5c756990-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginLeynew + IntegrationPluginLeynew diff --git a/leynew/translations/9a6d23e6-fad8-4203-aeab-2e6e5c756990-en_US.ts b/leynew/translations/9a6d23e6-fad8-4203-aeab-2e6e5c756990-en_US.ts index c9d72431..5e71492e 100644 --- a/leynew/translations/9a6d23e6-fad8-4203-aeab-2e6e5c756990-en_US.ts +++ b/leynew/translations/9a6d23e6-fad8-4203-aeab-2e6e5c756990-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginLeynew + IntegrationPluginLeynew diff --git a/lgsmarttv/translations/4ef7a68b-9da0-4c62-b9ac-f478dc6f9f52-de_DE.ts b/lgsmarttv/translations/4ef7a68b-9da0-4c62-b9ac-f478dc6f9f52-de_DE.ts index 2bc30090..8e685ab1 100644 --- a/lgsmarttv/translations/4ef7a68b-9da0-4c62-b9ac-f478dc6f9f52-de_DE.ts +++ b/lgsmarttv/translations/4ef7a68b-9da0-4c62-b9ac-f478dc6f9f52-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginLgSmartTv + IntegrationPluginLgSmartTv Error discovering devices. Please check your network connection. diff --git a/lgsmarttv/translations/4ef7a68b-9da0-4c62-b9ac-f478dc6f9f52-en_US.ts b/lgsmarttv/translations/4ef7a68b-9da0-4c62-b9ac-f478dc6f9f52-en_US.ts index 9cb74122..c6da6609 100644 --- a/lgsmarttv/translations/4ef7a68b-9da0-4c62-b9ac-f478dc6f9f52-en_US.ts +++ b/lgsmarttv/translations/4ef7a68b-9da0-4c62-b9ac-f478dc6f9f52-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginLgSmartTv + IntegrationPluginLgSmartTv Error discovering devices. Please check your network connection. diff --git a/mailnotification/translations/1ae35df1-1b51-4c93-94fa-3febc77e0318-de_DE.ts b/mailnotification/translations/1ae35df1-1b51-4c93-94fa-3febc77e0318-de_DE.ts index 2db232e1..1780e2d1 100644 --- a/mailnotification/translations/1ae35df1-1b51-4c93-94fa-3febc77e0318-de_DE.ts +++ b/mailnotification/translations/1ae35df1-1b51-4c93-94fa-3febc77e0318-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginMailNotification + IntegrationPluginMailNotification Please enter your username and password for the e-mail account. diff --git a/mailnotification/translations/1ae35df1-1b51-4c93-94fa-3febc77e0318-en_US.ts b/mailnotification/translations/1ae35df1-1b51-4c93-94fa-3febc77e0318-en_US.ts index 7daab1cd..6bd0d5bf 100644 --- a/mailnotification/translations/1ae35df1-1b51-4c93-94fa-3febc77e0318-en_US.ts +++ b/mailnotification/translations/1ae35df1-1b51-4c93-94fa-3febc77e0318-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginMailNotification + IntegrationPluginMailNotification Please enter your username and password for the e-mail account. diff --git a/nanoleaf/translations/360867ec-1594-498d-8182-fbab1fe17489-en_US.ts b/nanoleaf/translations/360867ec-1594-498d-8182-fbab1fe17489-en_US.ts index 7b452eaa..3d3f4b00 100644 --- a/nanoleaf/translations/360867ec-1594-498d-8182-fbab1fe17489-en_US.ts +++ b/nanoleaf/translations/360867ec-1594-498d-8182-fbab1fe17489-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginNanoleaf + IntegrationPluginNanoleaf On the Nanoleaf controller, hold the on-off button for 5-7 seconds until the LED starts flashing. diff --git a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-cs.ts b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-cs.ts index 26267333..6daf4b36 100644 --- a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-cs.ts +++ b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-cs.ts @@ -2,7 +2,7 @@ - DevicePluginNetatmo + IntegrationPluginNetatmo Error logging in to Netatmo server. diff --git a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-da.ts b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-da.ts index c1793eb1..1a434571 100644 --- a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-da.ts +++ b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-da.ts @@ -2,7 +2,7 @@ - DevicePluginNetatmo + IntegrationPluginNetatmo Error logging in to Netatmo server. diff --git a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-de_DE.ts b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-de_DE.ts index 1dc456e2..386a21fd 100644 --- a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-de_DE.ts +++ b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginNetatmo + IntegrationPluginNetatmo Error logging in to Netatmo server. diff --git a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-en_US.ts b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-en_US.ts index 33939137..7acffa71 100644 --- a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-en_US.ts +++ b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginNetatmo + IntegrationPluginNetatmo Error logging in to Netatmo server. diff --git a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-es.ts b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-es.ts index 2074a559..f11ba9b1 100644 --- a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-es.ts +++ b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-es.ts @@ -2,7 +2,7 @@ - DevicePluginNetatmo + IntegrationPluginNetatmo Error logging in to Netatmo server. diff --git a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-fr.ts b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-fr.ts index ec7222f9..2b56380d 100644 --- a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-fr.ts +++ b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-fr.ts @@ -2,7 +2,7 @@ - DevicePluginNetatmo + IntegrationPluginNetatmo Error logging in to Netatmo server. diff --git a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-it.ts b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-it.ts index aaaba23e..06c7baa3 100644 --- a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-it.ts +++ b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-it.ts @@ -2,7 +2,7 @@ - DevicePluginNetatmo + IntegrationPluginNetatmo Error logging in to Netatmo server. diff --git a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-nl.ts b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-nl.ts index 7faa7a45..e6eaf3fa 100644 --- a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-nl.ts +++ b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-nl.ts @@ -2,7 +2,7 @@ - DevicePluginNetatmo + IntegrationPluginNetatmo Error logging in to Netatmo server. diff --git a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-pt.ts b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-pt.ts index 822895c0..e64a4879 100644 --- a/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-pt.ts +++ b/netatmo/translations/69d14951-0c02-4877-bcef-dffdf48b7ccb-pt.ts @@ -2,7 +2,7 @@ - DevicePluginNetatmo + IntegrationPluginNetatmo Error logging in to Netatmo server. diff --git a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-cs.ts b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-cs.ts index 71982880..5863a3f5 100644 --- a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-cs.ts +++ b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-cs.ts @@ -2,7 +2,7 @@ - DevicePluginNuki + IntegrationPluginNuki Device is already in use. @@ -11,14 +11,14 @@ Bluetooth is not available on this system. - - Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. - Stiskněte tlačítko Nuki na 5 sekund k aktivování režimu párování dříve než budete pokračovat. - Bluetooth thing not found. + + Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. + Stiskněte tlačítko Nuki na 5 sekund k aktivování režimu párování dříve než budete pokračovat. + Nuki diff --git a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-da.ts b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-da.ts index cd5a22f1..0af4f920 100644 --- a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-da.ts +++ b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-da.ts @@ -2,7 +2,7 @@ - DevicePluginNuki + IntegrationPluginNuki Device is already in use. @@ -11,14 +11,14 @@ Bluetooth is not available on this system. - - Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. - Tryk på Nuki-knappen i fem sekunder for at aktivere parringstilstanden, før du fortsætter. - Bluetooth thing not found. + + Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. + Tryk på Nuki-knappen i fem sekunder for at aktivere parringstilstanden, før du fortsætter. + Nuki diff --git a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-de.ts b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-de.ts index b712ff08..ee9d5e14 100644 --- a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-de.ts +++ b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-de.ts @@ -2,7 +2,7 @@ - DevicePluginNuki + IntegrationPluginNuki Device is already in use. @@ -11,14 +11,14 @@ Bluetooth is not available on this system. - - Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. - Bevor es weitergeht drücke bitte die Nuki-Taste für 5 Sekunden um den Pairing-Modus zu aktivieren. - Bluetooth thing not found. + + Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. + Bevor es weitergeht drücke bitte die Nuki-Taste für 5 Sekunden um den Pairing-Modus zu aktivieren. + Nuki diff --git a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-en_US.ts b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-en_US.ts index 5c881ae7..988e03be 100644 --- a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-en_US.ts +++ b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginNuki + IntegrationPluginNuki Device is already in use. @@ -12,11 +12,11 @@ - Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. + Bluetooth thing not found. - Bluetooth thing not found. + Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. diff --git a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-es.ts b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-es.ts index a098118a..9f7d8967 100644 --- a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-es.ts +++ b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-es.ts @@ -2,7 +2,7 @@ - DevicePluginNuki + IntegrationPluginNuki Device is already in use. @@ -11,14 +11,14 @@ Bluetooth is not available on this system. - - Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. - Pulse el botón Nuki durante 5 segundos para activar el modo de enlazado antes de continuar. - Bluetooth thing not found. + + Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. + Pulse el botón Nuki durante 5 segundos para activar el modo de enlazado antes de continuar. + Nuki diff --git a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-fr.ts b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-fr.ts index 38d8d482..28c063d0 100644 --- a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-fr.ts +++ b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-fr.ts @@ -2,7 +2,7 @@ - DevicePluginNuki + IntegrationPluginNuki Device is already in use. @@ -11,14 +11,14 @@ Bluetooth is not available on this system. - - Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. - Veuillez appuyer pendant 5 secondes sur le bouton Nuki afin d'activer le mode de couplage avant de continuer. - Bluetooth thing not found. + + Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. + Veuillez appuyer pendant 5 secondes sur le bouton Nuki afin d'activer le mode de couplage avant de continuer. + Nuki diff --git a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-it.ts b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-it.ts index 7cea9b83..dec43c9a 100644 --- a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-it.ts +++ b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-it.ts @@ -2,7 +2,7 @@ - DevicePluginNuki + IntegrationPluginNuki Device is already in use. @@ -11,14 +11,14 @@ Bluetooth is not available on this system. - - Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. - Premi il pulsante Nuki per 5 secondi per attivare la sincronizzazione prima di continuare. - Bluetooth thing not found. + + Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. + Premi il pulsante Nuki per 5 secondi per attivare la sincronizzazione prima di continuare. + Nuki diff --git a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-nl.ts b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-nl.ts index 348fc2f7..c8f18f4c 100644 --- a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-nl.ts +++ b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-nl.ts @@ -2,7 +2,7 @@ - DevicePluginNuki + IntegrationPluginNuki Device is already in use. @@ -11,14 +11,14 @@ Bluetooth is not available on this system. - - Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. - Houd, alvorens verder te gaan, de Nuki-knop 5 seconden ingedrukt om de koppelmodus te activeren. - Bluetooth thing not found. + + Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. + Houd, alvorens verder te gaan, de Nuki-knop 5 seconden ingedrukt om de koppelmodus te activeren. + Nuki diff --git a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-pt.ts b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-pt.ts index c758bdb1..160c620e 100644 --- a/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-pt.ts +++ b/nuki/translations/e5806d75-a40e-4766-a272-5a3a8d3ed625-pt.ts @@ -2,7 +2,7 @@ - DevicePluginNuki + IntegrationPluginNuki Device is already in use. @@ -11,14 +11,14 @@ Bluetooth is not available on this system. - - Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. - Pressione o botão Nuki durante 5 segundos para ativar o modo de emparelhamento antes de continuar. - Bluetooth thing not found. + + Please press the Nuki button for 5 seconds in order to activate the pairing mode before you continue. + Pressione o botão Nuki durante 5 segundos para ativar o modo de emparelhamento antes de continuar. + Nuki diff --git a/onewire/translations/2c697fb7-0645-466d-9cb9-aa1922c85bee-en_US.ts b/onewire/translations/2c697fb7-0645-466d-9cb9-aa1922c85bee-en_US.ts index 624039e5..2164ac3e 100644 --- a/onewire/translations/2c697fb7-0645-466d-9cb9-aa1922c85bee-en_US.ts +++ b/onewire/translations/2c697fb7-0645-466d-9cb9-aa1922c85bee-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginOneWire + IntegrationPluginOneWire No one wire interface initialized. Please set up a one wire interface first. diff --git a/openuv/translations/9b7d9cc8-77df-4197-a6fc-8a365747a3b1-en_US.ts b/openuv/translations/9b7d9cc8-77df-4197-a6fc-8a365747a3b1-en_US.ts index 2b154fea..59d52e60 100644 --- a/openuv/translations/9b7d9cc8-77df-4197-a6fc-8a365747a3b1-en_US.ts +++ b/openuv/translations/9b7d9cc8-77df-4197-a6fc-8a365747a3b1-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginOpenUv + IntegrationPluginOpenUv Failed to fetch data from the internet. diff --git a/openweathermap/translations/bc6af567-2338-41d5-aac1-462dec6e4783-de_DE.ts b/openweathermap/translations/bc6af567-2338-41d5-aac1-462dec6e4783-de_DE.ts index dda92549..3490a85b 100644 --- a/openweathermap/translations/bc6af567-2338-41d5-aac1-462dec6e4783-de_DE.ts +++ b/openweathermap/translations/bc6af567-2338-41d5-aac1-462dec6e4783-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginOpenweathermap + IntegrationPluginOpenweathermap Error detecting current location. diff --git a/openweathermap/translations/bc6af567-2338-41d5-aac1-462dec6e4783-en_US.ts b/openweathermap/translations/bc6af567-2338-41d5-aac1-462dec6e4783-en_US.ts index b2a92286..99dc85f0 100644 --- a/openweathermap/translations/bc6af567-2338-41d5-aac1-462dec6e4783-en_US.ts +++ b/openweathermap/translations/bc6af567-2338-41d5-aac1-462dec6e4783-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginOpenweathermap + IntegrationPluginOpenweathermap Error detecting current location. diff --git a/osdomotics/translations/78927596-e266-4a23-8634-7311b2c5fe32-de_DE.ts b/osdomotics/translations/78927596-e266-4a23-8634-7311b2c5fe32-de_DE.ts index f05c78e4..58a2dfca 100644 --- a/osdomotics/translations/78927596-e266-4a23-8634-7311b2c5fe32-de_DE.ts +++ b/osdomotics/translations/78927596-e266-4a23-8634-7311b2c5fe32-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginOsdomotics + IntegrationPluginOsdomotics The given RPL address is not valid. diff --git a/osdomotics/translations/78927596-e266-4a23-8634-7311b2c5fe32-en_US.ts b/osdomotics/translations/78927596-e266-4a23-8634-7311b2c5fe32-en_US.ts index fbecb596..caf38e80 100644 --- a/osdomotics/translations/78927596-e266-4a23-8634-7311b2c5fe32-en_US.ts +++ b/osdomotics/translations/78927596-e266-4a23-8634-7311b2c5fe32-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginOsdomotics + IntegrationPluginOsdomotics The given RPL address is not valid. diff --git a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-cs.ts b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-cs.ts index 2f03969b..033ed3f3 100644 --- a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-cs.ts +++ b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-cs.ts @@ -2,7 +2,7 @@ - DevicePluginPhilipsHue + IntegrationPluginPhilipsHue Please press the button on the Hue Bridge within 30 seconds before you continue diff --git a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-da.ts b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-da.ts index 97120ded..b3648f50 100644 --- a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-da.ts +++ b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-da.ts @@ -2,7 +2,7 @@ - DevicePluginPhilipsHue + IntegrationPluginPhilipsHue Please press the button on the Hue Bridge within 30 seconds before you continue diff --git a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-de_DE.ts b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-de_DE.ts index 603614a5..a0593583 100644 --- a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-de_DE.ts +++ b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-de_DE.ts @@ -2,11 +2,11 @@ - DevicePluginPhilipsHue + IntegrationPluginPhilipsHue Please press the button on the Hue Bridge within 30 seconds before you continue - Bitte drücke den Knopf auf der Hue Bridge innerhalb von 30 Sekunden bevor Du fortfährst + Bitte drücke den Knopf auf der Hue Bridge innerhalb von 30 Sekunden bevor Du fortfährst @@ -16,43 +16,43 @@ Error connecting to hue bridge. - Fehler beim Verbinden zur Hue Bridge. + Fehler beim Verbinden zur Hue Bridge. Received unexpected data from hue bridge. - Unerwartete Daten von Hue Brige empfangen. + Unerwartete Daten von Hue Brige empfangen. An error happened pairing the hue bridge. - Ein Fehler ist beim Pairen der Hue Bridge aufgetreten. + Ein Fehler ist beim Pairen der Hue Bridge aufgetreten. The hue bridge has rejected the connection request. - Die Hue Bridge hat unsere Verbindungsanfrage abegelehnt. + Die Hue Bridge hat unsere Verbindungsanfrage abegelehnt. Error sending command to hue bridge. - Fehler beim Senden der Kommandso zur Hue Bridge. + Fehler beim Senden der Kommandso zur Hue Bridge. An unexpected error happened when sending the command to the hue bridge. - Ein unerwarteter Fehler ist beim Senden von Befehlen zur Hue Bridge aufgetreten. + Ein unerwarteter Fehler ist beim Senden von Befehlen zur Hue Bridge aufgetreten. Philips Hue Motion sensor - Philips Hue Bewegungsmelder + Philips Hue Bewegungsmelder Philips Hue Outdoor sensor - Philips Hue Aussensensor + Philips Hue Aussensensor diff --git a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-en_US.ts b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-en_US.ts index d35a55fb..77150b41 100644 --- a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-en_US.ts +++ b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginPhilipsHue + IntegrationPluginPhilipsHue Please press the button on the Hue Bridge within 30 seconds before you continue diff --git a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-es.ts b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-es.ts index 8a856e9b..e5b5a111 100644 --- a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-es.ts +++ b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-es.ts @@ -2,7 +2,7 @@ - DevicePluginPhilipsHue + IntegrationPluginPhilipsHue Please press the button on the Hue Bridge within 30 seconds before you continue diff --git a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-fr.ts b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-fr.ts index c21a4c83..a45c5113 100644 --- a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-fr.ts +++ b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-fr.ts @@ -2,7 +2,7 @@ - DevicePluginPhilipsHue + IntegrationPluginPhilipsHue Please press the button on the Hue Bridge within 30 seconds before you continue diff --git a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-it.ts b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-it.ts index 8f65bf6c..13e392ba 100644 --- a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-it.ts +++ b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-it.ts @@ -2,7 +2,7 @@ - DevicePluginPhilipsHue + IntegrationPluginPhilipsHue Please press the button on the Hue Bridge within 30 seconds before you continue diff --git a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-nl.ts b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-nl.ts index fffbb241..5092c488 100644 --- a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-nl.ts +++ b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-nl.ts @@ -2,7 +2,7 @@ - DevicePluginPhilipsHue + IntegrationPluginPhilipsHue Please press the button on the Hue Bridge within 30 seconds before you continue diff --git a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-pt.ts b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-pt.ts index 09a800fd..4789861e 100644 --- a/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-pt.ts +++ b/philipshue/translations/5f2e634b-b7f3-48ee-976a-b5ae22aa5c55-pt.ts @@ -2,7 +2,7 @@ - DevicePluginPhilipsHue + IntegrationPluginPhilipsHue Please press the button on the Hue Bridge within 30 seconds before you continue diff --git a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-cs.ts b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-cs.ts index 1ac2f9a7..90d8437b 100644 --- a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-cs.ts +++ b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-cs.ts @@ -2,10 +2,11 @@ - DevicePluginPushbullet + IntegrationPluginPushbullet - - Not authenticated to Pushbullet. + + The provided token must not be empty. + Error setting up thing @@ -14,12 +15,6 @@ Error setting up thing - - - The provided token must not be empty. - Error setting up thing - - Error connecting to Pushbullet. @@ -39,6 +34,11 @@ Error setting up thing + + + Not authenticated to Pushbullet. + + Pushbullet diff --git a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-da.ts b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-da.ts index a0dbe493..3cf7a939 100644 --- a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-da.ts +++ b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-da.ts @@ -2,10 +2,11 @@ - DevicePluginPushbullet + IntegrationPluginPushbullet - - Not authenticated to Pushbullet. + + The provided token must not be empty. + Error setting up thing @@ -14,12 +15,6 @@ Error setting up thing - - - The provided token must not be empty. - Error setting up thing - - Error connecting to Pushbullet. @@ -39,6 +34,11 @@ Error setting up thing + + + Not authenticated to Pushbullet. + + Pushbullet diff --git a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-de_DE.ts b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-de_DE.ts index 40a89d3b..d0269f91 100644 --- a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-de_DE.ts +++ b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-de_DE.ts @@ -2,10 +2,11 @@ - DevicePluginPushbullet + IntegrationPluginPushbullet - - Not authenticated to Pushbullet. + + The provided token must not be empty. + Error setting up thing @@ -14,12 +15,6 @@ Error setting up thing - - - The provided token must not be empty. - Error setting up thing - - Error connecting to Pushbullet. @@ -39,6 +34,11 @@ Error setting up thing + + + Not authenticated to Pushbullet. + + Pushbullet diff --git a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-en_US.ts b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-en_US.ts index b349d198..3db8604a 100644 --- a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-en_US.ts +++ b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-en_US.ts @@ -2,10 +2,11 @@ - DevicePluginPushbullet + IntegrationPluginPushbullet - - Not authenticated to Pushbullet. + + The provided token must not be empty. + Error setting up thing @@ -14,12 +15,6 @@ Error setting up thing - - - The provided token must not be empty. - Error setting up thing - - Error connecting to Pushbullet. @@ -39,6 +34,11 @@ Error setting up thing + + + Not authenticated to Pushbullet. + + Pushbullet diff --git a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-es.ts b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-es.ts index 5d3e19e0..a263fb4b 100644 --- a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-es.ts +++ b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-es.ts @@ -2,10 +2,11 @@ - DevicePluginPushbullet + IntegrationPluginPushbullet - - Not authenticated to Pushbullet. + + The provided token must not be empty. + Error setting up thing @@ -14,12 +15,6 @@ Error setting up thing - - - The provided token must not be empty. - Error setting up thing - - Error connecting to Pushbullet. @@ -39,6 +34,11 @@ Error setting up thing + + + Not authenticated to Pushbullet. + + Pushbullet diff --git a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-fr.ts b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-fr.ts index 731c9ac8..22602a98 100644 --- a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-fr.ts +++ b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-fr.ts @@ -2,10 +2,11 @@ - DevicePluginPushbullet + IntegrationPluginPushbullet - - Not authenticated to Pushbullet. + + The provided token must not be empty. + Error setting up thing @@ -14,12 +15,6 @@ Error setting up thing - - - The provided token must not be empty. - Error setting up thing - - Error connecting to Pushbullet. @@ -39,6 +34,11 @@ Error setting up thing + + + Not authenticated to Pushbullet. + + Pushbullet diff --git a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-it.ts b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-it.ts index 742b524b..e53c3483 100644 --- a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-it.ts +++ b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-it.ts @@ -2,10 +2,11 @@ - DevicePluginPushbullet + IntegrationPluginPushbullet - - Not authenticated to Pushbullet. + + The provided token must not be empty. + Error setting up thing @@ -14,12 +15,6 @@ Error setting up thing - - - The provided token must not be empty. - Error setting up thing - - Error connecting to Pushbullet. @@ -39,6 +34,11 @@ Error setting up thing + + + Not authenticated to Pushbullet. + + Pushbullet diff --git a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-nl.ts b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-nl.ts index 283d3672..eb5f3258 100644 --- a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-nl.ts +++ b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-nl.ts @@ -2,10 +2,11 @@ - DevicePluginPushbullet + IntegrationPluginPushbullet - - Not authenticated to Pushbullet. + + The provided token must not be empty. + Error setting up thing @@ -14,12 +15,6 @@ Error setting up thing - - - The provided token must not be empty. - Error setting up thing - - Error connecting to Pushbullet. @@ -39,6 +34,11 @@ Error setting up thing + + + Not authenticated to Pushbullet. + + Pushbullet diff --git a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-pt.ts b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-pt.ts index 0222faa9..93386865 100644 --- a/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-pt.ts +++ b/pushbullet/translations/46986575-0e62-483d-b5a8-76ac356fcce7-pt.ts @@ -2,10 +2,11 @@ - DevicePluginPushbullet + IntegrationPluginPushbullet - - Not authenticated to Pushbullet. + + The provided token must not be empty. + Error setting up thing @@ -14,12 +15,6 @@ Error setting up thing - - - The provided token must not be empty. - Error setting up thing - - Error connecting to Pushbullet. @@ -39,6 +34,11 @@ Error setting up thing + + + Not authenticated to Pushbullet. + + Pushbullet diff --git a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-cs.ts b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-cs.ts index e16dd76f..3d92c48b 100644 --- a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-cs.ts +++ b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-cs.ts @@ -2,7 +2,7 @@ - DevicePluginSenic + IntegrationPluginSenic Bluetooth is not available on this system. diff --git a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-da.ts b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-da.ts index bdb98563..e7cc6446 100644 --- a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-da.ts +++ b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-da.ts @@ -2,7 +2,7 @@ - DevicePluginSenic + IntegrationPluginSenic Bluetooth is not available on this system. diff --git a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-de_DE.ts b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-de_DE.ts index 6761d946..3d952979 100644 --- a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-de_DE.ts +++ b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginSenic + IntegrationPluginSenic Bluetooth is not available on this system. diff --git a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-en_US.ts b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-en_US.ts index c35e3d41..bebf0576 100644 --- a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-en_US.ts +++ b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginSenic + IntegrationPluginSenic Bluetooth is not available on this system. diff --git a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-es.ts b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-es.ts index a0d6da6c..028186a3 100644 --- a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-es.ts +++ b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-es.ts @@ -2,7 +2,7 @@ - DevicePluginSenic + IntegrationPluginSenic Bluetooth is not available on this system. diff --git a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-fr.ts b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-fr.ts index adcf71a7..80689d22 100644 --- a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-fr.ts +++ b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-fr.ts @@ -2,7 +2,7 @@ - DevicePluginSenic + IntegrationPluginSenic Bluetooth is not available on this system. diff --git a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-it.ts b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-it.ts index a43c5b16..fd9d1f5d 100644 --- a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-it.ts +++ b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-it.ts @@ -2,7 +2,7 @@ - DevicePluginSenic + IntegrationPluginSenic Bluetooth is not available on this system. diff --git a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-nl.ts b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-nl.ts index 804fe52e..70a8d504 100644 --- a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-nl.ts +++ b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-nl.ts @@ -2,7 +2,7 @@ - DevicePluginSenic + IntegrationPluginSenic Bluetooth is not available on this system. diff --git a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-pt.ts b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-pt.ts index 4439d44e..efc6f006 100644 --- a/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-pt.ts +++ b/senic/translations/413e9d77-335f-4ecf-abbc-8f2a8a399c39-pt.ts @@ -2,7 +2,7 @@ - DevicePluginSenic + IntegrationPluginSenic Bluetooth is not available on this system. diff --git a/serialportcommander/translations/fe93a12e-36f4-4015-8019-26b659817773-en_US.ts b/serialportcommander/translations/fe93a12e-36f4-4015-8019-26b659817773-en_US.ts index ee0abb0b..e90f38a7 100644 --- a/serialportcommander/translations/fe93a12e-36f4-4015-8019-26b659817773-en_US.ts +++ b/serialportcommander/translations/fe93a12e-36f4-4015-8019-26b659817773-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginSerialPortCommander + IntegrationPluginSerialPortCommander Could not open serial port. diff --git a/shelly/translations/6162773b-0435-408c-a4f8-7860d38031a9-en_US.ts b/shelly/translations/6162773b-0435-408c-a4f8-7860d38031a9-en_US.ts index eb9db5fe..e4966a40 100644 --- a/shelly/translations/6162773b-0435-408c-a4f8-7860d38031a9-en_US.ts +++ b/shelly/translations/6162773b-0435-408c-a4f8-7860d38031a9-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginShelly + IntegrationPluginShelly Unable to find the thing in the network. diff --git a/simulation/translations/b7368429-e312-4c82-9eab-e1cd996e43d6-en_US.ts b/simulation/translations/b7368429-e312-4c82-9eab-e1cd996e43d6-en_US.ts index f4a0b403..e504e457 100644 --- a/simulation/translations/b7368429-e312-4c82-9eab-e1cd996e43d6-en_US.ts +++ b/simulation/translations/b7368429-e312-4c82-9eab-e1cd996e43d6-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginSimulation + IntegrationPluginSimulation Fingerprint could not be scanned. Please try again. diff --git a/sonos/translations/cdb07719-c445-4fa5-9c7a-564ee02a4412-en_US.ts b/sonos/translations/cdb07719-c445-4fa5-9c7a-564ee02a4412-en_US.ts index 736b6b65..394b3389 100644 --- a/sonos/translations/cdb07719-c445-4fa5-9c7a-564ee02a4412-en_US.ts +++ b/sonos/translations/cdb07719-c445-4fa5-9c7a-564ee02a4412-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginSonos + IntegrationPluginSonos Authentication failed. Please try again. diff --git a/tado/translations/b4f2d2ee-50bb-4786-b7f5-261fed204fa5-en_US.ts b/tado/translations/b4f2d2ee-50bb-4786-b7f5-261fed204fa5-en_US.ts index 32cc7ded..3a745b4c 100644 --- a/tado/translations/b4f2d2ee-50bb-4786-b7f5-261fed204fa5-en_US.ts +++ b/tado/translations/b4f2d2ee-50bb-4786-b7f5-261fed204fa5-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginTado + IntegrationPluginTado Please enter the login credentials. diff --git a/tasmota/translations/d136e0c0-0cbf-4731-aabb-b2201088d6cb-en_US.ts b/tasmota/translations/d136e0c0-0cbf-4731-aabb-b2201088d6cb-en_US.ts index 2c110156..73598448 100644 --- a/tasmota/translations/d136e0c0-0cbf-4731-aabb-b2201088d6cb-en_US.ts +++ b/tasmota/translations/d136e0c0-0cbf-4731-aabb-b2201088d6cb-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginTasmota + IntegrationPluginTasmota The given IP address is not valid. Error setting up thing diff --git a/tcpcommander/translations/741b7b0a-0c9c-4c93-be99-0d0bcf5a4643-de_DE.ts b/tcpcommander/translations/741b7b0a-0c9c-4c93-be99-0d0bcf5a4643-de_DE.ts index 1fa33efd..e0bd008b 100644 --- a/tcpcommander/translations/741b7b0a-0c9c-4c93-be99-0d0bcf5a4643-de_DE.ts +++ b/tcpcommander/translations/741b7b0a-0c9c-4c93-be99-0d0bcf5a4643-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginTcpCommander + IntegrationPluginTcpCommander Error connecting to remote server. diff --git a/tcpcommander/translations/741b7b0a-0c9c-4c93-be99-0d0bcf5a4643-en_US.ts b/tcpcommander/translations/741b7b0a-0c9c-4c93-be99-0d0bcf5a4643-en_US.ts index ed36bca2..8bef8d39 100644 --- a/tcpcommander/translations/741b7b0a-0c9c-4c93-be99-0d0bcf5a4643-en_US.ts +++ b/tcpcommander/translations/741b7b0a-0c9c-4c93-be99-0d0bcf5a4643-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginTcpCommander + IntegrationPluginTcpCommander Error connecting to remote server. diff --git a/texasinstruments/translations/ae550a91-e734-4331-9d71-9f37df0b0fa6-en_US.ts b/texasinstruments/translations/ae550a91-e734-4331-9d71-9f37df0b0fa6-en_US.ts index 1b421510..b4a734e7 100644 --- a/texasinstruments/translations/ae550a91-e734-4331-9d71-9f37df0b0fa6-en_US.ts +++ b/texasinstruments/translations/ae550a91-e734-4331-9d71-9f37df0b0fa6-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginTexasInstruments + IntegrationPluginTexasInstruments Bluetooth is not available on this system. diff --git a/tplink/translations/024ff2e3-30df-44a1-9c8d-63cc416f1fb8-de.ts b/tplink/translations/024ff2e3-30df-44a1-9c8d-63cc416f1fb8-de.ts index e5610bae..b3c69278 100644 --- a/tplink/translations/024ff2e3-30df-44a1-9c8d-63cc416f1fb8-de.ts +++ b/tplink/translations/024ff2e3-30df-44a1-9c8d-63cc416f1fb8-de.ts @@ -2,26 +2,26 @@ - DevicePluginTPLink + IntegrationPluginTPLink An error happened sending the discovery to the network. - Beim Durchsuchen des Netzwerks ist ein Fehler aufgetreten. + Beim Durchsuchen des Netzwerks ist ein Fehler aufgetreten. An error happened finding the device in the network. - Beim Suchen des Geräts ist ein Fehler aufgetreten. + Beim Suchen des Geräts ist ein Fehler aufgetreten. The device could not be found on the network. - Das Gerät konnte nicht im Netzwerk gefunden werden. + Das Gerät konnte nicht im Netzwerk gefunden werden. Error sending command to the network. - Der Befehl konnte nicht ins Netzwerk gesendet werden. + Der Befehl konnte nicht ins Netzwerk gesendet werden. diff --git a/tplink/translations/024ff2e3-30df-44a1-9c8d-63cc416f1fb8-en_US.ts b/tplink/translations/024ff2e3-30df-44a1-9c8d-63cc416f1fb8-en_US.ts index cbcf6a5a..50aebe6a 100644 --- a/tplink/translations/024ff2e3-30df-44a1-9c8d-63cc416f1fb8-en_US.ts +++ b/tplink/translations/024ff2e3-30df-44a1-9c8d-63cc416f1fb8-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginTPLink + IntegrationPluginTPLink An error happened sending the discovery to the network. diff --git a/tuya/translations/405643b3-22ec-4a36-9808-e8b1405b01c9-en_US.ts b/tuya/translations/405643b3-22ec-4a36-9808-e8b1405b01c9-en_US.ts index bc4d23f8..4e39bd4c 100644 --- a/tuya/translations/405643b3-22ec-4a36-9808-e8b1405b01c9-en_US.ts +++ b/tuya/translations/405643b3-22ec-4a36-9808-e8b1405b01c9-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginTuya + IntegrationPluginTuya Error authenticating to Tuya thing. diff --git a/udpcommander/translations/24a8474c-1d86-499e-a76e-9cbfbf48dd72-de_DE.ts b/udpcommander/translations/24a8474c-1d86-499e-a76e-9cbfbf48dd72-de_DE.ts index 2b513406..5b453be2 100644 --- a/udpcommander/translations/24a8474c-1d86-499e-a76e-9cbfbf48dd72-de_DE.ts +++ b/udpcommander/translations/24a8474c-1d86-499e-a76e-9cbfbf48dd72-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginUdpCommander + IntegrationPluginUdpCommander Error opening UDP port. diff --git a/udpcommander/translations/24a8474c-1d86-499e-a76e-9cbfbf48dd72-en_US.ts b/udpcommander/translations/24a8474c-1d86-499e-a76e-9cbfbf48dd72-en_US.ts index c4c42425..63bcaf14 100644 --- a/udpcommander/translations/24a8474c-1d86-499e-a76e-9cbfbf48dd72-en_US.ts +++ b/udpcommander/translations/24a8474c-1d86-499e-a76e-9cbfbf48dd72-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginUdpCommander + IntegrationPluginUdpCommander Error opening UDP port. diff --git a/unifi/translations/88bc00c7-9ea8-4aa6-8aec-831639e8fccc-en_US.ts b/unifi/translations/88bc00c7-9ea8-4aa6-8aec-831639e8fccc-en_US.ts index 8aeba584..53222189 100644 --- a/unifi/translations/88bc00c7-9ea8-4aa6-8aec-831639e8fccc-en_US.ts +++ b/unifi/translations/88bc00c7-9ea8-4aa6-8aec-831639e8fccc-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginUnifi + IntegrationPluginUnifi Please configure a UniFi controller first. diff --git a/unitec/translations/aefca391-f8bf-4f6c-a205-6764de3c2c3c-de_DE.ts b/unitec/translations/aefca391-f8bf-4f6c-a205-6764de3c2c3c-de_DE.ts index d6deda31..0a512fb2 100644 --- a/unitec/translations/aefca391-f8bf-4f6c-a205-6764de3c2c3c-de_DE.ts +++ b/unitec/translations/aefca391-f8bf-4f6c-a205-6764de3c2c3c-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginUnitec + IntegrationPluginUnitec diff --git a/unitec/translations/aefca391-f8bf-4f6c-a205-6764de3c2c3c-en_US.ts b/unitec/translations/aefca391-f8bf-4f6c-a205-6764de3c2c3c-en_US.ts index ee65573d..1e5a8aea 100644 --- a/unitec/translations/aefca391-f8bf-4f6c-a205-6764de3c2c3c-en_US.ts +++ b/unitec/translations/aefca391-f8bf-4f6c-a205-6764de3c2c3c-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginUnitec + IntegrationPluginUnitec diff --git a/usbrelay/translations/ed0035d3-561c-498e-bdb2-2b574cbd0a2f-en_US.ts b/usbrelay/translations/ed0035d3-561c-498e-bdb2-2b574cbd0a2f-en_US.ts index 7509768b..90aaaee7 100644 --- a/usbrelay/translations/ed0035d3-561c-498e-bdb2-2b574cbd0a2f-en_US.ts +++ b/usbrelay/translations/ed0035d3-561c-498e-bdb2-2b574cbd0a2f-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginUsbRelay + IntegrationPluginUsbRelay Cannot discover USB devices. HID initialisation failed on this system. diff --git a/wemo/translations/2e3b5ce0-ecf1-43de-98f0-07df4068a583-de_DE.ts b/wemo/translations/2e3b5ce0-ecf1-43de-98f0-07df4068a583-de_DE.ts index a9efd377..37bc628c 100644 --- a/wemo/translations/2e3b5ce0-ecf1-43de-98f0-07df4068a583-de_DE.ts +++ b/wemo/translations/2e3b5ce0-ecf1-43de-98f0-07df4068a583-de_DE.ts @@ -2,7 +2,7 @@ - DevicePluginWemo + IntegrationPluginWemo An error happened during discovery. diff --git a/wemo/translations/2e3b5ce0-ecf1-43de-98f0-07df4068a583-en_US.ts b/wemo/translations/2e3b5ce0-ecf1-43de-98f0-07df4068a583-en_US.ts index a739bbdb..53ef353c 100644 --- a/wemo/translations/2e3b5ce0-ecf1-43de-98f0-07df4068a583-en_US.ts +++ b/wemo/translations/2e3b5ce0-ecf1-43de-98f0-07df4068a583-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginWemo + IntegrationPluginWemo An error happened during discovery. diff --git a/ws2812fx/translations/5a3c8ca5-4ef7-47a3-bf3f-c257b9f11ef0-en_US.ts b/ws2812fx/translations/5a3c8ca5-4ef7-47a3-bf3f-c257b9f11ef0-en_US.ts index ded343d1..b744df9d 100644 --- a/ws2812fx/translations/5a3c8ca5-4ef7-47a3-bf3f-c257b9f11ef0-en_US.ts +++ b/ws2812fx/translations/5a3c8ca5-4ef7-47a3-bf3f-c257b9f11ef0-en_US.ts @@ -2,7 +2,7 @@ - DevicePluginWs2812fx + IntegrationPluginWs2812fx This serial port is already used. From cc9e225457b3c8e482e3f2f8abf4827397d226e7 Mon Sep 17 00:00:00 2001 From: nymea Date: Thu, 29 Aug 2019 18:38:35 +0200 Subject: [PATCH 02/18] moved files from doorbird branch --- doorbird/deviceplugindoorbird.cpp | 216 ++++++++++++++++++ doorbird/deviceplugindoorbird.h | 56 +++++ doorbird/deviceplugindoorbird.json | 70 ++++++ doorbird/doorbird.pro | 11 + ...1614a-fc47-4eb2-a47c-13c50f1798ee-en_US.ts | 4 + ...68429-e312-4c82-9eab-e1cd996e43d6-en_US.ts | 4 + nymea-plugins.pro | 1 + 7 files changed, 362 insertions(+) create mode 100644 doorbird/deviceplugindoorbird.cpp create mode 100644 doorbird/deviceplugindoorbird.h create mode 100644 doorbird/deviceplugindoorbird.json create mode 100644 doorbird/doorbird.pro create mode 100644 doorbird/translations/6fe1614a-fc47-4eb2-a47c-13c50f1798ee-en_US.ts create mode 100644 doorbird/translations/b7368429-e312-4c82-9eab-e1cd996e43d6-en_US.ts diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp new file mode 100644 index 00000000..e62e4cf7 --- /dev/null +++ b/doorbird/deviceplugindoorbird.cpp @@ -0,0 +1,216 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Bernhard Trinnes * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * nymea is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "deviceplugindoorbird.h" +#include "plugininfo.h" + +#include "platform/platformzeroconfcontroller.h" +#include "network/zeroconf/zeroconfservicebrowser.h" +#include "network/zeroconf/zeroconfserviceentry.h" + +#include +#include +#include +#include + +DevicePluginDoorbird::DevicePluginDoorbird() +{ + m_nam = new QNetworkAccessManager(this); + connect(m_nam, &QNetworkAccessManager::authenticationRequired, this, [this](QNetworkReply *reply, QAuthenticator *authenticator) { + Device *dev = m_networkRequests.value(reply); + if (!myDevices().contains(dev)) { + qCWarning(dcDoorBird) << "Credentials requested for a device which doesn't exist any more"; + return; + } + qCDebug(dcDoorBird) << "Credentials requested for device:" << dev->name(); + authenticator->setUser(dev->paramValue(doorBirdDeviceUsernameParamTypeId).toString()); + authenticator->setPassword(dev->paramValue(doorBirdDevicePasswordParamTypeId).toString()); + }); +} + +DevicePluginDoorbird::~DevicePluginDoorbird() +{ + +} + +Device::DeviceError DevicePluginDoorbird::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) +{ + Q_UNUSED(deviceClassId) + Q_UNUSED(params) + + // NOTE: Discovery is currently disabled in json file because we don't support discovery & login as parameters in combination + // and there isn't any setupMethod which would allow us to enter user & password. + + ZeroConfServiceBrowser *serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_xbmc-jsonrpc._tcp"); + QTimer::singleShot(5000, this, [this, serviceBrowser](){ + QList deviceDescriptors; + foreach (const ZeroConfServiceEntry serviceEntry, serviceBrowser->serviceEntries()) { + if (serviceEntry.serviceType() == "_axis-video._tcp" && serviceEntry.hostName().startsWith("bha-")) { + qCDebug(dcDoorBird) << "Found DoorBird device"; + DeviceDescriptor deviceDescriptor(doorBirdDeviceClassId, serviceEntry.name(), serviceEntry.hostAddress().toString()); + ParamList params; + //TODO add rediscovery + params.append(Param(doorBirdDeviceAddressParamTypeId, serviceEntry.hostAddress().toString())); + deviceDescriptor.setParams(params); + deviceDescriptors.append(deviceDescriptor); + } + } + emit devicesDiscovered(doorBirdDeviceClassId, deviceDescriptors); + serviceBrowser->deleteLater(); + }); + return Device::DeviceErrorAsync; +} + +Device::DeviceSetupStatus DevicePluginDoorbird::setupDevice(Device *device) +{ + connectToEventMonitor(device); + return Device::DeviceSetupStatusSuccess; +} + +Device::DeviceError DevicePluginDoorbird::executeAction(Device *device, const Action &action) +{ + if (action.actionTypeId() == doorBirdUnlatchActionTypeId) { + QNetworkRequest request(QString("http://%1/bha-api/open-door.cgi?r=1").arg(device->paramValue(doorBirdDeviceAddressParamTypeId).toString())); + qCDebug(dcDoorBird) << "Sending request:" << request.url(); + QNetworkReply *reply = m_nam->get(request); + m_networkRequests.insert(reply, device); + connect(reply, &QNetworkReply::finished, this, [this, reply, device, action](){ + reply->deleteLater(); + m_networkRequests.remove(reply); + if (!myDevices().contains(device)) { + // Device must have been removed in the meantime + return; + } + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error unlatching DoorBird device" << device->name(); + emit actionExecutionFinished(action.id(), Device::DeviceErrorHardwareFailure); + return; + } + qCDebug(dcDoorBird) << "DoorBird unlatched:" << reply->error() << reply->errorString(); + emit actionExecutionFinished(action.id(), Device::DeviceErrorNoError); + }); + } + return Device::DeviceErrorDeviceClassNotFound; +} + +void DevicePluginDoorbird::connectToEventMonitor(Device *device) +{ + qCDebug(dcDoorBird) << "Starting monitoring" << device->name(); + + QNetworkRequest request(QString("http://%1/bha-api/monitor.cgi?ring=doorbell,motionsensor").arg(device->paramValue(doorBirdDeviceAddressParamTypeId).toString())); + QNetworkReply *reply = m_nam->get(request); + m_networkRequests.insert(reply, device); + connect(reply, &QNetworkReply::downloadProgress, this, [this, device, reply](qint64 bytesReceived, qint64 bytesTotal){ + Q_UNUSED(bytesReceived) + Q_UNUSED(bytesTotal); + if (!myDevices().contains(device)) { + qCWarning(dcDoorBird) << "Device disappeared for monitor stream."; + reply->abort(); + return; + } + device->setStateValue(doorBirdConnectedStateTypeId, true); + m_readBuffers[device].append(reply->readAll()); + // qCDebug(dcDoorBird) << "Monitor data for" << device->name(); + // qCDebug(dcDoorBird) << m_readBuffers[device]; + + // Input data looks like: + // "--ioboundary\r\nContent-Type: text/plain\r\n\r\ndoorbell:H\r\n\r\n" + + while (!m_readBuffers[device].isEmpty()) { + // find next --ioboundary + QString boundary = QStringLiteral("--ioboundary"); + int startIndex = m_readBuffers[device].indexOf(boundary); + if (startIndex == -1) { + qCWarning(dcDoorBird) << "No meaningful data in buffer:" << m_readBuffers[device]; + if (m_readBuffers[device].size() > 1024) { + qCWarning(dcDoorBird) << "Buffer size > 1KB and still no meaningful data. Discarding buffer..."; + m_readBuffers[device].clear(); + } + // Assuming we don't have enough data yet... + return; + } + + QByteArray contentType = QByteArrayLiteral("Content-Type: text/plain"); + int contentTypeIndex = m_readBuffers[device].indexOf(contentType); + if (contentTypeIndex == -1) { + qCWarning(dcDoorBird) << "Cannot find Content-Type in buffer:" << m_readBuffers[device]; + if (m_readBuffers[device].size() > startIndex + 50) { + qCWarning(dcDoorBird) << boundary << "found but unexpected data follows. Skipping this element..."; + m_readBuffers[device].remove(0, startIndex + boundary.length()); + continue; + } + // Assuming we don't have enough data yet... + return; + } + + // At this point we have the boundary and Content-Type. Remove all of that and take the entire string to either end or next boundary + m_readBuffers[device].remove(0, contentTypeIndex + contentType.length()); + int nextStartIndex = m_readBuffers[device].indexOf(boundary); + QByteArray data; + if (nextStartIndex == -1) { + data = m_readBuffers[device]; + m_readBuffers[device].clear(); + } else { + data = m_readBuffers[device].left(nextStartIndex); + m_readBuffers[device].remove(0, nextStartIndex); + } + + QString message = data.trimmed(); + QStringList parts = message.split(":"); + if (parts.count() != 2) { + qCWarning(dcDoorBird) << "Message has invalid format:" << message << "Expected device:state"; + continue; + } + if (parts.first() == "doorbell") { + if (parts.at(1) == "H") { + qCDebug(dcDoorBird) << "Doorbell ringing!"; + emitEvent(Event(doorBirdTriggeredEventTypeId, device->id())); + } + } else if (parts.first() == "motionsensor") { + if (parts.at(1) == "H") { + qCDebug(dcDoorBird) << "Motion sensor detected a person"; + emitEvent(Event(doorBirdMotionDetectedEventTypeId, device->id())); + } + } else { + qCWarning(dcDoorBird) << "Unhandled DoorBird data:" << message; + } + } + }); + connect(reply, &QNetworkReply::finished, this, [this, device, reply](){ + reply->deleteLater(); + m_networkRequests.remove(reply); + + if (!myDevices().contains(device)) { + qCWarning(dcDoorBird) << "Device has disappeared. Exiting monitor."; + return; + } + + device->setStateValue(doorBirdConnectedStateTypeId, false); + qCDebug(dcDoorBird) << "Monitor request finished:" << reply->error(); + + QTimer::singleShot(2000, this, [this, device] { + if (!myDevices().contains(device)) { + return; + } + connectToEventMonitor(device); + }); + }); +} diff --git a/doorbird/deviceplugindoorbird.h b/doorbird/deviceplugindoorbird.h new file mode 100644 index 00000000..89edfb46 --- /dev/null +++ b/doorbird/deviceplugindoorbird.h @@ -0,0 +1,56 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * nymea is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef DEVICEPLUGINDOORBIRD_H +#define DEVICEPLUGINDOORBIRD_H + +#include "devices/deviceplugin.h" +#include "devices/devicemanager.h" + +class QNetworkAccessManager; +class QNetworkReply; + +class DevicePluginDoorbird: public DevicePlugin +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "deviceplugindoorbird.json") + Q_INTERFACES(DevicePlugin) + + +public: + explicit DevicePluginDoorbird(); + ~DevicePluginDoorbird() override; + + Device::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override; + + Device::DeviceSetupStatus setupDevice(Device *device) override; + Device::DeviceError executeAction(Device *device, const Action &action) override; + + void connectToEventMonitor(Device *device); +private: + + QNetworkAccessManager *m_nam = nullptr; + + QHash m_networkRequests; + QHash m_readBuffers; +}; + +#endif // DEVICEPLUGINDOORBIRD_H diff --git a/doorbird/deviceplugindoorbird.json b/doorbird/deviceplugindoorbird.json new file mode 100644 index 00000000..974da11a --- /dev/null +++ b/doorbird/deviceplugindoorbird.json @@ -0,0 +1,70 @@ +{ + "name": "doorBird", + "displayName": "DoorBird", + "id": "6fe1614a-fc47-4eb2-a47c-13c50f1798ee", + "vendors": [ + { + "name": "doorBird", + "displayName": "DoorBird", + "id": "2da07435-571e-4956-a387-6caa51d6e845", + "deviceClasses": [ + { + "id": "0485eb61-2a22-42ba-9dd2-a5961485bf08", + "name": "doorBird", + "displayName": "DoorBird", + "createMethods": ["discovery", "user" ], + "interfaces": [ "inputtrigger", "connectable" ], + "paramTypes": [ + { + "id": "8873b17d-526e-408d-95d8-6439b501f489", + "name": "address", + "displayName": "IP address", + "type": "QString" + }, + { + "id": "7ccd8f3a-2a5f-4b90-8042-92899d0ee32a", + "name": "username", + "displayName": "Username", + "type": "QString" + }, + { + "id": "ea285a57-47c5-43f1-b0d6-e0a4d6230f3c", + "name": "password", + "displayName": "Password", + "type": "QString" + } + ], + "actionTypes": [ + { + "id": "b6c3377b-91de-411a-9d48-8b509c39d67c", + "name": "unlatch", + "displayName": "Unlatch the door" + } + ], + "stateTypes": [ + { + "id": "186c270b-923c-46e4-a7da-33e45427cdbb", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false + } + ], + "eventTypes": [ + { + "id": "9bc89937-a2ab-4e8e-af0e-a9ba41caa89b", + "name": "triggered", + "displayName": "Doorbell pressed" + }, + { + "id": "e9bb229b-8776-4110-a813-9c0dc67375db", + "name": "motionDetected", + "displayName": "Motion detected" + } + ] + } + ] + } + ] +} diff --git a/doorbird/doorbird.pro b/doorbird/doorbird.pro new file mode 100644 index 00000000..c10ea83a --- /dev/null +++ b/doorbird/doorbird.pro @@ -0,0 +1,11 @@ +include(../plugins.pri) + +QT += network + +TARGET = $$qtLibraryTarget(nymea_deviceplugindoorbird) + +SOURCES += \ + deviceplugindoorbird.cpp \ + +HEADERS += \ + deviceplugindoorbird.h \ diff --git a/doorbird/translations/6fe1614a-fc47-4eb2-a47c-13c50f1798ee-en_US.ts b/doorbird/translations/6fe1614a-fc47-4eb2-a47c-13c50f1798ee-en_US.ts new file mode 100644 index 00000000..f7f66d85 --- /dev/null +++ b/doorbird/translations/6fe1614a-fc47-4eb2-a47c-13c50f1798ee-en_US.ts @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/doorbird/translations/b7368429-e312-4c82-9eab-e1cd996e43d6-en_US.ts b/doorbird/translations/b7368429-e312-4c82-9eab-e1cd996e43d6-en_US.ts new file mode 100644 index 00000000..f7f66d85 --- /dev/null +++ b/doorbird/translations/b7368429-e312-4c82-9eab-e1cd996e43d6-en_US.ts @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/nymea-plugins.pro b/nymea-plugins.pro index 23d78cdf..f20cccb2 100644 --- a/nymea-plugins.pro +++ b/nymea-plugins.pro @@ -12,6 +12,7 @@ PLUGIN_DIRS = \ datetime \ daylightsensor \ denon \ + doorbird \ dweetio \ elgato \ elro \ From bb645fed61359ebad056a7e77f41ef13790eacd0 Mon Sep 17 00:00:00 2001 From: nymea Date: Sun, 22 Sep 2019 22:56:56 +0200 Subject: [PATCH 03/18] refactored code --- doorbird/README.md | 0 doorbird/deviceplugindoorbird.cpp | 248 +++++++++---------------- doorbird/deviceplugindoorbird.h | 12 +- doorbird/deviceplugindoorbird.json | 56 ++++-- doorbird/doorbird.cpp | 282 +++++++++++++++++++++++++++++ doorbird/doorbird.h | 76 ++++++++ doorbird/doorbird.pro | 2 + 7 files changed, 489 insertions(+), 187 deletions(-) create mode 100644 doorbird/README.md create mode 100644 doorbird/doorbird.cpp create mode 100644 doorbird/doorbird.h diff --git a/doorbird/README.md b/doorbird/README.md new file mode 100644 index 00000000..e69de29b diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp index e62e4cf7..09123d25 100644 --- a/doorbird/deviceplugindoorbird.cpp +++ b/doorbird/deviceplugindoorbird.cpp @@ -28,22 +28,11 @@ #include #include -#include +#include #include DevicePluginDoorbird::DevicePluginDoorbird() { - m_nam = new QNetworkAccessManager(this); - connect(m_nam, &QNetworkAccessManager::authenticationRequired, this, [this](QNetworkReply *reply, QAuthenticator *authenticator) { - Device *dev = m_networkRequests.value(reply); - if (!myDevices().contains(dev)) { - qCWarning(dcDoorBird) << "Credentials requested for a device which doesn't exist any more"; - return; - } - qCDebug(dcDoorBird) << "Credentials requested for device:" << dev->name(); - authenticator->setUser(dev->paramValue(doorBirdDeviceUsernameParamTypeId).toString()); - authenticator->setPassword(dev->paramValue(doorBirdDevicePasswordParamTypeId).toString()); - }); } DevicePluginDoorbird::~DevicePluginDoorbird() @@ -53,164 +42,97 @@ DevicePluginDoorbird::~DevicePluginDoorbird() Device::DeviceError DevicePluginDoorbird::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) { - Q_UNUSED(deviceClassId) Q_UNUSED(params) - - // NOTE: Discovery is currently disabled in json file because we don't support discovery & login as parameters in combination - // and there isn't any setupMethod which would allow us to enter user & password. - - ZeroConfServiceBrowser *serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_xbmc-jsonrpc._tcp"); - QTimer::singleShot(5000, this, [this, serviceBrowser](){ - QList deviceDescriptors; - foreach (const ZeroConfServiceEntry serviceEntry, serviceBrowser->serviceEntries()) { - if (serviceEntry.serviceType() == "_axis-video._tcp" && serviceEntry.hostName().startsWith("bha-")) { - qCDebug(dcDoorBird) << "Found DoorBird device"; - DeviceDescriptor deviceDescriptor(doorBirdDeviceClassId, serviceEntry.name(), serviceEntry.hostAddress().toString()); - ParamList params; - //TODO add rediscovery - params.append(Param(doorBirdDeviceAddressParamTypeId, serviceEntry.hostAddress().toString())); - deviceDescriptor.setParams(params); - deviceDescriptors.append(deviceDescriptor); + if (deviceClassId == doorBirdDeviceClassId) { + ZeroConfServiceBrowser *serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser(); + QTimer::singleShot(5000, this, [this, serviceBrowser](){ + QList deviceDescriptors; + foreach (const ZeroConfServiceEntry serviceEntry, serviceBrowser->serviceEntries()) { + if (serviceEntry.hostName().startsWith("bha-")) { + qCDebug(dcDoorBird) << "Found DoorBird device"; + DeviceDescriptor deviceDescriptor(doorBirdDeviceClassId, serviceEntry.name(), serviceEntry.hostAddress().toString()); + ParamList params; + //TODO add rediscovery + params.append(Param(doorBirdDeviceSerialnumberParamTypeId, serviceEntry.hostName())); + params.append(Param(doorBirdDeviceAddressParamTypeId, serviceEntry.hostAddress().toString())); + deviceDescriptor.setParams(params); + deviceDescriptors.append(deviceDescriptor); + } } - } - emit devicesDiscovered(doorBirdDeviceClassId, deviceDescriptors); - serviceBrowser->deleteLater(); - }); - return Device::DeviceErrorAsync; -} - -Device::DeviceSetupStatus DevicePluginDoorbird::setupDevice(Device *device) -{ - connectToEventMonitor(device); - return Device::DeviceSetupStatusSuccess; -} - -Device::DeviceError DevicePluginDoorbird::executeAction(Device *device, const Action &action) -{ - if (action.actionTypeId() == doorBirdUnlatchActionTypeId) { - QNetworkRequest request(QString("http://%1/bha-api/open-door.cgi?r=1").arg(device->paramValue(doorBirdDeviceAddressParamTypeId).toString())); - qCDebug(dcDoorBird) << "Sending request:" << request.url(); - QNetworkReply *reply = m_nam->get(request); - m_networkRequests.insert(reply, device); - connect(reply, &QNetworkReply::finished, this, [this, reply, device, action](){ - reply->deleteLater(); - m_networkRequests.remove(reply); - if (!myDevices().contains(device)) { - // Device must have been removed in the meantime - return; - } - if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcDoorBird) << "Error unlatching DoorBird device" << device->name(); - emit actionExecutionFinished(action.id(), Device::DeviceErrorHardwareFailure); - return; - } - qCDebug(dcDoorBird) << "DoorBird unlatched:" << reply->error() << reply->errorString(); - emit actionExecutionFinished(action.id(), Device::DeviceErrorNoError); + emit devicesDiscovered(doorBirdDeviceClassId, deviceDescriptors); + serviceBrowser->deleteLater(); }); + return Device::DeviceErrorAsync; } return Device::DeviceErrorDeviceClassNotFound; } -void DevicePluginDoorbird::connectToEventMonitor(Device *device) +DevicePairingInfo DevicePluginDoorbird::pairDevice(DevicePairingInfo &devicePairingInfo) { - qCDebug(dcDoorBird) << "Starting monitoring" << device->name(); + qCDebug(dcDoorBird()) << "PairDevice:" << devicePairingInfo.deviceClassId(); - QNetworkRequest request(QString("http://%1/bha-api/monitor.cgi?ring=doorbell,motionsensor").arg(device->paramValue(doorBirdDeviceAddressParamTypeId).toString())); - QNetworkReply *reply = m_nam->get(request); - m_networkRequests.insert(reply, device); - connect(reply, &QNetworkReply::downloadProgress, this, [this, device, reply](qint64 bytesReceived, qint64 bytesTotal){ - Q_UNUSED(bytesReceived) - Q_UNUSED(bytesTotal); - if (!myDevices().contains(device)) { - qCWarning(dcDoorBird) << "Device disappeared for monitor stream."; - reply->abort(); - return; - } - device->setStateValue(doorBirdConnectedStateTypeId, true); - m_readBuffers[device].append(reply->readAll()); - // qCDebug(dcDoorBird) << "Monitor data for" << device->name(); - // qCDebug(dcDoorBird) << m_readBuffers[device]; - - // Input data looks like: - // "--ioboundary\r\nContent-Type: text/plain\r\n\r\ndoorbell:H\r\n\r\n" - - while (!m_readBuffers[device].isEmpty()) { - // find next --ioboundary - QString boundary = QStringLiteral("--ioboundary"); - int startIndex = m_readBuffers[device].indexOf(boundary); - if (startIndex == -1) { - qCWarning(dcDoorBird) << "No meaningful data in buffer:" << m_readBuffers[device]; - if (m_readBuffers[device].size() > 1024) { - qCWarning(dcDoorBird) << "Buffer size > 1KB and still no meaningful data. Discarding buffer..."; - m_readBuffers[device].clear(); - } - // Assuming we don't have enough data yet... - return; - } - - QByteArray contentType = QByteArrayLiteral("Content-Type: text/plain"); - int contentTypeIndex = m_readBuffers[device].indexOf(contentType); - if (contentTypeIndex == -1) { - qCWarning(dcDoorBird) << "Cannot find Content-Type in buffer:" << m_readBuffers[device]; - if (m_readBuffers[device].size() > startIndex + 50) { - qCWarning(dcDoorBird) << boundary << "found but unexpected data follows. Skipping this element..."; - m_readBuffers[device].remove(0, startIndex + boundary.length()); - continue; - } - // Assuming we don't have enough data yet... - return; - } - - // At this point we have the boundary and Content-Type. Remove all of that and take the entire string to either end or next boundary - m_readBuffers[device].remove(0, contentTypeIndex + contentType.length()); - int nextStartIndex = m_readBuffers[device].indexOf(boundary); - QByteArray data; - if (nextStartIndex == -1) { - data = m_readBuffers[device]; - m_readBuffers[device].clear(); - } else { - data = m_readBuffers[device].left(nextStartIndex); - m_readBuffers[device].remove(0, nextStartIndex); - } - - QString message = data.trimmed(); - QStringList parts = message.split(":"); - if (parts.count() != 2) { - qCWarning(dcDoorBird) << "Message has invalid format:" << message << "Expected device:state"; - continue; - } - if (parts.first() == "doorbell") { - if (parts.at(1) == "H") { - qCDebug(dcDoorBird) << "Doorbell ringing!"; - emitEvent(Event(doorBirdTriggeredEventTypeId, device->id())); - } - } else if (parts.first() == "motionsensor") { - if (parts.at(1) == "H") { - qCDebug(dcDoorBird) << "Motion sensor detected a person"; - emitEvent(Event(doorBirdMotionDetectedEventTypeId, device->id())); - } - } else { - qCWarning(dcDoorBird) << "Unhandled DoorBird data:" << message; - } - } - }); - connect(reply, &QNetworkReply::finished, this, [this, device, reply](){ - reply->deleteLater(); - m_networkRequests.remove(reply); - - if (!myDevices().contains(device)) { - qCWarning(dcDoorBird) << "Device has disappeared. Exiting monitor."; - return; - } - - device->setStateValue(doorBirdConnectedStateTypeId, false); - qCDebug(dcDoorBird) << "Monitor request finished:" << reply->error(); - - QTimer::singleShot(2000, this, [this, device] { - if (!myDevices().contains(device)) { - return; - } - connectToEventMonitor(device); - }); - }); + devicePairingInfo.setStatus(Device::DeviceErrorNoError); + devicePairingInfo.setMessage(tr("Please enter username and password for your Doorbird device.")); + return devicePairingInfo; +} + +DevicePairingInfo DevicePluginDoorbird::confirmPairing(DevicePairingInfo &devicePairingInfo, const QString &username, const QString &secret) +{ + qCDebug(dcDoorBird()) << "confirm pairing called"; + + pluginStorage()->beginGroup(devicePairingInfo.deviceId().toString()); + pluginStorage()->setValue("username", username); + pluginStorage()->setValue("password", secret); + pluginStorage()->endGroup(); + + devicePairingInfo.setStatus(Device::DeviceErrorNoError); + + return devicePairingInfo; +} + + +Device::DeviceSetupStatus DevicePluginDoorbird::setupDevice(Device *device) +{ + if (device->deviceClassId() == doorBirdDeviceClassId) { + QHostAddress address = QHostAddress(device->paramValue(doorBirdDeviceAddressParamTypeId).toString()); + + pluginStorage()->beginGroup(device->id().toString()); + QString username = pluginStorage()->value("username").toString(); + QString password = pluginStorage()->value("password").toString(); + pluginStorage()->endGroup(); + + Doorbird *doorbird = new Doorbird(address, username, password, this); + doorbird->connectToEventMonitor(); + m_doorbirdConnections.insert(device, doorbird); + return Device::DeviceSetupStatusSuccess; + } + return Device::DeviceSetupStatusFailure; +} + +Device::DeviceError DevicePluginDoorbird::executeAction(Device *device, const Action &action) +{ + if (device->deviceClassId() == doorBirdDeviceClassId) { + Doorbird *doorbird = m_doorbirdConnections.value(device); + if (!doorbird) + return Device::DeviceErrorDeviceNotFound; + + if (action.actionTypeId() == doorBirdOpenDoorActionTypeId) { + //Todo get action param + doorbird->openDoor(1); + return Device::DeviceErrorNoError; + } + if (action.actionTypeId() == doorBirdLightOnActionTypeId) { + doorbird->lightOn(); + return Device::DeviceErrorNoError; + } + } + return Device::DeviceErrorDeviceClassNotFound; +} + +void DevicePluginDoorbird::deviceRemoved(Device *device) +{ + if (device->deviceClassId() == doorBirdDeviceClassId) { + Doorbird *doorbirdConnection = m_doorbirdConnections.take(device); + doorbirdConnection->deleteLater(); + } } diff --git a/doorbird/deviceplugindoorbird.h b/doorbird/deviceplugindoorbird.h index 89edfb46..e18b250e 100644 --- a/doorbird/deviceplugindoorbird.h +++ b/doorbird/deviceplugindoorbird.h @@ -23,6 +23,7 @@ #include "devices/deviceplugin.h" #include "devices/devicemanager.h" +#include "doorbird.h" class QNetworkAccessManager; class QNetworkReply; @@ -44,13 +45,12 @@ public: Device::DeviceSetupStatus setupDevice(Device *device) override; Device::DeviceError executeAction(Device *device, const Action &action) override; - void connectToEventMonitor(Device *device); + DevicePairingInfo confirmPairing(DevicePairingInfo &devicePairingInfo, const QString &username, const QString &secret) override; + DevicePairingInfo pairDevice(DevicePairingInfo &devicePairingInfo) override; + void deviceRemoved(Device *device)override; + private: - - QNetworkAccessManager *m_nam = nullptr; - - QHash m_networkRequests; - QHash m_readBuffers; + QHash m_doorbirdConnections; }; #endif // DEVICEPLUGINDOORBIRD_H diff --git a/doorbird/deviceplugindoorbird.json b/doorbird/deviceplugindoorbird.json index 974da11a..309c918d 100644 --- a/doorbird/deviceplugindoorbird.json +++ b/doorbird/deviceplugindoorbird.json @@ -13,7 +13,8 @@ "name": "doorBird", "displayName": "DoorBird", "createMethods": ["discovery", "user" ], - "interfaces": [ "inputtrigger", "connectable" ], + "interfaces": [ "doorbell", "presencesensor", "connectable" ], + "setupMethod": "userandpassword", "paramTypes": [ { "id": "8873b17d-526e-408d-95d8-6439b501f489", @@ -22,23 +23,30 @@ "type": "QString" }, { - "id": "7ccd8f3a-2a5f-4b90-8042-92899d0ee32a", - "name": "username", - "displayName": "Username", - "type": "QString" - }, - { - "id": "ea285a57-47c5-43f1-b0d6-e0a4d6230f3c", - "name": "password", - "displayName": "Password", + "id": "67ea5534-330a-4291-93b5-0237034e15fa", + "name": "serialnumber", + "displayName": "Serial number", "type": "QString" } ], "actionTypes": [ { "id": "b6c3377b-91de-411a-9d48-8b509c39d67c", - "name": "unlatch", - "displayName": "Unlatch the door" + "name": "openDoor", + "displayName": "Open door", + "paramTypes": [ + { + "id": "6dcce056-e4d4-49c4-8b68-d3f478c00a52", + "name": "number", + "displayName": "Number", + "type": "int" + } + ] + }, + { + "id": "3a6cfc5d-804c-4d21-91b5-999913d4f1a5", + "name": "lightOn", + "displayName": "Light on" } ], "stateTypes": [ @@ -49,18 +57,30 @@ "displayNameEvent": "Connected changed", "type": "bool", "defaultValue": false + }, + { + "id": "0f5eb200-6c0d-45c5-9156-3060fd66d332", + "name": "isPresent", + "displayName": "Motion sensor presence", + "displayNameEvent": "Motion sensor presence detected", + "type": "bool", + "defaultValue": false + }, + { + "id": "295c9700-b598-4681-898f-d63e2889cedf", + "name": "lastSeenTime", + "displayName": "Motion sensor last seen time", + "displayNameEvent": "Motion sensor last seen time changedd", + "type": "int", + "unit": "UnixTime", + "defaultValue": 0 } ], "eventTypes": [ { "id": "9bc89937-a2ab-4e8e-af0e-a9ba41caa89b", - "name": "triggered", + "name": "doorbellPressed", "displayName": "Doorbell pressed" - }, - { - "id": "e9bb229b-8776-4110-a813-9c0dc67375db", - "name": "motionDetected", - "displayName": "Motion detected" } ] } diff --git a/doorbird/doorbird.cpp b/doorbird/doorbird.cpp new file mode 100644 index 00000000..46174ed4 --- /dev/null +++ b/doorbird/doorbird.cpp @@ -0,0 +1,282 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Bernhard Trinnes * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * nymea is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "doorbird.h" +#include "extern-plugininfo.h" + +#include +#include +#include +#include +#include +#include +#include + +Doorbird::Doorbird(const QHostAddress &address, const QString &username, const QString &password, QObject *parent) : + QObject(parent), + m_address(address), + m_username(username), + m_password(password) +{ + m_networkAccessManager = new QNetworkAccessManager(this); + connect(m_networkAccessManager, &QNetworkAccessManager::authenticationRequired, this, [this](QNetworkReply *reply, QAuthenticator *authenticator) { + qCDebug(dcDoorBird) << "Credentials requested:"; + authenticator->setUser(username); + authenticator->setPassword(password); + }); +} + +QUuid Doorbird::getSession() +{ + QNetworkRequest request(QString("http://%1/bha-api/getsession.cgi").arg(m_address.toString())); + qCDebug(dcDoorBird) << "Sending request:" << request.url(); + QNetworkReply *reply = m_networkAccessManager->get(request); + QUuid requestId = QUuid::createUuid(); + + connect(reply, &QNetworkReply::finished, this, [this, reply, requestId](){ + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error unlatching DoorBird device"; + emit requestSent(requestId, false); + return; + } + emit requestSent(requestId, true); + + QByteArray data = reply->readAll(); + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcDoorBird()) << "Error parsing json:" << data; + return; + } + }); + return requestId; +} + +QUuid Doorbird::openDoor(int value) +{ + QNetworkRequest request(QString("http://%1/bha-api/open-door.cgi?r=%2").arg(m_address.toString()).arg(QString::number(value))); + qCDebug(dcDoorBird) << "Sending request:" << request.url(); + QNetworkReply *reply = m_networkAccessManager->get(request); + QUuid requestId = QUuid::createUuid(); + connect(reply, &QNetworkReply::finished, this, [this, reply, requestId](){ + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error opening DoorBird " << reply->error() << reply->errorString(); + emit requestSent(requestId, false); + return; + } + qCDebug(dcDoorBird) << "DoorBird unlatched:"; + emit requestSent(requestId, true); + }); + return requestId; +} + +QUuid Doorbird::lightOn() +{ + QNetworkRequest request(QString("http://%1/bha-api/light-on.cgi").arg(m_address.toString())); + qCDebug(dcDoorBird) << "Sending request:" << request.url(); + QNetworkReply *reply = m_networkAccessManager->get(request); + QUuid requestId = QUuid::createUuid(); + connect(reply, &QNetworkReply::finished, this, [this, reply, requestId](){ + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error unlatching DoorBird device" << reply->error() << reply->errorString(); + emit requestSent(requestId, false); + return; + } + qCDebug(dcDoorBird) << "DoorBird light on:"; + emit requestSent(requestId, true); + }); + return requestId; +} + +QUuid Doorbird::liveVideoRequest() +{ + +} + +QUuid Doorbird::liveImageRequest() +{ + QNetworkRequest request(QString("http://%1/bha-api/light-on.cgi").arg(m_address.toString())); + qCDebug(dcDoorBird) << "Sending request:" << request.url(); + QNetworkReply *reply = m_networkAccessManager->get(request); + QUuid requestId = QUuid::createUuid(); + connect(reply, &QNetworkReply::finished, this, [this, reply, requestId](){ + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error unlatching DoorBird device" << reply->error() << reply->errorString(); + emit requestSent(requestId, false); + return; + } + qCDebug(dcDoorBird) << "DoorBird light on:"; + emit requestSent(requestId, true); + + QImage* image = new QImage(); + image->loadFromData(reply->readAll()); + }); + return requestId; +} + +QUuid Doorbird::historyImageRequest(int index) +{ + +} + +QUuid Doorbird::infoRequest() +{ + QNetworkRequest request(QString("http://%1/bha-api/info.cgi").arg(m_address.toString())); + qCDebug(dcDoorBird) << "Sending request:" << request.url(); + QNetworkReply *reply = m_networkAccessManager->get(request); + + connect(reply, &QNetworkReply::finished, this, [this, reply, action](){ + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error unlatching DoorBird device"; + return; + } + qCDebug(dcDoorBird) << "DoorBird unlatched:" << reply->error() << reply->errorString(); + }); +} + +QUuid Doorbird::listFavorites() +{ + +} + +QUuid Doorbird::listSchedules() +{ + +} + +QUuid Doorbird::restart() +{ + QNetworkRequest request(QString("http://%1/bha-api/restart.cgi").arg(m_address.toString())); + qCDebug(dcDoorBird) << "Sending request:" << request.url(); + QNetworkReply *reply = m_networkAccessManager->get(request); + + connect(reply, &QNetworkReply::finished, this, [this, reply, action](){ + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error restarting DoorBird device" << reply; + return; + } + qCDebug(dcDoorBird) << "DoorBird restarting"; + }); +} + +void Doorbird::connectToEventMonitor() +{ + qCDebug(dcDoorBird) << "Starting monitoring"; + + QNetworkRequest request(QString("http://%1/bha-api/monitor.cgi?ring=doorbell,motionsensor").arg(m_address.toString()); + QNetworkReply *reply = m_networkAccessManager->get(request); + + connect(reply, &QNetworkReply::downloadProgress, this, [this, reply](qint64 bytesReceived, qint64 bytesTotal){ + Q_UNUSED(bytesReceived) + Q_UNUSED(bytesTotal); + + //TODO emit signal connected + m_readBuffers.append(reply->readAll()); + // qCDebug(dcDoorBird) << "Monitor data for" << device->name(); + // qCDebug(dcDoorBird) << m_readBuffers[device]; + + // Input data looks like: + // "--ioboundary\r\nContent-Type: text/plain\r\n\r\ndoorbell:H\r\n\r\n" + + while (!m_readBuffers.isEmpty()) { + // find next --ioboundary + QString boundary = QStringLiteral("--ioboundary"); + int startIndex = m_readBuffers.indexOf(boundary); + if (startIndex == -1) { + qCWarning(dcDoorBird) << "No meaningful data in buffer:" << m_readBuffers; + if (m_readBuffers.size() > 1024) { + qCWarning(dcDoorBird) << "Buffer size > 1KB and still no meaningful data. Discarding buffer..."; + m_readBuffers.clear(); + } + // Assuming we don't have enough data yet... + return; + } + + QByteArray contentType = QByteArrayLiteral("Content-Type: text/plain"); + int contentTypeIndex = m_readBuffers.indexOf(contentType); + if (contentTypeIndex == -1) { + qCWarning(dcDoorBird) << "Cannot find Content-Type in buffer:" << m_readBuffers; + if (m_readBuffers.size() > startIndex + 50) { + qCWarning(dcDoorBird) << boundary << "found but unexpected data follows. Skipping this element..."; + m_readBuffers.remove(0, startIndex + boundary.length()); + continue; + } + // Assuming we don't have enough data yet... + return; + } + + // At this point we have the boundary and Content-Type. Remove all of that and take the entire string to either end or next boundary + m_readBuffers.remove(0, contentTypeIndex + contentType.length()); + int nextStartIndex = m_readBuffers.indexOf(boundary); + QByteArray data; + if (nextStartIndex == -1) { + data = m_readBuffers; + m_readBuffers.clear(); + } else { + data = m_readBuffers.left(nextStartIndex); + m_readBuffers.remove(0, nextStartIndex); + } + + QString message = data.trimmed(); + QStringList parts = message.split(":"); + if (parts.count() != 2) { + qCWarning(dcDoorBird) << "Message has invalid format:" << message << "Expected device:state"; + continue; + } + if (parts.first() == "doorbell") { + if (parts.at(1) == "H") { + qCDebug(dcDoorBird) << "Doorbell ringing!"; + //emitEvent(Event(doorBirdTriggeredEventTypeId, device->id())); + } + } else if (parts.first() == "motionsensor") { + if (parts.at(1) == "H") { + qCDebug(dcDoorBird) << "Motion sensor detected a person"; + //emitEvent(Event(doorBirdMotionDetectedEventTypeId, device->id())); + } + } else { + qCWarning(dcDoorBird) << "Unhandled DoorBird data:" << message; + } + } + }); + connect(reply, &QNetworkReply::finished, this, [this, reply](){ + reply->deleteLater(); + + //device->setStateValue(doorBirdConnectedStateTypeId, false); + qCDebug(dcDoorBird) << "Monitor request finished:" << reply->error(); + + QTimer::singleShot(2000, this, [this] { + connectToEventMonitor(device); + }); + }); +} + diff --git a/doorbird/doorbird.h b/doorbird/doorbird.h new file mode 100644 index 00000000..69e05d0b --- /dev/null +++ b/doorbird/doorbird.h @@ -0,0 +1,76 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Bernhard Trinnes * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * nymea is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef DOORBIRD_H +#define DOORBIRD_H + +#include +#include +#include +#include + +class Doorbird : public QObject +{ + Q_OBJECT +public: + explicit Doorbird(const QHostAddress &address, const QString &username, const QString &password, QObject *parent = nullptr); + + QUuid getSession(); + QUuid openDoor(int value); + QUuid lightOn(); + QUuid liveVideoRequest(); + QUuid liveImageRequest(); + QUuid historyImageRequest(int index); + + QUuid liveAudioReceive(); + QUuid liveAudioTransmit(); + QUuid infoRequest(); + + QUuid listFavorites(); + QUuid addFavorite(); + QUuid deleteFavorite(); + + QUuid listSchedules(); + QUuid daddScheduleEntry(); + QUuid deleteScheduleEntry(); + + QUuid restart(); + + void connectToEventMonitor(); +private: + QNetworkAccessManager *m_networkAccessManager; + QList m_readBuffers; + + QHostAddress m_address; + QList m_networkRequests; + + QString m_username; + QString m_password; + + QByteArray sessionId; + +signals: + void requestSent(QUuid requestId, bool success); + +public slots: +}; + +#endif // DOORBIRD_H diff --git a/doorbird/doorbird.pro b/doorbird/doorbird.pro index c10ea83a..0ea9d1fb 100644 --- a/doorbird/doorbird.pro +++ b/doorbird/doorbird.pro @@ -6,6 +6,8 @@ TARGET = $$qtLibraryTarget(nymea_deviceplugindoorbird) SOURCES += \ deviceplugindoorbird.cpp \ + doorbird.cpp HEADERS += \ deviceplugindoorbird.h \ + doorbird.h From 20aa068d18f6a39bbb4b39ff57992283eb119366 Mon Sep 17 00:00:00 2001 From: nymea Date: Sun, 22 Sep 2019 23:30:43 +0200 Subject: [PATCH 04/18] added some more API calls --- doorbird/deviceplugindoorbird.json | 10 +-- doorbird/doorbird.cpp | 122 ++++++++++++++++++++++++++--- 2 files changed, 111 insertions(+), 21 deletions(-) diff --git a/doorbird/deviceplugindoorbird.json b/doorbird/deviceplugindoorbird.json index 309c918d..8f9ed2ee 100644 --- a/doorbird/deviceplugindoorbird.json +++ b/doorbird/deviceplugindoorbird.json @@ -33,15 +33,7 @@ { "id": "b6c3377b-91de-411a-9d48-8b509c39d67c", "name": "openDoor", - "displayName": "Open door", - "paramTypes": [ - { - "id": "6dcce056-e4d4-49c4-8b68-d3f478c00a52", - "name": "number", - "displayName": "Number", - "type": "int" - } - ] + "displayName": "Open door" }, { "id": "3a6cfc5d-804c-4d21-91b5-999913d4f1a5", diff --git a/doorbird/doorbird.cpp b/doorbird/doorbird.cpp index 46174ed4..a2a6dce9 100644 --- a/doorbird/doorbird.cpp +++ b/doorbird/doorbird.cpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include Doorbird::Doorbird(const QHostAddress &address, const QString &username, const QString &password, QObject *parent) : QObject(parent), @@ -38,9 +40,10 @@ Doorbird::Doorbird(const QHostAddress &address, const QString &username, const Q { m_networkAccessManager = new QNetworkAccessManager(this); connect(m_networkAccessManager, &QNetworkAccessManager::authenticationRequired, this, [this](QNetworkReply *reply, QAuthenticator *authenticator) { + Q_UNUSED(reply); qCDebug(dcDoorBird) << "Credentials requested:"; - authenticator->setUser(username); - authenticator->setPassword(password); + authenticator->setUser(m_username); + authenticator->setPassword(m_password); }); } @@ -114,7 +117,22 @@ QUuid Doorbird::lightOn() QUuid Doorbird::liveVideoRequest() { + QNetworkRequest request(QString("http://%1/bha-api/info.cgi").arg(m_address.toString())); + qCDebug(dcDoorBird) << "Sending request:" << request.url(); + QNetworkReply *reply = m_networkAccessManager->get(request); + QUuid requestId = QUuid::createUuid(); + connect(reply, &QNetworkReply::finished, this, [this, reply, requestId](){ + reply->deleteLater(); + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error unlatching DoorBird device"; + emit requestSent(requestId, false); + return; + } + qCDebug(dcDoorBird) << "DoorBird unlatched:" << reply->error() << reply->errorString(); + emit requestSent(requestId, true); + }); + return requestId; } QUuid Doorbird::liveImageRequest() @@ -142,7 +160,52 @@ QUuid Doorbird::liveImageRequest() QUuid Doorbird::historyImageRequest(int index) { + QUrl url(QString("http://%1/bha-api/history.cgi").arg(m_address.toString())); + QUrlQuery query; + query.addQueryItem("index", QString::number(index)); + url.setQuery(query); + qCDebug(dcDoorBird) << "Sending request:" << url; + QNetworkReply *reply = m_networkAccessManager->get(QNetworkRequest(url)); + QUuid requestId = QUuid::createUuid(); + connect(reply, &QNetworkReply::finished, this, [this, reply, requestId](){ + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error unlatching DoorBird device"; + emit requestSent(requestId, false); + return; + } + qCDebug(dcDoorBird) << "DoorBird unlatched:" << reply->error() << reply->errorString(); + emit requestSent(requestId, true); + }); + return requestId; +} + +QUuid Doorbird::liveAudioReceive() +{ + QNetworkRequest request(QString("http://%1/bha-api/audio-receive.cgi").arg(m_address.toString())); + qCDebug(dcDoorBird) << "Sending request:" << request.url(); + QNetworkReply *reply = m_networkAccessManager->get(request); + QUuid requestId = QUuid::createUuid(); + connect(reply, &QNetworkReply::finished, this, [this, reply, requestId](){ + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error DoorBird device"; + emit requestSent(requestId, false); + return; + } + qCDebug(dcDoorBird) << "DoorBird unlatched:" << reply->error() << reply->errorString(); + emit requestSent(requestId, true); + }); + return requestId; +} + +QUuid Doorbird::liveAudioTransmit() +{ + + return QUuid::createUuid(); } QUuid Doorbird::infoRequest() @@ -150,26 +213,57 @@ QUuid Doorbird::infoRequest() QNetworkRequest request(QString("http://%1/bha-api/info.cgi").arg(m_address.toString())); qCDebug(dcDoorBird) << "Sending request:" << request.url(); QNetworkReply *reply = m_networkAccessManager->get(request); - - connect(reply, &QNetworkReply::finished, this, [this, reply, action](){ + QUuid requestId = QUuid::createUuid(); + connect(reply, &QNetworkReply::finished, this, [this, reply, requestId](){ reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { qCWarning(dcDoorBird) << "Error unlatching DoorBird device"; + emit requestSent(requestId, false); return; } qCDebug(dcDoorBird) << "DoorBird unlatched:" << reply->error() << reply->errorString(); + emit requestSent(requestId, true); }); + return requestId; } QUuid Doorbird::listFavorites() { + QNetworkRequest request(QString("http://%1/bha-api/favorites.cgi").arg(m_address.toString())); + qCDebug(dcDoorBird) << "Sending request:" << request.url(); + QNetworkReply *reply = m_networkAccessManager->get(request); + QUuid requestId = QUuid::createUuid(); + connect(reply, &QNetworkReply::finished, this, [this, reply, requestId](){ + reply->deleteLater(); + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error DoorBird device" << reply->error() << reply->errorString(); + emit requestSent(requestId, false); + return; + } + emit requestSent(requestId, true); + }); + return requestId; } QUuid Doorbird::listSchedules() { + QNetworkRequest request(QString("http://%1/bha-api/schedule.cgi").arg(m_address.toString())); + qCDebug(dcDoorBird) << "Sending request:" << request.url(); + QNetworkReply *reply = m_networkAccessManager->get(request); + QUuid requestId = QUuid::createUuid(); + connect(reply, &QNetworkReply::finished, this, [this, reply, requestId](){ + reply->deleteLater(); + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error DoorBird device" << reply->error() << reply->errorString(); + emit requestSent(requestId, false); + return; + } + emit requestSent(requestId, true); + }); + return requestId; } QUuid Doorbird::restart() @@ -177,24 +271,27 @@ QUuid Doorbird::restart() QNetworkRequest request(QString("http://%1/bha-api/restart.cgi").arg(m_address.toString())); qCDebug(dcDoorBird) << "Sending request:" << request.url(); QNetworkReply *reply = m_networkAccessManager->get(request); - - connect(reply, &QNetworkReply::finished, this, [this, reply, action](){ + QUuid requestId = QUuid::createUuid(); + connect(reply, &QNetworkReply::finished, this, [this, reply, requestId](){ reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { qCWarning(dcDoorBird) << "Error restarting DoorBird device" << reply; + emit requestSent(requestId, false); return; } qCDebug(dcDoorBird) << "DoorBird restarting"; + emit requestSent(requestId, true); }); + return requestId; } void Doorbird::connectToEventMonitor() { qCDebug(dcDoorBird) << "Starting monitoring"; - QNetworkRequest request(QString("http://%1/bha-api/monitor.cgi?ring=doorbell,motionsensor").arg(m_address.toString()); - QNetworkReply *reply = m_networkAccessManager->get(request); + QNetworkRequest request(QString("http://%1/bha-api/monitor.cgi?ring=doorbell,motionsensor").arg(m_address.toString())); + QNetworkReply *reply = m_networkAccessManager->get(request); connect(reply, &QNetworkReply::downloadProgress, this, [this, reply](qint64 bytesReceived, qint64 bytesTotal){ Q_UNUSED(bytesReceived) @@ -210,7 +307,7 @@ void Doorbird::connectToEventMonitor() while (!m_readBuffers.isEmpty()) { // find next --ioboundary - QString boundary = QStringLiteral("--ioboundary"); + /*QString boundary = QStringLiteral("--ioboundary"); int startIndex = m_readBuffers.indexOf(boundary); if (startIndex == -1) { qCWarning(dcDoorBird) << "No meaningful data in buffer:" << m_readBuffers; @@ -265,17 +362,18 @@ void Doorbird::connectToEventMonitor() } } else { qCWarning(dcDoorBird) << "Unhandled DoorBird data:" << message; - } + }*/ } }); - connect(reply, &QNetworkReply::finished, this, [this, reply](){ + + connect(reply, &QNetworkReply::finished, this, [this, reply]() { reply->deleteLater(); //device->setStateValue(doorBirdConnectedStateTypeId, false); qCDebug(dcDoorBird) << "Monitor request finished:" << reply->error(); QTimer::singleShot(2000, this, [this] { - connectToEventMonitor(device); + connectToEventMonitor(); }); }); } From 6d0c479d18ebd468b878b8162797471b88245240 Mon Sep 17 00:00:00 2001 From: nymea Date: Tue, 24 Sep 2019 17:21:53 +0200 Subject: [PATCH 05/18] added qr code reader --- doorbird/doorbird.pro | 8 +- doorbird/qrcodereader.cpp | 189 ++++++++++++++++++++++++++++++++++++++ doorbird/qrcodereader.h | 88 ++++++++++++++++++ 3 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 doorbird/qrcodereader.cpp create mode 100644 doorbird/qrcodereader.h diff --git a/doorbird/doorbird.pro b/doorbird/doorbird.pro index 0ea9d1fb..c519c376 100644 --- a/doorbird/doorbird.pro +++ b/doorbird/doorbird.pro @@ -2,12 +2,16 @@ include(../plugins.pri) QT += network +LIBS += -lzbar + TARGET = $$qtLibraryTarget(nymea_deviceplugindoorbird) SOURCES += \ deviceplugindoorbird.cpp \ - doorbird.cpp + doorbird.cpp \ + qrcodereader.cpp \ HEADERS += \ deviceplugindoorbird.h \ - doorbird.h + doorbird.h \ + qrcodereader.h \ diff --git a/doorbird/qrcodereader.cpp b/doorbird/qrcodereader.cpp new file mode 100644 index 00000000..658a2496 --- /dev/null +++ b/doorbird/qrcodereader.cpp @@ -0,0 +1,189 @@ +/***************************************************************************** + * Copyright: 2013 Michael Zanetti * + * * + * This file is part of ubuntu-authenticator * + * * + * This prject is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This project is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ****************************************************************************/ + +#include "qrcodereader.h" + +#include +#include +#include +#include + +QRCodeReader::QRCodeReader(QObject *parent) : + QObject(parent) +{ + connect(&m_readerThread, &QThread::started, this, &QRCodeReader::scanningChanged); + connect(&m_readerThread, &QThread::finished, this, &QRCodeReader::scanningChanged); +} + +bool QRCodeReader::valid() const +{ + return !m_type.isEmpty() && !m_text.isEmpty(); +} + +QString QRCodeReader::type() const +{ + return m_type; +} + +QString QRCodeReader::text() const +{ + return m_text; +} + +QImage QRCodeReader::image() const +{ + return m_image; +} + +QRect QRCodeReader::scanRect() const +{ + return m_scanRect; +} + +void QRCodeReader::setScanRect(const QRect &rect) +{ + if (m_scanRect != rect) { + m_scanRect = rect; + emit scanRectChanged(); + } +} + +bool QRCodeReader::scanning() const +{ + return m_readerThread.isRunning(); +} + +void QRCodeReader::grab(QImage image) +{ + m_type.clear(); + m_text.clear(); + emit validChanged(); + + if (m_scanRect.isValid()) { + image = image.copy(m_scanRect); + } + + Reader *reader = new Reader; + reader->moveToThread(&m_readerThread); + connect(reader, SIGNAL(finished()), reader, SLOT(deleteLater())); + connect(reader, SIGNAL(finished()), &m_readerThread, SLOT(quit())); + connect(reader, SIGNAL(resultReady(QString, QString, QImage)), this, SLOT(handleResults(QString, QString, QImage))); + m_readerThread.start(); + + QMetaObject::invokeMethod(reader, "doWork", Q_ARG(QImage, img), Q_ARG(bool, false)); +} + +void QRCodeReader::processImage(const QUrl &url) +{ + QImage image; + if (!image.load(url.path())) { + qWarning() << "can't open" << url.path(); + return; + } + + Reader *reader = new Reader; + reader->moveToThread(&m_readerThread); + connect(reader, SIGNAL(finished()), reader, SLOT(deleteLater())); + connect(reader, SIGNAL(finished()), &m_readerThread, SLOT(quit())); + connect(reader, SIGNAL(resultReady(QString, QString, QImage)), this, SLOT(handleResults(QString, QString, QImage))); + m_readerThread.start(); + + QMetaObject::invokeMethod(reader, "doWork", Q_ARG(QImage, image), Q_ARG(bool, false)); +} + +void QRCodeReader::handleResults(const QString &type, const QString &text, const QImage &codeImage) +{ + m_type = type; + m_text = text; + m_image = codeImage; + m_imageUuid = QUuid::createUuid(); + emit validChanged(); +} + +void Reader::doWork(const QImage &image, bool invert) +{ + // Prepare image + QImage copy = image; + if (invert) { + copy.invertPixels(); + } + zbar::QZBarImage img(copy.convertToFormat(QImage::Format_RGB32)); + zbar::Image tmp = img.convert(*(long*)"Y800"); + + // create a reader + zbar::ImageScanner scanner; + + // configure the reader + scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1); + scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_POSITION, 1); + scanner.set_config(zbar::ZBAR_PARTIAL, zbar::ZBAR_CFG_ENABLE, 0); + + // scan the image for barcodes + int n = scanner.scan(tmp); +// qDebug() << "scanned. have" << n << "symbols"; + if (!invert && n == 0) { + // Nothing found... try again inverted + doWork(image, true); + return; + } + + img.set_symbols(tmp.get_symbols()); + + // extract results + for(zbar::Image::SymbolIterator symbol = img.symbol_begin(); symbol != img.symbol_end(); ++symbol) { + + QString typeName = QString::fromStdString(symbol->get_type_name()); + QString symbolString = QString::fromStdString(symbol->get_data()); + + int x0 = 999999; + int y0 = 999999; + int x1 = 0; + int y1 = 0; + + for (int i = 0; i < symbol->get_location_size(); ++i) { + int x = symbol->get_location_x(i); + int y = symbol->get_location_y(i); + qDebug() << "got point" << x << y; + if (x < x0) x0 = x; + if (y < y0) y0 = y; + if (x > x1) x1 = x; + if (y > y1) y1 = y; + } + + int width = x1 - x0; + int height = y1 - y0; + + // Workaround for zBar sometimes only giving us the first bar in a barcode. + if (width < 10) width = img.get_width() - x0; + if (height < 10) height = img.get_height() - y0; + + qDebug() << "extracting code image (" << x0 << y0 << ") ("<< x1 << y1 << ")"; + QImage codeImage = image.copy(x0, y0, width, height); + + qDebug() << "Code recognized:" << typeName << ", Text:" << symbolString; + + emit resultReady(typeName, symbolString, codeImage); + } + + tmp.set_data(NULL, 0); + img.set_data(NULL, 0); + + emit finished(); +} diff --git a/doorbird/qrcodereader.h b/doorbird/qrcodereader.h new file mode 100644 index 00000000..f0c22b05 --- /dev/null +++ b/doorbird/qrcodereader.h @@ -0,0 +1,88 @@ +/***************************************************************************** + * Copyright: 2013 Michael Zanetti * + * * + * This file is part of tagger * + * * + * This prject is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This project is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ****************************************************************************/ + +#ifndef QRCODEREADER_H +#define QRCODEREADER_H + +#include +#include +#include +#include + +class QRCodeReader : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool valid READ valid NOTIFY validChanged) + Q_PROPERTY(QString type READ type NOTIFY validChanged) + Q_PROPERTY(QString text READ text NOTIFY validChanged) + Q_PROPERTY(QImage image READ image NOTIFY validChanged) + Q_PROPERTY(QString imageSource READ imageSource NOTIFY validChanged) + Q_PROPERTY(QRect scanRect READ scanRect WRITE setScanRect NOTIFY scanRectChanged) + Q_PROPERTY(bool scanning READ scanning NOTIFY scanningChanged) + Q_PROPERTY(HistoryModel* history READ history CONSTANT) + +public: + explicit QRCodeReader(QObject *parent = nullptr); + + bool valid() const; + QString type() const; + QString text() const; + QImage image() const; + QString imageSource() const; + QRect scanRect() const; + void setScanRect(const QRect &rect); + bool scanning() const; + + +public slots: + void grab(QImage image); + void processImage(const QUrl &url); + +signals: + void validChanged(); + void scanRectChanged(); + void scanningChanged(); + +private slots: + void handleResults(const QString &type, const QString &text, const QImage &codeImage); + +private: + QString m_type; + QString m_text; + QImage m_image; + QUuid m_imageUuid; + QRect m_scanRect; + + QThread m_readerThread; +}; + +class Reader : public QObject +{ + Q_OBJECT + +public slots: + void doWork(const QImage &image, bool invert); + +signals: + void resultReady(const QString &type, const QString &text, const QImage &codeImage); + void finished(); +}; + +#endif // QRCODEREADER_H From 527dc6050801160112ba4fcbf5e473c37b92802b Mon Sep 17 00:00:00 2001 From: nymea Date: Tue, 24 Sep 2019 23:05:30 +0200 Subject: [PATCH 06/18] updated to new nymea api --- doorbird/deviceplugindoorbird.cpp | 211 +++++++++++++++++++++-------- doorbird/deviceplugindoorbird.h | 22 ++- doorbird/deviceplugindoorbird.json | 20 ++- doorbird/doorbird.cpp | 122 +++++++++++++---- doorbird/doorbird.h | 31 ++++- doorbird/qrcodereader.cpp | 5 +- doorbird/qrcodereader.h | 4 +- 7 files changed, 315 insertions(+), 100 deletions(-) diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp index 09123d25..03f117eb 100644 --- a/doorbird/deviceplugindoorbird.cpp +++ b/doorbird/deviceplugindoorbird.cpp @@ -35,64 +35,74 @@ DevicePluginDoorbird::DevicePluginDoorbird() { } -DevicePluginDoorbird::~DevicePluginDoorbird() -{ -} - -Device::DeviceError DevicePluginDoorbird::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) +void DevicePluginDoorbird::discoverDevices(DeviceDiscoveryInfo *info) { - Q_UNUSED(params) - if (deviceClassId == doorBirdDeviceClassId) { - ZeroConfServiceBrowser *serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser(); - QTimer::singleShot(5000, this, [this, serviceBrowser](){ - QList deviceDescriptors; + if (info->deviceClassId() == doorBirdDeviceClassId) { + ZeroConfServiceBrowser *serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_axis-video._tcp"); + connect(info, &QObject::destroyed, serviceBrowser, &QObject::deleteLater); + + QTimer::singleShot(5000, this, [this, info, serviceBrowser](){ foreach (const ZeroConfServiceEntry serviceEntry, serviceBrowser->serviceEntries()) { if (serviceEntry.hostName().startsWith("bha-")) { - qCDebug(dcDoorBird) << "Found DoorBird device"; + qCDebug(dcDoorBird) << "Found DoorBird device, name: " << serviceEntry.name() << "\n host address:" << serviceEntry.hostAddress().toString() << "\n text:" << serviceEntry.txt() << serviceEntry.protocol() << serviceEntry.serviceType(); DeviceDescriptor deviceDescriptor(doorBirdDeviceClassId, serviceEntry.name(), serviceEntry.hostAddress().toString()); ParamList params; - //TODO add rediscovery - params.append(Param(doorBirdDeviceSerialnumberParamTypeId, serviceEntry.hostName())); + QString macAddress = serviceEntry.txt().first(); + if (!myDevices().filterByParam(doorBirdDeviceSerialnumberParamTypeId, macAddress).isEmpty()) { + Device *existingDevice = myDevices().filterByParam(doorBirdDeviceSerialnumberParamTypeId, serviceEntry.hostName()).first(); + deviceDescriptor.setDeviceId(existingDevice->id()); + } + params.append(Param(doorBirdDeviceSerialnumberParamTypeId, macAddress)); params.append(Param(doorBirdDeviceAddressParamTypeId, serviceEntry.hostAddress().toString())); deviceDescriptor.setParams(params); - deviceDescriptors.append(deviceDescriptor); + info->addDeviceDescriptor(deviceDescriptor); } } - emit devicesDiscovered(doorBirdDeviceClassId, deviceDescriptors); serviceBrowser->deleteLater(); + info->finish(Device::DeviceErrorNoError); }); - return Device::DeviceErrorAsync; + return; } - return Device::DeviceErrorDeviceClassNotFound; -} - -DevicePairingInfo DevicePluginDoorbird::pairDevice(DevicePairingInfo &devicePairingInfo) -{ - qCDebug(dcDoorBird()) << "PairDevice:" << devicePairingInfo.deviceClassId(); - - devicePairingInfo.setStatus(Device::DeviceErrorNoError); - devicePairingInfo.setMessage(tr("Please enter username and password for your Doorbird device.")); - return devicePairingInfo; -} - -DevicePairingInfo DevicePluginDoorbird::confirmPairing(DevicePairingInfo &devicePairingInfo, const QString &username, const QString &secret) -{ - qCDebug(dcDoorBird()) << "confirm pairing called"; - - pluginStorage()->beginGroup(devicePairingInfo.deviceId().toString()); - pluginStorage()->setValue("username", username); - pluginStorage()->setValue("password", secret); - pluginStorage()->endGroup(); - - devicePairingInfo.setStatus(Device::DeviceErrorNoError); - - return devicePairingInfo; + qCWarning(dcDoorBird()) << "Cannot discover for deviceClassId" << info->deviceClassId(); + info->finish(Device::DeviceErrorDeviceNotFound); } -Device::DeviceSetupStatus DevicePluginDoorbird::setupDevice(Device *device) +void DevicePluginDoorbird::startPairing(DevicePairingInfo *info) { + + if (info->deviceClassId() == doorBirdDeviceClassId) { + qCDebug(dcDoorBird()) << "User and password. Login is \"user\" and \"password\"."; + info->finish(Device::DeviceErrorNoError, QT_TR_NOOP("Please enter the user credentials")); + return; + } + info->finish(Device::DeviceErrorCreationMethodNotSupported); +} + + +void DevicePluginDoorbird::confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) +{ + if (info->deviceClassId() == doorBirdDeviceClassId) { + qCDebug(dcDoorBird()) << "confirm pairing called"; + + pluginStorage()->beginGroup(info->deviceId().toString()); + pluginStorage()->setValue("username", username); + pluginStorage()->setValue("password", secret); + pluginStorage()->endGroup(); + + info->finish(Device::DeviceErrorNoError); + return; + } + info->finish(Device::DeviceErrorDeviceClassNotFound); + return; +} + + +void DevicePluginDoorbird::setupDevice(DeviceSetupInfo *info) +{ + Device *device = info->device(); + if (device->deviceClassId() == doorBirdDeviceClassId) { QHostAddress address = QHostAddress(device->paramValue(doorBirdDeviceAddressParamTypeId).toString()); @@ -101,32 +111,61 @@ Device::DeviceSetupStatus DevicePluginDoorbird::setupDevice(Device *device) QString password = pluginStorage()->value("password").toString(); pluginStorage()->endGroup(); + qCDebug(dcDoorBird()) << "Device setup" << device->name() << username << password; Doorbird *doorbird = new Doorbird(address, username, password, this); + connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected); + connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent); + connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); doorbird->connectToEventMonitor(); m_doorbirdConnections.insert(device, doorbird); - return Device::DeviceSetupStatusSuccess; + info->finish(Device::DeviceErrorNoError); + return; } - return Device::DeviceSetupStatusFailure; + qCWarning(dcDoorBird()) << "Unhandled device class" << info->device()->deviceClass(); + info->finish(Device::DeviceErrorDeviceClassNotFound); } -Device::DeviceError DevicePluginDoorbird::executeAction(Device *device, const Action &action) + +void DevicePluginDoorbird::postSetupDevice(Device *device) { if (device->deviceClassId() == doorBirdDeviceClassId) { - Doorbird *doorbird = m_doorbirdConnections.value(device); - if (!doorbird) - return Device::DeviceErrorDeviceNotFound; - - if (action.actionTypeId() == doorBirdOpenDoorActionTypeId) { - //Todo get action param - doorbird->openDoor(1); - return Device::DeviceErrorNoError; - } - if (action.actionTypeId() == doorBirdLightOnActionTypeId) { - doorbird->lightOn(); - return Device::DeviceErrorNoError; - } + Doorbird *doorbird = m_doorbirdConnections.value(device); + doorbird->infoRequest(); + doorbird->listFavorites(); + doorbird->listSchedules(); } - return Device::DeviceErrorDeviceClassNotFound; +} + + +void DevicePluginDoorbird::executeAction(DeviceActionInfo *info) +{ + Device *device = info->device(); + Action action = info->action(); + + if (device->deviceClassId() == doorBirdDeviceClassId) { + Doorbird *doorbird = m_doorbirdConnections.value(device); + if (!doorbird) { + info->finish(Device::DeviceErrorHardwareFailure); + return; + } + if (action.actionTypeId() == doorBirdOpenDoorActionTypeId) { + int number = action.param(doorBirdOpenDoorActionNumberParamTypeId).value().toInt(); + doorbird->openDoor(number); + info->finish(Device::DeviceErrorNoError); + return; + } else if (action.actionTypeId() == doorBirdLightOnActionTypeId) { + doorbird->lightOn(); + info->finish(Device::DeviceErrorNoError); + return; + } else if (action.actionTypeId() == doorBirdRestartActionTypeId) { + doorbird->restart(); + info->finish(Device::DeviceErrorNoError); + return; + } + info->finish(Device::DeviceErrorActionTypeNotFound); + return; + } + info->finish(Device::DeviceErrorDeviceClassNotFound); } void DevicePluginDoorbird::deviceRemoved(Device *device) @@ -136,3 +175,59 @@ void DevicePluginDoorbird::deviceRemoved(Device *device) doorbirdConnection->deleteLater(); } } + +void DevicePluginDoorbird::onDoorBirdConnected(bool status) +{ + Doorbird *doorbird = static_cast(sender()); + Device *device = m_doorbirdConnections.key(doorbird); + if (!device) + return; + + device->setStateValue(doorBirdConnectedStateTypeId, status); +} + +void DevicePluginDoorbird::onDoorBirdEvent(Doorbird::EventType eventType, bool status) +{ + Doorbird *doorbird = static_cast(sender()); + Device *device = m_doorbirdConnections.key(doorbird); + if (!device) + return; + + switch (eventType) { + case Doorbird::EventType::Rfid: + break; + case Doorbird::EventType::Input: + break; + case Doorbird::EventType::Motion: + device->setStateValue(doorBirdIsPresentStateTypeId, status); + if (status) { + doorbird->liveImageRequest(); + } + break; + case Doorbird::EventType::Doorbell: + if (status) { + emit emitEvent(Event(doorBirdDoorbellPressedEventTypeId ,device->id())); + } + break; + } +} + +void DevicePluginDoorbird::onDoorBirdRequestSent(QUuid requestId, bool success) +{ + Doorbird *doorbird = static_cast(sender()); + Device *device = m_doorbirdConnections.key(doorbird); + if (!device) + return; + + if (!m_asyncActions.contains(requestId)) + return; + + DeviceActionInfo* actionInfo = m_asyncActions.take(requestId); + actionInfo->finish(success ? Device::DeviceErrorNoError : Device::DeviceErrorInvalidParameter); +} + +void DevicePluginDoorbird::onImageReceived(QImage image) +{ + Q_UNUSED(image) + //QString code = +} diff --git a/doorbird/deviceplugindoorbird.h b/doorbird/deviceplugindoorbird.h index e18b250e..9be0a4ee 100644 --- a/doorbird/deviceplugindoorbird.h +++ b/doorbird/deviceplugindoorbird.h @@ -21,6 +21,8 @@ #ifndef DEVICEPLUGINDOORBIRD_H #define DEVICEPLUGINDOORBIRD_H +#include + #include "devices/deviceplugin.h" #include "devices/devicemanager.h" #include "doorbird.h" @@ -35,22 +37,28 @@ class DevicePluginDoorbird: public DevicePlugin Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "deviceplugindoorbird.json") Q_INTERFACES(DevicePlugin) - public: explicit DevicePluginDoorbird(); - ~DevicePluginDoorbird() override; - Device::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override; + void discoverDevices(DeviceDiscoveryInfo *info) override; + void setupDevice(DeviceSetupInfo *info) override; + void postSetupDevice(Device *device) override; + void executeAction(DeviceActionInfo *info) override; - Device::DeviceSetupStatus setupDevice(Device *device) override; - Device::DeviceError executeAction(Device *device, const Action &action) override; + void startPairing(DevicePairingInfo *info) override; + void confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) override; - DevicePairingInfo confirmPairing(DevicePairingInfo &devicePairingInfo, const QString &username, const QString &secret) override; - DevicePairingInfo pairDevice(DevicePairingInfo &devicePairingInfo) override; void deviceRemoved(Device *device)override; private: QHash m_doorbirdConnections; + QHash m_asyncActions; + +private slots: + void onDoorBirdConnected(bool status); + void onDoorBirdEvent(Doorbird::EventType eventType, bool status); + void onDoorBirdRequestSent(QUuid requestId, bool success); + void onImageReceived(QImage image); }; #endif // DEVICEPLUGINDOORBIRD_H diff --git a/doorbird/deviceplugindoorbird.json b/doorbird/deviceplugindoorbird.json index 8f9ed2ee..caa78c48 100644 --- a/doorbird/deviceplugindoorbird.json +++ b/doorbird/deviceplugindoorbird.json @@ -33,12 +33,30 @@ { "id": "b6c3377b-91de-411a-9d48-8b509c39d67c", "name": "openDoor", - "displayName": "Open door" + "displayName": "Open door", + "paramTypes": [ + { + "id": "95dd35d7-0bc3-49e1-af96-d8da8ea5244d", + "name": "number", + "displayName": "Relay number", + "type": "QString", + "allowedValues": [ + "1", + "2" + ], + "defaultValue": 1 + } + ] }, { "id": "3a6cfc5d-804c-4d21-91b5-999913d4f1a5", "name": "lightOn", "displayName": "Light on" + }, + { + "id": "e874242e-5acb-4d98-94c7-0a70db65150c", + "name": "restart", + "displayName": "Restart" } ], "stateTypes": [ diff --git a/doorbird/doorbird.cpp b/doorbird/doorbird.cpp index a2a6dce9..429b4b45 100644 --- a/doorbird/doorbird.cpp +++ b/doorbird/doorbird.cpp @@ -218,11 +218,11 @@ QUuid Doorbird::infoRequest() reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcDoorBird) << "Error unlatching DoorBird device"; + qCWarning(dcDoorBird) << "Error DoorBird" << reply->error() << reply->errorString(); emit requestSent(requestId, false); return; } - qCDebug(dcDoorBird) << "DoorBird unlatched:" << reply->error() << reply->errorString(); + qCDebug(dcDoorBird) << "DoorBird info:" << reply->readAll() ; emit requestSent(requestId, true); }); return requestId; @@ -247,6 +247,36 @@ QUuid Doorbird::listFavorites() return requestId; } +QUuid Doorbird::addFavorite(FavoriteType type, const QString &name, const QUrl &commandUrl, int id) +{ + QUrl url(QString("http://%1/bha-api/favorites.cgi").arg(m_address.toString())); + QUrlQuery query; + query.addQueryItem("action", "save"); + if (type == FavoriteType::Http) { + query.addQueryItem("type", "http"); + } else { + query.addQueryItem("type", "sip"); + } + query.addQueryItem("title", name); + query.addQueryItem("value", commandUrl.toString()); + query.addQueryItem("id", QString::number(id)); + url.setQuery(query); + + QNetworkReply *reply = m_networkAccessManager->get(QNetworkRequest(url)); + QUuid requestId = QUuid::createUuid(); + connect(reply, &QNetworkReply::finished, this, [this, reply, requestId](){ + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcDoorBird) << "Error DoorBird device" << reply->error() << reply->errorString(); + emit requestSent(requestId, false); + return; + } + emit requestSent(requestId, true); + }); + return requestId; +} + QUuid Doorbird::listSchedules() { QNetworkRequest request(QString("http://%1/bha-api/schedule.cgi").arg(m_address.toString())); @@ -297,35 +327,34 @@ void Doorbird::connectToEventMonitor() Q_UNUSED(bytesReceived) Q_UNUSED(bytesTotal); - //TODO emit signal connected - m_readBuffers.append(reply->readAll()); - // qCDebug(dcDoorBird) << "Monitor data for" << device->name(); - // qCDebug(dcDoorBird) << m_readBuffers[device]; + emit deviceConnected(true); + m_readBuffer.append(reply->readAll()); + qCDebug(dcDoorBird) << "Event received" << m_readBuffer; // Input data looks like: // "--ioboundary\r\nContent-Type: text/plain\r\n\r\ndoorbell:H\r\n\r\n" - while (!m_readBuffers.isEmpty()) { + while (!m_readBuffer.isEmpty()) { // find next --ioboundary - /*QString boundary = QStringLiteral("--ioboundary"); - int startIndex = m_readBuffers.indexOf(boundary); + QString boundary = QStringLiteral("--ioboundary"); + int startIndex = m_readBuffer.indexOf(boundary); if (startIndex == -1) { - qCWarning(dcDoorBird) << "No meaningful data in buffer:" << m_readBuffers; - if (m_readBuffers.size() > 1024) { + qCWarning(dcDoorBird) << "No meaningful data in buffer:" << m_readBuffer; + if (m_readBuffer.size() > 1024) { qCWarning(dcDoorBird) << "Buffer size > 1KB and still no meaningful data. Discarding buffer..."; - m_readBuffers.clear(); + m_readBuffer.clear(); } // Assuming we don't have enough data yet... return; } QByteArray contentType = QByteArrayLiteral("Content-Type: text/plain"); - int contentTypeIndex = m_readBuffers.indexOf(contentType); + int contentTypeIndex = m_readBuffer.indexOf(contentType); if (contentTypeIndex == -1) { - qCWarning(dcDoorBird) << "Cannot find Content-Type in buffer:" << m_readBuffers; - if (m_readBuffers.size() > startIndex + 50) { + qCWarning(dcDoorBird) << "Cannot find Content-Type in buffer:" << m_readBuffer; + if (m_readBuffer.size() > startIndex + 50) { qCWarning(dcDoorBird) << boundary << "found but unexpected data follows. Skipping this element..."; - m_readBuffers.remove(0, startIndex + boundary.length()); + m_readBuffer.remove(0, startIndex + boundary.length()); continue; } // Assuming we don't have enough data yet... @@ -333,15 +362,15 @@ void Doorbird::connectToEventMonitor() } // At this point we have the boundary and Content-Type. Remove all of that and take the entire string to either end or next boundary - m_readBuffers.remove(0, contentTypeIndex + contentType.length()); - int nextStartIndex = m_readBuffers.indexOf(boundary); + m_readBuffer.remove(0, contentTypeIndex + contentType.length()); + int nextStartIndex = m_readBuffer.indexOf(boundary); QByteArray data; if (nextStartIndex == -1) { - data = m_readBuffers; - m_readBuffers.clear(); + data = m_readBuffer; + m_readBuffer.clear(); } else { - data = m_readBuffers.left(nextStartIndex); - m_readBuffers.remove(0, nextStartIndex); + data = m_readBuffer.left(nextStartIndex); + m_readBuffer.remove(0, nextStartIndex); } QString message = data.trimmed(); @@ -353,23 +382,27 @@ void Doorbird::connectToEventMonitor() if (parts.first() == "doorbell") { if (parts.at(1) == "H") { qCDebug(dcDoorBird) << "Doorbell ringing!"; - //emitEvent(Event(doorBirdTriggeredEventTypeId, device->id())); + emit eventReveiced(EventType::Doorbell, true); + } else { + emit eventReveiced(EventType::Doorbell, false); } } else if (parts.first() == "motionsensor") { if (parts.at(1) == "H") { qCDebug(dcDoorBird) << "Motion sensor detected a person"; - //emitEvent(Event(doorBirdMotionDetectedEventTypeId, device->id())); + emit eventReveiced(EventType::Motion, true); + } else { + emit eventReveiced(EventType::Motion, false); } } else { qCWarning(dcDoorBird) << "Unhandled DoorBird data:" << message; - }*/ + } } }); connect(reply, &QNetworkReply::finished, this, [this, reply]() { reply->deleteLater(); - //device->setStateValue(doorBirdConnectedStateTypeId, false); + emit deviceConnected(false); qCDebug(dcDoorBird) << "Monitor request finished:" << reply->error(); QTimer::singleShot(2000, this, [this] { @@ -378,3 +411,40 @@ void Doorbird::connectToEventMonitor() }); } +void Doorbird::onUdpBroadcast(const QByteArray &data) +{ + Q_UNUSED(data); + //TODO decryption +} + + +/*NotifyBroadcastCiphertext decryptBroadcastNotification(const NotifyBroadcast* notification, const + StretchedPassword* password) { + NotifyBroadcastCiphertext decrypted = {{0},{0},0}; + if(crypto_aead_chacha20poly1305_decrypt((unsigned char*)&decrypted, NULL, NULL, notification->ciphertext, + sizeof(notification->ciphertext), NULL, 0, notification->nonce, password->key)!=0){ + LOGGING("crypto_aead_chacha20poly1305_decrypt() failed"); + } + return decrypted; +} + +unsigned char* stretchPasswordArgon(const char *password, unsigned char *salt, unsigned* oplimit, unsigned* memlimit) { + if (sodium_is_zero(salt, CRYPTO_SALT_BYTES) && random_bytes(salt, CRYPTO_SALT_BYTES)) { + return NULL; + } + unsigned char* key = malloc(CRYPTO_ARGON_OUT_SIZE); + if (!*oplimit) { + *oplimit = crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE; + } + if (!*memlimit) { + *memlimit = crypto_pwhash_MEMLIMIT_MIN; + } + if (crypto_pwhash(key, CRYPTO_ARGON_OUT_SIZE, password, str_len(password), salt, *oplimit, *memlimit, crypto_pwhash_ALG_ARGON2I13)) { + LOGGING("Argon2 Failed"); + *oplimit = 0; + *memlimit = 0; + CLEAN(key); + return NULL; + } + return key; +}*/ diff --git a/doorbird/doorbird.h b/doorbird/doorbird.h index 69e05d0b..1f376345 100644 --- a/doorbird/doorbird.h +++ b/doorbird/doorbird.h @@ -1,4 +1,4 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2019 Bernhard Trinnes * * Copyright (C) 2019 Michael Zanetti * @@ -33,6 +33,24 @@ class Doorbird : public QObject public: explicit Doorbird(const QHostAddress &address, const QString &username, const QString &password, QObject *parent = nullptr); + enum EventType { + Doorbell, + Motion, + Input, + Rfid + }; + enum FavoriteType { + Http, + Sip + }; + + struct FavoriteObject { + FavoriteType type; + QString title; + QUrl value; + int id; + }; + QUuid getSession(); QUuid openDoor(int value); QUuid lightOn(); @@ -45,11 +63,11 @@ public: QUuid infoRequest(); QUuid listFavorites(); - QUuid addFavorite(); + QUuid addFavorite(FavoriteType type, const QString &name, const QUrl &url, int id); QUuid deleteFavorite(); QUuid listSchedules(); - QUuid daddScheduleEntry(); + QUuid addScheduleEntry(EventType event, int favoriteNumber, bool enabled); QUuid deleteScheduleEntry(); QUuid restart(); @@ -57,7 +75,7 @@ public: void connectToEventMonitor(); private: QNetworkAccessManager *m_networkAccessManager; - QList m_readBuffers; + QByteArray m_readBuffer; QHostAddress m_address; QList m_networkRequests; @@ -68,9 +86,14 @@ private: QByteArray sessionId; signals: + void deviceConnected(bool status); void requestSent(QUuid requestId, bool success); + void eventReveiced(EventType eventType, bool status); + void favoritesReceived(QList favourites); + public slots: + void onUdpBroadcast(const QByteArray &data); }; #endif // DOORBIRD_H diff --git a/doorbird/qrcodereader.cpp b/doorbird/qrcodereader.cpp index 658a2496..e16fa363 100644 --- a/doorbird/qrcodereader.cpp +++ b/doorbird/qrcodereader.cpp @@ -17,7 +17,7 @@ * along with this program. If not, see . * * * ****************************************************************************/ - +/* #include "qrcodereader.h" #include @@ -87,7 +87,7 @@ void QRCodeReader::grab(QImage image) connect(reader, SIGNAL(resultReady(QString, QString, QImage)), this, SLOT(handleResults(QString, QString, QImage))); m_readerThread.start(); - QMetaObject::invokeMethod(reader, "doWork", Q_ARG(QImage, img), Q_ARG(bool, false)); + //QMetaObject::invokeMethod(reader, "doWork", Q_ARG(QImage, img), Q_ARG(bool, false)); } void QRCodeReader::processImage(const QUrl &url) @@ -187,3 +187,4 @@ void Reader::doWork(const QImage &image, bool invert) emit finished(); } +*/ diff --git a/doorbird/qrcodereader.h b/doorbird/qrcodereader.h index f0c22b05..7b2edd15 100644 --- a/doorbird/qrcodereader.h +++ b/doorbird/qrcodereader.h @@ -17,7 +17,7 @@ * along with this program. If not, see . * * * ****************************************************************************/ - +/* #ifndef QRCODEREADER_H #define QRCODEREADER_H @@ -36,7 +36,6 @@ class QRCodeReader : public QObject Q_PROPERTY(QString imageSource READ imageSource NOTIFY validChanged) Q_PROPERTY(QRect scanRect READ scanRect WRITE setScanRect NOTIFY scanRectChanged) Q_PROPERTY(bool scanning READ scanning NOTIFY scanningChanged) - Q_PROPERTY(HistoryModel* history READ history CONSTANT) public: explicit QRCodeReader(QObject *parent = nullptr); @@ -86,3 +85,4 @@ signals: }; #endif // QRCODEREADER_H +*/ From 4eec7e271749baf8a0df647331766b3dca9a090c Mon Sep 17 00:00:00 2001 From: Boernsman Date: Fri, 15 Nov 2019 16:44:27 +0100 Subject: [PATCH 07/18] removed qr code added image request --- doorbird/deviceplugindoorbird.cpp | 14 ++- doorbird/deviceplugindoorbird.json | 13 ++ doorbird/doorbird.cpp | 30 ++--- doorbird/doorbird.h | 3 + doorbird/doorbird.pro | 4 - doorbird/qrcodereader.cpp | 190 ----------------------------- doorbird/qrcodereader.h | 88 ------------- 7 files changed, 44 insertions(+), 298 deletions(-) diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp index 03f117eb..e34eb03a 100644 --- a/doorbird/deviceplugindoorbird.cpp +++ b/doorbird/deviceplugindoorbird.cpp @@ -116,6 +116,7 @@ void DevicePluginDoorbird::setupDevice(DeviceSetupInfo *info) connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected); connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent); connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); + connect(doorbird, &Doorbird::liveImageReceived, this, &DevicePluginDoorbird::onImageReceived); doorbird->connectToEventMonitor(); m_doorbirdConnections.insert(device, doorbird); info->finish(Device::DeviceErrorNoError); @@ -228,6 +229,15 @@ void DevicePluginDoorbird::onDoorBirdRequestSent(QUuid requestId, bool success) void DevicePluginDoorbird::onImageReceived(QImage image) { - Q_UNUSED(image) - //QString code = + Q_UNUSED(image); + Doorbird *doorbird = static_cast(sender()); + Device *device = m_doorbirdConnections.key(doorbird); + if (!device) + return; + //TODO add QR code detection + Event event; + event.setDeviceId(device->id()); + event.setEventTypeId(doorBirdQrCodeDetectedEventTypeId); + event.setParams(ParamList() << Param(doorBirdQrCodeDetectedEventDataParamTypeId, "image received")); + emit emitEvent(event); } diff --git a/doorbird/deviceplugindoorbird.json b/doorbird/deviceplugindoorbird.json index caa78c48..6e0057c7 100644 --- a/doorbird/deviceplugindoorbird.json +++ b/doorbird/deviceplugindoorbird.json @@ -91,6 +91,19 @@ "id": "9bc89937-a2ab-4e8e-af0e-a9ba41caa89b", "name": "doorbellPressed", "displayName": "Doorbell pressed" + }, + { + "id": "224f1be5-17d3-460d-9bb8-a25fcdf28936", + "name": "qrCodeDetected", + "displayName": "QR code detected", + "paramTypes": [ + { + "id": "c53068b9-604e-4dfc-8d23-26e8bab0233c", + "name": "data", + "displayName": "Data", + "type": "QString" + } + ] } ] } diff --git a/doorbird/doorbird.cpp b/doorbird/doorbird.cpp index 429b4b45..4fb99b79 100644 --- a/doorbird/doorbird.cpp +++ b/doorbird/doorbird.cpp @@ -105,7 +105,7 @@ QUuid Doorbird::lightOn() reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcDoorBird) << "Error unlatching DoorBird device" << reply->error() << reply->errorString(); + qCWarning(dcDoorBird) << "Error light on" << reply->error() << reply->errorString(); emit requestSent(requestId, false); return; } @@ -117,7 +117,7 @@ QUuid Doorbird::lightOn() QUuid Doorbird::liveVideoRequest() { - QNetworkRequest request(QString("http://%1/bha-api/info.cgi").arg(m_address.toString())); + QNetworkRequest request(QString("http://%1/bha-api/video.cgi").arg(m_address.toString())); qCDebug(dcDoorBird) << "Sending request:" << request.url(); QNetworkReply *reply = m_networkAccessManager->get(request); QUuid requestId = QUuid::createUuid(); @@ -125,11 +125,11 @@ QUuid Doorbird::liveVideoRequest() reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcDoorBird) << "Error unlatching DoorBird device"; + qCWarning(dcDoorBird) << "Error live video request" << reply->error() << reply->errorString(); emit requestSent(requestId, false); return; } - qCDebug(dcDoorBird) << "DoorBird unlatched:" << reply->error() << reply->errorString(); + qCDebug(dcDoorBird) << "DoorBird live video request" ; emit requestSent(requestId, true); }); return requestId; @@ -137,7 +137,7 @@ QUuid Doorbird::liveVideoRequest() QUuid Doorbird::liveImageRequest() { - QNetworkRequest request(QString("http://%1/bha-api/light-on.cgi").arg(m_address.toString())); + QNetworkRequest request(QString("http://%1/bha-api/image.cgi").arg(m_address.toString())); qCDebug(dcDoorBird) << "Sending request:" << request.url(); QNetworkReply *reply = m_networkAccessManager->get(request); QUuid requestId = QUuid::createUuid(); @@ -145,15 +145,17 @@ QUuid Doorbird::liveImageRequest() reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcDoorBird) << "Error unlatching DoorBird device" << reply->error() << reply->errorString(); + qCWarning(dcDoorBird) << "Error live image request" << reply->error() << reply->errorString(); emit requestSent(requestId, false); return; } - qCDebug(dcDoorBird) << "DoorBird light on:"; - emit requestSent(requestId, true); - QImage* image = new QImage(); - image->loadFromData(reply->readAll()); + QByteArrayList tokens = reply->readAll().split('\n'); + QImage image = QImage::fromData(tokens.last()); + //image.save("testfile"); + emit liveImageReceived(image); + qCDebug(dcDoorBird) << "DoorBird live image request:"; + emit requestSent(requestId, true); }); return requestId; } @@ -172,11 +174,11 @@ QUuid Doorbird::historyImageRequest(int index) reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcDoorBird) << "Error unlatching DoorBird device"; + qCWarning(dcDoorBird) << "Error history image request" << reply->error() << reply->errorString(); emit requestSent(requestId, false); return; } - qCDebug(dcDoorBird) << "DoorBird unlatched:" << reply->error() << reply->errorString(); + qCDebug(dcDoorBird) << "DoorBird history image received:"; emit requestSent(requestId, true); }); return requestId; @@ -192,11 +194,11 @@ QUuid Doorbird::liveAudioReceive() reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcDoorBird) << "Error DoorBird device"; + qCWarning(dcDoorBird) << "Error live audio receive"; emit requestSent(requestId, false); return; } - qCDebug(dcDoorBird) << "DoorBird unlatched:" << reply->error() << reply->errorString(); + qCDebug(dcDoorBird) << "DoorBird live audio receive"; emit requestSent(requestId, true); }); return requestId; diff --git a/doorbird/doorbird.h b/doorbird/doorbird.h index 1f376345..75a8bb18 100644 --- a/doorbird/doorbird.h +++ b/doorbird/doorbird.h @@ -26,6 +26,7 @@ #include #include #include +#include class Doorbird : public QObject { @@ -92,6 +93,8 @@ signals: void eventReveiced(EventType eventType, bool status); void favoritesReceived(QList favourites); + void liveImageReceived(QImage image); + public slots: void onUdpBroadcast(const QByteArray &data); }; diff --git a/doorbird/doorbird.pro b/doorbird/doorbird.pro index c519c376..55b1f7e0 100644 --- a/doorbird/doorbird.pro +++ b/doorbird/doorbird.pro @@ -2,16 +2,12 @@ include(../plugins.pri) QT += network -LIBS += -lzbar - TARGET = $$qtLibraryTarget(nymea_deviceplugindoorbird) SOURCES += \ deviceplugindoorbird.cpp \ doorbird.cpp \ - qrcodereader.cpp \ HEADERS += \ deviceplugindoorbird.h \ doorbird.h \ - qrcodereader.h \ diff --git a/doorbird/qrcodereader.cpp b/doorbird/qrcodereader.cpp index e16fa363..e69de29b 100644 --- a/doorbird/qrcodereader.cpp +++ b/doorbird/qrcodereader.cpp @@ -1,190 +0,0 @@ -/***************************************************************************** - * Copyright: 2013 Michael Zanetti * - * * - * This file is part of ubuntu-authenticator * - * * - * This prject is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This project is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - * * - ****************************************************************************/ -/* -#include "qrcodereader.h" - -#include -#include -#include -#include - -QRCodeReader::QRCodeReader(QObject *parent) : - QObject(parent) -{ - connect(&m_readerThread, &QThread::started, this, &QRCodeReader::scanningChanged); - connect(&m_readerThread, &QThread::finished, this, &QRCodeReader::scanningChanged); -} - -bool QRCodeReader::valid() const -{ - return !m_type.isEmpty() && !m_text.isEmpty(); -} - -QString QRCodeReader::type() const -{ - return m_type; -} - -QString QRCodeReader::text() const -{ - return m_text; -} - -QImage QRCodeReader::image() const -{ - return m_image; -} - -QRect QRCodeReader::scanRect() const -{ - return m_scanRect; -} - -void QRCodeReader::setScanRect(const QRect &rect) -{ - if (m_scanRect != rect) { - m_scanRect = rect; - emit scanRectChanged(); - } -} - -bool QRCodeReader::scanning() const -{ - return m_readerThread.isRunning(); -} - -void QRCodeReader::grab(QImage image) -{ - m_type.clear(); - m_text.clear(); - emit validChanged(); - - if (m_scanRect.isValid()) { - image = image.copy(m_scanRect); - } - - Reader *reader = new Reader; - reader->moveToThread(&m_readerThread); - connect(reader, SIGNAL(finished()), reader, SLOT(deleteLater())); - connect(reader, SIGNAL(finished()), &m_readerThread, SLOT(quit())); - connect(reader, SIGNAL(resultReady(QString, QString, QImage)), this, SLOT(handleResults(QString, QString, QImage))); - m_readerThread.start(); - - //QMetaObject::invokeMethod(reader, "doWork", Q_ARG(QImage, img), Q_ARG(bool, false)); -} - -void QRCodeReader::processImage(const QUrl &url) -{ - QImage image; - if (!image.load(url.path())) { - qWarning() << "can't open" << url.path(); - return; - } - - Reader *reader = new Reader; - reader->moveToThread(&m_readerThread); - connect(reader, SIGNAL(finished()), reader, SLOT(deleteLater())); - connect(reader, SIGNAL(finished()), &m_readerThread, SLOT(quit())); - connect(reader, SIGNAL(resultReady(QString, QString, QImage)), this, SLOT(handleResults(QString, QString, QImage))); - m_readerThread.start(); - - QMetaObject::invokeMethod(reader, "doWork", Q_ARG(QImage, image), Q_ARG(bool, false)); -} - -void QRCodeReader::handleResults(const QString &type, const QString &text, const QImage &codeImage) -{ - m_type = type; - m_text = text; - m_image = codeImage; - m_imageUuid = QUuid::createUuid(); - emit validChanged(); -} - -void Reader::doWork(const QImage &image, bool invert) -{ - // Prepare image - QImage copy = image; - if (invert) { - copy.invertPixels(); - } - zbar::QZBarImage img(copy.convertToFormat(QImage::Format_RGB32)); - zbar::Image tmp = img.convert(*(long*)"Y800"); - - // create a reader - zbar::ImageScanner scanner; - - // configure the reader - scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1); - scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_POSITION, 1); - scanner.set_config(zbar::ZBAR_PARTIAL, zbar::ZBAR_CFG_ENABLE, 0); - - // scan the image for barcodes - int n = scanner.scan(tmp); -// qDebug() << "scanned. have" << n << "symbols"; - if (!invert && n == 0) { - // Nothing found... try again inverted - doWork(image, true); - return; - } - - img.set_symbols(tmp.get_symbols()); - - // extract results - for(zbar::Image::SymbolIterator symbol = img.symbol_begin(); symbol != img.symbol_end(); ++symbol) { - - QString typeName = QString::fromStdString(symbol->get_type_name()); - QString symbolString = QString::fromStdString(symbol->get_data()); - - int x0 = 999999; - int y0 = 999999; - int x1 = 0; - int y1 = 0; - - for (int i = 0; i < symbol->get_location_size(); ++i) { - int x = symbol->get_location_x(i); - int y = symbol->get_location_y(i); - qDebug() << "got point" << x << y; - if (x < x0) x0 = x; - if (y < y0) y0 = y; - if (x > x1) x1 = x; - if (y > y1) y1 = y; - } - - int width = x1 - x0; - int height = y1 - y0; - - // Workaround for zBar sometimes only giving us the first bar in a barcode. - if (width < 10) width = img.get_width() - x0; - if (height < 10) height = img.get_height() - y0; - - qDebug() << "extracting code image (" << x0 << y0 << ") ("<< x1 << y1 << ")"; - QImage codeImage = image.copy(x0, y0, width, height); - - qDebug() << "Code recognized:" << typeName << ", Text:" << symbolString; - - emit resultReady(typeName, symbolString, codeImage); - } - - tmp.set_data(NULL, 0); - img.set_data(NULL, 0); - - emit finished(); -} -*/ diff --git a/doorbird/qrcodereader.h b/doorbird/qrcodereader.h index 7b2edd15..e69de29b 100644 --- a/doorbird/qrcodereader.h +++ b/doorbird/qrcodereader.h @@ -1,88 +0,0 @@ -/***************************************************************************** - * Copyright: 2013 Michael Zanetti * - * * - * This file is part of tagger * - * * - * This prject is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This project is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - * * - ****************************************************************************/ -/* -#ifndef QRCODEREADER_H -#define QRCODEREADER_H - -#include -#include -#include -#include - -class QRCodeReader : public QObject -{ - Q_OBJECT - Q_PROPERTY(bool valid READ valid NOTIFY validChanged) - Q_PROPERTY(QString type READ type NOTIFY validChanged) - Q_PROPERTY(QString text READ text NOTIFY validChanged) - Q_PROPERTY(QImage image READ image NOTIFY validChanged) - Q_PROPERTY(QString imageSource READ imageSource NOTIFY validChanged) - Q_PROPERTY(QRect scanRect READ scanRect WRITE setScanRect NOTIFY scanRectChanged) - Q_PROPERTY(bool scanning READ scanning NOTIFY scanningChanged) - -public: - explicit QRCodeReader(QObject *parent = nullptr); - - bool valid() const; - QString type() const; - QString text() const; - QImage image() const; - QString imageSource() const; - QRect scanRect() const; - void setScanRect(const QRect &rect); - bool scanning() const; - - -public slots: - void grab(QImage image); - void processImage(const QUrl &url); - -signals: - void validChanged(); - void scanRectChanged(); - void scanningChanged(); - -private slots: - void handleResults(const QString &type, const QString &text, const QImage &codeImage); - -private: - QString m_type; - QString m_text; - QImage m_image; - QUuid m_imageUuid; - QRect m_scanRect; - - QThread m_readerThread; -}; - -class Reader : public QObject -{ - Q_OBJECT - -public slots: - void doWork(const QImage &image, bool invert); - -signals: - void resultReady(const QString &type, const QString &text, const QImage &codeImage); - void finished(); -}; - -#endif // QRCODEREADER_H -*/ From 8dd4067d7095cb4386e636f9fd374221af5ca7e8 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Mon, 10 Feb 2020 18:23:38 +0500 Subject: [PATCH 08/18] removed QR code scanner and fixed last seen state --- doorbird/README.md | 8 ++ doorbird/deviceplugindoorbird.cpp | 77 ++++++------ doorbird/deviceplugindoorbird.h | 49 ++++---- doorbird/deviceplugindoorbird.json | 13 -- doorbird/doorbird.cpp | 50 ++++---- doorbird/doorbird.h | 49 ++++---- doorbird/qrcodereader.cpp | 0 doorbird/qrcodereader.h | 0 ...1614a-fc47-4eb2-a47c-13c50f1798ee-en_US.ts | 112 +++++++++++++++++- ...68429-e312-4c82-9eab-e1cd996e43d6-en_US.ts | 4 - 10 files changed, 243 insertions(+), 119 deletions(-) delete mode 100644 doorbird/qrcodereader.cpp delete mode 100644 doorbird/qrcodereader.h delete mode 100644 doorbird/translations/b7368429-e312-4c82-9eab-e1cd996e43d6-en_US.ts diff --git a/doorbird/README.md b/doorbird/README.md index e69de29b..bba30f16 100644 --- a/doorbird/README.md +++ b/doorbird/README.md @@ -0,0 +1,8 @@ +# DoorBird + +This plug-in let'S you capture doorbell pressed and motion events, +you are also able to set the power of the IR and the relays. + +It uses a local connection and will work without Internet. + + diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp index e34eb03a..ef85a647 100644 --- a/doorbird/deviceplugindoorbird.cpp +++ b/doorbird/deviceplugindoorbird.cpp @@ -1,23 +1,32 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2019 Bernhard Trinnes * - * Copyright (C) 2019 Michael Zanetti * - * * - * This file is part of nymea. * - * * - * nymea is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, version 2 of the License. * - * * - * nymea is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with nymea. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "deviceplugindoorbird.h" #include "plugininfo.h" @@ -48,7 +57,13 @@ void DevicePluginDoorbird::discoverDevices(DeviceDiscoveryInfo *info) qCDebug(dcDoorBird) << "Found DoorBird device, name: " << serviceEntry.name() << "\n host address:" << serviceEntry.hostAddress().toString() << "\n text:" << serviceEntry.txt() << serviceEntry.protocol() << serviceEntry.serviceType(); DeviceDescriptor deviceDescriptor(doorBirdDeviceClassId, serviceEntry.name(), serviceEntry.hostAddress().toString()); ParamList params; - QString macAddress = serviceEntry.txt().first(); + QString macAddress; + if (serviceEntry.txt().first().split("=").length() == 2) { + macAddress = serviceEntry.txt().first().split("=").last(); + } else { + qCWarning(dcDoorBird()) << "Could not parse MAC Address" << serviceEntry.txt().first(); + return; + } if (!myDevices().filterByParam(doorBirdDeviceSerialnumberParamTypeId, macAddress).isEmpty()) { Device *existingDevice = myDevices().filterByParam(doorBirdDeviceSerialnumberParamTypeId, serviceEntry.hostName()).first(); deviceDescriptor.setDeviceId(existingDevice->id()); @@ -116,7 +131,6 @@ void DevicePluginDoorbird::setupDevice(DeviceSetupInfo *info) connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected); connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent); connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); - connect(doorbird, &Doorbird::liveImageReceived, this, &DevicePluginDoorbird::onImageReceived); doorbird->connectToEventMonitor(); m_doorbirdConnections.insert(device, doorbird); info->finish(Device::DeviceErrorNoError); @@ -201,9 +215,7 @@ void DevicePluginDoorbird::onDoorBirdEvent(Doorbird::EventType eventType, bool s break; case Doorbird::EventType::Motion: device->setStateValue(doorBirdIsPresentStateTypeId, status); - if (status) { - doorbird->liveImageRequest(); - } + device->setStateValue(doorBirdLastSeenTimeStateTypeId, QDateTime::currentDateTime().toTime_t()); break; case Doorbird::EventType::Doorbell: if (status) { @@ -226,18 +238,3 @@ void DevicePluginDoorbird::onDoorBirdRequestSent(QUuid requestId, bool success) DeviceActionInfo* actionInfo = m_asyncActions.take(requestId); actionInfo->finish(success ? Device::DeviceErrorNoError : Device::DeviceErrorInvalidParameter); } - -void DevicePluginDoorbird::onImageReceived(QImage image) -{ - Q_UNUSED(image); - Doorbird *doorbird = static_cast(sender()); - Device *device = m_doorbirdConnections.key(doorbird); - if (!device) - return; - //TODO add QR code detection - Event event; - event.setDeviceId(device->id()); - event.setEventTypeId(doorBirdQrCodeDetectedEventTypeId); - event.setParams(ParamList() << Param(doorBirdQrCodeDetectedEventDataParamTypeId, "image received")); - emit emitEvent(event); -} diff --git a/doorbird/deviceplugindoorbird.h b/doorbird/deviceplugindoorbird.h index 9be0a4ee..9c7ebd7f 100644 --- a/doorbird/deviceplugindoorbird.h +++ b/doorbird/deviceplugindoorbird.h @@ -1,22 +1,32 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2019 Michael Zanetti * - * * - * This file is part of nymea. * - * * - * nymea is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, version 2 of the License. * - * * - * nymea is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with nymea. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef DEVICEPLUGINDOORBIRD_H #define DEVICEPLUGINDOORBIRD_H @@ -58,7 +68,6 @@ private slots: void onDoorBirdConnected(bool status); void onDoorBirdEvent(Doorbird::EventType eventType, bool status); void onDoorBirdRequestSent(QUuid requestId, bool success); - void onImageReceived(QImage image); }; #endif // DEVICEPLUGINDOORBIRD_H diff --git a/doorbird/deviceplugindoorbird.json b/doorbird/deviceplugindoorbird.json index 6e0057c7..caa78c48 100644 --- a/doorbird/deviceplugindoorbird.json +++ b/doorbird/deviceplugindoorbird.json @@ -91,19 +91,6 @@ "id": "9bc89937-a2ab-4e8e-af0e-a9ba41caa89b", "name": "doorbellPressed", "displayName": "Doorbell pressed" - }, - { - "id": "224f1be5-17d3-460d-9bb8-a25fcdf28936", - "name": "qrCodeDetected", - "displayName": "QR code detected", - "paramTypes": [ - { - "id": "c53068b9-604e-4dfc-8d23-26e8bab0233c", - "name": "data", - "displayName": "Data", - "type": "QString" - } - ] } ] } diff --git a/doorbird/doorbird.cpp b/doorbird/doorbird.cpp index 4fb99b79..0d8b591f 100644 --- a/doorbird/doorbird.cpp +++ b/doorbird/doorbird.cpp @@ -1,23 +1,32 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2019 Bernhard Trinnes * - * Copyright (C) 2019 Michael Zanetti * - * * - * This file is part of nymea. * - * * - * nymea is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, version 2 of the License. * - * * - * nymea is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with nymea. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "doorbird.h" #include "extern-plugininfo.h" @@ -206,7 +215,6 @@ QUuid Doorbird::liveAudioReceive() QUuid Doorbird::liveAudioTransmit() { - return QUuid::createUuid(); } diff --git a/doorbird/doorbird.h b/doorbird/doorbird.h index 75a8bb18..da95ab56 100644 --- a/doorbird/doorbird.h +++ b/doorbird/doorbird.h @@ -1,23 +1,32 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2019 Bernhard Trinnes * - * Copyright (C) 2019 Michael Zanetti * - * * - * This file is part of nymea. * - * * - * nymea is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, version 2 of the License. * - * * - * nymea is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with nymea. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef DOORBIRD_H #define DOORBIRD_H diff --git a/doorbird/qrcodereader.cpp b/doorbird/qrcodereader.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/doorbird/qrcodereader.h b/doorbird/qrcodereader.h deleted file mode 100644 index e69de29b..00000000 diff --git a/doorbird/translations/6fe1614a-fc47-4eb2-a47c-13c50f1798ee-en_US.ts b/doorbird/translations/6fe1614a-fc47-4eb2-a47c-13c50f1798ee-en_US.ts index f7f66d85..3dbea2ab 100644 --- a/doorbird/translations/6fe1614a-fc47-4eb2-a47c-13c50f1798ee-en_US.ts +++ b/doorbird/translations/6fe1614a-fc47-4eb2-a47c-13c50f1798ee-en_US.ts @@ -1,4 +1,114 @@ - \ No newline at end of file + + DevicePluginDoorbird + + + Please enter the user credentials + + + + + doorBird + + + + Connected + The name of the ParamType (DeviceClass: doorBird, EventType: connected, ID: {186c270b-923c-46e4-a7da-33e45427cdbb}) +---------- +The name of the StateType ({186c270b-923c-46e4-a7da-33e45427cdbb}) of DeviceClass doorBird + + + + + Connected changed + The name of the EventType ({186c270b-923c-46e4-a7da-33e45427cdbb}) of DeviceClass doorBird + + + + + + + DoorBird + The name of the DeviceClass ({0485eb61-2a22-42ba-9dd2-a5961485bf08}) +---------- +The name of the vendor ({2da07435-571e-4956-a387-6caa51d6e845}) +---------- +The name of the plugin doorBird ({6fe1614a-fc47-4eb2-a47c-13c50f1798ee}) + + + + + Doorbell pressed + The name of the EventType ({9bc89937-a2ab-4e8e-af0e-a9ba41caa89b}) of DeviceClass doorBird + + + + + IP address + The name of the ParamType (DeviceClass: doorBird, Type: device, ID: {8873b17d-526e-408d-95d8-6439b501f489}) + + + + + Light on + The name of the ActionType ({3a6cfc5d-804c-4d21-91b5-999913d4f1a5}) of DeviceClass doorBird + + + + + + Motion sensor last seen time + The name of the ParamType (DeviceClass: doorBird, EventType: lastSeenTime, ID: {295c9700-b598-4681-898f-d63e2889cedf}) +---------- +The name of the StateType ({295c9700-b598-4681-898f-d63e2889cedf}) of DeviceClass doorBird + + + + + Motion sensor last seen time changedd + The name of the EventType ({295c9700-b598-4681-898f-d63e2889cedf}) of DeviceClass doorBird + + + + + + Motion sensor presence + The name of the ParamType (DeviceClass: doorBird, EventType: isPresent, ID: {0f5eb200-6c0d-45c5-9156-3060fd66d332}) +---------- +The name of the StateType ({0f5eb200-6c0d-45c5-9156-3060fd66d332}) of DeviceClass doorBird + + + + + Motion sensor presence detected + The name of the EventType ({0f5eb200-6c0d-45c5-9156-3060fd66d332}) of DeviceClass doorBird + + + + + Open door + The name of the ActionType ({b6c3377b-91de-411a-9d48-8b509c39d67c}) of DeviceClass doorBird + + + + + Relay number + The name of the ParamType (DeviceClass: doorBird, ActionType: openDoor, ID: {95dd35d7-0bc3-49e1-af96-d8da8ea5244d}) + + + + + Restart + The name of the ActionType ({e874242e-5acb-4d98-94c7-0a70db65150c}) of DeviceClass doorBird + + + + + Serial number + The name of the ParamType (DeviceClass: doorBird, Type: device, ID: {67ea5534-330a-4291-93b5-0237034e15fa}) + + + + diff --git a/doorbird/translations/b7368429-e312-4c82-9eab-e1cd996e43d6-en_US.ts b/doorbird/translations/b7368429-e312-4c82-9eab-e1cd996e43d6-en_US.ts deleted file mode 100644 index f7f66d85..00000000 --- a/doorbird/translations/b7368429-e312-4c82-9eab-e1cd996e43d6-en_US.ts +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From d19fb44c1415e7ae9ecc3d3fc5a6e713919907c7 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Mon, 10 Feb 2020 18:28:46 +0500 Subject: [PATCH 09/18] added debian packaging for doorbird --- debian/control | 16 ++++++++++++++++ debian/nymea-plugin-doorbird.install.in | 1 + doorbird/deviceplugindoorbird.json | 1 + 3 files changed, 18 insertions(+) create mode 100644 debian/nymea-plugin-doorbird.install.in diff --git a/debian/control b/debian/control index 6efef76e..d0b530df 100644 --- a/debian/control +++ b/debian/control @@ -200,6 +200,21 @@ Description: nymea.io plugin for denon This package will install the nymea.io plugin for denon +Package: nymea-plugin-doorbird +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, + nymea-plugins-translations, +Description: nymea.io plugin for DoorBird + The nymea daemon is a plugin based IoT (Internet of Things) server. The + server works like a translator for devices, things and services and + allows them to interact. + With the powerful rule engine you are able to connect any device available + in the system and create individual scenes and behaviors for your environment. + . + This package will install the nymea.io plugin for DoorBird + + Package: nymea-plugin-dweetio Architecture: any Depends: ${shlibs:Depends}, @@ -965,6 +980,7 @@ Depends: nymea-plugin-anel, nymea-plugin-datetime, nymea-plugin-daylightsensor, nymea-plugin-denon, + nymea-plugin-doorbird, nymea-plugin-eq-3, nymea-plugin-flowercare, nymea-plugin-kodi, diff --git a/debian/nymea-plugin-doorbird.install.in b/debian/nymea-plugin-doorbird.install.in new file mode 100644 index 00000000..3a517946 --- /dev/null +++ b/debian/nymea-plugin-doorbird.install.in @@ -0,0 +1 @@ +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_deviceplugindoorbird.so diff --git a/doorbird/deviceplugindoorbird.json b/doorbird/deviceplugindoorbird.json index caa78c48..a5e348f7 100644 --- a/doorbird/deviceplugindoorbird.json +++ b/doorbird/deviceplugindoorbird.json @@ -66,6 +66,7 @@ "displayName": "Connected", "displayNameEvent": "Connected changed", "type": "bool", + "cached": false, "defaultValue": false }, { From 2be130884ef2d24e6cc20d3ef773be64d8ec2466 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Mon, 10 Feb 2020 18:38:41 +0500 Subject: [PATCH 10/18] fixed rediscovery --- doorbird/deviceplugindoorbird.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp index ef85a647..89fec001 100644 --- a/doorbird/deviceplugindoorbird.cpp +++ b/doorbird/deviceplugindoorbird.cpp @@ -58,14 +58,19 @@ void DevicePluginDoorbird::discoverDevices(DeviceDiscoveryInfo *info) DeviceDescriptor deviceDescriptor(doorBirdDeviceClassId, serviceEntry.name(), serviceEntry.hostAddress().toString()); ParamList params; QString macAddress; + if (serviceEntry.txt().length() == 0) { + qCWarning(dcDoorBird()) << "Discovery failed, service entry missing"; + continue; + } + if (serviceEntry.txt().first().split("=").length() == 2) { macAddress = serviceEntry.txt().first().split("=").last(); } else { qCWarning(dcDoorBird()) << "Could not parse MAC Address" << serviceEntry.txt().first(); - return; + continue; } if (!myDevices().filterByParam(doorBirdDeviceSerialnumberParamTypeId, macAddress).isEmpty()) { - Device *existingDevice = myDevices().filterByParam(doorBirdDeviceSerialnumberParamTypeId, serviceEntry.hostName()).first(); + Device *existingDevice = myDevices().filterByParam(doorBirdDeviceSerialnumberParamTypeId, macAddress).first(); deviceDescriptor.setDeviceId(existingDevice->id()); } params.append(Param(doorBirdDeviceSerialnumberParamTypeId, macAddress)); @@ -86,7 +91,6 @@ void DevicePluginDoorbird::discoverDevices(DeviceDiscoveryInfo *info) void DevicePluginDoorbird::startPairing(DevicePairingInfo *info) { - if (info->deviceClassId() == doorBirdDeviceClassId) { qCDebug(dcDoorBird()) << "User and password. Login is \"user\" and \"password\"."; info->finish(Device::DeviceErrorNoError, QT_TR_NOOP("Please enter the user credentials")); From 64631790b4009d7fb467e2626f693a666218a223 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Mon, 10 Feb 2020 21:57:53 +0500 Subject: [PATCH 11/18] added async device setup --- doorbird/deviceplugindoorbird.cpp | 127 +++++++++++++++++++++--------- doorbird/deviceplugindoorbird.h | 6 +- doorbird/doorbird.cpp | 37 ++++++--- doorbird/doorbird.h | 11 +-- 4 files changed, 128 insertions(+), 53 deletions(-) diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp index 89fec001..aea749c6 100644 --- a/doorbird/deviceplugindoorbird.cpp +++ b/doorbird/deviceplugindoorbird.cpp @@ -83,38 +83,57 @@ void DevicePluginDoorbird::discoverDevices(DeviceDiscoveryInfo *info) info->finish(Device::DeviceErrorNoError); }); return; + } else { + qCWarning(dcDoorBird()) << "Cannot discover for deviceClassId" << info->deviceClassId(); + info->finish(Device::DeviceErrorDeviceNotFound); } - qCWarning(dcDoorBird()) << "Cannot discover for deviceClassId" << info->deviceClassId(); - info->finish(Device::DeviceErrorDeviceNotFound); } void DevicePluginDoorbird::startPairing(DevicePairingInfo *info) { if (info->deviceClassId() == doorBirdDeviceClassId) { - qCDebug(dcDoorBird()) << "User and password. Login is \"user\" and \"password\"."; - info->finish(Device::DeviceErrorNoError, QT_TR_NOOP("Please enter the user credentials")); + info->finish(Device::DeviceErrorNoError, QT_TR_NOOP("Please enter username and password for the DoorBird device")); return; + } else { + qCWarning(dcDoorBird()) << "StartPairing unhandled deviceClassId" << info->deviceClassId(); + info->finish(Device::DeviceErrorCreationMethodNotSupported); } - info->finish(Device::DeviceErrorCreationMethodNotSupported); } -void DevicePluginDoorbird::confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) +void DevicePluginDoorbird::confirmPairing(DevicePairingInfo *info, const QString &username, const QString &password) { if (info->deviceClassId() == doorBirdDeviceClassId) { - qCDebug(dcDoorBird()) << "confirm pairing called"; + QHostAddress address = QHostAddress(info->params().paramValue(doorBirdDeviceAddressParamTypeId).toString()); + + Doorbird *doorbird = new Doorbird(address, this); + connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected); + connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent); + connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); + connect(doorbird, &Doorbird::sessionIdReceived, this, &DevicePluginDoorbird::onSessionIdReceived); + doorbird->initConnection(username, password); + doorbird->connectToEventMonitor(); + m_doorbirdConnections.insert(info->deviceId(), doorbird); + m_pendingPairings.insert(doorbird, info); + doorbird->getSession(); + connect(info, &DevicePairingInfo::aborted, this, [this, info]{ + if (m_pendingPairings.values().contains(info)) { + Doorbird *doorbird = m_pendingPairings.key(info); + m_pendingPairings.remove(doorbird); + doorbird->deleteLater(); + } + m_doorbirdConnections.remove(info->deviceId()); + }); pluginStorage()->beginGroup(info->deviceId().toString()); pluginStorage()->setValue("username", username); - pluginStorage()->setValue("password", secret); + pluginStorage()->setValue("password", password); pluginStorage()->endGroup(); - - info->finish(Device::DeviceErrorNoError); - return; + } else { + qCWarning(dcDoorBird()) << "Confirm pairing DeviceClassNotFound" << info->deviceClassId(); + info->finish(Device::DeviceErrorDeviceClassNotFound); } - info->finish(Device::DeviceErrorDeviceClassNotFound); - return; } @@ -125,30 +144,45 @@ void DevicePluginDoorbird::setupDevice(DeviceSetupInfo *info) if (device->deviceClassId() == doorBirdDeviceClassId) { QHostAddress address = QHostAddress(device->paramValue(doorBirdDeviceAddressParamTypeId).toString()); - pluginStorage()->beginGroup(device->id().toString()); - QString username = pluginStorage()->value("username").toString(); - QString password = pluginStorage()->value("password").toString(); - pluginStorage()->endGroup(); + if (m_doorbirdConnections.contains(device->id())) { + info->finish(Device::DeviceErrorNoError); + } else { + pluginStorage()->beginGroup(device->id().toString()); + QString username = pluginStorage()->value("username").toString(); + QString password = pluginStorage()->value("password").toString(); + pluginStorage()->endGroup(); - qCDebug(dcDoorBird()) << "Device setup" << device->name() << username << password; - Doorbird *doorbird = new Doorbird(address, username, password, this); - connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected); - connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent); - connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); - doorbird->connectToEventMonitor(); - m_doorbirdConnections.insert(device, doorbird); - info->finish(Device::DeviceErrorNoError); - return; + qCDebug(dcDoorBird()) << "Device setup" << device->name() << username << password; + Doorbird *doorbird = new Doorbird(address, this); + connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected); + connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent); + connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); + connect(doorbird, &Doorbird::sessionIdReceived, this, &DevicePluginDoorbird::onSessionIdReceived); + doorbird->initConnection(username, password); + doorbird->connectToEventMonitor(); + m_doorbirdConnections.insert(device->id(), doorbird); + m_pendingDeviceSetups.insert(doorbird, info); + doorbird->getSession(); + connect(info, &DeviceSetupInfo::aborted, this, [device, doorbird, this] { + if (!doorbird) { + doorbird->deleteLater(); + } + m_doorbirdConnections.remove(device->id()); + m_pendingPairings.remove(doorbird); + }); + } + } else { + qCWarning(dcDoorBird()) << "Unhandled device class" << info->device()->deviceClass(); + info->finish(Device::DeviceErrorDeviceClassNotFound); } - qCWarning(dcDoorBird()) << "Unhandled device class" << info->device()->deviceClass(); - info->finish(Device::DeviceErrorDeviceClassNotFound); } void DevicePluginDoorbird::postSetupDevice(Device *device) { if (device->deviceClassId() == doorBirdDeviceClassId) { - Doorbird *doorbird = m_doorbirdConnections.value(device); + device->setStateValue(doorBirdConnectedStateTypeId, true); //since we checked the connection in the deviceSetup + Doorbird *doorbird = m_doorbirdConnections.value(device->id()); doorbird->infoRequest(); doorbird->listFavorites(); doorbird->listSchedules(); @@ -162,7 +196,7 @@ void DevicePluginDoorbird::executeAction(DeviceActionInfo *info) Action action = info->action(); if (device->deviceClassId() == doorBirdDeviceClassId) { - Doorbird *doorbird = m_doorbirdConnections.value(device); + Doorbird *doorbird = m_doorbirdConnections.value(device->id()); if (!doorbird) { info->finish(Device::DeviceErrorHardwareFailure); return; @@ -180,17 +214,20 @@ void DevicePluginDoorbird::executeAction(DeviceActionInfo *info) doorbird->restart(); info->finish(Device::DeviceErrorNoError); return; + } else { + qCWarning(dcDoorBird()) << "Unhandled ActionTypeId:" << action.actionTypeId(); + info->finish(Device::DeviceErrorActionTypeNotFound); } - info->finish(Device::DeviceErrorActionTypeNotFound); - return; + } else { + qCWarning(dcDoorBird()) << "Execute action, unhandled device class" << device->deviceClass(); + info->finish(Device::DeviceErrorDeviceClassNotFound); } - info->finish(Device::DeviceErrorDeviceClassNotFound); } void DevicePluginDoorbird::deviceRemoved(Device *device) { if (device->deviceClassId() == doorBirdDeviceClassId) { - Doorbird *doorbirdConnection = m_doorbirdConnections.take(device); + Doorbird *doorbirdConnection = m_doorbirdConnections.take(device->id()); doorbirdConnection->deleteLater(); } } @@ -198,7 +235,7 @@ void DevicePluginDoorbird::deviceRemoved(Device *device) void DevicePluginDoorbird::onDoorBirdConnected(bool status) { Doorbird *doorbird = static_cast(sender()); - Device *device = m_doorbirdConnections.key(doorbird); + Device *device = myDevices().findById(m_doorbirdConnections.key(doorbird)); if (!device) return; @@ -208,7 +245,7 @@ void DevicePluginDoorbird::onDoorBirdConnected(bool status) void DevicePluginDoorbird::onDoorBirdEvent(Doorbird::EventType eventType, bool status) { Doorbird *doorbird = static_cast(sender()); - Device *device = m_doorbirdConnections.key(doorbird); + Device *device = myDevices().findById(m_doorbirdConnections.key(doorbird)); if (!device) return; @@ -232,7 +269,7 @@ void DevicePluginDoorbird::onDoorBirdEvent(Doorbird::EventType eventType, bool s void DevicePluginDoorbird::onDoorBirdRequestSent(QUuid requestId, bool success) { Doorbird *doorbird = static_cast(sender()); - Device *device = m_doorbirdConnections.key(doorbird); + Device *device = myDevices().findById(m_doorbirdConnections.key(doorbird)); if (!device) return; @@ -242,3 +279,19 @@ void DevicePluginDoorbird::onDoorBirdRequestSent(QUuid requestId, bool success) DeviceActionInfo* actionInfo = m_asyncActions.take(requestId); actionInfo->finish(success ? Device::DeviceErrorNoError : Device::DeviceErrorInvalidParameter); } + +void DevicePluginDoorbird::onSessionIdReceived(const QString &sessionId) +{ + Q_UNUSED(sessionId); + Doorbird *doorbird = static_cast(sender()); + + if (m_pendingPairings.contains(doorbird)) { + DevicePairingInfo *info = m_pendingPairings.take(doorbird); + info->finish(Device::DeviceErrorNoError); + } + + if (m_pendingDeviceSetups.contains(doorbird)) { + DeviceSetupInfo *info = m_pendingDeviceSetups.take(doorbird); + info->finish(Device::DeviceErrorNoError); + } +} diff --git a/doorbird/deviceplugindoorbird.h b/doorbird/deviceplugindoorbird.h index 9c7ebd7f..594decb0 100644 --- a/doorbird/deviceplugindoorbird.h +++ b/doorbird/deviceplugindoorbird.h @@ -61,13 +61,17 @@ public: void deviceRemoved(Device *device)override; private: - QHash m_doorbirdConnections; + QHash m_doorbirdConnections; + QHash m_pendingPairings; + QHash m_pendingDeviceSetups; + QHash m_asyncActions; private slots: void onDoorBirdConnected(bool status); void onDoorBirdEvent(Doorbird::EventType eventType, bool status); void onDoorBirdRequestSent(QUuid requestId, bool success); + void onSessionIdReceived(const QString &sessionId); }; #endif // DEVICEPLUGINDOORBIRD_H diff --git a/doorbird/doorbird.cpp b/doorbird/doorbird.cpp index 0d8b591f..2db09e10 100644 --- a/doorbird/doorbird.cpp +++ b/doorbird/doorbird.cpp @@ -41,18 +41,30 @@ #include #include -Doorbird::Doorbird(const QHostAddress &address, const QString &username, const QString &password, QObject *parent) : +Doorbird::Doorbird(const QHostAddress &address, QObject *parent) : QObject(parent), - m_address(address), - m_username(username), - m_password(password) + m_address(address) +{ + +} + +QHostAddress Doorbird::address() +{ + return m_address; +} + +void Doorbird::setAddress(const QHostAddress &address) +{ + m_address = address; +} + +void Doorbird::initConnection(const QString &username, const QString &password) { m_networkAccessManager = new QNetworkAccessManager(this); - connect(m_networkAccessManager, &QNetworkAccessManager::authenticationRequired, this, [this](QNetworkReply *reply, QAuthenticator *authenticator) { + connect(m_networkAccessManager, &QNetworkAccessManager::authenticationRequired, this, [username, password, this](QNetworkReply *reply, QAuthenticator *authenticator) { Q_UNUSED(reply); - qCDebug(dcDoorBird) << "Credentials requested:"; - authenticator->setUser(m_username); - authenticator->setPassword(m_password); + authenticator->setUser(username); + authenticator->setPassword(password); }); } @@ -67,12 +79,11 @@ QUuid Doorbird::getSession() reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcDoorBird) << "Error unlatching DoorBird device"; + qCWarning(dcDoorBird) << "Error DoorBird device"; emit requestSent(requestId, false); return; } emit requestSent(requestId, true); - QByteArray data = reply->readAll(); QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); @@ -80,6 +91,12 @@ QUuid Doorbird::getSession() qCWarning(dcDoorBird()) << "Error parsing json:" << data; return; } + QVariantMap map = jsonDoc.toVariant().toMap().value("BHA").toMap(); + if (map.contains("SESSIONID")) { + QString sessionId = map.value("SESSIONID").toString(); + qCDebug(dcDoorBird) << "Got sessionId" << sessionId; + emit sessionIdReceived(sessionId); + } }); return requestId; } diff --git a/doorbird/doorbird.h b/doorbird/doorbird.h index da95ab56..163e9516 100644 --- a/doorbird/doorbird.h +++ b/doorbird/doorbird.h @@ -41,7 +41,7 @@ class Doorbird : public QObject { Q_OBJECT public: - explicit Doorbird(const QHostAddress &address, const QString &username, const QString &password, QObject *parent = nullptr); + explicit Doorbird(const QHostAddress &address, QObject *parent = nullptr); enum EventType { Doorbell, @@ -61,6 +61,9 @@ public: int id; }; + QHostAddress address(); + void setAddress(const QHostAddress &address); + void initConnection(const QString &username, const QString &password); QUuid getSession(); QUuid openDoor(int value); QUuid lightOn(); @@ -90,10 +93,7 @@ private: QHostAddress m_address; QList m_networkRequests; - QString m_username; - QString m_password; - - QByteArray sessionId; + //QByteArray sessionId; signals: void deviceConnected(bool status); @@ -102,6 +102,7 @@ signals: void eventReveiced(EventType eventType, bool status); void favoritesReceived(QList favourites); + void sessionIdReceived(const QString &sessionId); void liveImageReceived(QImage image); public slots: From 48d30baab13fecbbe9deb36017d0d305d9f77531 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Fri, 14 Feb 2020 15:53:30 +0500 Subject: [PATCH 12/18] added authentication failure handling --- doorbird/deviceplugindoorbird.cpp | 23 ++++++++++++++--------- doorbird/doorbird.cpp | 18 +++++++++++++----- doorbird/doorbird.h | 2 ++ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp index aea749c6..6e8fe3d4 100644 --- a/doorbird/deviceplugindoorbird.cpp +++ b/doorbird/deviceplugindoorbird.cpp @@ -113,7 +113,6 @@ void DevicePluginDoorbird::confirmPairing(DevicePairingInfo *info, const QString connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); connect(doorbird, &Doorbird::sessionIdReceived, this, &DevicePluginDoorbird::onSessionIdReceived); doorbird->initConnection(username, password); - doorbird->connectToEventMonitor(); m_doorbirdConnections.insert(info->deviceId(), doorbird); m_pendingPairings.insert(doorbird, info); doorbird->getSession(); @@ -159,7 +158,6 @@ void DevicePluginDoorbird::setupDevice(DeviceSetupInfo *info) connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); connect(doorbird, &Doorbird::sessionIdReceived, this, &DevicePluginDoorbird::onSessionIdReceived); doorbird->initConnection(username, password); - doorbird->connectToEventMonitor(); m_doorbirdConnections.insert(device->id(), doorbird); m_pendingDeviceSetups.insert(doorbird, info); doorbird->getSession(); @@ -183,6 +181,7 @@ void DevicePluginDoorbird::postSetupDevice(Device *device) if (device->deviceClassId() == doorBirdDeviceClassId) { device->setStateValue(doorBirdConnectedStateTypeId, true); //since we checked the connection in the deviceSetup Doorbird *doorbird = m_doorbirdConnections.value(device->id()); + doorbird->connectToEventMonitor(); doorbird->infoRequest(); doorbird->listFavorites(); doorbird->listSchedules(); @@ -269,15 +268,21 @@ void DevicePluginDoorbird::onDoorBirdEvent(Doorbird::EventType eventType, bool s void DevicePluginDoorbird::onDoorBirdRequestSent(QUuid requestId, bool success) { Doorbird *doorbird = static_cast(sender()); - Device *device = myDevices().findById(m_doorbirdConnections.key(doorbird)); - if (!device) - return; - if (!m_asyncActions.contains(requestId)) - return; + if (m_asyncActions.contains(requestId)) { + DeviceActionInfo* actionInfo = m_asyncActions.take(requestId); + actionInfo->finish(success ? Device::DeviceErrorNoError : Device::DeviceErrorInvalidParameter); + } - DeviceActionInfo* actionInfo = m_asyncActions.take(requestId); - actionInfo->finish(success ? Device::DeviceErrorNoError : Device::DeviceErrorInvalidParameter); + if (m_pendingPairings.contains(doorbird) && !success) { + DevicePairingInfo *info = m_pendingPairings.take(doorbird); + info->finish(Device::DeviceErrorAuthenticationFailure, tr("Wrong username or password")); + } + + if (m_pendingDeviceSetups.contains(doorbird) && !success) { + DeviceSetupInfo *info = m_pendingDeviceSetups.take(doorbird); + info->finish(Device::DeviceErrorAuthenticationFailure, tr("Wrong username or password")); + } } void DevicePluginDoorbird::onSessionIdReceived(const QString &sessionId) diff --git a/doorbird/doorbird.cpp b/doorbird/doorbird.cpp index 2db09e10..2b399619 100644 --- a/doorbird/doorbird.cpp +++ b/doorbird/doorbird.cpp @@ -61,10 +61,17 @@ void Doorbird::setAddress(const QHostAddress &address) void Doorbird::initConnection(const QString &username, const QString &password) { m_networkAccessManager = new QNetworkAccessManager(this); - connect(m_networkAccessManager, &QNetworkAccessManager::authenticationRequired, this, [username, password, this](QNetworkReply *reply, QAuthenticator *authenticator) { - Q_UNUSED(reply); - authenticator->setUser(username); - authenticator->setPassword(password); + connect(m_networkAccessManager, &QNetworkAccessManager::authenticationRequired, this, [username, password, this] (QNetworkReply *reply, QAuthenticator *authenticator) { + + qCWarning(dcDoorBird()) << "Authenticator" << reply->errorString() << reply->error(); + if (m_pendingAuthentications.contains(reply)) { + m_pendingAuthentications.removeOne(reply); + reply->abort(); + } else { + authenticator->setUser(username); + authenticator->setPassword(password); + m_pendingAuthentications.append(reply); + } }); } @@ -79,7 +86,7 @@ QUuid Doorbird::getSession() reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcDoorBird) << "Error DoorBird device"; + qCWarning(dcDoorBird) << "Error DoorBird device:" << reply->errorString(); emit requestSent(requestId, false); return; } @@ -98,6 +105,7 @@ QUuid Doorbird::getSession() emit sessionIdReceived(sessionId); } }); + return requestId; } diff --git a/doorbird/doorbird.h b/doorbird/doorbird.h index 163e9516..0d519412 100644 --- a/doorbird/doorbird.h +++ b/doorbird/doorbird.h @@ -93,6 +93,8 @@ private: QHostAddress m_address; QList m_networkRequests; + QList m_pendingAuthentications; + //QByteArray sessionId; signals: From 80e08f567584a93b101f9a5531e8f6a13936b07d Mon Sep 17 00:00:00 2001 From: Boernsman Date: Fri, 14 Feb 2020 22:36:00 +0500 Subject: [PATCH 13/18] authentication now with url credentials --- doorbird/deviceplugindoorbird.cpp | 10 ++++------ doorbird/doorbird.cpp | 32 +++++++++++-------------------- doorbird/doorbird.h | 15 +++++++++------ 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp index 6e8fe3d4..5bccd648 100644 --- a/doorbird/deviceplugindoorbird.cpp +++ b/doorbird/deviceplugindoorbird.cpp @@ -107,15 +107,14 @@ void DevicePluginDoorbird::confirmPairing(DevicePairingInfo *info, const QString if (info->deviceClassId() == doorBirdDeviceClassId) { QHostAddress address = QHostAddress(info->params().paramValue(doorBirdDeviceAddressParamTypeId).toString()); - Doorbird *doorbird = new Doorbird(address, this); + Doorbird *doorbird = new Doorbird(hardwareManager()->networkManager(), address, this); connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected); connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent); connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); connect(doorbird, &Doorbird::sessionIdReceived, this, &DevicePluginDoorbird::onSessionIdReceived); - doorbird->initConnection(username, password); m_doorbirdConnections.insert(info->deviceId(), doorbird); m_pendingPairings.insert(doorbird, info); - doorbird->getSession(); + doorbird->getSession(username, password); connect(info, &DevicePairingInfo::aborted, this, [this, info]{ if (m_pendingPairings.values().contains(info)) { Doorbird *doorbird = m_pendingPairings.key(info); @@ -152,15 +151,14 @@ void DevicePluginDoorbird::setupDevice(DeviceSetupInfo *info) pluginStorage()->endGroup(); qCDebug(dcDoorBird()) << "Device setup" << device->name() << username << password; - Doorbird *doorbird = new Doorbird(address, this); + Doorbird *doorbird = new Doorbird(hardwareManager()->networkManager(), address, this); connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected); connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent); connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); connect(doorbird, &Doorbird::sessionIdReceived, this, &DevicePluginDoorbird::onSessionIdReceived); - doorbird->initConnection(username, password); m_doorbirdConnections.insert(device->id(), doorbird); m_pendingDeviceSetups.insert(doorbird, info); - doorbird->getSession(); + doorbird->getSession(username, password); connect(info, &DeviceSetupInfo::aborted, this, [device, doorbird, this] { if (!doorbird) { doorbird->deleteLater(); diff --git a/doorbird/doorbird.cpp b/doorbird/doorbird.cpp index 2b399619..a6074acb 100644 --- a/doorbird/doorbird.cpp +++ b/doorbird/doorbird.cpp @@ -41,9 +41,10 @@ #include #include -Doorbird::Doorbird(const QHostAddress &address, QObject *parent) : +Doorbird::Doorbird(NetworkAccessManager *networkAccessManager, const QHostAddress &address, QObject *parent) : QObject(parent), - m_address(address) + m_address(address), + m_networkAccessManager(networkAccessManager) { } @@ -58,26 +59,15 @@ void Doorbird::setAddress(const QHostAddress &address) m_address = address; } -void Doorbird::initConnection(const QString &username, const QString &password) +QUuid Doorbird::getSession(const QString &username, const QString &password) { - m_networkAccessManager = new QNetworkAccessManager(this); - connect(m_networkAccessManager, &QNetworkAccessManager::authenticationRequired, this, [username, password, this] (QNetworkReply *reply, QAuthenticator *authenticator) { - - qCWarning(dcDoorBird()) << "Authenticator" << reply->errorString() << reply->error(); - if (m_pendingAuthentications.contains(reply)) { - m_pendingAuthentications.removeOne(reply); - reply->abort(); - } else { - authenticator->setUser(username); - authenticator->setPassword(password); - m_pendingAuthentications.append(reply); - } - }); -} - -QUuid Doorbird::getSession() -{ - QNetworkRequest request(QString("http://%1/bha-api/getsession.cgi").arg(m_address.toString())); + QUrl url; + url.setHost(m_address.toString()); + url.setScheme("http"); + url.setPath("/bha-api/getsession.cgi"); + url.setUserName(username); + url.setPassword(password); + QNetworkRequest request(url); qCDebug(dcDoorBird) << "Sending request:" << request.url(); QNetworkReply *reply = m_networkAccessManager->get(request); QUuid requestId = QUuid::createUuid(); diff --git a/doorbird/doorbird.h b/doorbird/doorbird.h index 0d519412..7f26da9b 100644 --- a/doorbird/doorbird.h +++ b/doorbird/doorbird.h @@ -37,11 +37,13 @@ #include #include +#include "network/networkaccessmanager.h" + class Doorbird : public QObject { Q_OBJECT public: - explicit Doorbird(const QHostAddress &address, QObject *parent = nullptr); + explicit Doorbird(NetworkAccessManager *networkAccessManager, const QHostAddress &address, QObject *parent = nullptr); enum EventType { Doorbell, @@ -63,8 +65,7 @@ public: QHostAddress address(); void setAddress(const QHostAddress &address); - void initConnection(const QString &username, const QString &password); - QUuid getSession(); + QUuid getSession(const QString &username, const QString &password); QUuid openDoor(int value); QUuid lightOn(); QUuid liveVideoRequest(); @@ -87,15 +88,17 @@ public: void connectToEventMonitor(); private: - QNetworkAccessManager *m_networkAccessManager; + QHostAddress m_address; + NetworkAccessManager *m_networkAccessManager; QByteArray m_readBuffer; - QHostAddress m_address; + QList m_networkRequests; QList m_pendingAuthentications; - //QByteArray sessionId; + QString m_username; + QString m_password; signals: void deviceConnected(bool status); From 1dd0cdb6e6db742f3d5202bdcd44f8edb49d313b Mon Sep 17 00:00:00 2001 From: Boernsman Date: Fri, 14 Feb 2020 22:48:46 +0500 Subject: [PATCH 14/18] fixed connection time-out --- doorbird/deviceplugindoorbird.cpp | 8 +++++--- doorbird/doorbird.cpp | 7 +++---- doorbird/doorbird.h | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp index 5bccd648..3668bc5c 100644 --- a/doorbird/deviceplugindoorbird.cpp +++ b/doorbird/deviceplugindoorbird.cpp @@ -107,7 +107,7 @@ void DevicePluginDoorbird::confirmPairing(DevicePairingInfo *info, const QString if (info->deviceClassId() == doorBirdDeviceClassId) { QHostAddress address = QHostAddress(info->params().paramValue(doorBirdDeviceAddressParamTypeId).toString()); - Doorbird *doorbird = new Doorbird(hardwareManager()->networkManager(), address, this); + Doorbird *doorbird = new Doorbird(address, this); connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected); connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent); connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); @@ -151,7 +151,7 @@ void DevicePluginDoorbird::setupDevice(DeviceSetupInfo *info) pluginStorage()->endGroup(); qCDebug(dcDoorBird()) << "Device setup" << device->name() << username << password; - Doorbird *doorbird = new Doorbird(hardwareManager()->networkManager(), address, this); + Doorbird *doorbird = new Doorbird(address, this); connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected); connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent); connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); @@ -253,7 +253,9 @@ void DevicePluginDoorbird::onDoorBirdEvent(Doorbird::EventType eventType, bool s break; case Doorbird::EventType::Motion: device->setStateValue(doorBirdIsPresentStateTypeId, status); - device->setStateValue(doorBirdLastSeenTimeStateTypeId, QDateTime::currentDateTime().toTime_t()); + if (status) { + device->setStateValue(doorBirdLastSeenTimeStateTypeId, QDateTime::currentDateTime().toTime_t()); + } break; case Doorbird::EventType::Doorbell: if (status) { diff --git a/doorbird/doorbird.cpp b/doorbird/doorbird.cpp index a6074acb..a8bda046 100644 --- a/doorbird/doorbird.cpp +++ b/doorbird/doorbird.cpp @@ -41,12 +41,11 @@ #include #include -Doorbird::Doorbird(NetworkAccessManager *networkAccessManager, const QHostAddress &address, QObject *parent) : +Doorbird::Doorbird(const QHostAddress &address, QObject *parent) : QObject(parent), - m_address(address), - m_networkAccessManager(networkAccessManager) + m_address(address) { - + m_networkAccessManager = new QNetworkAccessManager(this); } QHostAddress Doorbird::address() diff --git a/doorbird/doorbird.h b/doorbird/doorbird.h index 7f26da9b..a09bb788 100644 --- a/doorbird/doorbird.h +++ b/doorbird/doorbird.h @@ -43,7 +43,7 @@ class Doorbird : public QObject { Q_OBJECT public: - explicit Doorbird(NetworkAccessManager *networkAccessManager, const QHostAddress &address, QObject *parent = nullptr); + explicit Doorbird(const QHostAddress &address, QObject *parent = nullptr); enum EventType { Doorbell, @@ -89,7 +89,7 @@ public: void connectToEventMonitor(); private: QHostAddress m_address; - NetworkAccessManager *m_networkAccessManager; + QNetworkAccessManager *m_networkAccessManager; QByteArray m_readBuffer; From 0e1aab8a61dd3ac31bfa4d8a719394f6764fa638 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Mon, 17 Feb 2020 11:04:39 +0500 Subject: [PATCH 15/18] made actions async --- doorbird/README.md | 12 +++++++++--- doorbird/deviceplugindoorbird.cpp | 16 ++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/doorbird/README.md b/doorbird/README.md index bba30f16..ab687dc5 100644 --- a/doorbird/README.md +++ b/doorbird/README.md @@ -1,8 +1,14 @@ # DoorBird -This plug-in let'S you capture doorbell pressed and motion events, -you are also able to set the power of the IR and the relays. +This plugin integrates DoorBird video doorbells into nymea. All the communication between nymea and the DoorBird device happens locally and will work without internet connection. -It uses a local connection and will work without Internet. +Currently supported features are: +* Doorbell presses +* Motion events +* Enable/disable IR light +* Switching door relays + +The user must have the permission to act as DoorBird API-operator. +You can check the permissions in the DoorBird app. diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp index 3668bc5c..70a7c42a 100644 --- a/doorbird/deviceplugindoorbird.cpp +++ b/doorbird/deviceplugindoorbird.cpp @@ -195,21 +195,25 @@ void DevicePluginDoorbird::executeAction(DeviceActionInfo *info) if (device->deviceClassId() == doorBirdDeviceClassId) { Doorbird *doorbird = m_doorbirdConnections.value(device->id()); if (!doorbird) { + qCWarning(dcDoorBird()) << "Doorbird object not found" << device->name(); info->finish(Device::DeviceErrorHardwareFailure); return; } if (action.actionTypeId() == doorBirdOpenDoorActionTypeId) { int number = action.param(doorBirdOpenDoorActionNumberParamTypeId).value().toInt(); - doorbird->openDoor(number); - info->finish(Device::DeviceErrorNoError); + QUuid requestId = doorbird->openDoor(number); + m_asyncActions.insert(requestId, info); + connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);}); return; } else if (action.actionTypeId() == doorBirdLightOnActionTypeId) { - doorbird->lightOn(); - info->finish(Device::DeviceErrorNoError); + QUuid requestId = doorbird->lightOn(); + m_asyncActions.insert(requestId, info); + connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);}); return; } else if (action.actionTypeId() == doorBirdRestartActionTypeId) { - doorbird->restart(); - info->finish(Device::DeviceErrorNoError); + QUuid requestId = doorbird->restart(); + m_asyncActions.insert(requestId, info); + connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);}); return; } else { qCWarning(dcDoorBird()) << "Unhandled ActionTypeId:" << action.actionTypeId(); From f8da4797841812c7d2609de94340a7b1b6faaf51 Mon Sep 17 00:00:00 2001 From: "bernhard.trinnes" Date: Fri, 20 Mar 2020 08:16:10 +0100 Subject: [PATCH 16/18] devices to things --- doorbird/README.md | 26 +- doorbird/deviceplugindoorbird.cpp | 306 ------------------ doorbird/doorbird.cpp | 2 +- doorbird/doorbird.pro | 6 +- doorbird/integrationplugindoorbird.cpp | 306 ++++++++++++++++++ ...doorbird.h => integrationplugindoorbird.h} | 39 ++- ...rd.json => integrationplugindoorbird.json} | 2 +- 7 files changed, 349 insertions(+), 338 deletions(-) delete mode 100644 doorbird/deviceplugindoorbird.cpp create mode 100644 doorbird/integrationplugindoorbird.cpp rename doorbird/{deviceplugindoorbird.h => integrationplugindoorbird.h} (64%) rename doorbird/{deviceplugindoorbird.json => integrationplugindoorbird.json} (99%) diff --git a/doorbird/README.md b/doorbird/README.md index ab687dc5..05134aea 100644 --- a/doorbird/README.md +++ b/doorbird/README.md @@ -2,13 +2,25 @@ This plugin integrates DoorBird video doorbells into nymea. All the communication between nymea and the DoorBird device happens locally and will work without internet connection. -Currently supported features are: +## Supported Things -* Doorbell presses -* Motion events -* Enable/disable IR light -* Switching door relays +* All video doorbells + * Auto discovery + * Doorbell presses + * Motion events + * Enable/disable IR light + * Switching door relays + * No internet connection required -The user must have the permission to act as DoorBird API-operator. -You can check the permissions in the DoorBird app. +## Requirements +* The DoorBird device must be in the same local area network as nymea. +* The router must not block avahi/zeroconf multicast messages. +* TCP Sockets on port 80 must not be blocked by the router. +* The user must have the permission to act as DoorBird API-operator. + * You can check the permissions in the DoorBird app. +* The package "nymea-plugin-doorbird" must be installed. + +## More + +https://www.doorbird.com/ diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp deleted file mode 100644 index 70a7c42a..00000000 --- a/doorbird/deviceplugindoorbird.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2020, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "deviceplugindoorbird.h" -#include "plugininfo.h" - -#include "platform/platformzeroconfcontroller.h" -#include "network/zeroconf/zeroconfservicebrowser.h" -#include "network/zeroconf/zeroconfserviceentry.h" - -#include -#include -#include -#include - -DevicePluginDoorbird::DevicePluginDoorbird() -{ -} - - -void DevicePluginDoorbird::discoverDevices(DeviceDiscoveryInfo *info) -{ - if (info->deviceClassId() == doorBirdDeviceClassId) { - ZeroConfServiceBrowser *serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_axis-video._tcp"); - connect(info, &QObject::destroyed, serviceBrowser, &QObject::deleteLater); - - QTimer::singleShot(5000, this, [this, info, serviceBrowser](){ - foreach (const ZeroConfServiceEntry serviceEntry, serviceBrowser->serviceEntries()) { - if (serviceEntry.hostName().startsWith("bha-")) { - qCDebug(dcDoorBird) << "Found DoorBird device, name: " << serviceEntry.name() << "\n host address:" << serviceEntry.hostAddress().toString() << "\n text:" << serviceEntry.txt() << serviceEntry.protocol() << serviceEntry.serviceType(); - DeviceDescriptor deviceDescriptor(doorBirdDeviceClassId, serviceEntry.name(), serviceEntry.hostAddress().toString()); - ParamList params; - QString macAddress; - if (serviceEntry.txt().length() == 0) { - qCWarning(dcDoorBird()) << "Discovery failed, service entry missing"; - continue; - } - - if (serviceEntry.txt().first().split("=").length() == 2) { - macAddress = serviceEntry.txt().first().split("=").last(); - } else { - qCWarning(dcDoorBird()) << "Could not parse MAC Address" << serviceEntry.txt().first(); - continue; - } - if (!myDevices().filterByParam(doorBirdDeviceSerialnumberParamTypeId, macAddress).isEmpty()) { - Device *existingDevice = myDevices().filterByParam(doorBirdDeviceSerialnumberParamTypeId, macAddress).first(); - deviceDescriptor.setDeviceId(existingDevice->id()); - } - params.append(Param(doorBirdDeviceSerialnumberParamTypeId, macAddress)); - params.append(Param(doorBirdDeviceAddressParamTypeId, serviceEntry.hostAddress().toString())); - deviceDescriptor.setParams(params); - info->addDeviceDescriptor(deviceDescriptor); - } - } - serviceBrowser->deleteLater(); - info->finish(Device::DeviceErrorNoError); - }); - return; - } else { - qCWarning(dcDoorBird()) << "Cannot discover for deviceClassId" << info->deviceClassId(); - info->finish(Device::DeviceErrorDeviceNotFound); - } -} - - -void DevicePluginDoorbird::startPairing(DevicePairingInfo *info) -{ - if (info->deviceClassId() == doorBirdDeviceClassId) { - info->finish(Device::DeviceErrorNoError, QT_TR_NOOP("Please enter username and password for the DoorBird device")); - return; - } else { - qCWarning(dcDoorBird()) << "StartPairing unhandled deviceClassId" << info->deviceClassId(); - info->finish(Device::DeviceErrorCreationMethodNotSupported); - } -} - - -void DevicePluginDoorbird::confirmPairing(DevicePairingInfo *info, const QString &username, const QString &password) -{ - if (info->deviceClassId() == doorBirdDeviceClassId) { - QHostAddress address = QHostAddress(info->params().paramValue(doorBirdDeviceAddressParamTypeId).toString()); - - Doorbird *doorbird = new Doorbird(address, this); - connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected); - connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent); - connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); - connect(doorbird, &Doorbird::sessionIdReceived, this, &DevicePluginDoorbird::onSessionIdReceived); - m_doorbirdConnections.insert(info->deviceId(), doorbird); - m_pendingPairings.insert(doorbird, info); - doorbird->getSession(username, password); - connect(info, &DevicePairingInfo::aborted, this, [this, info]{ - if (m_pendingPairings.values().contains(info)) { - Doorbird *doorbird = m_pendingPairings.key(info); - m_pendingPairings.remove(doorbird); - doorbird->deleteLater(); - } - m_doorbirdConnections.remove(info->deviceId()); - }); - - pluginStorage()->beginGroup(info->deviceId().toString()); - pluginStorage()->setValue("username", username); - pluginStorage()->setValue("password", password); - pluginStorage()->endGroup(); - } else { - qCWarning(dcDoorBird()) << "Confirm pairing DeviceClassNotFound" << info->deviceClassId(); - info->finish(Device::DeviceErrorDeviceClassNotFound); - } -} - - -void DevicePluginDoorbird::setupDevice(DeviceSetupInfo *info) -{ - Device *device = info->device(); - - if (device->deviceClassId() == doorBirdDeviceClassId) { - QHostAddress address = QHostAddress(device->paramValue(doorBirdDeviceAddressParamTypeId).toString()); - - if (m_doorbirdConnections.contains(device->id())) { - info->finish(Device::DeviceErrorNoError); - } else { - pluginStorage()->beginGroup(device->id().toString()); - QString username = pluginStorage()->value("username").toString(); - QString password = pluginStorage()->value("password").toString(); - pluginStorage()->endGroup(); - - qCDebug(dcDoorBird()) << "Device setup" << device->name() << username << password; - Doorbird *doorbird = new Doorbird(address, this); - connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected); - connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent); - connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent); - connect(doorbird, &Doorbird::sessionIdReceived, this, &DevicePluginDoorbird::onSessionIdReceived); - m_doorbirdConnections.insert(device->id(), doorbird); - m_pendingDeviceSetups.insert(doorbird, info); - doorbird->getSession(username, password); - connect(info, &DeviceSetupInfo::aborted, this, [device, doorbird, this] { - if (!doorbird) { - doorbird->deleteLater(); - } - m_doorbirdConnections.remove(device->id()); - m_pendingPairings.remove(doorbird); - }); - } - } else { - qCWarning(dcDoorBird()) << "Unhandled device class" << info->device()->deviceClass(); - info->finish(Device::DeviceErrorDeviceClassNotFound); - } -} - - -void DevicePluginDoorbird::postSetupDevice(Device *device) -{ - if (device->deviceClassId() == doorBirdDeviceClassId) { - device->setStateValue(doorBirdConnectedStateTypeId, true); //since we checked the connection in the deviceSetup - Doorbird *doorbird = m_doorbirdConnections.value(device->id()); - doorbird->connectToEventMonitor(); - doorbird->infoRequest(); - doorbird->listFavorites(); - doorbird->listSchedules(); - } -} - - -void DevicePluginDoorbird::executeAction(DeviceActionInfo *info) -{ - Device *device = info->device(); - Action action = info->action(); - - if (device->deviceClassId() == doorBirdDeviceClassId) { - Doorbird *doorbird = m_doorbirdConnections.value(device->id()); - if (!doorbird) { - qCWarning(dcDoorBird()) << "Doorbird object not found" << device->name(); - info->finish(Device::DeviceErrorHardwareFailure); - return; - } - if (action.actionTypeId() == doorBirdOpenDoorActionTypeId) { - int number = action.param(doorBirdOpenDoorActionNumberParamTypeId).value().toInt(); - QUuid requestId = doorbird->openDoor(number); - m_asyncActions.insert(requestId, info); - connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);}); - return; - } else if (action.actionTypeId() == doorBirdLightOnActionTypeId) { - QUuid requestId = doorbird->lightOn(); - m_asyncActions.insert(requestId, info); - connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);}); - return; - } else if (action.actionTypeId() == doorBirdRestartActionTypeId) { - QUuid requestId = doorbird->restart(); - m_asyncActions.insert(requestId, info); - connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);}); - return; - } else { - qCWarning(dcDoorBird()) << "Unhandled ActionTypeId:" << action.actionTypeId(); - info->finish(Device::DeviceErrorActionTypeNotFound); - } - } else { - qCWarning(dcDoorBird()) << "Execute action, unhandled device class" << device->deviceClass(); - info->finish(Device::DeviceErrorDeviceClassNotFound); - } -} - -void DevicePluginDoorbird::deviceRemoved(Device *device) -{ - if (device->deviceClassId() == doorBirdDeviceClassId) { - Doorbird *doorbirdConnection = m_doorbirdConnections.take(device->id()); - doorbirdConnection->deleteLater(); - } -} - -void DevicePluginDoorbird::onDoorBirdConnected(bool status) -{ - Doorbird *doorbird = static_cast(sender()); - Device *device = myDevices().findById(m_doorbirdConnections.key(doorbird)); - if (!device) - return; - - device->setStateValue(doorBirdConnectedStateTypeId, status); -} - -void DevicePluginDoorbird::onDoorBirdEvent(Doorbird::EventType eventType, bool status) -{ - Doorbird *doorbird = static_cast(sender()); - Device *device = myDevices().findById(m_doorbirdConnections.key(doorbird)); - if (!device) - return; - - switch (eventType) { - case Doorbird::EventType::Rfid: - break; - case Doorbird::EventType::Input: - break; - case Doorbird::EventType::Motion: - device->setStateValue(doorBirdIsPresentStateTypeId, status); - if (status) { - device->setStateValue(doorBirdLastSeenTimeStateTypeId, QDateTime::currentDateTime().toTime_t()); - } - break; - case Doorbird::EventType::Doorbell: - if (status) { - emit emitEvent(Event(doorBirdDoorbellPressedEventTypeId ,device->id())); - } - break; - } -} - -void DevicePluginDoorbird::onDoorBirdRequestSent(QUuid requestId, bool success) -{ - Doorbird *doorbird = static_cast(sender()); - - if (m_asyncActions.contains(requestId)) { - DeviceActionInfo* actionInfo = m_asyncActions.take(requestId); - actionInfo->finish(success ? Device::DeviceErrorNoError : Device::DeviceErrorInvalidParameter); - } - - if (m_pendingPairings.contains(doorbird) && !success) { - DevicePairingInfo *info = m_pendingPairings.take(doorbird); - info->finish(Device::DeviceErrorAuthenticationFailure, tr("Wrong username or password")); - } - - if (m_pendingDeviceSetups.contains(doorbird) && !success) { - DeviceSetupInfo *info = m_pendingDeviceSetups.take(doorbird); - info->finish(Device::DeviceErrorAuthenticationFailure, tr("Wrong username or password")); - } -} - -void DevicePluginDoorbird::onSessionIdReceived(const QString &sessionId) -{ - Q_UNUSED(sessionId); - Doorbird *doorbird = static_cast(sender()); - - if (m_pendingPairings.contains(doorbird)) { - DevicePairingInfo *info = m_pendingPairings.take(doorbird); - info->finish(Device::DeviceErrorNoError); - } - - if (m_pendingDeviceSetups.contains(doorbird)) { - DeviceSetupInfo *info = m_pendingDeviceSetups.take(doorbird); - info->finish(Device::DeviceErrorNoError); - } -} diff --git a/doorbird/doorbird.cpp b/doorbird/doorbird.cpp index a8bda046..74225d16 100644 --- a/doorbird/doorbird.cpp +++ b/doorbird/doorbird.cpp @@ -75,7 +75,7 @@ QUuid Doorbird::getSession(const QString &username, const QString &password) reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcDoorBird) << "Error DoorBird device:" << reply->errorString(); + qCWarning(dcDoorBird) << "Error DoorBird thing:" << reply->errorString(); emit requestSent(requestId, false); return; } diff --git a/doorbird/doorbird.pro b/doorbird/doorbird.pro index 55b1f7e0..99666af5 100644 --- a/doorbird/doorbird.pro +++ b/doorbird/doorbird.pro @@ -2,12 +2,12 @@ include(../plugins.pri) QT += network -TARGET = $$qtLibraryTarget(nymea_deviceplugindoorbird) +TARGET = $$qtLibraryTarget(nymea_integrationplugindoorbird) SOURCES += \ - deviceplugindoorbird.cpp \ + integrationplugindoorbird.cpp \ doorbird.cpp \ HEADERS += \ - deviceplugindoorbird.h \ + integrationplugindoorbird.h \ doorbird.h \ diff --git a/doorbird/integrationplugindoorbird.cpp b/doorbird/integrationplugindoorbird.cpp new file mode 100644 index 00000000..85a5643a --- /dev/null +++ b/doorbird/integrationplugindoorbird.cpp @@ -0,0 +1,306 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "integrationplugindoorbird.h" +#include "plugininfo.h" + +#include "platform/platformzeroconfcontroller.h" +#include "network/zeroconf/zeroconfservicebrowser.h" +#include "network/zeroconf/zeroconfserviceentry.h" + +#include +#include +#include +#include + +IntegrationPluginDoorbird::IntegrationPluginDoorbird() +{ +} + + +void IntegrationPluginDoorbird::discoverThings(ThingDiscoveryInfo *info) +{ + if (info->thingClassId() == doorBirdThingClassId) { + ZeroConfServiceBrowser *serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_axis-video._tcp"); + connect(info, &QObject::destroyed, serviceBrowser, &QObject::deleteLater); + + QTimer::singleShot(5000, this, [this, info, serviceBrowser](){ + foreach (const ZeroConfServiceEntry serviceEntry, serviceBrowser->serviceEntries()) { + if (serviceEntry.hostName().startsWith("bha-")) { + qCDebug(dcDoorBird) << "Found DoorBird Thing, name: " << serviceEntry.name() << "\n host address:" << serviceEntry.hostAddress().toString() << "\n text:" << serviceEntry.txt() << serviceEntry.protocol() << serviceEntry.serviceType(); + ThingDescriptor ThingDescriptor(doorBirdThingClassId, serviceEntry.name(), serviceEntry.hostAddress().toString()); + ParamList params; + QString macAddress; + if (serviceEntry.txt().length() == 0) { + qCWarning(dcDoorBird()) << "Discovery failed, service entry missing"; + continue; + } + + if (serviceEntry.txt().first().split("=").length() == 2) { + macAddress = serviceEntry.txt().first().split("=").last(); + } else { + qCWarning(dcDoorBird()) << "Could not parse MAC Address" << serviceEntry.txt().first(); + continue; + } + if (!myThings().filterByParam(doorBirdThingSerialnumberParamTypeId, macAddress).isEmpty()) { + Thing *existingThing = myThings().filterByParam(doorBirdThingSerialnumberParamTypeId, macAddress).first(); + ThingDescriptor.setThingId(existingThing->id()); + } + params.append(Param(doorBirdThingSerialnumberParamTypeId, macAddress)); + params.append(Param(doorBirdThingAddressParamTypeId, serviceEntry.hostAddress().toString())); + ThingDescriptor.setParams(params); + info->addThingDescriptor(ThingDescriptor); + } + } + serviceBrowser->deleteLater(); + info->finish(Thing::ThingErrorNoError); + }); + return; + } else { + qCWarning(dcDoorBird()) << "Cannot discover for ThingClassId" << info->thingClassId(); + info->finish(Thing::ThingErrorThingNotFound); + } +} + + +void IntegrationPluginDoorbird::startPairing(ThingPairingInfo *info) +{ + if (info->thingClassId() == doorBirdThingClassId) { + info->finish(Thing::ThingErrorNoError, QT_TR_NOOP("Please enter username and password for the DoorBird Thing")); + return; + } else { + qCWarning(dcDoorBird()) << "StartPairing unhandled ThingClassId" << info->thingClassId(); + info->finish(Thing::ThingErrorCreationMethodNotSupported); + } +} + + +void IntegrationPluginDoorbird::confirmPairing(ThingPairingInfo *info, const QString &username, const QString &password) +{ + if (info->thingClassId() == doorBirdThingClassId) { + QHostAddress address = QHostAddress(info->params().paramValue(doorBirdThingAddressParamTypeId).toString()); + + Doorbird *doorbird = new Doorbird(address, this); + connect(doorbird, &Doorbird::deviceConnected, this, &IntegrationPluginDoorbird::onDoorBirdConnected); + connect(doorbird, &Doorbird::eventReveiced, this, &IntegrationPluginDoorbird::onDoorBirdEvent); + connect(doorbird, &Doorbird::requestSent, this, &IntegrationPluginDoorbird::onDoorBirdRequestSent); + connect(doorbird, &Doorbird::sessionIdReceived, this, &IntegrationPluginDoorbird::onSessionIdReceived); + m_doorbirdConnections.insert(info->thingId(), doorbird); + m_pendingPairings.insert(doorbird, info); + doorbird->getSession(username, password); + connect(info, &ThingPairingInfo::aborted, this, [this, info]{ + if (m_pendingPairings.values().contains(info)) { + Doorbird *doorbird = m_pendingPairings.key(info); + m_pendingPairings.remove(doorbird); + doorbird->deleteLater(); + } + m_doorbirdConnections.remove(info->thingId()); + }); + + pluginStorage()->beginGroup(info->thingId().toString()); + pluginStorage()->setValue("username", username); + pluginStorage()->setValue("password", password); + pluginStorage()->endGroup(); + } else { + qCWarning(dcDoorBird()) << "Confirm pairing ThingClassNotFound" << info->thingClassId(); + info->finish(Thing::ThingErrorThingClassNotFound); + } +} + + +void IntegrationPluginDoorbird::setupThing(ThingSetupInfo *info) +{ + Thing *thing = info->thing(); + + if (thing->thingClassId() == doorBirdThingClassId) { + QHostAddress address = QHostAddress(thing->paramValue(doorBirdThingAddressParamTypeId).toString()); + + if (m_doorbirdConnections.contains(thing->id())) { + info->finish(Thing::ThingErrorNoError); + } else { + pluginStorage()->beginGroup(thing->id().toString()); + QString username = pluginStorage()->value("username").toString(); + QString password = pluginStorage()->value("password").toString(); + pluginStorage()->endGroup(); + + qCDebug(dcDoorBird()) << "Thing setup" << thing->name() << username << password; + Doorbird *doorbird = new Doorbird(address, this); + connect(doorbird, &Doorbird::deviceConnected, this, &IntegrationPluginDoorbird::onDoorBirdConnected); + connect(doorbird, &Doorbird::eventReveiced, this, &IntegrationPluginDoorbird::onDoorBirdEvent); + connect(doorbird, &Doorbird::requestSent, this, &IntegrationPluginDoorbird::onDoorBirdRequestSent); + connect(doorbird, &Doorbird::sessionIdReceived, this, &IntegrationPluginDoorbird::onSessionIdReceived); + m_doorbirdConnections.insert(thing->id(), doorbird); + m_pendingThingSetups.insert(doorbird, info); + doorbird->getSession(username, password); + connect(info, &ThingSetupInfo::aborted, this, [thing, doorbird, this] { + if (!doorbird) { + doorbird->deleteLater(); + } + m_doorbirdConnections.remove(thing->id()); + m_pendingPairings.remove(doorbird); + }); + } + } else { + qCWarning(dcDoorBird()) << "Unhandled Thing class" << info->thing()->thingClass(); + info->finish(Thing::ThingErrorThingClassNotFound); + } +} + + +void IntegrationPluginDoorbird::postSetupThing(Thing *thing) +{ + if (thing->thingClassId() == doorBirdThingClassId) { + thing->setStateValue(doorBirdConnectedStateTypeId, true); //since we checked the connection in the ThingSetup + Doorbird *doorbird = m_doorbirdConnections.value(thing->id()); + doorbird->connectToEventMonitor(); + doorbird->infoRequest(); + doorbird->listFavorites(); + doorbird->listSchedules(); + } +} + + +void IntegrationPluginDoorbird::executeAction(ThingActionInfo *info) +{ + Thing *thing = info->thing(); + Action action = info->action(); + + if (thing->thingClassId() == doorBirdThingClassId) { + Doorbird *doorbird = m_doorbirdConnections.value(thing->id()); + if (!doorbird) { + qCWarning(dcDoorBird()) << "Doorbird object not found" << thing->name(); + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + if (action.actionTypeId() == doorBirdOpenDoorActionTypeId) { + int number = action.param(doorBirdOpenDoorActionNumberParamTypeId).value().toInt(); + QUuid requestId = doorbird->openDoor(number); + m_asyncActions.insert(requestId, info); + connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);}); + return; + } else if (action.actionTypeId() == doorBirdLightOnActionTypeId) { + QUuid requestId = doorbird->lightOn(); + m_asyncActions.insert(requestId, info); + connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);}); + return; + } else if (action.actionTypeId() == doorBirdRestartActionTypeId) { + QUuid requestId = doorbird->restart(); + m_asyncActions.insert(requestId, info); + connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);}); + return; + } else { + qCWarning(dcDoorBird()) << "Unhandled ActionTypeId:" << action.actionTypeId(); + info->finish(Thing::ThingErrorActionTypeNotFound); + } + } else { + qCWarning(dcDoorBird()) << "Execute action, unhandled Thing class" << thing->thingClass(); + info->finish(Thing::ThingErrorThingClassNotFound); + } +} + +void IntegrationPluginDoorbird::thingRemoved(Thing *thing) +{ + if (thing->thingClassId() == doorBirdThingClassId) { + Doorbird *doorbirdConnection = m_doorbirdConnections.take(thing->id()); + doorbirdConnection->deleteLater(); + } +} + +void IntegrationPluginDoorbird::onDoorBirdConnected(bool status) +{ + Doorbird *doorbird = static_cast(sender()); + Thing *thing = myThings().findById(m_doorbirdConnections.key(doorbird)); + if (!thing) + return; + + thing->setStateValue(doorBirdConnectedStateTypeId, status); +} + +void IntegrationPluginDoorbird::onDoorBirdEvent(Doorbird::EventType eventType, bool status) +{ + Doorbird *doorbird = static_cast(sender()); + Thing *thing = myThings().findById(m_doorbirdConnections.key(doorbird)); + if (!thing) + return; + + switch (eventType) { + case Doorbird::EventType::Rfid: + break; + case Doorbird::EventType::Input: + break; + case Doorbird::EventType::Motion: + thing->setStateValue(doorBirdIsPresentStateTypeId, status); + if (status) { + thing->setStateValue(doorBirdLastSeenTimeStateTypeId, QDateTime::currentDateTime().toTime_t()); + } + break; + case Doorbird::EventType::Doorbell: + if (status) { + emit emitEvent(Event(doorBirdDoorbellPressedEventTypeId ,thing->id())); + } + break; + } +} + +void IntegrationPluginDoorbird::onDoorBirdRequestSent(QUuid requestId, bool success) +{ + Doorbird *doorbird = static_cast(sender()); + + if (m_asyncActions.contains(requestId)) { + ThingActionInfo* actionInfo = m_asyncActions.take(requestId); + actionInfo->finish(success ? Thing::ThingErrorNoError : Thing::ThingErrorInvalidParameter); + } + + if (m_pendingPairings.contains(doorbird) && !success) { + ThingPairingInfo *info = m_pendingPairings.take(doorbird); + info->finish(Thing::ThingErrorAuthenticationFailure, tr("Wrong username or password")); + } + + if (m_pendingThingSetups.contains(doorbird) && !success) { + ThingSetupInfo *info = m_pendingThingSetups.take(doorbird); + info->finish(Thing::ThingErrorAuthenticationFailure, tr("Wrong username or password")); + } +} + +void IntegrationPluginDoorbird::onSessionIdReceived(const QString &sessionId) +{ + Q_UNUSED(sessionId); + Doorbird *doorbird = static_cast(sender()); + + if (m_pendingPairings.contains(doorbird)) { + ThingPairingInfo *info = m_pendingPairings.take(doorbird); + info->finish(Thing::ThingErrorNoError); + } + + if (m_pendingThingSetups.contains(doorbird)) { + ThingSetupInfo *info = m_pendingThingSetups.take(doorbird); + info->finish(Thing::ThingErrorNoError); + } +} diff --git a/doorbird/deviceplugindoorbird.h b/doorbird/integrationplugindoorbird.h similarity index 64% rename from doorbird/deviceplugindoorbird.h rename to doorbird/integrationplugindoorbird.h index 594decb0..3168785d 100644 --- a/doorbird/deviceplugindoorbird.h +++ b/doorbird/integrationplugindoorbird.h @@ -28,44 +28,43 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef DEVICEPLUGINDOORBIRD_H -#define DEVICEPLUGINDOORBIRD_H +#ifndef INTEGRATIONPLUGINDOORBIRD_H +#define INTEGRATIONPLUGINDOORBIRD_H #include -#include "devices/deviceplugin.h" -#include "devices/devicemanager.h" +#include "integrations/integrationplugin.h" #include "doorbird.h" class QNetworkAccessManager; class QNetworkReply; -class DevicePluginDoorbird: public DevicePlugin +class IntegrationPluginDoorbird: public IntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "deviceplugindoorbird.json") - Q_INTERFACES(DevicePlugin) + Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationplugindoorbird.json") + Q_INTERFACES(IntegrationPlugin) public: - explicit DevicePluginDoorbird(); + explicit IntegrationPluginDoorbird(); - void discoverDevices(DeviceDiscoveryInfo *info) override; - void setupDevice(DeviceSetupInfo *info) override; - void postSetupDevice(Device *device) override; - void executeAction(DeviceActionInfo *info) override; + void discoverThings(ThingDiscoveryInfo *info) override; + void setupThing(ThingSetupInfo *info) override; + void postSetupThing(Thing *thing) override; + void executeAction(ThingActionInfo *info) override; - void startPairing(DevicePairingInfo *info) override; - void confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) override; + void startPairing(ThingPairingInfo *info) override; + void confirmPairing(ThingPairingInfo *info, const QString &username, const QString &secret) override; - void deviceRemoved(Device *device)override; + void thingRemoved(Thing *thing)override; private: - QHash m_doorbirdConnections; - QHash m_pendingPairings; - QHash m_pendingDeviceSetups; + QHash m_doorbirdConnections; + QHash m_pendingPairings; + QHash m_pendingThingSetups; - QHash m_asyncActions; + QHash m_asyncActions; private slots: void onDoorBirdConnected(bool status); @@ -74,4 +73,4 @@ private slots: void onSessionIdReceived(const QString &sessionId); }; -#endif // DEVICEPLUGINDOORBIRD_H +#endif // INTEGRATIONPLUGINDOORBIRD_H diff --git a/doorbird/deviceplugindoorbird.json b/doorbird/integrationplugindoorbird.json similarity index 99% rename from doorbird/deviceplugindoorbird.json rename to doorbird/integrationplugindoorbird.json index a5e348f7..ac31c717 100644 --- a/doorbird/deviceplugindoorbird.json +++ b/doorbird/integrationplugindoorbird.json @@ -7,7 +7,7 @@ "name": "doorBird", "displayName": "DoorBird", "id": "2da07435-571e-4956-a387-6caa51d6e845", - "deviceClasses": [ + "thingClasses": [ { "id": "0485eb61-2a22-42ba-9dd2-a5961485bf08", "name": "doorBird", From 811fcad6516fc15dadf916e1d6d724cb764196c2 Mon Sep 17 00:00:00 2001 From: "bernhard.trinnes" Date: Mon, 23 Mar 2020 14:36:22 +0100 Subject: [PATCH 17/18] changes requested by reviewer --- doorbird/README.md | 6 ++++-- doorbird/doorbird.pro | 2 -- doorbird/integrationplugindoorbird.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doorbird/README.md b/doorbird/README.md index 05134aea..36130e22 100644 --- a/doorbird/README.md +++ b/doorbird/README.md @@ -12,10 +12,12 @@ This plugin integrates DoorBird video doorbells into nymea. All the communicatio * Switching door relays * No internet connection required +NOTE: This plug-in does not handle any video- or audio stream. + ## Requirements * The DoorBird device must be in the same local area network as nymea. -* The router must not block avahi/zeroconf multicast messages. +* The router must not block ZeroConf/mDNS multicast messages. * TCP Sockets on port 80 must not be blocked by the router. * The user must have the permission to act as DoorBird API-operator. * You can check the permissions in the DoorBird app. @@ -23,4 +25,4 @@ This plugin integrates DoorBird video doorbells into nymea. All the communicatio ## More -https://www.doorbird.com/ +https://www.doorbird.com diff --git a/doorbird/doorbird.pro b/doorbird/doorbird.pro index 99666af5..7efb2342 100644 --- a/doorbird/doorbird.pro +++ b/doorbird/doorbird.pro @@ -2,8 +2,6 @@ include(../plugins.pri) QT += network -TARGET = $$qtLibraryTarget(nymea_integrationplugindoorbird) - SOURCES += \ integrationplugindoorbird.cpp \ doorbird.cpp \ diff --git a/doorbird/integrationplugindoorbird.cpp b/doorbird/integrationplugindoorbird.cpp index 85a5643a..ddce2f09 100644 --- a/doorbird/integrationplugindoorbird.cpp +++ b/doorbird/integrationplugindoorbird.cpp @@ -85,7 +85,7 @@ void IntegrationPluginDoorbird::discoverThings(ThingDiscoveryInfo *info) return; } else { qCWarning(dcDoorBird()) << "Cannot discover for ThingClassId" << info->thingClassId(); - info->finish(Thing::ThingErrorThingNotFound); + info->finish(Thing::ThingErrorThingClassNotFound); } } @@ -97,7 +97,7 @@ void IntegrationPluginDoorbird::startPairing(ThingPairingInfo *info) return; } else { qCWarning(dcDoorBird()) << "StartPairing unhandled ThingClassId" << info->thingClassId(); - info->finish(Thing::ThingErrorCreationMethodNotSupported); + info->finish(Thing::ThingErrorThingClassNotFound); } } From cf221f1bfd3ec7e92a506534ea5b6c812a67ffad Mon Sep 17 00:00:00 2001 From: "bernhard.trinnes" Date: Mon, 23 Mar 2020 14:53:13 +0100 Subject: [PATCH 18/18] fixed debian packaging --- debian/nymea-plugin-doorbird.install.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/nymea-plugin-doorbird.install.in b/debian/nymea-plugin-doorbird.install.in index 3a517946..47568ef1 100644 --- a/debian/nymea-plugin-doorbird.install.in +++ b/debian/nymea-plugin-doorbird.install.in @@ -1 +1 @@ -usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_deviceplugindoorbird.so +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationplugindoorbird.so