diff --git a/README.md b/README.md index 5b5847c..378f42a 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ The application is designed around a simple scrollable menu where menu items hav It is important to note that your Home Assistant instance will need to be accessible via HTTPS with public SSL or all requests from the Garmin will not work. This cannot be a self-signed certificate, it must be a public certificate (You can get one for free from [Let's Encrypt](https://letsencrypt.org/) or you can pay for [Home Assistant cloud](https://www.nabucasa.com/)). +**If you are struggling with getting the application to work, please consult the [trouble shooting](Troubleshooting.md) guide first.** + ## Widget or Application? As of version 2.0, there are now two installable versions. For older devices before applications supported 'glances', there is a now widget version. @@ -168,8 +170,8 @@ This allows the `confirm` field to be accommodated in the `tap_action` along sid You have options. The first is what we use. 1. **Best!** Use the [Studio Code Server](https://community.home-assistant.io/t/home-assistant-community-add-on-visual-studio-code/107863) addon for Home Assistant. You can then edit your JSON file in place. -2. Locally installed VSCode, or if not installed -3. try the on-line version at https://vscode.dev/ +2. Locally installed VSCode, or if not installed, +3. try the on-line version at https://vscode.dev/. Paste in your JSON (and change the file type to JSON if not saving), it will then verify your file format and schema for you, highlighting any errors for you to fix. diff --git a/Troubleshooting.md b/Troubleshooting.md new file mode 100644 index 0000000..623150d --- /dev/null +++ b/Troubleshooting.md @@ -0,0 +1,107 @@ +# Troubleshooting Guide + +With either of the following setups, there are inevitably some problems along the way. GarminHomeAssistant is careful to rely only on having working URLs. Getting them working is the user's responsibility. However, we have developed some fault finding tools. + +## Nabu Casa Setup + +You can purchase cloud-based access to your Home Assistant from [Nabu Casa](https://www.nabucasa.com/), and then your setup will look something like this. + +![Nabu Casa Setup](images/nabu_casa_setup.png) + +* Your API URL would be of the format `https://.ui.nabu.casa/api` +* Your Garmin Watch Menu would be of the format Menu: `https://.ui.nabu.casa/local/garmin/menu.json` + +Where `` is your personal Nabu Casa account ID. + +## Do It Yourself Setup + +Before Nabu Casa, or if you wanted to manage your own infrastructure, you might have something like the following: + +![Do It Yourself Setup](images/do_it_yourself_setup.png) + +Now you have to manage: + +* Dynamic DNS +* Public access via router port forwarding +* Security via HTTPS and URL forwarding +* Certificates for HTTPS via say [Let's Encrypt](https://letsencrypt.org/) (Nginx web server helps here) +* Proxy allow list in `configuration.yaml` as follows: + +```yaml +http: + use_x_forwarded_for: true + trusted_proxies: + - 127.0.0.1 + - 192.168.xx.xx # Server IP - AMEND THIS + - 172.30.32.0/23 # Docker IPs for NGINX + - 172.30.33.0/24 # SSL proxy server + - 172.16.0.0/12 # +``` + +## Menu Configuration URL + +This URL is very simple, you should be able to read the contents returned in a standard web browser. + +![Browser Address Bar URL](images/menu_url.png) + +(Other browsers are available...) + +The browser page should then display the JSON string you saved to the file on the web server. The point is this is a simple HTTP GET request with no bells and whistles. + +The menu configuration can be hosted anywhere, it does not have to be on the Home Assistant web server. Just as long as it is reachable from your phone from which you Bluetooth connect to your watch, or you watch if it has direct Internet access. + +## Home Assistant API URL + +This is slightly trickier owning to the need to supply the API key. Here are three ways you can test your API URL is correctly configured. If successful, each of these should produce a JSON string output looking like: + +```json +{"message":"API running."} +``` + +### Linux, MacOS, UNIX, Cygwin etc + +Save the following as a file called `api_test.sh`, edit to include your personal values for the variables, `chmod +x api_test.sh` and then execute with `./api_test.sh`. + +```shell +#!/bin/bash + +API_KEY="" +URL="https:///api" + +curl -s -X GET \ + -H "Authorization: Bearer ${API_KEY}" \ + -H "Content-Type: application/json" \ + ${URL}/ +``` + +### MS Windows + +Save the following as a file called `api_test.cmd`, edit to include your personal values for the variables and then double click. + +```shell +@echo off + +set API_KEY= +set URL=https:///api + +curl -s -X GET ^ + -H "Authorization: Bearer %API_KEY%" ^ + -H "Content-Type: application/json" ^ + %URL%/ + +echo. +pause +``` + +![API Test MS-DOS Output](images/api_test_dos_output.png) + +### On-line + +There's an online way of testing the API URL too, thanks to [REQBIN](https://reqbin.com/post-online). This has less setup and it can be saved if you log into the web site. + +![API Test MS-DOS Output](images/api_test_online.png) + +## Top Problems + +1. Failure to copy & paste keys and URLs leading to minor and hard to see errors in strings, even with protestations they are the same! (No they weren't...) +2. Accessibility of URLs, hence the above help guide. diff --git a/export.cmd b/export.cmd index 7930e8b..8ce3b82 100644 --- a/export.cmd +++ b/export.cmd @@ -23,6 +23,8 @@ set JAVA_PATH=C:\Program Files (x86)\Common Files\Oracle\Java\javapath rem SDK_PATH should work for all users set /p SDK_PATH=<"%USERPROFILE%\AppData\Roaming\Garmin\ConnectIQ\current-sdk.cfg" set SDK_PATH=%SDK_PATH:~0,-1%\bin +rem Assume we can create and use this directory +set DEST=export rem C:\>java -jar %SDK_PATH%\monkeybrains.jar -h rem usage: monkeyc [-a ] [-b ] [--build-stats ] [-c ] [-d ] @@ -69,6 +71,10 @@ set SRC=%~dp0 rem drop last character '\' set SRC=%SRC:~0,-1% +if not exist %DEST% ( + md %DEST% +) + if exist %SRC%\export\HomeAssistant*.iq ( del /f /q %SRC%\export\HomeAssistant*.iq ) diff --git a/images/Actual_Venu2_LeanUI_500.jpg b/images/Actual_Venu2_LeanUI_500.jpg new file mode 100644 index 0000000..30ce882 Binary files /dev/null and b/images/Actual_Venu2_LeanUI_500.jpg differ diff --git a/images/Actual_Venu2_Theme_500.jpg b/images/Actual_Venu2_Theme_500.jpg new file mode 100644 index 0000000..9317828 Binary files /dev/null and b/images/Actual_Venu2_Theme_500.jpg differ diff --git a/images/api_test_dos_output.png b/images/api_test_dos_output.png new file mode 100644 index 0000000..d5cc1ca Binary files /dev/null and b/images/api_test_dos_output.png differ diff --git a/images/api_test_online.png b/images/api_test_online.png new file mode 100644 index 0000000..02c27f0 Binary files /dev/null and b/images/api_test_online.png differ diff --git a/images/do_it_yourself_setup.png b/images/do_it_yourself_setup.png new file mode 100644 index 0000000..70f8ed0 Binary files /dev/null and b/images/do_it_yourself_setup.png differ diff --git a/images/menu_url.png b/images/menu_url.png new file mode 100644 index 0000000..3775fb0 Binary files /dev/null and b/images/menu_url.png differ diff --git a/images/nabu_casa_setup.png b/images/nabu_casa_setup.png new file mode 100644 index 0000000..8d10f5d Binary files /dev/null and b/images/nabu_casa_setup.png differ diff --git a/images/source/Network_Generic.pptx b/images/source/Network_Generic.pptx new file mode 100644 index 0000000..e2abcdb Binary files /dev/null and b/images/source/Network_Generic.pptx differ diff --git a/include/app/WidgetApp.mc b/include/app/WidgetApp.mc new file mode 100644 index 0000000..1234385 --- /dev/null +++ b/include/app/WidgetApp.mc @@ -0,0 +1,28 @@ +//----------------------------------------------------------------------------------- +// +// Distributed under MIT Licence +// See https://github.com/house-of-abbey/GarminHomeAssistant/blob/main/LICENSE. +// +//----------------------------------------------------------------------------------- +// +// GarminHomeAssistant is a Garmin IQ application written in Monkey C and routinely +// tested on a Venu 2 device. The source code is provided at: +// https://github.com/house-of-abbey/GarminHomeAssistant. +// +// P A Abbey & J D Abbey & Someone0nEarth, 20 December 2023 +// +// +// Description: +// +// A tedious diversion intended to make it possible to have the same source code for +// both a widget and an application. This file provides a single constant to +// determine which, and then the source file is conditionally included by the each +// .jungle file. +// +//----------------------------------------------------------------------------------- + +using Toybox.Lang; + +class WidgetApp { + static const isWidget = false; +} diff --git a/include/widget/WidgetApp.mc b/include/widget/WidgetApp.mc new file mode 100644 index 0000000..b86ec4c --- /dev/null +++ b/include/widget/WidgetApp.mc @@ -0,0 +1,28 @@ +//----------------------------------------------------------------------------------- +// +// Distributed under MIT Licence +// See https://github.com/house-of-abbey/GarminHomeAssistant/blob/main/LICENSE. +// +//----------------------------------------------------------------------------------- +// +// GarminHomeAssistant is a Garmin IQ application written in Monkey C and routinely +// tested on a Venu 2 device. The source code is provided at: +// https://github.com/house-of-abbey/GarminHomeAssistant. +// +// P A Abbey & J D Abbey & Someone0nEarth, 20 December 2023 +// +// +// Description: +// +// A tedious diversion intended to make it possible to have the same source code for +// both a widget and an application. This file provides a single constant to +// determine which, and then the source file is conditionally included by the each +// .jungle file. +// +//----------------------------------------------------------------------------------- + +using Toybox.Lang; + +class WidgetApp { + static const isWidget = true; +} diff --git a/manifest.xml b/manifest.xml index d3c1211..5cf5860 100644 --- a/manifest.xml +++ b/manifest.xml @@ -24,7 +24,14 @@ Use "Monkey C: Edit Application" from the Visual Studio Code command palette to update the application attributes. --> + + مفتاح API لـ HomeAssistant. رمز الوصول طويل الأمد. diff --git a/resources-bul/strings/strings.xml b/resources-bul/strings/strings.xml index 93eb779..2308ae5 100644 --- a/resources-bul/strings/strings.xml +++ b/resources-bul/strings/strings.xml @@ -25,21 +25,22 @@ Докоснете Меню Сигурен? - Няма телефонна връзка + Няма телефонна връзка Няма интернет връзка Няма отговор, проверете интернет връзката - Грешка при извличане на менюто - Няма API ключ в настройките на приложението - Няма URL адрес на API в настройките на приложението - Няма конфигурационен URL адрес в настройките на приложението + Няма API ключ в настройките на приложението + Няма URL адрес на API в настройките на приложението + Няма конфигурационен URL адрес в настройките на приложението Извикванията на API са твърде бързи. Моля, забавете вашите заявки. URL не е намерен. Потенциална грешка в URL адреса на API в настройките. URL не е намерен. Потенциална грешка в URL адреса на конфигурацията в настройките. + Няма върнат JSON от HTTP заявка. HTTP заявката върна код на грешка = URL адресът на API не трябва да има наклонена черта '/' в края - Извличане на конфигурацията на менюто.. - Плъзнете надясно, за да излезете\nДокоснете, за да останете - Натиснете Назад, за да излезете\nВлезте, за да останете + На разположение + Проверка... + Недостъпен + Меню API ключ за HomeAssistant. Токен за дълготраен достъп. diff --git a/resources-ces/strings/strings.xml b/resources-ces/strings/strings.xml index 691fbee..88256db 100644 --- a/resources-ces/strings/strings.xml +++ b/resources-ces/strings/strings.xml @@ -25,21 +25,22 @@ Klepněte Jídelní lístek Tak určitě? - Žádné telefonní spojení + Žádné telefonní spojení Žádné internetové připojení Žádná odpověď, zkontrolujte připojení k internetu - Chyba načítání nabídky - V nastavení aplikace není žádný klíč API - V nastavení aplikace není žádná adresa URL API - V nastavení aplikace není žádná konfigurační URL + V nastavení aplikace není žádný klíč API + V nastavení aplikace není žádná adresa URL API + V nastavení aplikace není žádná konfigurační URL Příliš rychlá volání API. Zpomalte prosím své požadavky. Adresa URL nenalezena. Potenciální chyba adresy URL rozhraní API v nastavení. Adresa URL nenalezena. Potenciální chyba konfigurační adresy URL v nastavení. + Z požadavku HTTP se nevrátil žádný JSON. Požadavek HTTP vrátil kód chyby = Adresa URL rozhraní API nesmí mít koncové lomítko „/“ - Načítání konfigurace nabídky... - Přejetím prstem doprava ukončíte\nKlepnutím zůstanete - Stisknutím Zpět ukončíte\nVstupte a zůstanete + Dostupný + Kontrola... + Není k dispozici + Jídelní lístek Klíč API pro HomeAssistant. Přístupový token s dlouhou životností. diff --git a/resources-dan/strings/strings.xml b/resources-dan/strings/strings.xml index e3c6379..be369fc 100644 --- a/resources-dan/strings/strings.xml +++ b/resources-dan/strings/strings.xml @@ -25,21 +25,22 @@ Tryk på Menu Jo da? - Ingen telefonforbindelse + Ingen telefonforbindelse Ingen internetforbindelse Intet svar, tjek internetforbindelse - Fejl ved menuhentning - Ingen API-nøgle i applikationsindstillingerne - Ingen API-URL i applikationsindstillingerne - Ingen konfigurations-URL i applikationsindstillingerne + Ingen API-nøgle i applikationsindstillingerne + Ingen API-URL i applikationsindstillingerne + Ingen konfigurations-URL i applikationsindstillingerne API-kald for hurtigt. Sænk venligst dine anmodninger. URL ikke fundet. Potentiel API URL-fejl i indstillinger. URL ikke fundet. Potentiel konfigurations-URL-fejl i indstillinger. + Ingen JSON returneret fra HTTP-anmodning. HTTP-anmodning returnerede fejlkode = API URL må ikke have en efterfølgende skråstreg '/' - Henter menukonfiguration.. - Stryg til højre for at afslutte\nTryk for at blive - Tryk tilbage for at afslutte\nEnter for at blive + Ledig + Tjekker... + Ikke tilgængelig + Menu API-nøgle til HomeAssistant. Adgangstoken med lang levetid. diff --git a/resources-deu/strings/corrections.xml b/resources-deu/strings/corrections.xml index 3c50a66..343b56d 100644 --- a/resources-deu/strings/corrections.xml +++ b/resources-deu/strings/corrections.xml @@ -22,7 +22,4 @@ Antippen Menü Die HTTP-Anfrage gab folgenden Fehlercode zurück = - Zum Beenden nach rechts swipen\nZum Bleiben antippen - Drücke „Zurück“, um zu Beenden.\n„Enter“, um zu bleiben - Lade Config vom Server ... diff --git a/resources-deu/strings/strings.xml b/resources-deu/strings/strings.xml index 9ce65f9..0bc1dc3 100644 --- a/resources-deu/strings/strings.xml +++ b/resources-deu/strings/strings.xml @@ -23,23 +23,24 @@ An Aus Antippen - Menü + Menü Sicher? - Keine Telefonverbindung + Keine Telefonverbindung Keine Internetverbindung Keine Antwort, überprüfen Sie die Internetverbindung - Fehler beim Abrufen des Menüs - Kein API-Schlüssel in den Anwendungseinstellungen - Keine API-URL in den Anwendungseinstellungen - Keine Konfigurations-URL in den Anwendungseinstellungen + Kein API-Schlüssel in den Anwendungseinstellungen + Keine API-URL in den Anwendungseinstellungen + Keine Konfigurations-URL in den Anwendungseinstellungen API-Aufrufe zu schnell. Bitte verlangsamen Sie Ihre Anfragen. URL nicht gefunden. Möglicher API-URL-Fehler in den Einstellungen. URL nicht gefunden. Möglicher Konfigurations-URL-Fehler in den Einstellungen. - Die HTTP-Anfrage gab folgenden Fehlercode zurück = + Von der HTTP-Anfrage wurde kein JSON zurückgegeben. + Die HTTP-Anfrage gab folgenden Fehlercode zurück = Die API-URL darf keinen abschließenden Schrägstrich „/“ enthalten. - Lade Config vom Server ... - Zum Beenden nach rechts swipen\nZum Bleiben antippen - Drücke „Zurück“, um zu Beenden.\n„Enter“, um zu bleiben + Verfügbar + Überprüfung... + Nicht verfügbar + Speisekarte API-Schlüssel für HomeAssistant. Langlebiges Zugriffstoken. diff --git a/resources-dut/strings/strings.xml b/resources-dut/strings/strings.xml index 4821e85..17b8e52 100644 --- a/resources-dut/strings/strings.xml +++ b/resources-dut/strings/strings.xml @@ -25,21 +25,22 @@ Kraan Menu Zeker? - Geen telefoonverbinding + Geen telefoonverbinding Geen internet verbinding Geen reactie, controleer de internetverbinding - Fout bij ophalen van menu - Geen API-sleutel in de applicatie-instellingen - Geen API-URL in de applicatie-instellingen - Geen configuratie-URL in de applicatie-instellingen + Geen API-sleutel in de applicatie-instellingen + Geen API-URL in de applicatie-instellingen + Geen configuratie-URL in de applicatie-instellingen API-aanroepen te snel. Vertraag uw verzoeken. URL niet gevonden. Mogelijke API-URL-fout in instellingen. URL niet gevonden. Mogelijke configuratie-URL-fout in de instellingen. + Er is geen JSON geretourneerd door een HTTP-verzoek. HTTP-verzoek retourneerde foutcode = API-URL mag geen afsluitende slash '/' bevatten - Menuconfiguratie ophalen.. - Veeg naar rechts om af te sluiten\nTik om te blijven - Druk op Terug om af te sluiten\nEnter om te blijven + Beschikbaar + Controleren... + Niet beschikbaar + Menu API-sleutel voor HomeAssistant. Toegangstoken met lange levensduur. diff --git a/resources-est/strings/strings.xml b/resources-est/strings/strings.xml index 0153aba..a5519aa 100644 --- a/resources-est/strings/strings.xml +++ b/resources-est/strings/strings.xml @@ -15,7 +15,7 @@ @@ -25,21 +25,22 @@ Puudutage Menüü Muidugi? - Telefoniühendus puudub + Telefoniühendus puudub Interneti-ühendus puudub Ei reageeri, kontrollige Interneti-ühendust - Menüü toomise viga - Rakenduse seadetes pole API-võtit - Rakenduse seadetes pole API URL-i - Rakenduse seadetes pole konfiguratsiooni URL-i + Rakenduse seadetes pole API-võtit + Rakenduse seadetes pole API URL-i + Rakenduse seadetes pole konfiguratsiooni URL-i API-kutsed liiga kiired. Palun aeglustage taotluste esitamist. URL-i ei leitud. Võimalik API URL-i viga seadetes. URL-i ei leitud. Võimalik konfiguratsiooni URL-i viga seadetes. + HTTP-päringust ei tagastatud ühtegi JSON-i. HTTP päring tagastas veakoodi = API URL-i lõpus ei tohi olla kaldkriipsu „/” - Menüü konfiguratsiooni toomine... - Väljumiseks pühkige paremale\nPuudutage, et jääda - Väljumiseks vajutage Tagasi\nSisestage, et jääda + Saadaval + Kontrollimine... + Pole saadaval + Menüü API-võti HomeAssistantile. Pikaealine juurdepääsuluba. diff --git a/resources-fin/strings/strings.xml b/resources-fin/strings/strings.xml index 76830ed..a020ac2 100644 --- a/resources-fin/strings/strings.xml +++ b/resources-fin/strings/strings.xml @@ -25,21 +25,22 @@ Napauta Valikko Varma? - Ei puhelinyhteyttä + Ei puhelinyhteyttä Ei Internet-yhteyttä Ei vastausta, tarkista Internet-yhteys - Valikkohakuvirhe - Sovelluksen asetuksissa ei ole API-avainta - Sovellusasetuksissa ei ole API URL-osoitetta - Sovelluksen asetuksissa ei ole konfigurointi-URL-osoitetta + Sovellusasetuksissa ei ole API-avainta + Sovellusasetuksissa ei ole API URL-osoitetta + Sovelluksen asetuksissa ei ole konfigurointi-URL-osoitetta API-kutsut liian nopeita. Hidasta pyyntöjäsi. URL-osoitetta ei löydy. Mahdollinen API URL -virhe asetuksissa. URL-osoitetta ei löydy. Mahdollinen konfigurointi-URL-virhe asetuksissa. + HTTP-pyynnöstä ei palautettu JSON-tiedostoja. HTTP-pyyntö palautti virhekoodin = API-URL-osoitteessa ei saa olla perässä olevaa kauttaviivaa '/' - Haetaan valikon asetuksia... - Poistu pyyhkäisemällä oikealle\nPysy napauttamalla - Poistu painamalla Takaisin\nSyötä jäädäksesi + Saatavilla + Tarkistetaan... + Ei saatavilla + Valikko API-avain HomeAssistantille. Pitkäikäinen pääsytunnus. diff --git a/resources-fre/strings/strings.xml b/resources-fre/strings/strings.xml index d44d75c..ca90de6 100644 --- a/resources-fre/strings/strings.xml +++ b/resources-fre/strings/strings.xml @@ -20,26 +20,27 @@ HomeAssistant - Activé + Activé Désactivé Clic Menu Bien sûr? - Pas de connexion téléphonique + Pas de connexion téléphonique Pas de connexion Internet Pas de réponse, vérifiez la connexion Internet - Erreur de récupération du menu - Pas de clé API dans les paramètres de l'application - Aucune URL API dans les paramètres de l'application - Aucune URL de configuration dans les paramètres de l'application - Appels API trop rapide. Veuillez signaler cette erreur avec les détails de l'appareil. + Pas de clé API dans les paramètres de l'application + Aucune URL API dans les paramètres de l'application + Aucune URL de configuration dans les paramètres de l'application + Appels API trop rapide. Veuillez signaler cette erreur avec les détails de l'appareil. URL introuvable. Erreur potentielle d'URL d'API dans les paramètres. URL introuvable. Erreur potentielle d'URL de configuration dans les paramètres. + Aucun JSON renvoyé par la requête HTTP. La requête HTTP a renvoyé un code d'erreur = L'URL de l'API ne doit pas comporter de barre oblique finale '/' - Récupération de la configuration du menu. - Balayez vers la droite pour quitter\nAppuyez pour rester - Appuyez sur Retour pour quitter\nEntrez pour rester + Disponible + Vérification... + Indisponible + Menu Clé API pour HomeAssistant. Jeton d'accès de longue durée. diff --git a/resources-gre/strings/strings.xml b/resources-gre/strings/strings.xml index 31569c8..a3d0acb 100644 --- a/resources-gre/strings/strings.xml +++ b/resources-gre/strings/strings.xml @@ -25,21 +25,22 @@ Παρακέντηση Μενού Σίγουρος? - Δεν υπάρχει σύνδεση τηλεφώνου + Δεν υπάρχει σύνδεση τηλεφώνου Δεν υπάρχει σύνδεση στο διαδίκτυο Καμία απάντηση, ελέγξτε τη σύνδεση στο Διαδίκτυο - Σφάλμα ανάκτησης μενού - Δεν υπάρχει κλειδί API στις ρυθμίσεις της εφαρμογής - Δεν υπάρχει διεύθυνση URL API στις ρυθμίσεις της εφαρμογής - Δεν υπάρχει διεύθυνση URL διαμόρφωσης στις ρυθμίσεις της εφαρμογής + Δεν υπάρχει κλειδί API στις ρυθμίσεις της εφαρμογής + Δεν υπάρχει URL API στις ρυθμίσεις της εφαρμογής + Δεν υπάρχει διεύθυνση URL διαμόρφωσης στις ρυθμίσεις της εφαρμογής Κλήσεις API πολύ γρήγορες. Παρακαλώ επιβραδύνετε τα αιτήματά σας. Η διεύθυνση URL δεν βρέθηκε. Πιθανό σφάλμα διεύθυνσης URL API στις ρυθμίσεις. Η διεύθυνση URL δεν βρέθηκε. Πιθανό σφάλμα διεύθυνσης URL διαμόρφωσης στις ρυθμίσεις. + Δεν επιστράφηκε JSON από αίτημα HTTP. Το αίτημα HTTP επέστρεψε κωδικό σφάλματος = Η διεύθυνση URL του API δεν πρέπει να έχει τελική κάθετο "/" - Ανάκτηση παραμέτρων μενού.. - Σύρετε προς τα δεξιά για έξοδο\nΠατήστε για να μείνετε - Πατήστε Επιστροφή για Έξοδος\nEnter για να μείνετε + Διαθέσιμος + Ελεγχος... + Μη διαθέσιμο + Μενού Κλειδί API για το HomeAssistant. Διακριτικό πρόσβασης μακράς διαρκείας. diff --git a/resources-heb/strings/strings.xml b/resources-heb/strings/strings.xml index 36e0b9c..dd2f157 100644 --- a/resources-heb/strings/strings.xml +++ b/resources-heb/strings/strings.xml @@ -25,28 +25,29 @@ בֶּרֶז תַפרִיט בטוח? - אין חיבור לטלפון + אין חיבור לטלפון אין חיבור אינטרנט אין תגובה, בדוק חיבור לאינטרנט - שגיאת אחזור תפריט - אין מפתח API בהגדרות האפליקציה - אין כתובת API בהגדרות האפליקציה - אין כתובת אתר תצורה בהגדרות האפליקציה + אין מפתח API בהגדרות האפליקציה + אין כתובת API בהגדרות האפליקציה + אין כתובת אתר תצורה בהגדרות האפליקציה קריאות API מהירות מדי. נא להאט את הבקשות שלך. כתובת האתר לא נמצאה. שגיאה פוטנציאלית של כתובת ה-API בהגדרות. כתובת האתר לא נמצאה. שגיאת כתובת אתר פוטנציאלית של תצורה בהגדרות. + לא הוחזר JSON מבקשת HTTP. בקשת HTTP החזירה קוד שגיאה = כתובת ה-API לא חייבת לכלול לוכסן אחורי '/' - מביא את תצורת התפריט... - החלק ימינה כדי לצאת\nהקש כדי להישאר - לחץ על חזרה ליציאה\nEnter כדי להישאר + זמין + בודק... + אינו זמין + תַפרִיט מפתח API עבור HomeAssistant. אסימון גישה ארוך-חיים. כתובת URL עבור HomeAssistant API. - כתובת URL עבור תצורת תפריט (JSON). + כתובת URL לתצורת תפריט (JSON). פסק זמן בשניות. צא מהאפליקציה לאחר תקופה זו של חוסר פעילות כדי לחסוך בסוללת המכשיר. - לאחר זמן זה (בשניות), תיבת דו-שיח לאישור פעולה נסגרת אוטומטית והפעולה מבוטלת. הגדר ל-0 כדי להשבית את הזמן הקצוב. + לאחר זמן זה (בשניות), תיבת דו-שיח לאישור פעולה נסגרת אוטומטית והפעולה מבוטלת. הגדר ל-0 כדי לבטל את הזמן הקצוב. ייצוג סוגים עם סמלים (כבוי) או עם תוויות (מופעל). יישור תפריט שמאלה (כבוי) או ימינה (מופעל). \ No newline at end of file diff --git a/resources-hrv/strings/strings.xml b/resources-hrv/strings/strings.xml index 42219f1..c30697a 100644 --- a/resources-hrv/strings/strings.xml +++ b/resources-hrv/strings/strings.xml @@ -25,21 +25,22 @@ Dodirnite Jelovnik Naravno? - Nema telefonske veze + Nema telefonske veze Nema internetske veze Nema odgovora, provjerite internetsku vezu - Pogreška dohvaćanja izbornika - Nema API ključa u postavkama aplikacije - Nema API URL-a u postavkama aplikacije - Nema konfiguracijskog URL-a u postavkama aplikacije + Nema API ključa u postavkama aplikacije + Nema API URL-a u postavkama aplikacije + Nema konfiguracijskog URL-a u postavkama aplikacije API pozivi su prebrzi. Molimo usporite svoje zahtjeve. URL nije pronađen. Potencijalna pogreška API URL-a u postavkama. URL nije pronađen. Potencijalna pogreška URL-a konfiguracije u postavkama. + HTTP zahtjev nije vratio JSON. HTTP zahtjev vratio je kod greške = API URL ne smije imati kosu crtu na kraju '/' - Dohvaćanje konfiguracije izbornika.. - Prijeđite prstom udesno za izlaz\nDodirnite za ostanak - Pritisnite Natrag za izlaz\nUnesite za ostanak + Dostupno + Provjera... + Nedostupan + Jelovnik API ključ za HomeAssistant. Dugotrajni pristupni token. diff --git a/resources-hun/strings/strings.xml b/resources-hun/strings/strings.xml index 5af0554..cc7f2dc 100644 --- a/resources-hun/strings/strings.xml +++ b/resources-hun/strings/strings.xml @@ -25,21 +25,22 @@ Koppintson a Menü Biztos? - Nincs telefonkapcsolat + Nincs telefonkapcsolat Nincs internetkapcsolat Nincs válasz, ellenőrizze az internetkapcsolatot - Menü Lekérési hiba - Nincs API kulcs az alkalmazás beállításaiban - Nincs API URL az alkalmazás beállításai között - Nincs konfigurációs URL az alkalmazás beállításai között + Nincs API kulcs az alkalmazás beállításaiban + Nincs API URL az alkalmazás beállításai között + Nincs konfigurációs URL az alkalmazás beállításai között Az API-hívások túl gyorsak. Kérjük, lassítsa a kérések teljesítését. Az URL nem található. Lehetséges API URL hiba a beállításokban. Az URL nem található. Lehetséges konfigurációs URL hiba a beállításokban. + A HTTP-kérésből nem érkezett vissza JSON. A HTTP-kérés = hibakódot adott vissza Az API URL-ben nem lehet perjel a „/” - Menükonfiguráció lekérése... - Csúsztassa jobbra a kilépéshez.\nKoppintson a Maradáshoz - Nyomja meg a Vissza gombot a kilépéshez\nEnter a Maradáshoz + Elérhető + Ellenőrzés... + Nem érhető el + Menü API-kulcs a HomeAssistant számára. Hosszú életű hozzáférési token. diff --git a/resources-ind/strings/strings.xml b/resources-ind/strings/strings.xml index df1cb95..6d8e673 100644 --- a/resources-ind/strings/strings.xml +++ b/resources-ind/strings/strings.xml @@ -25,21 +25,22 @@ Mengetuk Menu Tentu? - Tidak ada koneksi Telepon + Tidak ada koneksi Telepon Tidak ada koneksi internet Tidak Ada Respon, periksa koneksi Internet - Kesalahan Pengambilan Menu - Tidak ada kunci API di pengaturan aplikasi - Tidak ada URL API di pengaturan aplikasi - Tidak ada URL konfigurasi di pengaturan aplikasi + Tidak ada kunci API di pengaturan aplikasi + Tidak ada URL API di pengaturan aplikasi + Tidak ada URL konfigurasi dalam pengaturan aplikasi Panggilan API terlalu cepat. Harap memperlambat permintaan Anda. URL tidak ditemukan. Potensi kesalahan URL API dalam pengaturan. URL tidak ditemukan. Potensi kesalahan URL Konfigurasi dalam pengaturan. + Tidak ada JSON yang dikembalikan dari permintaan HTTP. Permintaan HTTP mengembalikan kode kesalahan = URL API tidak boleh memiliki garis miring '/' - Mengambil Konfigurasi Menu.. - Geser ke Kanan untuk Keluar\nKetuk untuk Tetap - Tekan Kembali untuk Keluar\nMasuk untuk Tetap + Tersedia + Memeriksa... + Tidak tersedia + Menu Kunci API untuk HomeAssistant. Token Akses Berumur Panjang. diff --git a/resources-ita/strings/strings.xml b/resources-ita/strings/strings.xml index e782445..de8bcdb 100644 --- a/resources-ita/strings/strings.xml +++ b/resources-ita/strings/strings.xml @@ -25,21 +25,22 @@ Rubinetto Menù Sicuro? - Nessuna connessione telefonica + Nessuna connessione telefonica Nessuna connessione internet Nessuna risposta, controlla la connessione Internet - Errore di recupero del menu - Nessuna chiave API nelle impostazioni dell'applicazione - Nessun URL API nelle impostazioni dell'applicazione - Nessun URL di configurazione nelle impostazioni dell'applicazione + Nessuna chiave API nelle impostazioni dell'applicazione + Nessun URL API nelle impostazioni dell'applicazione + Nessun URL di configurazione nelle impostazioni dell'applicazione Chiamate API troppo rapide. Per favore rallenta le tue richieste. URL non trovato. Potenziale errore URL API nelle impostazioni. URL non trovato. Potenziale errore dell'URL di configurazione nelle impostazioni. + Nessun JSON restituito dalla richiesta HTTP. La richiesta HTTP ha restituito il codice di errore = L'URL dell'API non deve avere una barra finale "/" - Recupero configurazione menu.. - Scorri verso destra per uscire\nTocca per restare - Premi Indietro per uscire\nInvio per restare + Disponibile + Controllo... + Non disponibile + Menù Chiave API per HomeAssistant. Token di accesso di lunga durata. diff --git a/resources-jpn/strings/strings.xml b/resources-jpn/strings/strings.xml index 1930e08..2c5e3ab 100644 --- a/resources-jpn/strings/strings.xml +++ b/resources-jpn/strings/strings.xml @@ -25,24 +25,25 @@ タップ メニュー もちろん? - 電話が接続されていません + 電話が接続されていません インターネット接続なし 応答がありません。インターネット接続を確認してください - メニューフェッチエラー - アプリケーション設定に API キーがありません - アプリケーション設定に API URL がありません - アプリケーション設定に構成 URL がありません + アプリケーション設定に API キーがありません + アプリケーション設定に API URL がありません + アプリケーション設定に構成 URL がありません API 呼び出しが速すぎます。リクエストは遅くしてください。 URLが見つかりません。設定における API URL エラーの可能性があります。 URLが見つかりません。設定内の構成 URL エラーの可能性があります。 + HTTP リクエストから JSON が返されませんでした。 HTTP リクエストがエラー コードを返しました = API URL の末尾にスラッシュ「/」を含めることはできません - メニュー構成を取得しています。 - 右にスワイプして終了\nタップしてそのまま残ります - 終了するには戻るキーを押してください\n続行するには Enter キーを押してください + 利用可能 + チェック中... + 利用不可 + メニュー ホームアシスタントの API キー。 - 有効期間の長いアクセス トークン。 + 有効期限の長いアクセス トークン。 ホームアシスタント API の URL。 メニュー構成の URL (JSON)。 秒単位のタイムアウト。デバイスのバッテリーを節約するために、この期間非アクティブになった後はアプリケーションを終了してください。 diff --git a/resources-kor/strings/strings.xml b/resources-kor/strings/strings.xml index 6a10aaa..4497866 100644 --- a/resources-kor/strings/strings.xml +++ b/resources-kor/strings/strings.xml @@ -25,21 +25,22 @@ 수도꼭지 메뉴 확신하는? - 전화 연결 없음 + 전화 연결 없음 인터넷에 연결되지 않음 응답이 없습니다. 인터넷 연결을 확인하세요. - 메뉴 가져오기 오류 - 애플리케이션 설정에 API 키가 없습니다. - 애플리케이션 설정에 API URL이 없습니다. - 애플리케이션 설정에 구성 URL이 없습니다. + 애플리케이션 설정에 API 키가 없습니다. + 애플리케이션 설정에 API URL이 없습니다. + 애플리케이션 설정에 구성 URL이 없습니다. API 호출이 너무 빠릅니다. 요청 속도를 늦추시기 바랍니다. URL을 찾을 수 없습니다. 설정에 잠재적인 API URL 오류가 있습니다. URL을 찾을 수 없습니다. 설정에 잠재적인 구성 URL 오류가 있습니다. + HTTP 요청에서 JSON이 반환되지 않았습니다. HTTP 요청이 오류 코드를 반환했습니다 = - API URL에는 후행 슬래시 '/'가 없어야 합니다. - 메뉴 구성을 가져오는 중.. - 종료하려면 오른쪽으로 스와이프하세요.\n계속 유지하려면 탭하세요. - 종료하려면 뒤로 버튼을 누르세요.\n계속하려면 입력하세요. + API URL에는 후행 슬래시 '/'가 있어서는 안 됩니다. + 사용 가능 + 확인 중... + 없는 + 메뉴 HomeAssistant용 API 키. 장기 액세스 토큰. diff --git a/resources-lav/strings/strings.xml b/resources-lav/strings/strings.xml index 11f68cf..bae5625 100644 --- a/resources-lav/strings/strings.xml +++ b/resources-lav/strings/strings.xml @@ -25,21 +25,22 @@ Krāns Izvēlne Protams? - Nav tālruņa savienojuma + Nav tālruņa savienojuma Nav interneta savienojuma Nav atbildes, pārbaudiet interneta savienojumu - Izvēlnes ielādes kļūda - Lietojumprogrammas iestatījumos nav API atslēgas - Lietojumprogrammas iestatījumos nav API URL - Lietojumprogrammas iestatījumos nav konfigurācijas URL + Lietojumprogrammas iestatījumos nav API atslēgas + Lietojumprogrammas iestatījumos nav API URL + Lietojumprogrammas iestatījumos nav konfigurācijas URL API izsaukumi ir pārāk ātri. Lūdzu, palēniniet pieprasījumu izpildi. URL nav atrasts. Iespējama API URL kļūda iestatījumos. URL nav atrasts. Iespējama konfigurācijas URL kļūda iestatījumos. + No HTTP pieprasījuma netika atgriezts neviens JSON fails. HTTP pieprasījums atgrieza kļūdas kodu = API URL beigās nedrīkst būt slīpsvītra “/” - Notiek izvēlnes konfigurācijas iegūšana... - Lai izietu, velciet pa labi\nPieskarieties, lai paliktu - Noklikšķiniet uz Atpakaļ, lai izietu.\nIevadiet, lai paliktu + Pieejams + Notiek pārbaude... + Nav pieejams + Izvēlne API atslēga Home Assistant. Ilgmūžīgs piekļuves marķieris. diff --git a/resources-lit/strings/strings.xml b/resources-lit/strings/strings.xml index 9229062..c55a49b 100644 --- a/resources-lit/strings/strings.xml +++ b/resources-lit/strings/strings.xml @@ -25,21 +25,22 @@ Bakstelėkite Meniu Žinoma? - Nėra telefono ryšio + Nėra telefono ryšio Nėra interneto ryšio Neatsako, patikrinkite interneto ryšį - Meniu gavimo klaida - Programos nustatymuose nėra API rakto - Programos nustatymuose nėra API URL - Programos nustatymuose nėra konfigūracijos URL + Programos nustatymuose nėra API rakto + Programos nustatymuose nėra API URL + Programos nustatymuose nėra konfigūracijos URL API skambučiai per greiti. Sulėtinkite prašymų vykdymą. URL nerastas. Galima API URL klaida nustatymuose. URL nerastas. Galima konfigūracijos URL klaida nustatymuose. + Joks JSON negrąžintas iš HTTP užklausos. HTTP užklausa grąžino klaidos kodą = API URL pabaigoje negali būti pasvirojo brūkšnio „/“ - Gaunama meniu konfigūracija... - Norėdami išeiti, braukite į dešinę\nPalieskite, kad pasiliktumėte - Norėdami išeiti, paspauskite „Atgal“.\nĮveskite, kad pasiliktumėte + Yra + Tikrinama... + Nepasiekiamas + Meniu API raktas, skirtas „HomeAssistant“. Ilgalaikis prieigos raktas. diff --git a/resources-nob/strings/strings.xml b/resources-nob/strings/strings.xml index b18c833..37fdbea 100644 --- a/resources-nob/strings/strings.xml +++ b/resources-nob/strings/strings.xml @@ -25,21 +25,22 @@ Trykk på Meny Sikker? - Ingen telefonforbindelse + Ingen telefonforbindelse Ingen Internett-tilkobling Ingen svar, sjekk Internett-tilkoblingen - Menyhentingsfeil - Ingen API-nøkkel i applikasjonsinnstillingene - Ingen API-URL i applikasjonsinnstillingene - Ingen konfigurasjons-URL i applikasjonsinnstillingene + Ingen API-nøkkel i applikasjonsinnstillingene + Ingen API-URL i applikasjonsinnstillingene + Ingen konfigurasjons-URL i applikasjonsinnstillingene API-kall for raske. Vennligst senke forespørslene dine. Finner ikke URL. Potensiell API URL-feil i innstillingene. Finner ikke URL. Potensiell konfigurasjons-URL-feil i innstillingene. + Ingen JSON returnert fra HTTP-forespørsel. HTTP-forespørsel returnerte feilkode = API URL må ikke ha en etterfølgende skråstrek '/' - Henter menykonfigurasjon.. - Sveip til høyre for å avslutte\nTrykk for å bli - Trykk Tilbake for å avslutte\nEnter for å bli + Tilgjengelig + Sjekker... + Utilgjengelig + Meny API-nøkkel for HomeAssistant. Langlevd tilgangstoken. diff --git a/resources-pol/strings/strings.xml b/resources-pol/strings/strings.xml index bc5e094..783aeb8 100644 --- a/resources-pol/strings/strings.xml +++ b/resources-pol/strings/strings.xml @@ -25,21 +25,22 @@ Uzyskiwać Menu Jasne? - Brak połączenia telefonicznego + Brak połączenia telefonicznego Brak połączenia z internetem Brak odpowiedzi, sprawdź połączenie internetowe - Błąd pobierania menu - Brak klucza API w ustawieniach aplikacji - Brak adresu API w ustawieniach aplikacji - Brak adresu URL konfiguracji w ustawieniach aplikacji + Brak klucza API w ustawieniach aplikacji + Brak adresu API w ustawieniach aplikacji + Brak adresu URL konfiguracji w ustawieniach aplikacji Wywołania API są zbyt szybkie. Proszę spowolnić swoje żądania. Nie znaleziono adresu URL. Potencjalny błąd adresu URL interfejsu API w ustawieniach. Nie znaleziono adresu URL. Potencjalny błąd adresu URL konfiguracji w ustawieniach. + Z żądania HTTP nie zwrócono żadnego kodu JSON. Żądanie HTTP zwróciło kod błędu = Adres URL interfejsu API nie może zawierać końcowego ukośnika „/” - Pobieranie konfiguracji menu.. - Przesuń w prawo, aby wyjść\nDotknij, aby pozostać - Naciśnij Wstecz, aby wyjść\nEnter, aby pozostać + Dostępny + Kontrola... + Niedostępne + Menu Klucz API dla HomeAssistant. Długowieczny token dostępu. diff --git a/resources-por/strings/strings.xml b/resources-por/strings/strings.xml index a8f1880..ee84c84 100644 --- a/resources-por/strings/strings.xml +++ b/resources-por/strings/strings.xml @@ -25,21 +25,22 @@ Tocar Cardápio Claro? - Sem conexão telefônica + Sem conexão telefônica Sem conexão com a Internet Sem resposta, verifique a conexão com a Internet - Erro ao buscar menu - Nenhuma chave de API nas configurações do aplicativo - Nenhum URL de API nas configurações do aplicativo - Nenhum URL de configuração nas configurações do aplicativo + Nenhuma chave de API nas configurações do aplicativo + Nenhum URL de API nas configurações do aplicativo + Nenhum URL de configuração nas configurações do aplicativo Chamadas de API muito rápidas. Por favor, diminua a velocidade de seus pedidos. URL não encontrado. Possível erro de URL da API nas configurações. URL não encontrado. Possível erro de URL de configuração nas configurações. + Nenhum JSON foi retornado da solicitação HTTP. Solicitação HTTP retornou código de erro = O URL da API não deve ter uma barra final '/' - Buscando configuração do menu.. - Deslize para a direita para sair\nToque para permanecer - Volte para sair\nEntre para ficar + Disponível + Verificando... + Indisponível + Cardápio Chave de API para HomeAssistant. Token de acesso de longa duração. diff --git a/resources-ron/strings/strings.xml b/resources-ron/strings/strings.xml index 43cc8d5..479fb32 100644 --- a/resources-ron/strings/strings.xml +++ b/resources-ron/strings/strings.xml @@ -21,25 +21,26 @@ HomeAssistant Pe - Oprit + Off Atingeți Meniul Sigur? - Fără conexiune telefonică + Fără conexiune telefonică Fără conexiune internet Niciun răspuns, verificați conexiunea la internet - Eroare de preluare a meniului - Nicio cheie API în setările aplicației - Nicio adresă URL API în setările aplicației - Nicio adresă URL de configurare în setările aplicației + Nicio cheie API în setările aplicației + Nicio adresă URL API în setările aplicației + Nicio adresă URL de configurare în setările aplicației Apeluri API prea rapide. Vă rugăm să încetiniți cererile dvs. Adresa URL nu a fost găsită. Potențială eroare URL API în setări. Adresa URL nu a fost găsită. Potențială eroare URL de configurare în setări. + Niciun JSON nu a fost returnat de la solicitarea HTTP. Solicitarea HTTP a returnat codul de eroare = Adresa URL API nu trebuie să aibă o bară oblică „/” - Se preiau configurarea meniului... - Glisați spre dreapta pentru a ieși\nAtingeți pentru a rămâne - Apăsați Înapoi pentru a ieși\nIntră pentru a rămâne + Disponibil + Control... + Indisponibil + Meniul Cheie API pentru HomeAssistant. Token de acces cu viață lungă. diff --git a/resources-slo/strings/strings.xml b/resources-slo/strings/strings.xml index ae924f8..9ec5028 100644 --- a/resources-slo/strings/strings.xml +++ b/resources-slo/strings/strings.xml @@ -25,21 +25,22 @@ Klepnite Ponuka Samozrejme? - Žiadne telefónne spojenie + Žiadne telefónne spojenie Žiadne internetové pripojenie Žiadna odpoveď, skontrolujte internetové pripojenie - Chyba načítania ponuky - V nastaveniach aplikácie nie je žiadny kľúč API - V nastaveniach aplikácie nie je žiadna adresa URL rozhrania API - V nastaveniach aplikácie nie je žiadna konfiguračná URL + V nastaveniach aplikácie nie je žiadny kľúč API + V nastaveniach aplikácie nie je žiadna adresa URL rozhrania API + V nastaveniach aplikácie nie je žiadna konfiguračná URL Volania API sú príliš rýchle. Spomaľte svoje požiadavky. Adresa URL sa nenašla. Potenciálna chyba webovej adresy rozhrania API v nastaveniach. Adresa URL sa nenašla. Potenciálna chyba konfiguračnej adresy URL v nastaveniach. + Z požiadavky HTTP sa nevrátil žiadny JSON. Požiadavka HTTP vrátila kód chyby = Adresa URL rozhrania API nesmie obsahovať koncovú lomku „/“ - Načítava sa konfigurácia ponuky... - Ukončite prejdením prstom doprava\nKlepnutím zostanete - Stlačte Späť na ukončenie\nVstúpte a zostaňte + Dostupné + Prebieha kontrola... + nedostupné + Ponuka Kľúč API pre HomeAssistant. Dlhotrvajúci prístupový token. diff --git a/resources-slv/strings/strings.xml b/resources-slv/strings/strings.xml index 67c66af..b8b48cc 100644 --- a/resources-slv/strings/strings.xml +++ b/resources-slv/strings/strings.xml @@ -25,21 +25,22 @@ Tapnite meni Seveda? - Ni telefonske povezave + Ni telefonske povezave Ni internetne povezave Ni odgovora, preverite internetno povezavo - Napaka pri pridobivanju menija - V nastavitvah aplikacije ni ključa API - V nastavitvah aplikacije ni URL-ja API-ja - V nastavitvah aplikacije ni konfiguracijskega URL-ja + V nastavitvah aplikacije ni ključa API + V nastavitvah aplikacije ni URL-ja API-ja + V nastavitvah aplikacije ni konfiguracijskega URL-ja API klici so prehitri. Prosim, upočasnite svoje zahteve. URL-ja ni bilo mogoče najti. Morebitna napaka URL-ja API-ja v nastavitvah. URL-ja ni bilo mogoče najti. Morebitna napaka URL-ja konfiguracije v nastavitvah. + Zahteva HTTP ni vrnila JSON. Zahteva HTTP je vrnila kodo napake = URL API-ja ne sme imeti končne poševnice '/' - Pridobivanje konfiguracije menija.. - Povlecite v desno za izhod\nDotaknite se, da ostanete - Pritisnite Nazaj za izhod\nVstopite, da ostanete + Na voljo + Preverjanje ... + Ni na voljo + meni API ključ za HomeAssistant. Dolgoživ dostopni žeton. diff --git a/resources-spa/strings/strings.xml b/resources-spa/strings/strings.xml index b1a7bd2..e5d91f1 100644 --- a/resources-spa/strings/strings.xml +++ b/resources-spa/strings/strings.xml @@ -25,21 +25,22 @@ Grifo Menú ¿Seguro? - Sin conexión telefónica + Sin conexión telefónica Sin conexión a Internet No hay respuesta, verifique la conexión a Internet - Error de recuperación del menú - Sin clave API en la configuración de la aplicación - No hay URL de API en la configuración de la aplicación - No hay URL de configuración en la configuración de la aplicación. + Sin clave API en la configuración de la aplicación + No hay URL de API en la configuración de la aplicación + No hay URL de configuración en la configuración de la aplicación. Llamadas API demasiado rápidas. Por favor, ralentice sus solicitudes. URL no encontrada. Posible error de URL de API en la configuración. URL no encontrada. Posible error de URL de configuración en la configuración. + No se devolvió ningún JSON de la solicitud HTTP. La solicitud HTTP devolvió el código de error = La URL de API no debe tener una barra diagonal '/' - Obteniendo configuración del menú.. - Desliza hacia la derecha para salir\nToca para permanecer - Presione Atrás para salir\nEntrar para permanecer + Disponible + Comprobación... + Indisponible + Menú Clave API para HomeAssistant. Token de acceso de larga duración. diff --git a/resources-swe/strings/strings.xml b/resources-swe/strings/strings.xml index ee7550d..cf7bb44 100644 --- a/resources-swe/strings/strings.xml +++ b/resources-swe/strings/strings.xml @@ -25,21 +25,22 @@ Knacka Meny Säker? - Ingen telefonanslutning + Ingen telefonanslutning Ingen internetanslutning Inget svar, kontrollera internetanslutningen - Menyhämtningsfel - Ingen API-nyckel i applikationsinställningarna - Ingen API-URL i applikationsinställningarna - Ingen konfigurations-URL i programinställningarna + Ingen API-nyckel i applikationsinställningarna + Ingen API-URL i applikationsinställningarna + Ingen konfigurations-URL i programinställningarna API-anrop för snabba. Vänligen sakta ner dina förfrågningar. Webbadressen hittades inte. Potentiellt API-URL-fel i inställningarna. Webbadressen hittades inte. Potentiellt konfigurations-URL-fel i inställningarna. + Ingen JSON returnerades från HTTP-begäran. HTTP-begäran returnerade felkod = API-URL får inte ha ett snedstreck '/' - Hämtar menykonfiguration.. - Svep åt höger för att avsluta\nKnacka för att stanna - Tryck på Tillbaka för att avsluta\nEnter för att stanna + Tillgängliga + Kontroll... + Inte tillgänglig + Meny API-nyckel för HomeAssistant. Långlivad åtkomsttoken. diff --git a/resources-tha/strings/strings.xml b/resources-tha/strings/strings.xml index 4f10874..6aabc27 100644 --- a/resources-tha/strings/strings.xml +++ b/resources-tha/strings/strings.xml @@ -25,21 +25,22 @@ แตะ เมนู แน่นอน? - ไม่มีการเชื่อมต่อโทรศัพท์ + ไม่มีการเชื่อมต่อโทรศัพท์ ไม่มีการเชื่อมต่ออินเทอร์เน็ต ไม่มีการตอบสนอง ตรวจสอบการเชื่อมต่ออินเทอร์เน็ต - เมนูดึงข้อมูลผิดพลาด - ไม่มีคีย์ API ในการตั้งค่าแอปพลิเคชัน - ไม่มี URL API ในการตั้งค่าแอปพลิเคชัน - ไม่มี URL การกำหนดค่าในการตั้งค่าแอปพลิเคชัน + ไม่มีคีย์ API ในการตั้งค่าแอปพลิเคชัน + ไม่มี URL API ในการตั้งค่าแอปพลิเคชัน + ไม่มี URL การกำหนดค่าในการตั้งค่าแอปพลิเคชัน การเรียก API เร็วเกินไป กรุณาชะลอคำขอของคุณ ไม่พบ URL ข้อผิดพลาด URL API ที่อาจเกิดขึ้นในการตั้งค่า ไม่พบ URL ข้อผิดพลาด URL การกำหนดค่าที่อาจเกิดขึ้นในการตั้งค่า + ไม่มี JSON ที่ส่งคืนจากคำขอ HTTP คำขอ HTTP ส่งคืนรหัสข้อผิดพลาด = URL ของ API ต้องไม่มีเครื่องหมายทับต่อท้าย '/' - กำลังดึงข้อมูลการกำหนดค่าเมนู.. - ปัดไปทางขวาเพื่อออก\nแตะเพื่ออยู่ต่อ - กดกลับเพื่อออก\nเข้าไปเพื่ออยู่ต่อ + มีอยู่ + กำลังตรวจสอบ... + ไม่พร้อมใช้งาน + เมนู คีย์ API สำหรับ HomeAssistant โทเค็นการเข้าถึงที่มีอายุการใช้งานยาวนาน diff --git a/resources-tur/strings/strings.xml b/resources-tur/strings/strings.xml index ceb30dc..e52d78c 100644 --- a/resources-tur/strings/strings.xml +++ b/resources-tur/strings/strings.xml @@ -25,21 +25,22 @@ Musluk Menü Elbette? - Telefon bağlantısı yok + Telefon bağlantısı yok İnternet bağlantısı yok Yanıt Yok, İnternet bağlantısını kontrol edin - Menü Alma Hatası - Uygulama ayarlarında API anahtarı yok - Uygulama ayarlarında API URL'si yok - Uygulama ayarlarında yapılandırma URL'si yok + Uygulama ayarlarında API anahtarı yok + Uygulama ayarlarında API URL'si yok + Uygulama ayarlarında yapılandırma URL'si yok API çağrıları çok hızlı. Lütfen isteklerinizi yavaşlatın. URL bulunamadı. Ayarlarda olası API URL hatası. URL bulunamadı. Ayarlarda Olası Yapılandırma URL'si hatası. + HTTP isteğinden JSON döndürülmedi. HTTP isteği hata kodunu döndürdü = - API URL'sinin sonunda eğik çizgi '/' olmamalıdır - Menü Yapılandırması alınıyor.. - Çıkmak için Sağa Kaydırın\nKalmak için Dokunun - Çıkış için Geri tuşuna basın\nKalmak için Enter'a basın + API URL'sinin sonunda '/' eğik çizgi olmamalıdır + Mevcut + Kontrol etme... + Kullanım dışı + Menü HomeAssistant için API Anahtarı. Uzun Ömürlü Erişim Jetonu. diff --git a/resources-ukr/strings/strings.xml b/resources-ukr/strings/strings.xml index 0202455..10f571a 100644 --- a/resources-ukr/strings/strings.xml +++ b/resources-ukr/strings/strings.xml @@ -25,21 +25,22 @@ Торкніться Меню Зрозуміло? - Немає телефонного зв'язку + Немає телефонного зв'язку Немає підключення до Інтернету Немає відповіді, перевірте підключення до Інтернету - Помилка вибірки меню - У налаштуваннях програми немає ключа API - У налаштуваннях програми немає URL-адреси API - У налаштуваннях програми немає URL-адреси конфігурації + У налаштуваннях програми немає ключа API + У налаштуваннях програми немає URL-адреси API + У налаштуваннях програми немає URL-адреси конфігурації Надто швидкі виклики API. Будь ласка, сповільніть свої запити. URL не знайдено. Потенційна помилка URL-адреси API в налаштуваннях. URL не знайдено. Потенційна помилка URL-адреси конфігурації в налаштуваннях. + Запит HTTP не повертає JSON. Запит HTTP повернув код помилки = URL-адреса API не повинна містити косу риску '/' - Отримання конфігурації меню.. - Проведіть праворуч, щоб вийти\nТоркніться, щоб залишитися - Натисніть «Назад», щоб вийти\nВведіть, щоб залишитися + в наявності + Перевірка... + Недоступний + Меню Ключ API для HomeAssistant. Довговічний маркер доступу. diff --git a/resources-vie/strings/strings.xml b/resources-vie/strings/strings.xml index ea329c2..0ab56b6 100644 --- a/resources-vie/strings/strings.xml +++ b/resources-vie/strings/strings.xml @@ -25,21 +25,22 @@ Vỗ nhẹ Thực đơn Chắc chắn? - Không có kết nối điện thoại + Không có kết nối điện thoại Không có kết nối Internet Không có phản hồi, kiểm tra kết nối Internet - Lỗi tìm nạp menu - Không có khóa API trong cài đặt ứng dụng - Không có URL API trong cài đặt ứng dụng - Không có URL cấu hình trong cài đặt ứng dụng + Không có khóa API trong cài đặt ứng dụng + Không có URL API trong cài đặt ứng dụng + Không có URL cấu hình trong cài đặt ứng dụng Cuộc gọi API quá nhanh. Hãy làm chậm yêu cầu của bạn. Không tìm thấy URL. Lỗi URL API tiềm ẩn trong cài đặt. Không tìm thấy URL. Lỗi URL cấu hình tiềm ẩn trong cài đặt. + Không có JSON nào được trả về từ yêu cầu HTTP. Yêu cầu HTTP trả về mã lỗi = URL API không được có dấu gạch chéo ở cuối '/' - Đang tìm nạp cấu hình menu.. - Vuốt sang phải để thoát\nNhấn để ở lại - Nhấn Quay lại để thoát\nNhập để ở lại + Có sẵn + Đang kiểm tra... + Không có sẵn + Thực đơn Khóa API cho HomeAssistant. Mã thông báo truy cập tồn tại lâu dài. diff --git a/resources-zhs/strings/strings.xml b/resources-zhs/strings/strings.xml index 9a200a9..1d59279 100644 --- a/resources-zhs/strings/strings.xml +++ b/resources-zhs/strings/strings.xml @@ -25,21 +25,22 @@ 轻敲 菜单 当然? - 没有电话连接 + 没有电话连接 没有网络连接 无响应,请检查互联网连接 - 菜单获取错误 - 应用程序设置中没有 API 密钥 - 应用程序设置中没有 API URL - 应用程序设置中没有配置 URL + 应用程序设置中没有 API 密钥 + 应用程序设置中没有 API URL + 应用程序设置中没有配置 URL API 调用速度太快。请放慢您的请求。 找不到网址。设置中可能存在 API URL 错误。 找不到网址。设置中可能存在配置 URL 错误。 + HTTP 请求未返回 JSON。 HTTP请求返回错误码= API URL 不得有尾部斜杠“/” - 正在获取菜单配置.. - 向右滑动即可退出\n点击即可停留 - 按回车键退出\n按回车键继续 + 可用的 + 检查... + 不可用 + 菜单 HomeAssistant 的 API 密钥。 长期访问令牌。 diff --git a/resources-zht/strings/strings.xml b/resources-zht/strings/strings.xml index 8703056..0e9d36a 100644 --- a/resources-zht/strings/strings.xml +++ b/resources-zht/strings/strings.xml @@ -25,21 +25,22 @@ 輕敲 選單 當然? - 沒有電話連接 + 沒有電話連接 沒有網路連線 無響應,請檢查互聯網連接 - 選單取得錯誤 - 應用程式設定中沒有 API 金鑰 - 應用程式設定中沒有 API URL - 應用程式設定中沒有配置 URL + 應用程式設定中沒有 API 金鑰 + 應用程式設定中沒有 API URL + 應用程式設定中沒有配置 URL API 呼叫速度太快。請放慢您的請求。 找不到網址。設定中可能存在 API URL 錯誤。 找不到網址。設定中可能存在配置 URL 錯誤。 + HTTP 請求未傳回 JSON。 HTTP請求回傳錯誤碼= API URL 不得有尾部斜線“/” - 正在取得選單配置.. - 向右滑動即可退出\n點選即可停留 - 按回車鍵退出\n按回車鍵繼續 + 可用的 + 檢查... + 不可用 + 選單 HomeAssistant 的 API 金鑰。 長期訪問令牌。 diff --git a/resources-zsm/strings/strings.xml b/resources-zsm/strings/strings.xml index b4a79b8..8cceb5f 100644 --- a/resources-zsm/strings/strings.xml +++ b/resources-zsm/strings/strings.xml @@ -25,21 +25,22 @@ Ketik Menu pasti? - Tiada sambungan Telefon + Tiada sambungan Telefon Tiada sambungan internet Tiada Respons, semak sambungan Internet - Ralat Pengambilan Menu - Tiada kunci API dalam tetapan aplikasi - Tiada URL API dalam tetapan aplikasi - Tiada URL konfigurasi dalam tetapan aplikasi + Tiada kunci API dalam tetapan aplikasi + Tiada URL API dalam tetapan aplikasi + Tiada URL konfigurasi dalam tetapan aplikasi Panggilan API terlalu pantas. Sila perlahankan permintaan anda. URL tidak ditemui. Ralat URL API yang berpotensi dalam tetapan. URL tidak ditemui. Ralat URL Konfigurasi Potensi dalam tetapan. + Tiada JSON dikembalikan daripada permintaan HTTP. Permintaan HTTP mengembalikan kod ralat = URL API tidak boleh mempunyai garis miring '/' - Mengambil Konfigurasi Menu.. - Leret ke Kanan untuk Keluar\nKetik untuk Kekal - Tekan Kembali untuk Keluar\nMasuk untuk Kekal + Tersedia + Menyemak... + Tidak ada + Menu Kunci API untuk HomeAssistant. Token Akses Berumur Panjang. diff --git a/resources/strings/strings.xml b/resources/strings/strings.xml index 4d64b1a..a69dfca 100644 --- a/resources/strings/strings.xml +++ b/resources/strings/strings.xml @@ -19,21 +19,22 @@ Tap Menu Sure? - No Phone connection + No Phone connection No Internet connection No Response, check Internet connection - Menu Fetch Error - No API key in the application settings - No API URL in the application settings - No configuration URL in the application settings + No API key in the application settings + No API URL in the application settings + No configuration URL in the application settings API calls too rapid. Please slow down your requests. URL not found. Potential API URL error in settings. URL not found. Potential Configuration URL error in settings. + No JSON returned from HTTP request. HTTP request returned error code = API URL must not have a trailing slash '/' - Fetching Menu Config.. - Swipe to Right to Exit\nTap to Stay - Hit Back to Exit\nEnter to Stay + Available + Checking... + Unavailable + Menu API Key for HomeAssistant. diff --git a/source/ErrorView.mc b/source/ErrorView.mc index 0c5c5c8..701f473 100644 --- a/source/ErrorView.mc +++ b/source/ErrorView.mc @@ -106,10 +106,21 @@ class ErrorView extends ScalableView { create(text); // Ignore returned values if (!mShown) { WatchUi.pushView(instance, instance.getDelegate(), WatchUi.SLIDE_UP); + // This must be last to avoid a race condition with unShow(), where the + // ErrorView can't be dismissed. mShown = true; } } + static function unShow() as Void { + if (mShown) { + WatchUi.popView(WatchUi.SLIDE_DOWN); + // This must be last to avoid a race condition with show(), where the + // ErrorView can't be dismissed. + mShown = false; + } + } + // Internal show now we're not a static method like 'show()'. function setText(text as Lang.String) as Void { mText = text; @@ -119,13 +130,6 @@ class ErrorView extends ScalableView { } } - static function unShow() as Void { - if (mShown) { - mShown = false; - WatchUi.popView(WatchUi.SLIDE_DOWN); - } - } - } class ErrorDelegate extends WatchUi.BehaviorDelegate { diff --git a/source/Globals.mc b/source/Globals.mc index 510019c..17f1c39 100644 --- a/source/Globals.mc +++ b/source/Globals.mc @@ -26,4 +26,5 @@ class Globals { static const scDebug = false; static const scAlertTimeout = 2000; // ms static const scTapTimeout = 1000; // ms + static const scApiBackoff = 1000; // ms } diff --git a/source/HomeAssistantApp.mc b/source/HomeAssistantApp.mc index 1e667f0..0407678 100644 --- a/source/HomeAssistantApp.mc +++ b/source/HomeAssistantApp.mc @@ -24,31 +24,38 @@ using Toybox.WatchUi; using Toybox.Application.Properties; class HomeAssistantApp extends Application.AppBase { - private var mHaMenu as HomeAssistantView or Null; - private var mQuitTimer as QuitTimer or Null; private var strNoApiKey as Lang.String or Null; private var strNoApiUrl as Lang.String or Null; private var strNoConfigUrl as Lang.String or Null; private var strNoPhone as Lang.String or Null; private var strNoInternet as Lang.String or Null; private var strNoResponse as Lang.String or Null; - private var strNoMenu as Lang.String or Null; private var strApiFlood as Lang.String or Null; private var strConfigUrlNotFound as Lang.String or Null; + private var strNoJson as Lang.String or Null; private var strUnhandledHttpErr as Lang.String or Null; private var strTrailingSlashErr as Lang.String or Null; - private var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig() - private var mNextItemToUpdate = 0; // Index into the above array + private var strAvailable = WatchUi.loadResource($.Rez.Strings.Available); + private var strUnavailable = WatchUi.loadResource($.Rez.Strings.Unavailable); + + private var mApiKey as Lang.String; + private var mApiStatus as Lang.String = WatchUi.loadResource($.Rez.Strings.Checking); + private var mMenuStatus as Lang.String = WatchUi.loadResource($.Rez.Strings.Checking); + private var mHaMenu as HomeAssistantView or Null; + private var mQuitTimer as QuitTimer or Null; + private var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig() + private var mNextItemToUpdate = 0; // Index into the above array + private var mIsGlance as Lang.Boolean = false; function initialize() { AppBase.initialize(); - + mApiKey = Properties.getValue("api_key"); // ATTENTION when adding stuff into this block: // Because of the >>GlanceView<<, it should contain only // code, which is used as well for the glance: // - https://developer.garmin.com/connect-iq/core-topics/glances/ // - // Also dealing with resources "Rez" needs attention, too. See + // Also dealing with resources "Rez" needs attention, too. See // "Resource Scopes": // - https://developer.garmin.com/connect-iq/core-topics/resources/ // @@ -58,12 +65,13 @@ class HomeAssistantApp extends Application.AppBase { // onStart() is called on application start up function onStart(state as Lang.Dictionary?) as Void { + AppBase.onStart(state); // ATTENTION when adding stuff into this block: // Because of the >>GlanceView<<, it should contain only // code, which is used as well for the glance: // - https://developer.garmin.com/connect-iq/core-topics/glances/ // - // Also dealing with resources "Rez" needs attention, too. See + // Also dealing with resources "Rez" needs attention, too. See // "Resource Scopes": // - https://developer.garmin.com/connect-iq/core-topics/resources/ // @@ -73,12 +81,13 @@ class HomeAssistantApp extends Application.AppBase { // onStop() is called when your application is exiting function onStop(state as Lang.Dictionary?) as Void { + AppBase.onStop(state); // ATTENTION when adding stuff into this block: // Because of the >>GlanceView<<, it should contain only // code, which is used as well for the glance: // - https://developer.garmin.com/connect-iq/core-topics/glances/ // - // Also dealing with resources "Rez" needs attention, too. See + // Also dealing with resources "Rez" needs attention, too. See // "Resource Scopes": // - https://developer.garmin.com/connect-iq/core-topics/resources/ // @@ -88,16 +97,15 @@ class HomeAssistantApp extends Application.AppBase { // Return the initial view of your application here function getInitialView() as Lang.Array? { - strNoApiKey = WatchUi.loadResource($.Rez.Strings.NoAPIKey); strNoApiUrl = WatchUi.loadResource($.Rez.Strings.NoApiUrl); strNoConfigUrl = WatchUi.loadResource($.Rez.Strings.NoConfigUrl); strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone); strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet); strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse); - strNoMenu = WatchUi.loadResource($.Rez.Strings.NoMenu); strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood); strConfigUrlNotFound = WatchUi.loadResource($.Rez.Strings.ConfigUrlNotFound); + strNoJson = WatchUi.loadResource($.Rez.Strings.NoJson); strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr); strTrailingSlashErr = WatchUi.loadResource($.Rez.Strings.TrailingSlashErr); mQuitTimer = new QuitTimer(); @@ -136,61 +144,102 @@ class HomeAssistantApp extends Application.AppBase { return ErrorView.create(strNoInternet + "."); } else { fetchMenuConfig(); - return [new RootView(self), new RootViewDelegate(self)] as Lang.Array; + fetchApiStatus(); + if (WidgetApp.isWidget) { + return [new RootView(self), new RootViewDelegate(self)] as Lang.Array; + } else { + return [new WatchUi.View(), new WatchUi.BehaviorDelegate()] as Lang.Array; + } } } // Callback function after completing the GET request to fetch the configuration menu. // + (:glance) function onReturnFetchMenuConfig(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String) as Void { if (Globals.scDebug) { System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: " + responseCode); System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Data: " + data); } - if (responseCode == Communications.BLE_HOST_TIMEOUT || responseCode == Communications.BLE_CONNECTION_UNAVAILABLE) { - if (Globals.scDebug) { - System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed."); - } - ErrorView.show(strNoPhone + "."); - } else if (responseCode == Communications.BLE_QUEUE_FULL) { - if (Globals.scDebug) { - System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: BLE_QUEUE_FULL, API calls too rapid."); - } - // Don't need to worry about multiple ErrorViews here as the fetch does not happen a second time. - ErrorView.show(strApiFlood); - } else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) { - if (Globals.scDebug) { - System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection."); - } - ErrorView.show(strNoResponse); - } else if (responseCode == 404) { - if (Globals.scDebug) { - System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: 404, page not found. Check Configuration URL setting."); - } - ErrorView.show(strConfigUrlNotFound); - } else if (responseCode == 200) { - mHaMenu = new HomeAssistantView(data, null); - mQuitTimer.begin(); - pushHomeAssistantMenuView(); - mItemsToUpdate = mHaMenu.getItemsToUpdate(); - // Start the continuous update process that continues for as long as the application is running. - // The chain of functions from 'updateNextMenuItem()' calls 'updateNextMenuItem()' on completion. - if (mItemsToUpdate.size() > 0) { - updateNextMenuItem(); - } - } else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) { - if (Globals.scDebug) { - System.println("HomeAssistantApp onReturnFetchMenuConfig(): Network request timeout."); - } - ErrorView.show(strNoMenu + ". " + strNoInternet + "?"); - } else { - if (Globals.scDebug) { - System.println("HomeAssistantApp onReturnFetchMenuConfig(): Unhandled HTTP response code = " + responseCode); - } - ErrorView.show(strUnhandledHttpErr + responseCode ); + + mMenuStatus = strUnavailable; + switch (responseCode) { + case Communications.BLE_HOST_TIMEOUT: + case Communications.BLE_CONNECTION_UNAVAILABLE: + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed."); + } + if (!mIsGlance) { + ErrorView.show(strNoPhone + "."); + } + break; + + case Communications.BLE_QUEUE_FULL: + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: BLE_QUEUE_FULL, API calls too rapid."); + } + if (!mIsGlance) { + ErrorView.show(strApiFlood); + } + break; + + case Communications.NETWORK_REQUEST_TIMED_OUT: + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection."); + } + if (!mIsGlance) { + ErrorView.show(strNoResponse); + } + break; + + case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE: + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned."); + } + if (!mIsGlance) { + ErrorView.show(strNoJson); + } + break; + + case 404: + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: 404, page not found. Check Configuration URL setting."); + } + if (!mIsGlance) { + ErrorView.show(strConfigUrlNotFound); + } + break; + + case 200: + mMenuStatus = strAvailable; + if (!mIsGlance) { + mHaMenu = new HomeAssistantView(data, null); + mQuitTimer.begin(); + mItemsToUpdate = mHaMenu.getItemsToUpdate(); + // Start the continuous update process that continues for as long as the application is running. + // The chain of functions from 'updateNextMenuItem()' calls 'updateNextMenuItem()' on completion. + if (mItemsToUpdate.size() > 0) { + updateNextMenuItem(); + } + if (!WidgetApp.isWidget) { + WatchUi.switchToView(mHaMenu, new HomeAssistantViewDelegate(false), WatchUi.SLIDE_IMMEDIATE); + } + } + WatchUi.requestUpdate(); + break; + + default: + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchMenuConfig(): Unhandled HTTP response code = " + responseCode); + } + if (!mIsGlance) { + ErrorView.show(strUnhandledHttpErr + responseCode); + } + break; } } + (:glance) function fetchMenuConfig() as Void { var options = { :method => Communications.HTTP_REQUEST_METHOD_GET, @@ -204,11 +253,120 @@ class HomeAssistantApp extends Application.AppBase { ); } - function homeAssistantMenuIsLoaded() as Lang.Boolean{ - return mHaMenu!=null; + // Callback function after completing the GET request to fetch the API status. + // + (:glance) + function onReturnFetchApiStatus(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String) as Void { + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: " + responseCode); + System.println("HomeAssistantApp onReturnFetchApiStatus() Response Data: " + data); + } + + mApiStatus = strUnavailable; + switch (responseCode) { + case Communications.BLE_HOST_TIMEOUT: + case Communications.BLE_CONNECTION_UNAVAILABLE: + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed."); + } + if (!mIsGlance) { + ErrorView.show(strNoPhone + "."); + } + break; + + case Communications.BLE_QUEUE_FULL: + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: BLE_QUEUE_FULL, API calls too rapid."); + } + if (!mIsGlance) { + ErrorView.show(strApiFlood); + } + break; + + case Communications.NETWORK_REQUEST_TIMED_OUT: + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection."); + } + if (!mIsGlance) { + ErrorView.show(strNoResponse); + } + break; + + case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE: + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned."); + } + if (!mIsGlance) { + ErrorView.show(strNoJson); + } + break; + + case 404: + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: 404, page not found. Check Configuration URL setting."); + } + if (!mIsGlance) { + ErrorView.show(strConfigUrlNotFound); + } + break; + + case 200: + var msg = null; + if (data != null) { + msg = data.get("message"); + } + if (msg.equals("API running.")) { + mApiStatus = strAvailable; + } else { + if (!mIsGlance) { + ErrorView.show("API " + mApiStatus + "."); + } + } + WatchUi.requestUpdate(); + break; + + default: + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchApiStatus(): Unhandled HTTP response code = " + responseCode); + } + if (!mIsGlance) { + ErrorView.show(strUnhandledHttpErr + responseCode); + } + } } - function pushHomeAssistantMenuView() as Void{ + (:glance) + function fetchApiStatus() as Void { + var options = { + :method => Communications.HTTP_REQUEST_METHOD_GET, + :headers => { + "Authorization" => "Bearer " + mApiKey + }, + :responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON + }; + Communications.makeWebRequest( + Properties.getValue("api_url") + "/", + null, + options, + method(:onReturnFetchApiStatus) + ); + } + + (:glance) + function getApiStatus() as Lang.String { + return mApiStatus; + } + + (:glance) + function getMenuStatus() as Lang.String { + return mMenuStatus; + } + + function isHomeAssistantMenuLoaded() as Lang.Boolean { + return mHaMenu != null; + } + + function pushHomeAssistantMenuView() as Void { WatchUi.pushView(mHaMenu, new HomeAssistantViewDelegate(true), WatchUi.SLIDE_IMMEDIATE); } @@ -220,13 +378,16 @@ class HomeAssistantApp extends Application.AppBase { mNextItemToUpdate = (mNextItemToUpdate + 1) % itu.size(); } - function getQuitTimer() as QuitTimer{ + function getQuitTimer() as QuitTimer { return mQuitTimer; } (:glance) function getGlanceView() { - return [new HomeAssistantGlanceView()]; + mIsGlance = true; + fetchMenuConfig(); + fetchApiStatus(); + return [new HomeAssistantGlanceView(self)]; } } diff --git a/source/HomeAssistantGlanceView.mc b/source/HomeAssistantGlanceView.mc index 7bc68ee..8e5d9d8 100644 --- a/source/HomeAssistantGlanceView.mc +++ b/source/HomeAssistantGlanceView.mc @@ -24,19 +24,86 @@ using Toybox.Graphics; (:glance) class HomeAssistantGlanceView extends WatchUi.GlanceView { + private static const scLeftMargin = 20; // in pixels + private static const scLeftIndent = 10; // Left Indent "_text:" in pixels + private static const scMidSep = 10; // Middle Separator "text:_text" in pixels + private var mApp as HomeAssistantApp; + private var mTitle as WatchUi.Text or Null; + private var mApiText as WatchUi.Text or Null; + private var mApiStatus as WatchUi.Text or Null; + private var mMenuText as WatchUi.Text or Null; + private var mMenuStatus as WatchUi.Text or Null; - private var mText as Lang.String; - - function initialize() { + function initialize(app as HomeAssistantApp) { GlanceView.initialize(); + mApp = app; + } - mText = WatchUi.loadResource($.Rez.Strings.AppName); + function onLayout(dc as Graphics.Dc) as Void { + var strChecking = WatchUi.loadResource($.Rez.Strings.Checking); + var strGlanceMenu = WatchUi.loadResource($.Rez.Strings.GlanceMenu); + var h = dc.getHeight(); + var tw = dc.getTextWidthInPixels(strGlanceMenu, Graphics.FONT_XTINY); + + mTitle = new WatchUi.Text({ + :text => WatchUi.loadResource($.Rez.Strings.AppName), + :color => Graphics.COLOR_WHITE, + :font => Graphics.FONT_TINY, + :justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER, + :locX => scLeftMargin, + :locY => 1 * h / 6 + }); + + mApiText = new WatchUi.Text({ + :text => "API:", + :color => Graphics.COLOR_WHITE, + :font => Graphics.FONT_XTINY, + :justification => Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER, + :locX => scLeftMargin + scLeftIndent + tw, + :locY => 3 * h / 6 + }); + mApiStatus = new WatchUi.Text({ + :text => strChecking, + :color => Graphics.COLOR_WHITE, + :font => Graphics.FONT_XTINY, + :justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER, + :locX => scLeftMargin + scLeftIndent + scMidSep + tw, + :locY => 3 * h / 6 + }); + mMenuText = new WatchUi.Text({ + :text => strGlanceMenu + ":", + :color => Graphics.COLOR_WHITE, + :font => Graphics.FONT_XTINY, + :justification => Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER, + :locX => scLeftMargin + scLeftIndent + tw, + :locY => 5 * h / 6 + }); + mMenuStatus = new WatchUi.Text({ + :text => strChecking, + :color => Graphics.COLOR_WHITE, + :font => Graphics.FONT_XTINY, + :justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER, + :locX => scLeftMargin + scLeftIndent + scMidSep + tw, + :locY => 5 * h / 6 + }); } function onUpdate(dc) as Void { GlanceView.onUpdate(dc); - - dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK); - dc.drawText(0, dc.getHeight() / 2, Graphics.FONT_TINY, mText, Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER); + if(dc has :setAntiAlias) { + dc.setAntiAlias(true); + } + dc.setColor( + Graphics.COLOR_WHITE, + Graphics.COLOR_BLUE + ); + dc.clear(); + mTitle.draw(dc); + mApiText.draw(dc); + mApiStatus.setText(mApp.getApiStatus()); + mApiStatus.draw(dc); + mMenuText.draw(dc); + mMenuStatus.setText(mApp.getMenuStatus()); + mMenuStatus.draw(dc); } } diff --git a/source/HomeAssistantService.mc b/source/HomeAssistantService.mc index 14fd621..d5a84bd 100644 --- a/source/HomeAssistantService.mc +++ b/source/HomeAssistantService.mc @@ -24,22 +24,18 @@ using Toybox.Graphics; using Toybox.Application.Properties; class HomeAssistantService { - private var mApiKey as Lang.String; - private var strNoPhone as Lang.String; - private var strNoInternet as Lang.String; - private var strNoResponse as Lang.String; - private var strApiFlood as Lang.String; - private var strApiUrlNotFound as Lang.String; - private var strUnhandledHttpErr as Lang.String; + private var strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone); + private var strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet); + private var strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse); + private var strNoJson = WatchUi.loadResource($.Rez.Strings.NoJson); + private var strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood); + private var strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound); + private var strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr); + + private var mApiKey as Lang.String; function initialize() { - strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone); - strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet); - strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse); - strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood); - strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound); - strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr); - mApiKey = Properties.getValue("api_key"); + mApiKey = Properties.getValue("api_key"); } // Callback function after completing the POST request to call a service. @@ -50,54 +46,79 @@ class HomeAssistantService { System.println("HomeAssistantService onReturnCall() Response Code: " + responseCode); System.println("HomeAssistantService onReturnCall() Response Data: " + data); } - if (responseCode == Communications.BLE_HOST_TIMEOUT || responseCode == Communications.BLE_CONNECTION_UNAVAILABLE) { - if (Globals.scDebug) { - System.println("HomeAssistantService onReturnCall() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed."); - } - ErrorView.show(strNoPhone + "."); - } else if (responseCode == Communications.BLE_QUEUE_FULL) { - if (Globals.scDebug) { - System.println("HomeAssistantService onReturnCall() Response Code: BLE_QUEUE_FULL, API calls too rapid."); - } - // Don't need to worry about multiple ErrorViews here as the call is not on a repeat timer. - ErrorView.show(strApiFlood); - } else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) { - if (Globals.scDebug) { - System.println("HomeAssistantService onReturnCall() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection."); - } - ErrorView.show(strNoResponse); - } else if (responseCode == 404) { - if (Globals.scDebug) { - System.println("HomeAssistantService onReturnCall() Response Code: 404, page not found. Check API URL setting."); - } - ErrorView.show(strApiUrlNotFound); - } else if (responseCode == 200) { - if (Globals.scDebug) { - System.println("HomeAssistantService onReturnCall(): Service executed."); - } - var d = data as Lang.Array; - var toast = "Executed"; - for(var i = 0; i < d.size(); i++) { - if ((d[i].get("entity_id") as Lang.String).equals(identifier)) { - toast = (d[i].get("attributes") as Lang.Dictionary).get("friendly_name") as Lang.String; + + switch (responseCode) { + case Communications.BLE_HOST_TIMEOUT: + case Communications.BLE_CONNECTION_UNAVAILABLE: + if (Globals.scDebug) { + System.println("HomeAssistantService onReturnCall() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed."); } - } - if (WatchUi has :showToast) { - WatchUi.showToast(toast, null); - } else { - new Alert({ - :timeout => Globals.scAlertTimeout, - :font => Graphics.FONT_MEDIUM, - :text => toast, - :fgcolor => Graphics.COLOR_WHITE, - :bgcolor => Graphics.COLOR_BLACK - }).pushView(WatchUi.SLIDE_IMMEDIATE); - } - } else { - if (Globals.scDebug) { - System.println("HomeAssistantService onReturnCall(): Unhandled HTTP response code = " + responseCode); - } - ErrorView.show(strUnhandledHttpErr + responseCode ); + ErrorView.show(strNoPhone + "."); + break; + + case Communications.BLE_QUEUE_FULL: + if (Globals.scDebug) { + System.println("HomeAssistantService onReturnCall() Response Code: BLE_QUEUE_FULL, API calls too rapid."); + } + ErrorView.show(strApiFlood); + break; + + case Communications.NETWORK_REQUEST_TIMED_OUT: + if (Globals.scDebug) { + System.println("HomeAssistantService onReturnCall() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection."); + } + ErrorView.show(strNoResponse); + break; + + case Communications.NETWORK_RESPONSE_OUT_OF_MEMORY: + if (Globals.scDebug) { + System.println("HomeAssistantService onReturnCall() Response Code: NETWORK_RESPONSE_OUT_OF_MEMORY, are we going too fast?"); + } + // Ignore and see if we can carry on + break; + case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE: + if (Globals.scDebug) { + System.println("HomeAssistantService onReturnCall() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned."); + } + ErrorView.show(strNoJson); + break; + + case 404: + if (Globals.scDebug) { + System.println("HomeAssistantService onReturnCall() Response Code: 404, page not found. Check API URL setting."); + } + ErrorView.show(strApiUrlNotFound); + break; + + case 200: + if (Globals.scDebug) { + System.println("HomeAssistantService onReturnCall(): Service executed."); + } + var d = data as Lang.Array; + var toast = "Executed"; + for(var i = 0; i < d.size(); i++) { + if ((d[i].get("entity_id") as Lang.String).equals(identifier)) { + toast = (d[i].get("attributes") as Lang.Dictionary).get("friendly_name") as Lang.String; + } + } + if (WatchUi has :showToast) { + WatchUi.showToast(toast, null); + } else { + new Alert({ + :timeout => Globals.scAlertTimeout, + :font => Graphics.FONT_MEDIUM, + :text => toast, + :fgcolor => Graphics.COLOR_WHITE, + :bgcolor => Graphics.COLOR_BLACK + }).pushView(WatchUi.SLIDE_IMMEDIATE); + } + break; + + default: + if (Globals.scDebug) { + System.println("HomeAssistantService onReturnCall(): Unhandled HTTP response code = " + responseCode); + } + ErrorView.show(strUnhandledHttpErr + responseCode); } } diff --git a/source/HomeAssistantToggleMenuItem.mc b/source/HomeAssistantToggleMenuItem.mc index ad648e4..31d31f2 100644 --- a/source/HomeAssistantToggleMenuItem.mc +++ b/source/HomeAssistantToggleMenuItem.mc @@ -25,13 +25,15 @@ using Toybox.Application.Properties; using Toybox.Timer; class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { - private var mApiKey as Lang.String; - private var strNoPhone as Lang.String; - private var strNoInternet as Lang.String; - private var strNoResponse as Lang.String; - private var strApiFlood as Lang.String; - private var strApiUrlNotFound as Lang.String; - private var strUnhandledHttpErr as Lang.String; + private var strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone); + private var strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet); + private var strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse); + private var strNoJson = WatchUi.loadResource($.Rez.Strings.NoJson); + private var strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood); + private var strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound); + private var strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr); + + private var mApiKey as Lang.String; function initialize( label as Lang.String or Lang.Symbol, @@ -46,13 +48,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { :icon as Graphics.BitmapType or WatchUi.Drawable or Lang.Symbol } or Null ) { - strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone); - strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet); - strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse); - strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood); - strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound); - strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr); - mApiKey = Properties.getValue("api_key"); + mApiKey = Properties.getValue("api_key"); WatchUi.ToggleMenuItem.initialize(label, subLabel, identifier, enabled, options); } @@ -75,6 +71,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: " + responseCode); System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Data: " + data); } + // Provide the ability to terminate updating chain of calls for a permanent network error. var keepUpdating = true; switch (responseCode) { @@ -85,29 +82,50 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { } ErrorView.show(strNoPhone + "."); break; + case Communications.BLE_QUEUE_FULL: if (Globals.scDebug) { System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: BLE_QUEUE_FULL, API calls too rapid."); } ErrorView.show(strApiFlood); break; + case Communications.NETWORK_REQUEST_TIMED_OUT: if (Globals.scDebug) { System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection."); } ErrorView.show(strNoResponse); break; + + case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE: + if (Globals.scDebug) { + System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned."); + } + ErrorView.show(strNoJson); + break; + + case Communications.NETWORK_RESPONSE_OUT_OF_MEMORY: + if (Globals.scDebug) { + System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: NETWORK_RESPONSE_OUT_OF_MEMORY, are we going too fast?"); + } + // Pause updates + keepUpdating = false; + var myTimer = new Timer.Timer(); + // Now this feels very "closely coupled" to the application, but it is the most reliable method instead of using a timer. + myTimer.start(getApp().method(:updateNextMenuItem), Globals.scApiBackoff, false); + break; + case 404: var msg = null; if (data != null) { msg = data.get("message"); } if (msg != null) { - // Should be an HTTP 405 according to curl queries + // Should be an HTTP 404 according to curl queries if (Globals.scDebug) { System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: 404. " + mIdentifier + " " + msg); } - ErrorView.show("HTTP 405, " + mIdentifier + ". " + data.get("message")); + ErrorView.show("HTTP 404, " + mIdentifier + ". " + data.get("message")); } else { if (Globals.scDebug) { System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: 404, page not found. Check API URL setting."); @@ -116,6 +134,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { } keepUpdating = false; break; + case 405: if (Globals.scDebug) { System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: 405. " + mIdentifier + " " + data.get("message")); @@ -123,6 +142,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { ErrorView.show("HTTP 405, " + mIdentifier + ". " + data.get("message")); keepUpdating = false; break; + case 200: var state = data.get("state") as Lang.String; if (Globals.scDebug) { @@ -134,6 +154,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { setUiToggle(state); ErrorView.unShow(); break; + default: if (Globals.scDebug) { System.println("HomeAssistantToggleMenuItem onReturnGetState(): Unhandled HTTP response code = " + responseCode); @@ -199,43 +220,63 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: " + responseCode); System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Data: " + data); } - if (responseCode == Communications.BLE_HOST_TIMEOUT || responseCode == Communications.BLE_CONNECTION_UNAVAILABLE) { - if (Globals.scDebug) { - System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed."); - } - ErrorView.show(strNoPhone + "."); - } else if (responseCode == Communications.BLE_QUEUE_FULL) { - if (Globals.scDebug) { - System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: BLE_QUEUE_FULL, API calls too rapid."); - } - ErrorView.show(strApiFlood); - } else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) { - if (Globals.scDebug) { - System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection."); - } - ErrorView.show(strNoResponse); - } else if (responseCode == 404) { - if (Globals.scDebug) { - System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: 404, page not found. Check API URL setting."); - } - ErrorView.show(strApiUrlNotFound); - } else if (responseCode == 200) { - var state; - var d = data as Lang.Array; - for(var i = 0; i < d.size(); i++) { - if ((d[i].get("entity_id") as Lang.String).equals(mIdentifier)) { - state = d[i].get("state") as Lang.String; - if (Globals.scDebug) { - System.println((d[i].get("attributes") as Lang.Dictionary).get("friendly_name") + " State=" + state); - } - setUiToggle(state); + + switch (responseCode) { + case Communications.BLE_HOST_TIMEOUT: + case Communications.BLE_CONNECTION_UNAVAILABLE: + if (Globals.scDebug) { + System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed."); } - } - } else { - if (Globals.scDebug) { - System.println("HomeAssistantToggleMenuItem onReturnSetState(): Unhandled HTTP response code = " + responseCode); - } - ErrorView.show(strUnhandledHttpErr + responseCode ); + ErrorView.show(strNoPhone + "."); + break; + + case Communications.BLE_QUEUE_FULL: + if (Globals.scDebug) { + System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: BLE_QUEUE_FULL, API calls too rapid."); + } + ErrorView.show(strApiFlood); + break; + + case Communications.NETWORK_REQUEST_TIMED_OUT: + if (Globals.scDebug) { + System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection."); + } + ErrorView.show(strNoResponse); + break; + + case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE: + if (Globals.scDebug) { + System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned."); + } + ErrorView.show(strNoJson); + break; + + case 404: + if (Globals.scDebug) { + System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: 404, page not found. Check API URL setting."); + } + ErrorView.show(strApiUrlNotFound); + break; + + case 200: + var state; + var d = data as Lang.Array; + for(var i = 0; i < d.size(); i++) { + if ((d[i].get("entity_id") as Lang.String).equals(mIdentifier)) { + state = d[i].get("state") as Lang.String; + if (Globals.scDebug) { + System.println((d[i].get("attributes") as Lang.Dictionary).get("friendly_name") + " State=" + state); + } + setUiToggle(state); + } + } + break; + + default: + if (Globals.scDebug) { + System.println("HomeAssistantToggleMenuItem onReturnSetState(): Unhandled HTTP response code = " + responseCode); + } + ErrorView.show(strUnhandledHttpErr + responseCode); } } diff --git a/source/HomeAssistantView.mc b/source/HomeAssistantView.mc index 9fb8e3a..747adcb 100644 --- a/source/HomeAssistantView.mc +++ b/source/HomeAssistantView.mc @@ -103,20 +103,21 @@ class HomeAssistantView extends WatchUi.Menu2 { // Reference: https://developer.garmin.com/connect-iq/core-topics/input-handling/ // class HomeAssistantViewDelegate extends WatchUi.Menu2InputDelegate { - - private var mIsRootMenuView = false; + private var mIsRootMenuView as Lang.Boolean = false; + private var mTimer as QuitTimer; function initialize(isRootMenuView as Lang.Boolean) { Menu2InputDelegate.initialize(); mIsRootMenuView = isRootMenuView; + mTimer = getApp().getQuitTimer(); } function onBack() { - getApp().getQuitTimer().reset(); + mTimer.reset(); - if (mIsRootMenuView){ + if (mIsRootMenuView) { // If its started from glance or as an activity, directly exit the widget/app - // (on widgets without glance, this exit() won`t do anything, + // (on widgets without glance, this exit() won't do anything, // so the base view will be shown instead, through the popView below this "if body") System.exit(); } @@ -126,16 +127,16 @@ class HomeAssistantViewDelegate extends WatchUi.Menu2InputDelegate { // Only for CheckboxMenu function onDone() { - getApp().getQuitTimer().reset(); + mTimer.reset(); } // Only for CustomMenu function onFooter() { - getApp().getQuitTimer().reset(); + mTimer.reset(); } function onSelect(item as WatchUi.MenuItem) as Void { - getApp().getQuitTimer().reset(); + mTimer.reset(); if (item instanceof HomeAssistantToggleMenuItem) { var haToggleItem = item as HomeAssistantToggleMenuItem; if (Globals.scDebug) { @@ -175,7 +176,7 @@ class HomeAssistantViewDelegate extends WatchUi.Menu2InputDelegate { // Only for CustomMenu function onTitle() { - getApp().getQuitTimer().reset(); + mTimer.reset(); } } diff --git a/source/RootView.mc b/source/RootView.mc index ff20a42..102028f 100644 --- a/source/RootView.mc +++ b/source/RootView.mc @@ -25,76 +25,99 @@ using Toybox.WatchUi; class RootView extends ScalableView { // ATTENTION when the app is running as a "widget" (that means, it runs on devices - // without glance view support), the input events in this view are limited, as + // without glance view support), the input events in this view are limited, as // described under "Base View and the Widget Carousel" on: - // + // // https://developer.garmin.com/connect-iq/connect-iq-basics/app-types/ - // + // // Also the view type of the base view is limited too (for example "WatchUi.Menu2" // is not possible)). - // - // Also System.exit() is not working/do nothing when running as a widget: A widget will be + // + // Also System.exit() is not working/do nothing when running as a widget: A widget will be // terminated automatically by OS after some time or can be quit manually, when on the base // view a swipe to left / "back button" press is done. - private var mApp as HomeAssistantApp; - private var strFetchingMenuConfig as Lang.String; - private var strExit as Lang.String; - private var mTextAreaExit as WatchUi.TextArea or Null; - private var mTextAreaFetching as WatchUi.TextArea or Null; + private static const scMidSep = 10; // Middle Separator "text:_text" in pixels + private var mApp as HomeAssistantApp; + private var mTitle as WatchUi.Text or Null; + private var mApiText as WatchUi.Text or Null; + private var mApiStatus as WatchUi.Text or Null; + private var mMenuText as WatchUi.Text or Null; + private var mMenuStatus as WatchUi.Text or Null; function initialize(app as HomeAssistantApp) { ScalableView.initialize(); - mApp=app; - - strFetchingMenuConfig = WatchUi.loadResource($.Rez.Strings.FetchingMenuConfig); - - if (System.getDeviceSettings().isTouchScreen){ - strExit = WatchUi.loadResource($.Rez.Strings.ExitViewTouch); - } else { - strExit = WatchUi.loadResource($.Rez.Strings.ExitViewButtons); - } + mApp = app; } function onLayout(dc as Graphics.Dc) as Void { - var w = dc.getWidth(); - var h = dc.getHeight(); + var strChecking = WatchUi.loadResource($.Rez.Strings.Checking); + var w = dc.getWidth(); - mTextAreaExit = new WatchUi.TextArea({ - :text => strExit, + mTitle = new WatchUi.Text({ + :text => WatchUi.loadResource($.Rez.Strings.AppName), :color => Graphics.COLOR_WHITE, - :font => Graphics.FONT_XTINY, + :font => Graphics.FONT_TINY, :justification => Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER, - :locX => 0, - :locY => 83, - :width => w, - :height => h - 166 + :locX => w/2, + :locY => pixelsForScreen(30.0) }); - mTextAreaFetching = new WatchUi.TextArea({ - :text => strFetchingMenuConfig, + mApiText = new WatchUi.Text({ + :text => "API:", :color => Graphics.COLOR_WHITE, :font => Graphics.FONT_XTINY, - :justification => Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER, - :locX => 0, - :locY => 83, - :width => w, - :height => h - 166 + :justification => Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER, + :locX => w/2 - scMidSep/2, + :locY => pixelsForScreen(50.0) }); + mApiStatus = new WatchUi.Text({ + :text => strChecking, + :color => Graphics.COLOR_WHITE, + :font => Graphics.FONT_XTINY, + :justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER, + :locX => w/2 + scMidSep/2, + :locY => pixelsForScreen(50.0) + }); + mMenuText = new WatchUi.Text({ + :text => WatchUi.loadResource($.Rez.Strings.GlanceMenu) + ":", + :color => Graphics.COLOR_WHITE, + :font => Graphics.FONT_XTINY, + :justification => Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER, + :locX => w/2 - scMidSep/2, + :locY => pixelsForScreen(70.0) + }); + mMenuStatus = new WatchUi.Text({ + :text => strChecking, + :color => Graphics.COLOR_WHITE, + :font => Graphics.FONT_XTINY, + :justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER, + :locX => w/2 + scMidSep/2, + :locY => pixelsForScreen(70.0) + }); + + + } function onUpdate(dc as Graphics.Dc) as Void { - if(dc has :setAntiAlias) { + if (dc has :setAntiAlias) { dc.setAntiAlias(true); } dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK); dc.clear(); - - if(mApp.homeAssistantMenuIsLoaded()) { - mTextAreaExit.draw(dc); - } else { - mTextAreaFetching.draw(dc); - } + // Initialise this locally, otherwise the venu1 device runs out of memory when stored at class level. + var launcherIcon = Application.loadResource(Rez.Drawables.LauncherIcon); + var w = dc.getWidth(); + var h = dc.getHeight(); + dc.drawBitmap(w/2 - launcherIcon.getWidth()/2, h/8 - launcherIcon.getHeight()/2, launcherIcon); + mTitle.draw(dc); + mApiText.draw(dc); + mApiStatus.setText(mApp.getApiStatus()); + mApiStatus.draw(dc); + mMenuText.draw(dc); + mMenuStatus.setText(mApp.getMenuStatus()); + mMenuStatus.draw(dc); } } @@ -102,9 +125,9 @@ class RootViewDelegate extends WatchUi.BehaviorDelegate { var mApp as HomeAssistantApp; - function initialize(app as HomeAssistantApp ) { + function initialize(app as HomeAssistantApp) { BehaviorDelegate.initialize(); - mApp=app; + mApp = app; } function onTap(evt as WatchUi.ClickEvent) as Lang.Boolean { @@ -115,12 +138,12 @@ class RootViewDelegate extends WatchUi.BehaviorDelegate { return backToMainMenu(); } - function onMenu() as Lang.Boolean{ + function onMenu() as Lang.Boolean { return backToMainMenu(); } - private function backToMainMenu() as Lang.Boolean{ - if(mApp.homeAssistantMenuIsLoaded()){ + private function backToMainMenu() as Lang.Boolean { + if (mApp.isHomeAssistantMenuLoaded()) { mApp.pushHomeAssistantMenuView(); return true; } diff --git a/source/ScalableView.mc b/source/ScalableView.mc index febf84d..5d1a4bf 100644 --- a/source/ScalableView.mc +++ b/source/ScalableView.mc @@ -27,6 +27,7 @@ class ScalableView extends WatchUi.View { function initialize() { View.initialize(); + mScreenWidth = System.getDeviceSettings().screenWidth; } // Convert a fraction expressed as a percentage (%) to a number of pixels for the @@ -40,9 +41,6 @@ class ScalableView extends WatchUi.View { // height > width. // function pixelsForScreen(pc as Lang.Float) as Lang.Number { - if (mScreenWidth == null) { - mScreenWidth = System.getDeviceSettings().screenWidth; - } return Math.round(pc * mScreenWidth) / 100; } }