diff --git a/.github/workflows/translate.yml b/.github/workflows/translate.yml new file mode 100644 index 0000000..a6cbe52 --- /dev/null +++ b/.github/workflows/translate.yml @@ -0,0 +1,31 @@ +name: Translate +on: + push: + paths: + - "resources/strings/strings.xml" + - "resources-*/strings/corrections.xml" + +jobs: + translate: + runs-on: ubuntu-latest + + permissions: + # Give the default GITHUB_TOKEN write permission to commit and push the + # added or changed files to the repository. + contents: write + + steps: + - uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v4.7.1 + + - run: | + pip install beautifulsoup4 + pip install deep-translate + pip install xml + + - run: python translate.py + + # Commit all changed files back to the repository + - uses: stefanzweifel/git-auto-commit-action@v5 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9c38135 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "cSpell.words": [ + "usbs", + "Venu" + ] +} \ No newline at end of file diff --git a/HomeAssistant.code-workspace b/HomeAssistant.code-workspace index 1b7e21b..876a149 100644 --- a/HomeAssistant.code-workspace +++ b/HomeAssistant.code-workspace @@ -2,10 +2,6 @@ "folders": [ { "path": "." - }, - { - "name": "abc", - "path": "../blah/abc" } ], "settings": {} diff --git a/README.md b/README.md index d388441..68476f6 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,9 @@ A Garmin application to provide a "dashboard" to control your devices via [Home Assistant](https://www.home-assistant.io/). The application will never be as fully fledged as a Home Assistant dashboard, so it is designed to be good enough for the simple and essential things. Those things that can be activated via an on/off toggle or a tap. That should cover lights, switches, and anything requiring a single press such as an automation. For anything more complicated, e.g. thermostat, it would always be quicker and simpler to reach for your phone or tablet... or the device's own remote control! -The application is designed around a simple scrollable menu where menu items have been extended to interface with the [Home Assistant API](https://developers.home-assistant.io/docs/api/rest/), e.g. to get the status of switches or lights for display on the toggle menu item. It is possible to nest menus, so there is a menu item to open a sub-menu. This can be -arbitrarily deep and nested in the format of a tree of items, although you need to consider if reaching for your phone becomes quicker to select the device what you want to control. +The application is designed around a simple scrollable menu where menu items have been extended to interface with the [Home Assistant API](https://developers.home-assistant.io/docs/api/rest/), e.g. to get the status of switches or lights for display on the toggle menu item. It is possible to nest menus, so there is a menu item to open a sub-menu. This can be arbitrarily deep and nested in the format of a tree of items, although you need to consider if reaching for your phone becomes quicker to select the device what you want to control. -It is important to note that your homeassistant 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 or you can pay for homeassistant cloud). +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/)). ## Application Installation @@ -15,7 +14,7 @@ Head over to the [GarminHomeAssistant](https://apps.garmin.com/en-US/apps/61c91d ## Dashboard Definition -Setup for this menu is more complicated than the Connect IQ settings menu really allows you to specify. In order to make the dashboard easily configurable and easy to change, we have provided an external mechanism for specifying the menu layout, a JSON file you write, retrieved from a URL you specify. JSON was chosen over YAML because Garmin can parse JSON HTTP GET responses into its own internal dictionary, it cannot parse YAML, hence a choice of one really. We recommend you take advantage of [Home Assistant's own web server](https://www.home-assistant.io/integrations/http/#hosting-files) to provide the JSON definition. The advantage here are: +Setup for this menu is more complicated than the Connect IQ settings menu really allows you to specify. In order to make the dashboard easily configurable and easy to change, we have provided an external mechanism for specifying the menu layout, a JSON file you write, retrieved from a URL you specify. JSON was chosen over YAML because Garmin can parse JSON HTTP GET responses into its own internal dictionary, it cannot parse YAML, hence a choice of one really. Note that JSON and YAML are essentially a 1:1 format mapping except JSON does not have comments. We recommend you take advantage of [Home Assistant's own web server](https://www.home-assistant.io/integrations/http/#hosting-files) to provide the JSON definition. The advantage here are: 1. the file is as public as you make your Home Assistant, 2. the file is editable within Home Assistant via "Studio Code Server", and @@ -35,7 +34,8 @@ Example schema as shown in the images: { "entity": "script.food_on_table", "name": "Food is Ready!", - "type": "tap" + "type": "tap", + "service" : "script.turn_on" }, { "entity": "light.bedside_light_switch", @@ -76,9 +76,21 @@ Example schema as shown in the images: "type": "toggle" }, { - "entity": "switch.crnr_tbl_usbs", - "name": "Corner Table USBs", + "entity": "automation.garage_door_check", + "name": "Garage Door Check", "type": "toggle" + }, + { + "entity": "automation.turn_off_usb_chargers", + "name": "Turn off USBs", + "type": "tap", + "service" : "automation.trigger" + }, + { + "entity": "scene.tv_light", + "name": "TV Lights Scene", + "type": "tap", + "service": "scene.turn_on" } ] } @@ -86,6 +98,28 @@ Example schema as shown in the images: NB. Entity names are not real in case anyone's a hacker. +The example above illustrates how to configure: + +* Light or switch toggles +* Automation enable toggles +* Script invocation (tap) +* Service invocation, e.g. Scene setting, (tap) +* A sub-menu to open (tap) + +The example JSON shows an example usage of each of these Home Assistance entity types. Presently, an automation is the only one that can be either a 'tap' or a 'toggle'. + +| HA Type | Tap | Toggle | +|------------|:---:|:------:| +| Switch | N | Y | +| Light | N | Y | +| Automation | Y | Y | +| Script | Y | N | +| Scene | Y | N | + +NB. All 'tap' items must specify a 'service' tag. + +Possible future extensions might include specifying the alternative texts to use instead of "On" and "Off", e.g. "Locked" and "Unlocked" (but wouldn't having locks operated from your watch be a security concern ;-)) + The [schema](https://raw.githubusercontent.com/house-of-abbey/GarminHomeAssistant/main/config.schema.json) is checked by using a URL directly back to this GitHub source repository, so you do not need to install that file. You can just copy & paste your entity names from the YAML configuration files used to configure Home Assistant. With a submenu, there's a difference between "title" and "name". The "name" goes on the menu item, and the "title" at the head of the submenu. If your dashboard definition fails to meet the schema, the application will simply drop items with the wrong field names without warning. ## API Key Creation @@ -101,7 +135,7 @@ Having created that token, before you dismiss the dialogue box with the value yo 1. Paste your API key you've just created into the top field. -2. Add the URL for your Home Assistant API, e.g. `https:///api/`. +2. Add the URL for your Home Assistant API, e.g. `https:///api`. (No trailing slash `/`` character as one gets appended when creating the URL and you do not want two.) 3. Add the URL of your JSON file, e.g. `https:///local/garmin/.json`. You should now have a working application on your watch and be able to operate your Home Assistant devices for as long as your watch is within Bluetooth range of your phone. @@ -116,8 +150,22 @@ The application will display a 'toast' showing Home Assistant's friendly name of ## External Device Changes -Home Assistant will inevitably change the state of devices you are also controlling via your Garmin. The Garmin application does not maintain a web socket to listen for changes. Instead it must poll the Home Assistant API with your key. Therefore the application is not responsive to changes, instead there will be a delay of about 5 seconds to pick up state changes. The thinking here is that the watch application will only ever be open briefly not persistently, so the delay in picking up state changes won't be observed often for any race condition between two controllers. +Home Assistant will inevitably change the state of devices you are also controlling via your Garmin. The Garmin application does not maintain a web socket to listen for changes. Instead it must poll the Home Assistant API with your key. Therefore the application is not that responsive to changes. Instead there will be a delay of multiples of 100 ms per item whose status needs to be checked and amended. + +The per toggle item delay is caused by a queue of responses to web requests filling up a queue and giving a [Communications](https://developer.garmin.com/connect-iq/api-docs/Toybox/Communications.html).`BLE_QUEUE_FULL` response code. For a Venu 2 Garmin watch an API call delay of 600 ms was found to be sustainable (500 ms was still too fast). The code now chains a sequence of updates, so as one finishes it invokes the next item's update. The more items requiring a status update that you pack into your dashboard, the slower each individual item will be updated! + +The thinking here is that the watch application will only ever be open briefly not persistently, so the delay in picking up state changes won't be observed often for any race condition between two controllers. + +As a consequence of this update mechanism, if you request changes too quickly you will be notified that your device cannot keep up with the rate of API responses and you will have to dismiss the error in order to continue. The is a _feature not a bug_! ## Changes to the (JSON) Dashboard Definition When you change the JSON file defining your dashboard, you must exit the application and the reopen it. It only takes a matter of a few seconds to pick up the new definition, but it is not automatic. + +## Version History + +| Version | Comment | +|:-------:|---------| +| 1.0 | Initial release for 26 devices. | +| 1.1 | Updated for 54 more devices, 80 in total. Scene support. Added vibrate acknowledgement for tap-based menu items. Falls back to a custom visual confirmation in the absence of 'toast' and vibrate support. Bug fix for large menus needing status updates. | +| 1.2 | Do not crash on zero items to update. Report unreachable URLs. Verify API URL does not have a trailing slash '/'. Increased HTTP response diagnosis. Reduced minimum API Level required from 3.3.0 to 3.1.0 to allow more device "part numbers" to be satisfied. | diff --git a/config.schema.json b/config.schema.json index 99e59b6..1edd1e9 100644 --- a/config.schema.json +++ b/config.schema.json @@ -26,7 +26,7 @@ "type": { "const": "tap" }, "service": { "$ref": "#/$defs/entity" } }, - "required": ["entity", "name", "type"], + "required": ["entity", "name", "type", "service"], "additionalProperties": false }, "menu": { diff --git a/manifest.xml b/manifest.xml index 1c5790f..3f2a12b 100644 --- a/manifest.xml +++ b/manifest.xml @@ -21,7 +21,7 @@ Use "Monkey C: Edit Application" from the Visual Studio Code command palette to update the application attributes. --> - + @@ -124,6 +124,7 @@ + diff --git a/monkey.jungle b/monkey.jungle index cf3cf5b..cd12c66 100644 --- a/monkey.jungle +++ b/monkey.jungle @@ -18,8 +18,9 @@ project.manifest = manifest.xml -# Device Reference -# https://developer.garmin.com/connect-iq/reference-guides/devices-reference/ +# Device References +# * https://developer.garmin.com/connect-iq/compatible-devices/ +# * https://developer.garmin.com/connect-iq/reference-guides/devices-reference/ # # Widget launcher icon, multiple resolutions # https://forums.garmin.com/developer/connect-iq/f/discussion/255433/widget-launcher-icon-multiple-resolutions/1563305 @@ -121,7 +122,8 @@ instinct2.resourcePath = $(instinct2.resourcePath);resources-launcher-62-62;reso instinct2s.resourcePath = $(instinct2s.resourcePath);resources-launcher-54-54;resources-icons-18 # Screen Size 176x176 launcher icon size 62x62 instinct2x.resourcePath = $(instinct2x.resourcePath);resources-launcher-62-62;resources-icons-21 -instinctcrossover.resourcePath = $(instinctcrossover.resourcePath);resources-launcher-62-62;resources-icons-21 +# Screen Size 176x176 launcher icon size 26x26 +instinctcrossover.resourcePath = $(instinctcrossover.resourcePath);resources-launcher-26-26;resources-icons-21 # Screen Size 218x218 launcher icon size 30x30 legacyherocaptainmarvel.resourcePath = $(legacyherocaptainmarvel.resourcePath);resources-launcher-30-30;resources-icons-26 # Screen Size 260x260 launcher icon size 35x35 diff --git a/resources-ara/strings/strings.xml b/resources-ara/strings/strings.xml index c83e9a6..9c85190 100644 --- a/resources-ara/strings/strings.xml +++ b/resources-ara/strings/strings.xml @@ -29,5 +29,9 @@ لا يوجد مفتاح API في إعدادات التطبيق لا يوجد عنوان URL لواجهة برمجة التطبيقات في إعدادات التطبيق لا يوجد عنوان URL للتكوين في إعدادات التطبيق - مكالمات API سريعة جدًا. يرجى الإبلاغ عن هذا الخطأ مع تفاصيل الجهاز. + مكالمات API سريعة جدًا. يرجى إبطاء طلباتك. + لم يتم العثور على عنوان URL. خطأ محتمل في عنوان URL لواجهة برمجة التطبيقات في الإعدادات. + لم يتم العثور على عنوان URL. خطأ محتمل في عنوان URL للتكوين في الإعدادات. + قام طلب HTTP بإرجاع رمز الخطأ = + يجب ألا يحتوي عنوان URL لواجهة برمجة التطبيقات على شرطة مائلة لاحقة '/' \ No newline at end of file diff --git a/resources-bul/strings/strings.xml b/resources-bul/strings/strings.xml index 5d18ac1..cf2918f 100644 --- a/resources-bul/strings/strings.xml +++ b/resources-bul/strings/strings.xml @@ -29,5 +29,9 @@ Няма API ключ в настройките на приложението Няма URL адрес на API в настройките на приложението Няма конфигурационен URL адрес в настройките на приложението - Извикванията на API са твърде бързи. Моля, докладвайте тази грешка с подробности за устройството. + Извикванията на API са твърде бързи. Моля, забавете вашите заявки. + URL не е намерен. Потенциална грешка в URL адреса на API в настройките. + URL не е намерен. Потенциална грешка в URL адреса на конфигурацията в настройките. + HTTP заявката върна код на грешка = + URL адресът на API не трябва да има наклонена черта '/' в края \ No newline at end of file diff --git a/resources-ces/strings/strings.xml b/resources-ces/strings/strings.xml index 9681dc4..56f885b 100644 --- a/resources-ces/strings/strings.xml +++ b/resources-ces/strings/strings.xml @@ -29,5 +29,9 @@ 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. Nahlaste tuto chybu s podrobnostmi o zařízení. + 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í. + Požadavek HTTP vrátil kód chyby = + Adresa URL rozhraní API nesmí mít koncové lomítko „/“ \ No newline at end of file diff --git a/resources-dan/strings/strings.xml b/resources-dan/strings/strings.xml index 47bcf83..afedb13 100644 --- a/resources-dan/strings/strings.xml +++ b/resources-dan/strings/strings.xml @@ -25,9 +25,13 @@ Tryk på Menu Ingen internetforbindelse - Fejl ved menuhentning + Menuhentningsfejl Ingen API-nøgle i applikationsindstillingerne Ingen API-URL i applikationsindstillingerne Ingen konfigurations-URL i applikationsindstillingerne - API-kald for hurtigt. Rapportér venligst denne fejl med enhedsoplysninger. + 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. + HTTP-anmodning returnerede fejlkode = + API URL må ikke have en efterfølgende skråstreg '/' \ No newline at end of file diff --git a/resources-deu/strings/strings.xml b/resources-deu/strings/strings.xml index 4c06dec..df2dfd4 100644 --- a/resources-deu/strings/strings.xml +++ b/resources-deu/strings/strings.xml @@ -29,5 +29,9 @@ Kein API-Schlüssel in den Anwendungseinstellungen Keine API-URL in den Anwendungseinstellungen Keine Konfigurations-URL in den Anwendungseinstellungen - API-Aufrufe zu schnell. Bitte melden Sie diesen Fehler mit Gerätedetails. + 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 hat den Fehlercode = zurückgegeben + Die API-URL darf keinen abschließenden Schrägstrich „/“ enthalten. \ No newline at end of file diff --git a/resources-dut/strings/strings.xml b/resources-dut/strings/strings.xml index f61bc44..9447439 100644 --- a/resources-dut/strings/strings.xml +++ b/resources-dut/strings/strings.xml @@ -29,5 +29,9 @@ 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. Rapporteer deze fout met apparaatgegevens. + 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. + HTTP-verzoek retourneerde foutcode = + API-URL mag geen afsluitende slash '/' bevatten \ No newline at end of file diff --git a/resources-est/strings/strings.xml b/resources-est/strings/strings.xml index e0c1c98..9135982 100644 --- a/resources-est/strings/strings.xml +++ b/resources-est/strings/strings.xml @@ -29,5 +29,9 @@ Rakenduse seadetes pole API-võtit Rakenduse seadetes pole API URL-i Rakenduse seadetes pole konfiguratsiooni URL-i - API-kutsed liiga kiired. Teatage sellest veast koos seadme üksikasjadega. + 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äring tagastas veakoodi = + API URL-i lõpus ei tohi olla kaldkriipsu „/” \ No newline at end of file diff --git a/resources-fin/strings/strings.xml b/resources-fin/strings/strings.xml index 9a70bdd..b6c91eb 100644 --- a/resources-fin/strings/strings.xml +++ b/resources-fin/strings/strings.xml @@ -29,5 +29,9 @@ Sovellusasetuksissa ei ole API-avainta Sovellusasetuksissa ei ole API URL-osoitetta Sovelluksen asetuksissa ei ole konfigurointi-URL-osoitetta - API-kutsut liian nopeita. Ilmoita tästä virheestä laitteen tiedoilla. + 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-pyyntö palautti virhekoodin = + API-URL-osoitteessa ei saa olla perässä olevaa kauttaviivaa '/' \ No newline at end of file diff --git a/resources-fre/strings/strings.xml b/resources-fre/strings/strings.xml index e92666f..76ffa4e 100644 --- a/resources-fre/strings/strings.xml +++ b/resources-fre/strings/strings.xml @@ -30,4 +30,8 @@ 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. + La requête HTTP a renvoyé un code d'erreur = + L'URL de l'API ne doit pas comporter de barre oblique finale '/' diff --git a/resources-gre/strings/strings.xml b/resources-gre/strings/strings.xml index e058e69..98528b0 100644 --- a/resources-gre/strings/strings.xml +++ b/resources-gre/strings/strings.xml @@ -29,5 +29,9 @@ Δεν υπάρχει κλειδί API στις ρυθμίσεις της εφαρμογής Δεν υπάρχει URL API στις ρυθμίσεις της εφαρμογής Δεν υπάρχει διεύθυνση URL διαμόρφωσης στις ρυθμίσεις της εφαρμογής - Κλήσεις API πολύ γρήγορες. Αναφέρετε αυτό το σφάλμα με τα στοιχεία της συσκευής. + Κλήσεις API πολύ γρήγορες. Παρακαλώ επιβραδύνετε τα αιτήματά σας. + Η διεύθυνση URL δεν βρέθηκε. Πιθανό σφάλμα διεύθυνσης URL API στις ρυθμίσεις. + Η διεύθυνση URL δεν βρέθηκε. Πιθανό σφάλμα διεύθυνσης URL διαμόρφωσης στις ρυθμίσεις. + Το αίτημα HTTP επέστρεψε κωδικό σφάλματος = + Η διεύθυνση URL του API δεν πρέπει να έχει τελική κάθετο "/" \ No newline at end of file diff --git a/resources-heb/strings/strings.xml b/resources-heb/strings/strings.xml index fce9dd0..bcbeaf7 100644 --- a/resources-heb/strings/strings.xml +++ b/resources-heb/strings/strings.xml @@ -29,5 +29,9 @@ אין מפתח API בהגדרות האפליקציה אין כתובת API בהגדרות האפליקציה אין כתובת אתר תצורה בהגדרות האפליקציה - קריאות API מהירות מדי. אנא דווח על שגיאה זו עם פרטי המכשיר. + קריאות API מהירות מדי. נא להאט את הבקשות שלך. + כתובת האתר לא נמצאה. שגיאה פוטנציאלית של כתובת ה-API בהגדרות. + כתובת האתר לא נמצאה. שגיאת כתובת אתר פוטנציאלית של תצורה בהגדרות. + בקשת HTTP החזירה קוד שגיאה = + כתובת ה-API לא חייבת לכלול לוכסן אחורי '/' \ No newline at end of file diff --git a/resources-hrv/strings/strings.xml b/resources-hrv/strings/strings.xml index ec410fe..2ce08f4 100644 --- a/resources-hrv/strings/strings.xml +++ b/resources-hrv/strings/strings.xml @@ -29,5 +29,9 @@ 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. Prijavite ovu pogrešku s pojedinostima o uređaju. + 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 vratio je kod greške = + API URL ne smije imati kosu crtu na kraju '/' \ No newline at end of file diff --git a/resources-hun/strings/strings.xml b/resources-hun/strings/strings.xml index b0f0330..efe2c4b 100644 --- a/resources-hun/strings/strings.xml +++ b/resources-hun/strings/strings.xml @@ -29,5 +29,9 @@ 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, jelentse ezt a hibát az eszköz részleteivel. + 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és = hibakódot adott vissza + Az API URL-ben nem lehet perjel a „/” \ No newline at end of file diff --git a/resources-ind/strings/strings.xml b/resources-ind/strings/strings.xml index 3002087..c362590 100644 --- a/resources-ind/strings/strings.xml +++ b/resources-ind/strings/strings.xml @@ -29,5 +29,9 @@ Tidak ada kunci API di pengaturan aplikasi Tidak ada URL API di pengaturan aplikasi Tidak ada URL konfigurasi di pengaturan aplikasi - Panggilan API terlalu cepat. Silakan laporkan kesalahan ini dengan detail perangkat. + 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. + Permintaan HTTP mengembalikan kode kesalahan = + URL API tidak boleh memiliki garis miring '/' \ No newline at end of file diff --git a/resources-ita/strings/strings.xml b/resources-ita/strings/strings.xml index 4784cc3..0bdbc51 100644 --- a/resources-ita/strings/strings.xml +++ b/resources-ita/strings/strings.xml @@ -29,5 +29,9 @@ 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. Segnala questo errore con i dettagli del dispositivo. + 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. + La richiesta HTTP ha restituito il codice di errore = + L'URL dell'API non deve avere una barra finale "/" \ No newline at end of file diff --git a/resources-jpn/strings/strings.xml b/resources-jpn/strings/strings.xml index f14e825..d6bf394 100644 --- a/resources-jpn/strings/strings.xml +++ b/resources-jpn/strings/strings.xml @@ -29,5 +29,9 @@ アプリケーション設定に API キーがありません アプリケーション設定に API URL がありません アプリケーション設定に構成 URL がありません - API 呼び出しが速すぎます。このエラーをデバイスの詳細とともに報告してください。 + API 呼び出しが速すぎます。リクエストは遅くしてください。 + URLが見つかりません。設定における API URL エラーの可能性があります。 + URLが見つかりません。設定内の構成 URL エラーの可能性があります。 + HTTP リクエストがエラー コードを返しました = + API URL の末尾にスラッシュ「/」を含めることはできません \ No newline at end of file diff --git a/resources-kor/strings/strings.xml b/resources-kor/strings/strings.xml index 57f0304..4b6bb46 100644 --- a/resources-kor/strings/strings.xml +++ b/resources-kor/strings/strings.xml @@ -29,5 +29,9 @@ 애플리케이션 설정에 API 키가 없습니다. 애플리케이션 설정에 API URL이 없습니다. 애플리케이션 설정에 구성 URL이 없습니다. - API 호출이 너무 빠릅니다. 기기 세부정보와 함께 이 오류를 신고해 주세요. + API 호출이 너무 빠릅니다. 요청 속도를 늦추시기 바랍니다. + URL을 찾을 수 없습니다. 설정에 잠재적인 API URL 오류가 있습니다. + URL을 찾을 수 없습니다. 설정에 잠재적인 구성 URL 오류가 있습니다. + HTTP 요청이 오류 코드를 반환했습니다 = + API URL에는 후행 슬래시 '/'가 있어서는 안 됩니다. \ No newline at end of file diff --git a/resources-launcher-25-25 - DELETE/drawables.xml b/resources-launcher-26-26/drawables.xml similarity index 100% rename from resources-launcher-25-25 - DELETE/drawables.xml rename to resources-launcher-26-26/drawables.xml diff --git a/resources-launcher-25-25 - DELETE/launcher.png b/resources-launcher-26-26/launcher.png similarity index 68% rename from resources-launcher-25-25 - DELETE/launcher.png rename to resources-launcher-26-26/launcher.png index 7509b0b..c82ef3a 100644 Binary files a/resources-launcher-25-25 - DELETE/launcher.png and b/resources-launcher-26-26/launcher.png differ diff --git a/resources-lav/strings/strings.xml b/resources-lav/strings/strings.xml index 9fb0d95..6b3b24b 100644 --- a/resources-lav/strings/strings.xml +++ b/resources-lav/strings/strings.xml @@ -29,5 +29,9 @@ 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, ziņojiet par šo kļūdu, norādot informāciju par ierīci. + 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. + HTTP pieprasījums atgrieza kļūdas kodu = + API URL beigās nedrīkst būt slīpsvītra “/” \ No newline at end of file diff --git a/resources-lit/strings/strings.xml b/resources-lit/strings/strings.xml index 2b67606..98d316b 100644 --- a/resources-lit/strings/strings.xml +++ b/resources-lit/strings/strings.xml @@ -29,5 +29,9 @@ Programos nustatymuose nėra API rakto Programos nustatymuose nėra API URL Programos nustatymuose nėra konfigūracijos URL - API skambučiai per greiti. Praneškite apie šią klaidą pateikdami išsamią įrenginio informaciją. + 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. + HTTP užklausa grąžino klaidos kodą = + API URL pabaigoje negali būti pasvirojo brūkšnio „/“ \ No newline at end of file diff --git a/resources-nob/strings/strings.xml b/resources-nob/strings/strings.xml index e8cf47f..93235d4 100644 --- a/resources-nob/strings/strings.xml +++ b/resources-nob/strings/strings.xml @@ -29,5 +29,9 @@ Ingen API-nøkkel i applikasjonsinnstillingene Ingen API-URL i applikasjonsinnstillingene Ingen konfigurasjons-URL i applikasjonsinnstillingene - API-kall for raske. Rapporter denne feilen med enhetsdetaljer. + 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. + HTTP-forespørsel returnerte feilkode = + API URL må ikke ha en etterfølgende skråstrek '/' \ No newline at end of file diff --git a/resources-pol/strings/strings.xml b/resources-pol/strings/strings.xml index c229b79..5d72ce2 100644 --- a/resources-pol/strings/strings.xml +++ b/resources-pol/strings/strings.xml @@ -29,5 +29,9 @@ 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. Zgłoś ten błąd, podając szczegóły urządzenia. + 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. + Żądanie HTTP zwróciło kod błędu = + Adres URL interfejsu API nie może zawierać końcowego ukośnika „/” \ No newline at end of file diff --git a/resources-por/strings/strings.xml b/resources-por/strings/strings.xml index 13f5f8d..76e8186 100644 --- a/resources-por/strings/strings.xml +++ b/resources-por/strings/strings.xml @@ -29,5 +29,9 @@ 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, relate este erro com detalhes do dispositivo. + 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. + Solicitação HTTP retornou código de erro = + O URL da API não deve ter uma barra final '/' \ No newline at end of file diff --git a/resources-ron/strings/strings.xml b/resources-ron/strings/strings.xml index 46ef306..a2b08b0 100644 --- a/resources-ron/strings/strings.xml +++ b/resources-ron/strings/strings.xml @@ -29,5 +29,9 @@ 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ă raportați această eroare cu detaliile dispozitivului. + Apeluri API prea rapide. Vă rugăm să vă încetiniți solicitările. + 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. + Solicitarea HTTP a returnat codul de eroare = + Adresa URL API nu trebuie să aibă o bară oblică „/” \ No newline at end of file diff --git a/resources-slo/strings/strings.xml b/resources-slo/strings/strings.xml index 524d03d..ad337c3 100644 --- a/resources-slo/strings/strings.xml +++ b/resources-slo/strings/strings.xml @@ -29,5 +29,9 @@ 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. Nahláste túto chybu s podrobnosťami o zariadení. + 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. + Požiadavka HTTP vrátila kód chyby = + Adresa URL rozhrania API nesmie obsahovať koncovú lomku „/“ \ No newline at end of file diff --git a/resources-slv/strings/strings.xml b/resources-slv/strings/strings.xml index 31870bf..a4d9dc3 100644 --- a/resources-slv/strings/strings.xml +++ b/resources-slv/strings/strings.xml @@ -29,5 +29,9 @@ 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. Prijavite to napako s podrobnostmi o napravi. + 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 je vrnila kodo napake = + URL API-ja ne sme imeti končne poševnice '/' \ No newline at end of file diff --git a/resources-spa/strings/strings.xml b/resources-spa/strings/strings.xml index a016a52..81f7572 100644 --- a/resources-spa/strings/strings.xml +++ b/resources-spa/strings/strings.xml @@ -29,5 +29,9 @@ 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. Informe este error con los detalles del dispositivo. + 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. + La solicitud HTTP devolvió el código de error = + La URL de API no debe tener una barra diagonal '/' \ No newline at end of file diff --git a/resources-swe/strings/strings.xml b/resources-swe/strings/strings.xml index 91b6cf8..2cdacff 100644 --- a/resources-swe/strings/strings.xml +++ b/resources-swe/strings/strings.xml @@ -27,7 +27,11 @@ Ingen internetanslutning Menyhämtningsfel Ingen API-nyckel i applikationsinställningarna - Ingen API-URL i applikationsinställningarna + Ingen API-URL i programinställningarna Ingen konfigurations-URL i programinställningarna - API-anrop för snabba. Rapportera detta fel med enhetsinformation. + 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. + HTTP-begäran returnerade felkod = + API-URL får inte ha ett snedstreck '/' \ No newline at end of file diff --git a/resources-tha/strings/strings.xml b/resources-tha/strings/strings.xml index 03de333..a9e2fc1 100644 --- a/resources-tha/strings/strings.xml +++ b/resources-tha/strings/strings.xml @@ -29,5 +29,9 @@ ไม่มีคีย์ API ในการตั้งค่าแอปพลิเคชัน ไม่มี URL API ในการตั้งค่าแอปพลิเคชัน ไม่มี URL การกำหนดค่าในการตั้งค่าแอปพลิเคชัน - การเรียก API เร็วเกินไป โปรดรายงานข้อผิดพลาดนี้พร้อมรายละเอียดอุปกรณ์ + การเรียก API เร็วเกินไป กรุณาชะลอคำขอของคุณ + ไม่พบ URL ข้อผิดพลาด URL API ที่อาจเกิดขึ้นในการตั้งค่า + ไม่พบ URL ข้อผิดพลาด URL การกำหนดค่าที่อาจเกิดขึ้นในการตั้งค่า + คำขอ HTTP ส่งคืนรหัสข้อผิดพลาด = + URL ของ API ต้องไม่มีเครื่องหมายทับต่อท้าย '/' \ No newline at end of file diff --git a/resources-tur/strings/strings.xml b/resources-tur/strings/strings.xml index c7e7002..7031d9b 100644 --- a/resources-tur/strings/strings.xml +++ b/resources-tur/strings/strings.xml @@ -29,5 +29,9 @@ 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 bu hatayı cihaz ayrıntılarıyla birlikte bildirin. + 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ği hata kodunu döndürdü = + API URL'sinin sonunda '/' eğik çizgi olmamalıdır \ No newline at end of file diff --git a/resources-ukr/strings/strings.xml b/resources-ukr/strings/strings.xml index 4077a04..f23aca6 100644 --- a/resources-ukr/strings/strings.xml +++ b/resources-ukr/strings/strings.xml @@ -15,7 +15,7 @@ @@ -29,5 +29,9 @@ У налаштуваннях програми немає ключа API У налаштуваннях програми немає URL-адреси API У налаштуваннях програми немає URL-адреси конфігурації - Надто швидкі виклики API. Повідомте про цю помилку з деталями пристрою. + Надто швидкі виклики API. Будь ласка, сповільніть свої запити. + URL не знайдено. Потенційна помилка URL-адреси API в налаштуваннях. + URL не знайдено. Потенційна помилка URL-адреси конфігурації в налаштуваннях. + Запит HTTP повернув код помилки = + URL-адреса API не повинна містити косу риску '/' \ No newline at end of file diff --git a/resources-vie/strings/strings.xml b/resources-vie/strings/strings.xml index 01530c7..20d15ff 100644 --- a/resources-vie/strings/strings.xml +++ b/resources-vie/strings/strings.xml @@ -29,5 +29,9 @@ 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. Vui lòng báo cáo lỗi này với các chi tiết thiết bị. + 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. + Yêu cầu HTTP trả về mã lỗi = + URL API không được có dấu gạch chéo ở cuối '/' \ No newline at end of file diff --git a/resources-zhs/strings/strings.xml b/resources-zhs/strings/strings.xml index a70b1a6..dfdee43 100644 --- a/resources-zhs/strings/strings.xml +++ b/resources-zhs/strings/strings.xml @@ -29,5 +29,9 @@ 应用程序设置中没有 API 密钥 应用程序设置中没有 API URL 应用程序设置中没有配置 URL - API 调用速度太快。请报告此错误并提供设备详细信息。 + API 调用速度太快。请放慢您的请求。 + 找不到网址。设置中可能存在 API URL 错误。 + 找不到网址。设置中可能存在配置 URL 错误。 + HTTP请求返回错误码= + API URL 不得有尾部斜杠“/” \ No newline at end of file diff --git a/resources-zht/strings/strings.xml b/resources-zht/strings/strings.xml index acac8c8..8388437 100644 --- a/resources-zht/strings/strings.xml +++ b/resources-zht/strings/strings.xml @@ -29,5 +29,9 @@ 應用程式設定中沒有 API 金鑰 應用程式設定中沒有 API URL 應用程式設定中沒有配置 URL - API 呼叫速度太快。請報告此錯誤並提供設備詳細資訊。 + API 呼叫速度太快。請放慢您的請求。 + 找不到網址。設定中可能存在 API URL 錯誤。 + 找不到網址。設定中可能存在配置 URL 錯誤。 + HTTP請求回傳錯誤碼= + API URL 不得有尾部斜線“/” \ No newline at end of file diff --git a/resources-zsm/strings/strings.xml b/resources-zsm/strings/strings.xml index d56ae4c..72fd875 100644 --- a/resources-zsm/strings/strings.xml +++ b/resources-zsm/strings/strings.xml @@ -29,5 +29,9 @@ Tiada kunci API dalam tetapan aplikasi Tiada URL API dalam tetapan aplikasi Tiada URL konfigurasi dalam tetapan aplikasi - Panggilan API terlalu pantas. Sila laporkan ralat ini dengan butiran peranti. + 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. + Permintaan HTTP mengembalikan kod ralat = + URL API tidak boleh mempunyai garis miring '/' \ No newline at end of file diff --git a/resources/strings/strings.xml b/resources/strings/strings.xml index 6ca1034..753dce2 100644 --- a/resources/strings/strings.xml +++ b/resources/strings/strings.xml @@ -23,5 +23,9 @@ 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 report this error with device details. + 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. + HTTP request returned error code = + API URL must not have a trailing slash '/' diff --git a/source/Globals.mc b/source/Globals.mc index c5364a4..9475c94 100644 --- a/source/Globals.mc +++ b/source/Globals.mc @@ -23,9 +23,7 @@ using Toybox.Lang; class Globals { // Enable printing of messages to the debug console (don't make this a Property // as the messages can't be read from a watch!) - static const scDebug = false; - // There's a danger this time is device sensitive. - static const scMenuItemUpdateInterval = 100; // ms, 100 ms seems okay for Venu2 - static const scAlertTimeout = 2000; // ms - static const scTapTimeout = 1000; // ms + static const scDebug = false; + static const scAlertTimeout = 2000; // ms + static const scTapTimeout = 1000; // ms } diff --git a/source/HomeAssistantApp.mc b/source/HomeAssistantApp.mc index 6ab39e9..334cfca 100644 --- a/source/HomeAssistantApp.mc +++ b/source/HomeAssistantApp.mc @@ -26,25 +26,29 @@ using Toybox.Timer; class HomeAssistantApp extends Application.AppBase { hidden var mHaMenu; - hidden var strNoApiKey as Lang.String; - hidden var strNoApiUrl as Lang.String; - hidden var strNoConfigUrl as Lang.String; - hidden var strNoInternet as Lang.String; - hidden var strNoMenu as Lang.String; - hidden var strApiFlood as Lang.String; - hidden var mTimer as Timer.Timer; + hidden var strNoApiKey as Lang.String; + hidden var strNoApiUrl as Lang.String; + hidden var strNoConfigUrl as Lang.String; + hidden var strNoInternet as Lang.String; + hidden var strNoMenu as Lang.String; + hidden var strApiFlood as Lang.String; + hidden var strConfigUrlNotFound as Lang.String; + hidden var strUnhandledHttpErr as Lang.String; + hidden var strTrailingSlashErr as Lang.String; hidden var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig() hidden var mNextItemToUpdate = 0; // Index into the above array function initialize() { AppBase.initialize(); - strNoApiKey = WatchUi.loadResource($.Rez.Strings.NoAPIKey); - strNoApiUrl = WatchUi.loadResource($.Rez.Strings.NoApiUrl); - strNoConfigUrl = WatchUi.loadResource($.Rez.Strings.NoConfigUrl); - strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet); - strNoMenu = WatchUi.loadResource($.Rez.Strings.NoMenu); - strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood); - mTimer = new Timer.Timer(); + strNoApiKey = WatchUi.loadResource($.Rez.Strings.NoAPIKey); + strNoApiUrl = WatchUi.loadResource($.Rez.Strings.NoApiUrl); + strNoConfigUrl = WatchUi.loadResource($.Rez.Strings.NoConfigUrl); + strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet); + strNoMenu = WatchUi.loadResource($.Rez.Strings.NoMenu); + strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood); + strConfigUrlNotFound = WatchUi.loadResource($.Rez.Strings.ConfigUrlNotFound); + strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr); + strTrailingSlashErr = WatchUi.loadResource($.Rez.Strings.TrailingSlashErr); } // onStart() is called on application start up @@ -52,27 +56,30 @@ class HomeAssistantApp extends Application.AppBase { } // onStop() is called when your application is exiting - function onStop(state as Lang.Dictionary?) as Void { - if (mTimer != null) { - mTimer.stop(); - } - } + function onStop(state as Lang.Dictionary?) as Void {} // Return the initial view of your application here function getInitialView() as Lang.Array? { + var api_url = Properties.getValue("api_url") as Lang.String; + if ((Properties.getValue("api_key") as Lang.String).length() == 0) { if (Globals.scDebug) { - System.println("HomeAssistantMenuItem Note - execScript(): No API key in the application settings."); + System.println("HomeAssistantMenuItem execScript(): No API key in the application settings."); } return [new ErrorView(strNoApiKey + "."), new ErrorDelegate()] as Lang.Array; - } else if ((Properties.getValue("api_url") as Lang.String).length() == 0) { + } else if (api_url.length() == 0) { if (Globals.scDebug) { - System.println("HomeAssistantMenuItem Note - execScript(): No API URL in the application settings."); + System.println("HomeAssistantMenuItem execScript(): No API URL in the application settings."); } return [new ErrorView(strNoApiUrl + "."), new ErrorDelegate()] as Lang.Array; + } else if (api_url.substring(-1, api_url.length()).equals("/")) { + if (Globals.scDebug) { + System.println("HomeAssistantMenuItem execScript(): API URL must not have a trailing slash '/'."); + } + return [new ErrorView(strTrailingSlashErr + "."), new ErrorDelegate()] as Lang.Array; } else if ((Properties.getValue("config_url") as Lang.String).length() == 0) { if (Globals.scDebug) { - System.println("HomeAssistantMenuItem Note - execScript(): No configuration URL in the application settings."); + System.println("HomeAssistantMenuItem execScript(): No configuration URL in the application settings."); } return [new ErrorView(strNoConfigUrl + "."), new ErrorDelegate()] as Lang.Array; } else if (System.getDeviceSettings().phoneConnected && System.getDeviceSettings().connectionAvailable) { @@ -80,7 +87,7 @@ class HomeAssistantApp extends Application.AppBase { return [new WatchUi.View(), new WatchUi.BehaviorDelegate()] as Lang.Array; } else { if (Globals.scDebug) { - System.println("HomeAssistantApp Note - fetchMenuConfig(): No Internet connection, skipping API call."); + System.println("HomeAssistantApp fetchMenuConfig(): No Internet connection, skipping API call."); } return [new ErrorView(strNoInternet + "."), new ErrorDelegate()] as Lang.Array; } @@ -102,25 +109,30 @@ class HomeAssistantApp extends Application.AppBase { // Avoid pushing multiple ErrorViews WatchUi.pushView(new ErrorView(strApiFlood), new ErrorDelegate(), WatchUi.SLIDE_UP); } + } else if (responseCode == 404) { + if (Globals.scDebug) { + System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: 404, page not found. Check Configuration URL setting."); + } + WatchUi.pushView(new ErrorView(strConfigUrlNotFound), new ErrorDelegate(), WatchUi.SLIDE_UP); } else if (responseCode == 200) { mHaMenu = new HomeAssistantView(data, null); WatchUi.switchToView(mHaMenu, new HomeAssistantViewDelegate(), WatchUi.SLIDE_IMMEDIATE); mItemsToUpdate = mHaMenu.getItemsToUpdate(); - mTimer.start( - method(:updateNextMenuItem), - Globals.scMenuItemUpdateInterval, - true - ); - } else if (responseCode == -300) { + // 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 Note - onReturnFetchMenuConfig(): Network request timeout."); + System.println("HomeAssistantApp onReturnFetchMenuConfig(): Network request timeout."); } WatchUi.pushView(new ErrorView(strNoMenu + ". " + strNoInternet + "?"), new ErrorDelegate(), WatchUi.SLIDE_UP); } else { if (Globals.scDebug) { - System.println("HomeAssistantApp Note - onReturnFetchMenuConfig(): Configuration not found or potential validation issue."); + System.println("HomeAssistantApp onReturnFetchMenuConfig(): Unhandled HTTP response code = " + responseCode); } - WatchUi.pushView(new ErrorView(strNoMenu + " code=" + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP); + WatchUi.pushView(new ErrorView(strUnhandledHttpErr + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP); } } diff --git a/source/HomeAssistantMenuItem.mc b/source/HomeAssistantMenuItem.mc index 5db50eb..0212227 100644 --- a/source/HomeAssistantMenuItem.mc +++ b/source/HomeAssistantMenuItem.mc @@ -24,10 +24,12 @@ using Toybox.Graphics; using Toybox.Application.Properties; class HomeAssistantMenuItem extends WatchUi.MenuItem { - hidden var mApiKey = Properties.getValue("api_key"); - hidden var strNoInternet as Lang.String; - hidden var strApiFlood as Lang.String; - hidden var mService as Lang.String; + hidden var mApiKey as Lang.String; + hidden var strNoInternet as Lang.String; + hidden var strApiFlood as Lang.String; + hidden var strApiUrlNotFound as Lang.String; + hidden var strUnhandledHttpErr as Lang.String; + hidden var mService as Lang.String; function initialize( label as Lang.String or Lang.Symbol, @@ -39,8 +41,11 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem { :icon as Graphics.BitmapType or WatchUi.Drawable or Lang.Symbol } or Null ) { - strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet); - strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood); + strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet); + strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood); + strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound); + strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr); + mApiKey = Properties.getValue("api_key"); mService = service; WatchUi.MenuItem.initialize( label, @@ -66,37 +71,38 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem { // Avoid pushing multiple ErrorViews WatchUi.pushView(new ErrorView(strApiFlood), new ErrorDelegate(), WatchUi.SLIDE_UP); } + } else if (responseCode == 404) { + if (Globals.scDebug) { + System.println("HomeAssistantMenuItem onReturnExecScript() Response Code: 404, page not found. Check API URL setting."); + } + WatchUi.pushView(new ErrorView(strApiUrlNotFound), new ErrorDelegate(), WatchUi.SLIDE_UP); } else if (responseCode == 200) { - var d = data as Lang.Array; + if (Globals.scDebug) { + System.println("HomeAssistantMenuItem onReturnExecScript(): 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(mIdentifier)) { - if (Globals.scDebug) { - System.println("HomeAssistantMenuItem Note - onReturnExecScript(): Correct script executed."); - } - if (WatchUi has :showToast) { - WatchUi.showToast( - (d[i].get("attributes") as Lang.Dictionary).get("friendly_name") as Lang.String, - null - ); - } - if (Attention has :vibrate) { - Attention.vibrate([ - new Attention.VibeProfile(50, 100), // On for 100ms - new Attention.VibeProfile( 0, 100), // Off for 100ms - new Attention.VibeProfile(50, 100) // On for 100ms - ]); - } - if (!(WatchUi has :showToast) && !(Attention has :vibrate)) { - new Alert({ - :timeout => Globals.scAlertTimeout, - :font => Graphics.FONT_MEDIUM, - :text => (d[i].get("attributes") as Lang.Dictionary).get("friendly_name") as Lang.String, - :fgcolor => Graphics.COLOR_WHITE, - :bgcolor => Graphics.COLOR_BLACK - }).pushView(WatchUi.SLIDE_IMMEDIATE); - } + 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); + } + } else { + if (Globals.scDebug) { + System.println("HomeAssistantMenuItem onReturnExecScript(): Unhandled HTTP response code = " + responseCode); + } + WatchUi.pushView(new ErrorView(strUnhandledHttpErr + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP); } } @@ -114,7 +120,7 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem { // ERROR: venu: Cannot find symbol ':substring' on type 'PolyType'. var id = mIdentifier as Lang.String; if (mService == null) { - var url = (Properties.getValue("api_url") as Lang.String) + "/services/" + id.substring(0, id.find(".")) + "/" + id.substring(id.find(".")+1, id.length()); + var url = (Properties.getValue("api_url") as Lang.String) + "/services/" + id.substring(0, id.find(".")) + "/" + id.substring(id.find(".")+1, null); if (Globals.scDebug) { System.println("HomeAssistantMenuItem execScript() URL=" + url); System.println("HomeAssistantMenuItem execScript() mIdentifier=" + mIdentifier); @@ -129,7 +135,7 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem { var url = (Properties.getValue("api_url") as Lang.String) + "/services/" + mService.substring(0, mService.find(".")) + "/" + mService.substring(mService.find(".")+1, null); if (Globals.scDebug) { System.println("HomeAssistantMenuItem execScript() URL=" + url); - System.println("HomeAssistantMenuItem execScript() mIdentifier=" + mIdentifier); + System.println("HomeAssistantMenuItem execScript() mService=" + mService); } Communications.makeWebRequest( url, @@ -140,9 +146,16 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem { method(:onReturnExecScript) ); } + if (Attention has :vibrate) { + Attention.vibrate([ + new Attention.VibeProfile(50, 100), // On for 100ms + new Attention.VibeProfile( 0, 100), // Off for 100ms + new Attention.VibeProfile(50, 100) // On for 100ms + ]); + } } else { if (Globals.scDebug) { - System.println("HomeAssistantMenuItem Note - execScript(): No Internet connection, skipping API call."); + System.println("HomeAssistantMenuItem execScript(): No Internet connection, skipping API call."); } WatchUi.pushView(new ErrorView(strNoInternet + "."), new ErrorDelegate(), WatchUi.SLIDE_UP); } diff --git a/source/HomeAssistantToggleMenuItem.mc b/source/HomeAssistantToggleMenuItem.mc index ed6f340..33f13a2 100644 --- a/source/HomeAssistantToggleMenuItem.mc +++ b/source/HomeAssistantToggleMenuItem.mc @@ -24,9 +24,11 @@ using Toybox.Graphics; using Toybox.Application.Properties; class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { - hidden var mApiKey = Properties.getValue("api_key"); - hidden var strNoInternet as Lang.String; - hidden var strApiFlood as Lang.String; + hidden var mApiKey as Lang.String; + hidden var strNoInternet as Lang.String; + hidden var strApiFlood as Lang.String; + hidden var strApiUrlNotFound as Lang.String; + hidden var strUnhandledHttpErr as Lang.String; function initialize( label as Lang.String or Lang.Symbol, @@ -41,10 +43,12 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { :icon as Graphics.BitmapType or WatchUi.Drawable or Lang.Symbol } or Null ) { - strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet); - strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood); + strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet); + strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood); + strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound); + strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr); + mApiKey = Properties.getValue("api_key"); WatchUi.ToggleMenuItem.initialize(label, subLabel, identifier, enabled, options); - mApiKey = Properties.getValue("api_key"); } private function setUiToggle(state as Null or Lang.String) as Void { @@ -75,6 +79,17 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { // Avoid pushing multiple ErrorViews WatchUi.pushView(new ErrorView(strApiFlood), new ErrorDelegate(), WatchUi.SLIDE_UP); } + // Now this feels very "closely coupled" to the application, but it is the most reliable method instead of using a timer. + getApp().updateNextMenuItem(); + } else if (responseCode == 404) { + if (Globals.scDebug) { + System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: 404, page not found. Check API URL setting."); + } + var cw = WatchUi.getCurrentView(); + if (!(cw[0] instanceof ErrorView)) { + // Avoid pushing multiple ErrorViews + WatchUi.pushView(new ErrorView(strApiUrlNotFound), new ErrorDelegate(), WatchUi.SLIDE_UP); + } } else if (responseCode == 200) { var state = data.get("state") as Lang.String; if (Globals.scDebug) { @@ -84,6 +99,13 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { setLabel((data.get("attributes") as Lang.Dictionary).get("friendly_name") as Lang.String); } setUiToggle(state); + // Now this feels very "closely coupled" to the application, but it is the most reliable method instead of using a timer. + getApp().updateNextMenuItem(); + } else { + if (Globals.scDebug) { + System.println("HomeAssistantToggleMenuItem onReturnGetState(): Unhandled HTTP response code = " + responseCode); + } + WatchUi.pushView(new ErrorView(strUnhandledHttpErr + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP); } } @@ -108,7 +130,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { ); } else { if (Globals.scDebug) { - System.println("HomeAssistantToggleMenuItem Note - getState(): No Internet connection, skipping API call."); + System.println("HomeAssistantToggleMenuItem getState(): No Internet connection, skipping API call."); } WatchUi.pushView(new ErrorView(strNoInternet + "."), new ErrorDelegate(), WatchUi.SLIDE_UP); } @@ -125,10 +147,15 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { if (Globals.scDebug) { System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: BLE_QUEUE_FULL, API calls too rapid."); } + WatchUi.pushView(new ErrorView(strApiFlood), new ErrorDelegate(), WatchUi.SLIDE_UP); + } else if (responseCode == 404) { + if (Globals.scDebug) { + System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: 404, page not found. Check API URL setting."); + } var cw = WatchUi.getCurrentView(); if (!(cw[0] instanceof ErrorView)) { // Avoid pushing multiple ErrorViews - WatchUi.pushView(new ErrorView(strApiFlood), new ErrorDelegate(), WatchUi.SLIDE_UP); + WatchUi.pushView(new ErrorView(strApiUrlNotFound), new ErrorDelegate(), WatchUi.SLIDE_UP); } } else if (responseCode == 200) { var state; @@ -142,6 +169,11 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { setUiToggle(state); } } + } else { + if (Globals.scDebug) { + System.println("HomeAssistantToggleMenuItem onReturnSetState(): Unhandled HTTP response code = " + responseCode); + } + WatchUi.pushView(new ErrorView(strUnhandledHttpErr + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP); } } @@ -178,7 +210,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem { ); } else { if (Globals.scDebug) { - System.println("HomeAssistantToggleMenuItem Note - setState(): No Internet connection, skipping API call."); + System.println("HomeAssistantToggleMenuItem setState(): No Internet connection, skipping API call."); } WatchUi.pushView(new ErrorView(strNoInternet + "."), new ErrorDelegate(), WatchUi.SLIDE_UP); } diff --git a/translate.py b/translate.py index d4592a5..1ba9746 100644 --- a/translate.py +++ b/translate.py @@ -18,7 +18,7 @@ # language using Google Translate. # # Python installation: -# pip install BeautifulSoup +# pip install beautifulsoup4 # pip install deep-translator # NB. For XML formatting: # pip install lxml @@ -84,9 +84,15 @@ exceptionIds: list[str] = ["AppName", "AppVersionTitle"] titleIds: list[str] = ["setMode", "tapIcon"] i = 1 -with open("./resources/strings/strings.xml") as f: +with open("./resources/strings/strings.xml", "r") as f: c = f.read().replace('\r', '') for l in languages: + os.makedirs(f"./resources-{l[0]}/strings/", exist_ok=True) + try: + with open(f"./resources-{l[0]}/strings/corrections.xml", "r") as r: + curr = BeautifulSoup(r.read().replace('\r', ''), features="xml") + except FileNotFoundError: + curr = BeautifulSoup("", features=["xml"]) print(f"{i} of {langLength}: Translating English to {l[2]}") soup = BeautifulSoup(c, features="xml") soup.find(name="strings").insert_before("\n\n") @@ -99,7 +105,12 @@ with open("./resources/strings/strings.xml") as f: for s in soup.find(name="strings").findAll(name="string"): s.insert_before(" ") - if s["id"] not in exceptionIds: + if s["id"] in exceptionIds: continue + + s_curr = curr.find(name="string", attrs={ "id": s["id"] }) + if s_curr: + s.string = s_curr.string + else: a = GoogleTranslator(source='en', target=l[1]).translate(s.string) if s["id"] in titleIds: s.string = a.title() @@ -108,8 +119,8 @@ with open("./resources/strings/strings.xml") as f: for s in soup.find(name="strings").findAll(text=lambda text:isinstance(text, Comment)): s.insert_before(" ") s.replace_with(Comment(" " + GoogleTranslator(source='en', target=l[1]).translate(s) + " ")) + #print(str(soup)) - os.makedirs(f"./resources-{l[0]}/strings/", exist_ok=True) with open(f"./resources-{l[0]}/strings/strings.xml", "wb") as w: w.write(soup.encode("utf-8")) i += 1