Compare commits

...

30 Commits

Author SHA1 Message Date
Philip Abbey
9030a00d7d Update BackgroundServiceDelegate.mc
Put check for methods with 'has' back in.
2024-07-22 22:18:27 +01:00
Joseph Abbey
7bd5e98a1a More responsive status when using a polling delay (#153)
When using a polling delay, an action will trigger an immediate round of
updates.
2024-07-21 16:00:21 +00:00
Philip Abbey
a49dd6554f More responsive status when using a polling delay
When using a polling delay, an action will trigger an immediate round of updates.
2024-07-20 19:16:42 +01:00
Joseph Abbey
d2fc64836a Update HomeAssistantApp.mc (#152)
When Settings.getPollDelay() > 0, do not wait for this time before the
initial batch of updates, so the app is more responsive on opening.
2024-07-20 17:09:23 +00:00
Philip Abbey
fc1a0eeb6d Update HomeAssistantApp.mc
When Settings.getPollDelay() > 0, do not wait for this time before the initial batch of updates, so the app is more responsive on opening.
2024-07-20 18:07:37 +01:00
Philip Abbey
61f6d69e64 Update HISTORY.md
Added a second feature to 2.13 in anticipation.
2024-07-20 17:39:59 +01:00
Joseph Abbey
7f31cecfb5 Added update to telemetry on completion of an activity (#151)
@Someone0nEarth Note we could also add this to the widget version as the
changes are small and probably have a limited effect on the memory
footprint.
2024-07-20 16:37:29 +00:00
Philip Abbey
98af5578f0 Added update to telemetry on completion of an activity 2024-07-20 17:28:57 +01:00
Philip Abbey
c18736e40d Update Templates.md
Examples now up to date with schema changes.
2024-07-20 17:23:00 +01:00
Joseph Abbey
822c6ccca6 Moved template status updates to webhooks (#150)
This seems to work for non-privileged users.
2024-07-20 15:49:04 +00:00
Philip Abbey
a139742265 Update HISTORY.md
Ver 2.13 text added in anticipation.
2024-07-19 17:05:19 +01:00
Philip Abbey
dfa4cdd9b8 Moved template status updates to webhooks
This seems to work for non-privileged users.
2024-07-19 15:15:32 +01:00
Philip Abbey
1c4add693d Update README.md
Amended advice based on a report at https://community.home-assistant.io/t/home-assistant-app-for-garmin/637348/280.

Signed-off-by: Philip Abbey <philipabbey@users.noreply.github.com>
2024-07-01 08:40:04 +01:00
Joseph Abbey
e6544b5b20 Update monkey.jungle top up 145 (#147)
Missed the Jungle file.
2024-06-15 11:32:35 +01:00
Philip Abbey
83914e8d8d Update monkey.jungle
Missed the Jungle file.
2024-06-15 11:13:10 +01:00
Joseph Abbey
bd4b6d68a8 Devices Edge 540 and Edge 840 re-enabled (#146)
@Petucky reports the application works well on an Edge 840 by
sideloading the code from an Edge 830 device.
2024-06-15 11:12:46 +01:00
Philip Abbey
f4ca55d741 Devices Edge 540 and Edge 840 re-enabled
@Petucky reports the application works well on an Edge 840 by sideloading the code from an Edge 830 device.
2024-06-15 11:00:58 +01:00
Philip Abbey
5d34db7b6a Update README.md
Typo
2024-05-04 14:29:54 +01:00
Philip Abbey
cfaa31d5ee Update README.md
Typo
2024-05-04 14:28:33 +01:00
Philip Abbey
52ee270788 Update README.md
Note about HTTP
2024-05-04 10:06:59 +01:00
Philip Abbey
dec38889a5 Update HISTORY.md
Added version 2.11
2024-04-17 14:06:34 +01:00
Philip Abbey
586d85e706 Update export.cmd
Commit directly to main as not application code.
2024-04-17 08:26:52 +01:00
Philip Abbey
30b55aec3e Merge branch 'main' of https://github.com/house-of-abbey/GarminHomeAssistant 2024-04-17 08:24:52 +01:00
philipabbey
93d672dd40 Apply automatic changes 2024-04-17 07:09:18 +00:00
Philip Abbey
9130bc7121 Merge pull request #139 from house-of-abbey/138-cached-menu-will-still-be-used-even-if-the-setting-is-deactivated
When the cache is deactivated is now also cleared.
2024-04-17 07:56:49 +01:00
Philip Abbey
a6e386c5e6 Removed scope="glance" from another language corrections.xml file 2024-04-17 07:52:28 +01:00
Philip Abbey
2ffd83ebf5 When the cache is deactivated is now also cleared. 2024-04-16 22:58:53 +01:00
philipabbey
48b7e7efe5 Apply automatic changes 2024-04-16 06:35:49 +00:00
Philip Abbey
7bb270aae8 Update corrections.xml
Changed `<string id="Menu">Menu</string>` to `<string id="GlanceMenu">Menu</string>`.

A trivial fix so bypassing reviews.
2024-04-16 07:01:38 +01:00
Philip Abbey
ac117952d0 Merge pull request #136 from house-of-abbey/135-string-change-request-czech-translation-inappropriate
Corrected Czech language strings as advised
2024-04-16 06:31:26 +01:00
34 changed files with 324 additions and 200 deletions

View File

@@ -23,3 +23,6 @@
| 2.8 | Separation release. The application and widget are no longer joined and now have separate source code repositories. The widget version is now in "maintenance only mode" hence will not receive new features, whilst the application version can now take advantage of not being constrained by the widget's memory limitation, which should allow new features to be added in the future. |
| 2.9 | Added an option to enable confirmation vibration so it can be turned off by request of a user. Removed a redundant setting for the alternative Widget version that was not removed previously, and fixed a bug with dereferencing Null. |
| 2.10 | Added a user requested feature to slow down the rate of API calls in order to reduce battery wear for a situation where the application is kept open permanently on the device for convenience. Added 4 new devices. |
| 2.11 | Bug fix release for menu caching being turned off and language corrections (Czech & Slovenian). |
| 2.12 | Re-enabled Edge 540 and Edge 840 devices which we are unable to support due to simulator issues, but the Edge 840 device has been confirmed as working by a @Petucky. |
| 2.13 | Moved the template status queries to Webhooks in order to fix the situation where an account is a non-privileged user. Added telemetry update on activity completion to make automations more timely at the end of an activity. When using a polling delay, there is no longer a startup delay for status updates and an action will trigger an immediate round of updates. |

View File

@@ -43,7 +43,10 @@ Setup for this menu is more complicated than the Connect IQ settings menu really
2. the file is editable within Home Assistant via "[Studio Code Server](https://my.home-assistant.io/redirect/supervisor_addon/?addon=a0d7b954_vscode)", and
3. the schema is verifiable using [JSON Schema](https://json-schema.org/overview/what-is-jsonschema).
We have used `/config/www/garmin/<something>.json` on our Home Assistant's file system. That equates to a URL of `https://homeassistant.local/local/garmin/<something>.json`.
We have used `/config/www/garmin/<something>.json` on our home brew Home Assistant's file system. That equates to a URL of `https://homeassistant.local/local/garmin/<something>.json`.
> [!IMPORTANT]
> However [recent reports](https://community.home-assistant.io/t/www-folder-location-for-local-documents/24903/16) suggest this path may no longer work on [Nabu Casa](https://www.nabucasa.com/) and you should use `/homeassistant/www/` instead of `/config/www/`. We are unable to verify this since our free trial of Nabu Casa has expired.
Schema verification is a big part of this design choice. If the application cannot read your menu definition, there's a limited amount of debug it can reasonably provide on a small screen. That responsibility now falls to you and the schema checker for help.
@@ -308,4 +311,6 @@ The `id` attribute values are taken from the same names used in [`strings.xml`](
5. Parameters to tap menu items cannot have their parameter usage verified. If you get this wrong and crash the application, that's your fault not the application's. In this case, start by removing the parameters for the menu item causing the crash, and add them back one at a time until you find your fault. **Please don't give the application a poor review for your bad parameter definition!**
6. We are unable to support Edge 540 and Edge 840 devices at this time. The simulation of both these devices has two unexpected errors when toggling or executing taps. We get both `Communications.NETWORK_RESPONSE_OUT_OF_MEMORY` and `Communications.BLE_QUEUE_FULL` even though the memory usage is about 6% of the available RAM. We would appreciate any leads others may have on how to solve this issue.
6. We are unable to support Edge 540 and Edge 840 devices at this time. The simulation of both these devices has two unexpected errors when toggling or executing taps. We get both `Communications.NETWORK_RESPONSE_OUT_OF_MEMORY` and `Communications.BLE_QUEUE_FULL` even though the memory usage is about 6% of the available RAM. Based on a lead from user @Petucky, both devices are being re-enabled as testing on a real Edge 840 device has proven successful, however we remain unable to support either devices until the simulator is fixed.
7. We are unable to support HTTP without HTTPS. This is a limitation placed upon us by the Connect IQ API which for security reasons refuses to work with HTTP requests. There is nothing developers can do about this limitation. You will have to put an HTTPS proxy in front of your local Home Assistant to work with this application. See the [Trouble Shooting](TroubleShooting.md#do-it-yourself-setup) guide for an example setup. We would appreciate it if users did not leave poor reviews for the lack of this feature which is beyond our control to fix.

View File

@@ -21,7 +21,7 @@ rem
rem -----------------------------------------------------------------------------------
rem Check this path is correct for your Java installation
set JAVA_PATH=C:\Program Files (x86)\Common Files\Oracle\Java\javapath
set JAVA_PATH=C:\Program Files\Java\jdk-22\bin
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

View File

@@ -16,7 +16,6 @@ In this example we get the battery level of the device and add the percent sign.
```json
{
"entity": "sensor.<device>_battery_level",
"name": "Phone",
"type": "template",
"content": "{{ states('sensor.<device>_battery_level') }}%"
@@ -29,19 +28,16 @@ The first two keep to the simple proposal above. The last combines them into a s
```json
{
"entity": "sensor.hallway_temperature",
"name": "Hall Temp",
"type": "template",
"content": "{{ states('sensor.hallway_temperature') }}°C"
},
{
"entity": "sensor.hallway_humidity",
"name": "Hall Humidity",
"type": "template",
"content": "{{ states('sensor.hallway_humidity') }}%"
},
{
"entity": "sensor.hallway_temperature",
"name": "Hallway",
"type": "template",
"content": "{{ states('sensor.hallway_temperature') }}°C {{ states('sensor.hallway_humidity') }}%"
@@ -61,16 +57,16 @@ In order to keep the formatting of floating point numbers under control, you mig
Where your device supports unicode characters these example may work.
```json
{
"name": "Charge",
"type": "template",
"content": "☎ {{ states('sensor.my_phone_battery_level') }}%{% if is_state('binary_sensor.my_phone_is_charging', 'on') %}⚡{% endif %}, ⏳ {{ '%.0f'|format(states('sensor.my_watch_battery_level') | float) }}%{% if is_state('binary_binary_sensor.my_watch_battery_is_charging', 'on') %}⚡{% endif %}"
},
{
"name": "Hallway",
"type": "template",
"content": "🌡{% if is_state('sensor.hallway_temperature', 'unavailable') %}-{% else %}{{ '%.1f'|format(states('sensor.hallway_temperature')|float) }}°C{% if is_state_attr('climate.hallway', 'hvac_action', 'heating') or is_state_attr('climate.hallway', 'hvac_action', 'preheating') -%}🔥{%- endif %}{% endif %}, 💧{% if is_state('sensor.hallway_humidity', 'unavailable') %}-{% else %}{{ '%.1f'|format(states('sensor.hallway_humidity')|float) }}%{% endif %}"
}
{
"name": "Charge",
"type": "template",
"content": "☎ {{ states('sensor.my_phone_battery_level') }}%{% if is_state('binary_sensor.my_phone_is_charging', 'on') %}⚡{% endif %}, ⏳ {{ '%.0f'|format(states('sensor.my_watch_battery_level') | float) }}%{% if is_state('binary_binary_sensor.my_watch_battery_is_charging', 'on') %}⚡{% endif %}"
},
{
"name": "Hallway",
"type": "template",
"content": "🌡{% if is_state('sensor.hallway_temperature', 'unavailable') %}-{% else %}{{ '%.1f'|format(states('sensor.hallway_temperature')|float) }}°C{% if is_state_attr('climate.hallway', 'hvac_action', 'heating') or is_state_attr('climate.hallway', 'hvac_action', 'preheating') -%}🔥{%- endif %}{% endif %}, 💧{% if is_state('sensor.hallway_humidity', 'unavailable') %}-{% else %}{{ '%.1f'|format(states('sensor.hallway_humidity')|float) }}%{% endif %}"
}
```
![Unicode Characters in a Template](../images/Unicode_Template.png)
@@ -83,7 +79,6 @@ In this example we get the battery level of the device and add the percent sign.
```json
{
"entity": "sensor.<device>_battery_level",
"name": "Phone",
"type": "template",
"content": "{{ states('sensor.<device>_battery_level') }}%{% if is_state('binary_sensor.<device>_is_charging', 'on') %}+{% endif %}"
@@ -94,13 +89,32 @@ Here we also use the else clause as well to give proper text instead of just `on
```json
{
"entity": "binary_sensor.garage_doors",
"name": "Garage Doors",
"type": "template",
"content": "{% if is_state('binary_sensor.<door-0>', 'on') %}Open{% else %}Closed{% endif %} {% if is_state('binary_sensor.<door-1>', 'on') %}Open{% else %}Closed{% endif %}"
}
```
> [!IMPORTANT]
> We advise users against adding security devices.
However, users are doing this **against our advice** and asking how to operate 'covers'. This is an example of toggling a garage door open and closed with confirmation. *Do this at your own risk*.
Note: Only when you use the `tap_action` field do you also need to include the `entity` field. This is a change to a previous version of the application, hence the presence of the `entity` field will be ignored for backwards compatibility, and the schema will provide a warning only.
```json
{
"entity": "cover.garage_door",
"name": "Garage Door",
"type": "template",
"content": "{% if is_state('binary_sensor.garage_connected', 'on') %}{{state_translated('cover.garage_door')}} - {{state_attr('cover.garage_door', 'current_position')}}%{%else%}Unconnected{% endif %}",
"tap_action": {
"service": "cover.toggle",
"confirm": true
}
}
```
## Advanced
Here we generate a bar graph of the battery level. We use the following steps to do this:
@@ -114,7 +128,6 @@ Here we generate a bar graph of the battery level. We use the following steps to
```json
{
"entity": "sensor.<device>_battery_level",
"name": "Phone",
"type": "template",
"content": "{{ states('sensor.<device>_battery_level') }}%{% if is_state('binary_sensor.<device>_is_charging', 'on') %}+{% endif %} {{ '#' * (((states('sensor.<device>_battery_level') | int) / 100 * <width>) | int) }}{{ '_' * (<width> - (((states('sensor.<device>_battery_level') | int) / 100 * <width>) | int)) }}"
@@ -125,11 +138,10 @@ An example of a dimmer light with 4 brightness settings 0..3. Here our light wor
```json
{
"$schema": "./schema.json",
"$schema": "https://raw.githubusercontent.com/house-of-abbey/GarminHomeAssistant/main/config.schema.json",
"title": "Home",
"items": [
{
"entity": "light.green_house",
"name": "LEDs",
"type": "template",
"content": "{% if not (is_state('light.green_house', 'off') or is_state('light.green_house', 'unavailable')) %}{{ (((state_attr('light.green_house', 'brightness') | float) / 255 * 100) | round(0)) | int }}%{% else %}Off{% endif %}"
@@ -187,4 +199,4 @@ An example of a dimmer light with 4 brightness settings 0..3. Here our light wor
## Warnings
Just remember, **you have the ability to crash the application by creating an excessive menu definition**. Templates can require significant definition for highly customised text. Don't be silly.
Just remember, on older smaller memory devices **you have the ability to crash the application by creating an excessive menu definition**. Templates can require significant definition for highly customised text. Don't be silly.

View File

@@ -21,7 +21,7 @@ rem
rem -----------------------------------------------------------------------------------
rem Check this path is correct for your Java installation
set JAVA_PATH=C:\Program Files (x86)\Common Files\Oracle\Java\javapath
set JAVA_PATH=C:\Program Files\Java\jdk-22\bin
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

View File

@@ -56,8 +56,10 @@
<iq:product id="edge1040" />
<iq:product id="edge520plus" />
<iq:product id="edge530" />
<iq:product id="edge540" />
<iq:product id="edge820" />
<iq:product id="edge830" />
<iq:product id="edge840" />
<iq:product id="edgeexplore" />
<iq:product id="edgeexplore2" />
<iq:product id="enduro" />

View File

@@ -68,10 +68,12 @@ edge1040.resourcePath = $(edge1040.resourcePath);resources-launcher-40-40;resour
edge520plus.resourcePath = $(edge520plus.resourcePath);resources-launcher-35-35;resources-icons-24
# Screen Size 246x322 launcher icon size 35x35
edge530.resourcePath = $(edge530.resourcePath);resources-launcher-35-35;resources-icons-28
edge540.resourcePath = $(edge540.resourcePath);resources-launcher-35-35;resources-icons-28
# Screen Size 200x265 launcher icon size 35x35
edge820.resourcePath = $(edge820.resourcePath);resources-launcher-35-35;resources-icons-24
# Screen Size 246x322 launcher icon size 35x35
edge830.resourcePath = $(edge830.resourcePath);resources-launcher-35-35;resources-icons-28
edge840.resourcePath = $(edge840.resourcePath);resources-launcher-35-35;resources-icons-28
# Screen Size 240x400 launcher icon size 36x36
edgeexplore.resourcePath = $(edgeexplore.resourcePath);resources-launcher-36-36;resources-icons-28
edgeexplore2.resourcePath = $(edgeexplore2.resourcePath);resources-launcher-36-36;resources-icons-28

View File

@@ -51,15 +51,15 @@
<string id="SettingsConfigUrl">URL за конфигурация на менюто (JSON).</string>
<string id="SettingsCacheConfig">Трябва ли приложението да кешира конфигурацията на менюто?</string>
<string id="SettingsClearCache">Трябва ли приложението да изчисти съществуващия кеш при следващото стартиране?</string>
<string id="SettingsVibration">Трябва ли приложението да предоставя обратна връзка чрез вибрации?</string>
<string id="SettingsVibration">Трябва ли приложението да дава обратна връзка чрез вибрации?</string>
<string id="SettingsAppTimeout">Изчакване в секунди. Излезте от приложението след този период на неактивност, за да запазите батерията на устройството.</string>
<string id="SettingsPollDelay">Допълнително забавяне на анкетата (в секунди). Добавя забавяне между актуализацията на състоянието на всички елементи от менюто.</string>
<string id="SettingsConfirmTimeout">След това време (в секунди) диалоговият прозорец за потвърждение за действие се затваря автоматично и действието се отменя. Задайте 0, за да деактивирате изчакването.</string>
<string id="SettingsConfirmTimeout">След това време (в секунди) диалоговият прозорец за потвърждение на действие се затваря автоматично и действието се отменя. Задайте 0, за да деактивирате изчакването.</string>
<string id="SettingsTextAlign">Ляво (изключено) или дясно (включено) подравняване на менюто.</string>
<string id="LeftToRight">Отляво надясно</string>
<string id="RightToLeft">От дясно на ляво</string>
<string id="SettingsWidgetStart">(Само за джаджа) Автоматично стартирайте приложението от джаджата, без да чакате докосване.</string>
<string id="SettingsEnableBatteryLevel">Активирайте услугата на заден план, за да изпраща данни за нивото на батерията на устройството, местоположението и (ако се поддържа) за дейността до Home Assistant.</string>
<string id="SettingsBatteryLevelRefreshRate">Честотата на опресняване (в минути), с която фоновата услуга трябва да повтори изпращането на данни.</string>
<string id="WebhookId">(Само за четене) Идентификаторът на Webhook, създаден от устройството за актуализации на фонови услуги. Може да ви е необходимо това за отстраняване на грешки.</string>
<string id="WebhookId">(Само за четене) Идентификационният номер на Webhook, създаден от устройството за актуализации на фонови услуги. Може да ви е необходимо това за отстраняване на грешки.</string>
</strings>

View File

@@ -20,5 +20,5 @@
<strings>
<string id="Confirm">Určitě?</string>
<string id="Available">Dostupné</string>
<string id="Menu">Menu</string>
<string id="GlanceMenu">Menu</string>
</strings>

View File

@@ -20,28 +20,28 @@
<strings>
<string id="AppName" scope="glance">HomeAssistant</string>
<string id="Confirm">Tak určitě?</string>
<string id="Confirm">Určitě?</string>
<string id="Executed" scope="glance">Potvrzeno</string>
<string id="NoPhone" scope="glance">Žádné telefonní spojení</string>
<string id="NoInternet">Žádné internetové připojení</string>
<string id="NoResponse">Žádná odpověď, zkontrolujte připojení k internetu</string>
<string id="NoAPIKey" scope="glance">V nastavení aplikace není žádný klíč API</string>
<string id="NoAPIKey" scope="glance">V nastavení aplikace není klíč API</string>
<string id="NoApiUrl" scope="glance">V nastavení aplikace není žádná adresa URL API</string>
<string id="NoConfigUrl" scope="glance">V nastavení aplikace není žádná konfigurační URL</string>
<string id="ApiFlood">Příliš rychlá volání API. Zpomalte prosím své požadavky.</string>
<string id="ApiUrlNotFound">Adresa URL nenalezena. Potenciální chyba adresy URL rozhraní API v nastavení.</string>
<string id="ConfigUrlNotFound">Adresa URL nenalezena. Potenciální chyba konfigurační adresy URL v nastavení.</string>
<string id="ApiUrlNotFound">Adresa URL nebyla nalezena. Potenciální chyba adresy URL rozhraní API v nastavení.</string>
<string id="ConfigUrlNotFound">Adresa URL nebyla nalezena. Potenciální chyba konfigurační adresy URL v nastavení.</string>
<string id="NoJson">Z požadavku HTTP se nevrátil žádný JSON.</string>
<string id="UnhandledHttpErr">Požadavek HTTP vrátil kód chyby =</string>
<string id="TrailingSlashErr">Adresa URL rozhraní API nesmí mít koncové lomítko „/“</string>
<string id="WebhookFailed">Registrace Webhooku se nezdařila</string>
<string id="TemplateError">Vykreslení šablony se nezdařilo</string>
<string id="Available" scope="glance">Dostupný</string>
<string id="Available" scope="glance">Dostupné</string>
<string id="Checking" scope="glance">Kontrola...</string>
<string id="Unavailable" scope="glance">Není k dispozici</string>
<string id="Unconfigured" scope="glance">Nenakonfigurováno</string>
<string id="Cached" scope="glance">Uloženo do mezipaměti</string>
<string id="GlanceMenu" scope="glance">Jídelní lístek</string>
<string id="GlanceMenu" scope="glance">Menu</string>
<string id="Memory" scope="glance">Paměť</string>
<!-- Pro nastavení GUI -->
<string id="SettingsSelect">Vybrat...</string>

View File

@@ -15,7 +15,7 @@
<!--
Generated by Google Translate: English to Estonian
Inglise keelest loodud Google'i tõlke abil
Loodud Google'i tõlke abil inglise keelest
-->
<strings>
@@ -28,13 +28,13 @@
<string id="NoAPIKey" scope="glance">Rakenduse seadetes pole API-võtit</string>
<string id="NoApiUrl" scope="glance">Rakenduse seadetes pole API URL-i</string>
<string id="NoConfigUrl" scope="glance">Rakenduse seadetes pole konfiguratsiooni URL-i</string>
<string id="ApiFlood">API-kutsed liiga kiired. Palun aeglustage taotluste esitamist.</string>
<string id="ApiFlood">API-kutsed liiga kiired. Palun aeglustage oma taotlusi.</string>
<string id="ApiUrlNotFound">URL-i ei leitud. Võimalik API URL-i viga seadetes.</string>
<string id="ConfigUrlNotFound">URL-i ei leitud. Võimalik konfiguratsiooni URL-i viga seadetes.</string>
<string id="NoJson">HTTP päringust ei tagastatud ühtegi JSON-i.</string>
<string id="NoJson">HTTP-päringust ei tagastatud ühtegi JSON-i.</string>
<string id="UnhandledHttpErr">HTTP päring tagastas veakoodi =</string>
<string id="TrailingSlashErr">API URL-i lõpus ei tohi olla kaldkriipsu „/”</string>
<string id="WebhookFailed">Veebihaagi registreerimine ebaõnnestus</string>
<string id="WebhookFailed">Webhaoki registreerimine ebaõnnestus</string>
<string id="TemplateError">Malli renderdamine ebaõnnestus</string>
<string id="Available" scope="glance">Saadaval</string>
<string id="Checking" scope="glance">Kontrollimine...</string>
@@ -59,7 +59,7 @@
<string id="LeftToRight">Vasakult paremale</string>
<string id="RightToLeft">Paremalt vasakule</string>
<string id="SettingsWidgetStart">(Ainult vidin) Käivitage rakendus automaatselt vidinast ilma puudutust ootamata.</string>
<string id="SettingsEnableBatteryLevel">Lubage taustateenus, et saata Home Assistantile seadme aku tase, asukoht ja (kui see on toetatud) tegevusandmed.</string>
<string id="SettingsEnableBatteryLevel">Lubage taustteenus, et saata Home Assistantile seadme aku tase, asukoht ja (kui see on toetatud) tegevusandmed.</string>
<string id="SettingsBatteryLevelRefreshRate">Värskendussagedus (minutites), millega taustateenus peaks andmete saatmist kordama.</string>
<string id="WebhookId">(Ainult lugemiseks) Seadme loodud veebihaagi ID taustateenuste värskenduste jaoks. Võib-olla vajate seda silumiseks.</string>
</strings>

View File

@@ -54,7 +54,7 @@
<string id="SettingsVibration">Pitäisikö sovelluksen antaa palautetta tärinän kautta?</string>
<string id="SettingsAppTimeout">Aikakatkaisu sekunneissa. Poistu sovelluksesta tämän käyttämättömyyden jälkeen säästääksesi laitteen akkua.</string>
<string id="SettingsPollDelay">Ylimääräinen kyselyn viive (sekunneissa). Lisää viiveen kaikkien valikkokohtien tilapäivitysten välille.</string>
<string id="SettingsConfirmTimeout">Tämän ajan kuluttua (sekunneissa) toiminnon vahvistusikkuna suljetaan automaattisesti ja toiminto peruutetaan. Aseta arvoksi 0, jos haluat poistaa aikakatkaisun käytöstä.</string>
<string id="SettingsConfirmTimeout">Tämän ajan kuluttua (sekunneissa) toiminnon vahvistusikkuna suljetaan automaattisesti ja toiminto peruutetaan. Aseta arvoksi 0 poistaaksesi aikakatkaisun käytöstä.</string>
<string id="SettingsTextAlign">Vasen (pois) tai oikea (päällä) valikon kohdistus.</string>
<string id="LeftToRight">Vasemmalta oikealle</string>
<string id="RightToLeft">Oikealta vasemmalle</string>

View File

@@ -48,18 +48,18 @@
<string id="SettingsApiKey">מפתח API עבור HomeAssistant.</string>
<string id="SettingsApiKeyPrompt">אסימון גישה ארוך-חיים.</string>
<string id="SettingsApiUrl">כתובת URL עבור HomeAssistant API.</string>
<string id="SettingsConfigUrl">כתובת URL עבור תצורת תפריט (JSON).</string>
<string id="SettingsConfigUrl">כתובת URL לתצורת תפריט (JSON).</string>
<string id="SettingsCacheConfig">האם האפליקציה צריכה לשמור את תצורת התפריט במטמון?</string>
<string id="SettingsClearCache">האם היישום צריך לנקות את המטמון הקיים בפעם הבאה שהוא יופעל?</string>
<string id="SettingsVibration">האם האפליקציה צריכה לספק משוב באמצעות רעידות?</string>
<string id="SettingsAppTimeout">פסק זמן בשניות. צא מהאפליקציה לאחר תקופה זו של חוסר פעילות כדי לחסוך בסוללת המכשיר.</string>
<string id="SettingsPollDelay">עיכוב נוסף בסקר (בשניות). מוסיף עיכוב בין עדכון המצב של כל פריטי התפריט.</string>
<string id="SettingsConfirmTimeout">לאחר זמן זה (בשניות), תיבת דו-שיח לאישור פעולה נסגרת אוטומטית והפעולה מבוטלת. הגדר ל-0 כדי לבטל את הזמן הקצוב.</string>
<string id="SettingsConfirmTimeout">לאחר זמן זה (בשניות), תיבת דו-שיח לאישור פעולה נסגרת אוטומטית והפעולה מבוטלת. הגדר ל-0 כדי להשבית את הזמן הקצוב.</string>
<string id="SettingsTextAlign">יישור תפריט שמאלה (כבוי) או ימינה (מופעל).</string>
<string id="LeftToRight">משמאל לימין</string>
<string id="RightToLeft">מימין לשמאל</string>
<string id="SettingsWidgetStart">(יישומון בלבד) הפעל אוטומטית את האפליקציה מהווידג'ט מבלי לחכות להקשה.</string>
<string id="SettingsEnableBatteryLevel">אפשר את שירות הרקע כדי לשלוח את נתוני רמת הסוללה של המכשיר, המיקום (אם נתמכים) ל-Home Assistant.</string>
<string id="SettingsBatteryLevelRefreshRate">קצב הרענון (בדקות) שבו שירות הרקע צריך לחזור על שליחת נתונים.</string>
<string id="WebhookId">(לקריאה בלבד) מזהה ה-Webhook שנוצר על ידי המכשיר עבור עדכוני שירות ברקע. ייתכן שתדרוש את זה בשביל איתור באגים.</string>
<string id="WebhookId">(לקריאה בלבד) מזהה ה-Webhook שנוצר על ידי המכשיר עבור עדכוני שירות ברקע. ייתכן שתדרוש זאת לצורך איתור באגים.</string>
</strings>

View File

@@ -40,11 +40,11 @@
<string id="Checking" scope="glance">Ellenőrzés...</string>
<string id="Unavailable" scope="glance">Nem érhető el</string>
<string id="Unconfigured" scope="glance">Nincs konfigurálva</string>
<string id="Cached" scope="glance">Gyorsítótárazott</string>
<string id="Cached" scope="glance">Gyorsítótárban</string>
<string id="GlanceMenu" scope="glance">Menü</string>
<string id="Memory" scope="glance">memória</string>
<!-- A beállítások GUI-hoz -->
<string id="SettingsSelect">Válassz...</string>
<string id="SettingsSelect">Válasszon...</string>
<string id="SettingsApiKey">API-kulcs a HomeAssistant számára.</string>
<string id="SettingsApiKeyPrompt">Hosszú életű hozzáférési token.</string>
<string id="SettingsApiUrl">A HomeAssistant API URL-je.</string>
@@ -58,7 +58,7 @@
<string id="SettingsTextAlign">Balra (ki) vagy Jobbra (be) Menüigazítás.</string>
<string id="LeftToRight">Balról jobbra</string>
<string id="RightToLeft">Jobbról balra</string>
<string id="SettingsWidgetStart">(Csak Widget) Az alkalmazás automatikus indítása a widgetről anélkül, hogy egy érintésre várna.</string>
<string id="SettingsWidgetStart">(Csak widget) Az alkalmazás automatikus indítása a widgetről anélkül, hogy egy érintésre várna.</string>
<string id="SettingsEnableBatteryLevel">Engedélyezze a háttérszolgáltatást, hogy elküldje az eszköz akkumulátorának töltöttségi szintjét, helyét és (ha támogatott) tevékenységi adatait a Home Assistantnek.</string>
<string id="SettingsBatteryLevelRefreshRate">Az a frissítési gyakoriság (percben), amellyel a háttérszolgáltatásnak meg kell ismételnie az adatok küldését.</string>
<string id="WebhookId">(Csak olvasható) Az eszköz által a háttérszolgáltatás frissítéséhez létrehozott Webhook-azonosító. Erre szükség lehet a hibakereséshez.</string>

View File

@@ -27,7 +27,7 @@
<string id="NoResponse">Tidak Ada Respon, periksa koneksi Internet</string>
<string id="NoAPIKey" scope="glance">Tidak ada kunci API di pengaturan aplikasi</string>
<string id="NoApiUrl" scope="glance">Tidak ada URL API di pengaturan aplikasi</string>
<string id="NoConfigUrl" scope="glance">Tidak ada URL konfigurasi di pengaturan aplikasi</string>
<string id="NoConfigUrl" scope="glance">Tidak ada URL konfigurasi dalam pengaturan aplikasi</string>
<string id="ApiFlood">Panggilan API terlalu cepat. Harap memperlambat permintaan Anda.</string>
<string id="ApiUrlNotFound">URL tidak ditemukan. Potensi kesalahan URL API dalam pengaturan.</string>
<string id="ConfigUrlNotFound">URL tidak ditemukan. Potensi kesalahan URL Konfigurasi dalam pengaturan.</string>

View File

@@ -46,7 +46,7 @@
<!-- 設定GUIの場合 -->
<string id="SettingsSelect">選択する...</string>
<string id="SettingsApiKey">ホームアシスタントの API キー。</string>
<string id="SettingsApiKeyPrompt">有効期の長いアクセス トークン。</string>
<string id="SettingsApiKeyPrompt">有効期の長いアクセス トークン。</string>
<string id="SettingsApiUrl">ホームアシスタント API の URL。</string>
<string id="SettingsConfigUrl">メニュー構成の URL (JSON)。</string>
<string id="SettingsCacheConfig">アプリケーションはメニュー構成をキャッシュする必要がありますか?</string>

View File

@@ -55,7 +55,7 @@
<string id="SettingsAppTimeout">Taimauts sekundēs. Pēc šī neaktivitātes perioda izejiet no lietojumprogrammas, lai taupītu ierīces akumulatoru.</string>
<string id="SettingsPollDelay">Papildu aptaujas aizkave (sekundēs). Pievieno aizkavi starp visu izvēlnes vienumu statusa atjaunināšanu.</string>
<string id="SettingsConfirmTimeout">Pēc šī laika (sekundēs) tiek automātiski aizvērts darbības apstiprinājuma dialoglodziņš un darbība tiek atcelta. Iestatiet uz 0, lai atspējotu taimautu.</string>
<string id="SettingsTextAlign">Kreisā (izslēgta) vai labā (ieslēgta) izvēlnes izlīdzināšana.</string>
<string id="SettingsTextAlign">Kreisā (izslēgta) vai labā (ieslēgta) izvēlnes līdzināšana.</string>
<string id="LeftToRight">No kreisās uz labo</string>
<string id="RightToLeft">No labās uz kreiso</string>
<string id="SettingsWidgetStart">(tikai logrīkam) Automātiski startējiet lietojumprogrammu no logrīka, negaidot pieskārienu.</string>

View File

@@ -20,7 +20,7 @@
<strings>
<string id="AppName" scope="glance">HomeAssistant</string>
<string id="Confirm">Žinoma?</string>
<string id="Confirm">Aišku?</string>
<string id="Executed" scope="glance">Patvirtinta</string>
<string id="NoPhone" scope="glance">Nėra telefono ryšio</string>
<string id="NoInternet">Nėra interneto ryšio</string>
@@ -34,7 +34,7 @@
<string id="NoJson">Joks JSON negrąžintas iš HTTP užklausos.</string>
<string id="UnhandledHttpErr">HTTP užklausa grąžino klaidos kodą =</string>
<string id="TrailingSlashErr">API URL pabaigoje negali būti pasvirojo brūkšnio „/“</string>
<string id="WebhookFailed">Nepavyko užregistruoti Webhook</string>
<string id="WebhookFailed">Nepavyko užregistruoti Webhook“.</string>
<string id="TemplateError">Nepavyko pateikti šablono</string>
<string id="Available" scope="glance">Galima</string>
<string id="Checking" scope="glance">Tikrinama...</string>
@@ -45,12 +45,12 @@
<string id="Memory" scope="glance">Atmintis</string>
<!-- Dėl nustatymų GUI -->
<string id="SettingsSelect">Pasirinkite...</string>
<string id="SettingsApiKey">API raktas, skirtas HomeAssistant.</string>
<string id="SettingsApiKey">API raktas, skirtas HomeAssistant.</string>
<string id="SettingsApiKeyPrompt">Ilgalaikis prieigos raktas.</string>
<string id="SettingsApiUrl">„HomeAssistant“ API URL.</string>
<string id="SettingsConfigUrl">Meniu konfigūravimo URL (JSON).</string>
<string id="SettingsCacheConfig">Ar programa turėtų talpykloje išsaugoti meniu konfigūraciją?</string>
<string id="SettingsClearCache">Ar programa turėtų išvalyti esamą talpyklą kitą kartą paleidus?</string>
<string id="SettingsCacheConfig">Ar programa turėtų išsaugoti meniu konfigūraciją talpykloje?</string>
<string id="SettingsClearCache">Ar kitą kartą paleisdama programa turėtų išvalyti esamą talpyklą?</string>
<string id="SettingsVibration">Ar programa turėtų teikti grįžtamąjį ryšį per vibraciją?</string>
<string id="SettingsAppTimeout">Skirtasis laikas sekundėmis. Po šio neveiklumo laikotarpio išeikite iš programos, kad taupytumėte įrenginio akumuliatorių.</string>
<string id="SettingsPollDelay">Papildoma apklausos delsa (sekundėmis). Prideda delsą tarp visų meniu elementų būsenos atnaujinimo.</string>
@@ -58,7 +58,7 @@
<string id="SettingsTextAlign">Kairysis (išjungtas) arba dešinysis (įjungtas) meniu lygiavimas.</string>
<string id="LeftToRight">Iš kairės į dešinę</string>
<string id="RightToLeft">Iš dešinės į kairę</string>
<string id="SettingsWidgetStart">(Tik valdikliui) Automatiškai paleiskite programą iš valdiklio, nelaukdami, kol bus palietus.</string>
<string id="SettingsWidgetStart">(Tik valdiklis) Automatiškai paleiskite programą iš valdiklio, nelaukdami palietimo.</string>
<string id="SettingsEnableBatteryLevel">Įgalinkite foninę paslaugą, kad į „Home Assistant“ būtų išsiųsti įrenginio akumuliatoriaus lygio, vietos ir (jei palaikoma) veiklos duomenys.</string>
<string id="SettingsBatteryLevelRefreshRate">Atnaujinimo dažnis (minutėmis), kuriuo foninė paslauga turėtų pakartoti duomenų siuntimą.</string>
<string id="WebhookId">(Tik skaitoma) Įrenginio sukurtas „Webhook“ ID, skirtas foninėms paslaugoms atnaujinti. Jums gali prireikti derinimo.</string>

View File

@@ -53,7 +53,7 @@
<string id="SettingsClearCache">Czy aplikacja powinna wyczyścić istniejącą pamięć podręczną przy następnym uruchomieniu?</string>
<string id="SettingsVibration">Czy aplikacja powinna przekazywać informację zwrotną za pomocą wibracji?</string>
<string id="SettingsAppTimeout">Limit czasu w sekundach. Wyjdź z aplikacji po tym okresie bezczynności, aby oszczędzać baterię urządzenia.</string>
<string id="SettingsPollDelay">Dodatkowe opóźnienie odpytywania (w sekundach). Dodaje opóźnienie pomiędzy aktualizacją stanu wszystkich pozycji menu.</string>
<string id="SettingsPollDelay">Dodatkowe opóźnienie odpytywania (w sekundach). Dodaje opóźnienie pomiędzy aktualizacją statusu wszystkich pozycji menu.</string>
<string id="SettingsConfirmTimeout">Po tym czasie (w sekundach) okno dialogowe z potwierdzeniem akcji zamyka się automatycznie, a akcja zostaje anulowana. Ustaw na 0, aby wyłączyć limit czasu.</string>
<string id="SettingsTextAlign">Wyrównanie menu do lewej (wyłączone) lub do prawej (włączone).</string>
<string id="LeftToRight">Od lewej do prawej</string>
@@ -61,5 +61,5 @@
<string id="SettingsWidgetStart">(Tylko widget) Automatycznie uruchamiaj aplikację z widgetu, bez czekania na dotknięcie.</string>
<string id="SettingsEnableBatteryLevel">Włącz usługę działającą w tle, aby wysyłać dane dotyczące poziomu naładowania baterii urządzenia, lokalizacji i (jeśli są obsługiwane) do Home Assistant.</string>
<string id="SettingsBatteryLevelRefreshRate">Częstotliwość odświeżania (w minutach), z jaką usługa działająca w tle powinna powtarzać wysyłanie danych.</string>
<string id="WebhookId">(Tylko do odczytu) Identyfikator webhooka utworzony przez urządzenie na potrzeby aktualizacji usług w tle. Możesz tego potrzebować do debugowania.</string>
<string id="WebhookId">(Tylko do odczytu) Identyfikator webhook utworzony przez urządzenie na potrzeby aktualizacji usług w tle. Możesz tego potrzebować do debugowania.</string>
</strings>

View File

@@ -28,9 +28,9 @@
<string id="NoAPIKey" scope="glance">Nicio cheie API în setările aplicației</string>
<string id="NoApiUrl" scope="glance">Nicio adresă URL API în setările aplicației</string>
<string id="NoConfigUrl" scope="glance">Nicio adresă URL de configurare în setările aplicației</string>
<string id="ApiFlood">Apeluri API prea rapide. Vă rugăm să încetiniți cererile dvs.</string>
<string id="ApiUrlNotFound">Adresa URL nu a fost găsită. Potențială eroare URL API în setări.</string>
<string id="ConfigUrlNotFound">Adresa URL nu a fost găsită. Potențială eroare URL de configurare în setări.</string>
<string id="ApiFlood">Apeluri API prea rapide. Vă rugăm să încetiniți solicitările.</string>
<string id="ApiUrlNotFound">URL nu a fost găsit. Potențială eroare URL API în setări.</string>
<string id="ConfigUrlNotFound">URL nu a fost găsit. Potențială eroare URL de configurare în setări.</string>
<string id="NoJson">Niciun JSON nu a fost returnat de la solicitarea HTTP.</string>
<string id="UnhandledHttpErr">Solicitarea HTTP a returnat codul de eroare =</string>
<string id="TrailingSlashErr">Adresa URL API nu trebuie să aibă o bară oblică „/”</string>

View File

@@ -20,11 +20,11 @@
<strings>
<string id="Confirm">Potvrďte</string>
<string id="Executed" scope="glance">Spustený</string>
<string id="NoAPIKey" scope="glance">V nastaveniach aplikácie chýba kľúč API</string>
<string id="NoApiUrl" scope="glance">V nastaveniach aplikácie chýba adresa URL rozhrania API</string>
<string id="NoConfigUrl" scope="glance">V nastaveniach aplikácie chýba konfiguračná adresa URL</string>
<string id="Unavailable" scope="glance">Nedostupné</string>
<string id="Executed">Spustený</string>
<string id="NoAPIKey">V nastaveniach aplikácie chýba kľúč API</string>
<string id="NoApiUrl">V nastaveniach aplikácie chýba adresa URL rozhrania API</string>
<string id="NoConfigUrl">V nastaveniach aplikácie chýba konfiguračná adresa URL</string>
<string id="Unavailable">Nedostupné</string>
<string id="RightToLeft">Sprava doľava</string>
<string id="SettingsEnableBatteryLevel">Povoľte službu na pozadí, ktorá bude do Home Assistenta odosielať údaje o stave batérie zariadenia, polohe a (ak je podporované) o aktivite.</string>
</strings>

View File

@@ -36,7 +36,7 @@
<string id="TrailingSlashErr">Adresa URL rozhrania API nesmie obsahovať koncovú lomku „/“</string>
<string id="WebhookFailed">Registrácia Webhooku zlyhala</string>
<string id="TemplateError">Vykreslenie šablóny zlyhalo</string>
<string id="Available" scope="glance">Dostupné</string>
<string id="Available" scope="glance">K dispozícii</string>
<string id="Checking" scope="glance">Prebieha kontrola...</string>
<string id="Unavailable" scope="glance">Nedostupné</string>
<string id="Unconfigured" scope="glance">Nekonfigurované</string>
@@ -54,7 +54,7 @@
<string id="SettingsVibration">Mala by aplikácia poskytovať spätnú väzbu prostredníctvom vibrácií?</string>
<string id="SettingsAppTimeout">Časový limit v sekundách. Po tejto dobe nečinnosti ukončite aplikáciu, aby ste šetrili batériu zariadenia.</string>
<string id="SettingsPollDelay">Dodatočné oneskorenie hlasovania (v sekundách). Pridáva oneskorenie medzi aktualizáciou stavu všetkých položiek ponuky.</string>
<string id="SettingsConfirmTimeout">Po tomto čase (v sekundách) sa dialógové okno s potvrdením akcie automaticky zatvorí a akcia sa zruší. Ak chcete časový limit deaktivovať, nastavte na 0.</string>
<string id="SettingsConfirmTimeout">Po tomto čase (v sekundách) sa dialógové okno s potvrdením akcie automaticky zatvorí a akcia sa zruší. Ak chcete vypnúť časový limit, nastavte na 0.</string>
<string id="SettingsTextAlign">Zarovnanie ponuky vľavo (vypnuté) alebo vpravo (zapnuté).</string>
<string id="LeftToRight">Zľava doprava</string>
<string id="RightToLeft">Sprava doľava</string>

View File

@@ -47,7 +47,7 @@
<string id="SettingsSelect">Izberite ...</string>
<string id="SettingsApiKey">API ključ za HomeAssistant.</string>
<string id="SettingsApiKeyPrompt">Dolgoživ dostopni žeton.</string>
<string id="SettingsApiUrl">URL za API HomeAssistant.</string>
<string id="SettingsApiUrl">URL za HomeAssistant API.</string>
<string id="SettingsConfigUrl">URL za konfiguracijo menija (JSON).</string>
<string id="SettingsCacheConfig">Ali naj aplikacija predpomni konfiguracijo menija?</string>
<string id="SettingsClearCache">Ali naj aplikacija ob naslednjem zagonu počisti obstoječi predpomnilnik?</string>

View File

@@ -52,7 +52,7 @@
<string id="SettingsCacheConfig">Ska programmet cachelagra menykonfigurationen?</string>
<string id="SettingsClearCache">Ska programmet rensa den befintliga cachen nästa gång den startas?</string>
<string id="SettingsVibration">Ska applikationen ge feedback via vibrationer?</string>
<string id="SettingsAppTimeout">Timeout sekunder. Avsluta programmet efter denna period av inaktivitet för att spara enhetens batteri.</string>
<string id="SettingsAppTimeout">Timeout i sekunder. Avsluta programmet efter denna period av inaktivitet för att spara enhetens batteri.</string>
<string id="SettingsPollDelay">Ytterligare fördröjning (i sekunder). Lägger till en fördröjning mellan statusuppdateringen av alla menyalternativ.</string>
<string id="SettingsConfirmTimeout">Efter denna tid (i sekunder) stängs en bekräftelsedialog för en åtgärd automatiskt och åtgärden avbryts. Ställ in på 0 för att inaktivera timeout.</string>
<string id="SettingsTextAlign">Vänster (av) eller höger (på) menyjustering.</string>

View File

@@ -15,7 +15,7 @@
<!--
Generated by Google Translate: English to Ukrainian
Створено Google Translate з англійської
Згенеровано Google Translate з англійської
-->
<strings>
@@ -48,10 +48,10 @@
<string id="SettingsApiKey">Ключ API для HomeAssistant.</string>
<string id="SettingsApiKeyPrompt">Довговічний маркер доступу.</string>
<string id="SettingsApiUrl">URL для HomeAssistant API.</string>
<string id="SettingsConfigUrl">URL для налаштування меню (JSON).</string>
<string id="SettingsConfigUrl">URL-адреса для налаштування меню (JSON).</string>
<string id="SettingsCacheConfig">Чи має програма кешувати конфігурацію меню?</string>
<string id="SettingsClearCache">Чи слід програмі очистити наявний кеш під час наступного запуску?</string>
<string id="SettingsVibration">Чи має програма надавати зворотній зв’язок за допомогою вібрації?</string>
<string id="SettingsVibration">Чи має додаток надавати зворотній зв’язок за допомогою вібрації?</string>
<string id="SettingsAppTimeout">Час очікування в секундах. Вийдіть із програми після цього періоду бездіяльності, щоб заощадити батарею пристрою.</string>
<string id="SettingsPollDelay">Додаткова затримка опитування (у секундах). Додає затримку між оновленням статусу всіх пунктів меню.</string>
<string id="SettingsConfirmTimeout">Після закінчення цього часу (у секундах) діалогове вікно підтвердження дії автоматично закривається, а дія скасовується. Встановіть 0, щоб вимкнути тайм-аут.</string>

View File

@@ -59,7 +59,7 @@
<string id="LeftToRight">左至右</string>
<string id="RightToLeft">右到左</string>
<string id="SettingsWidgetStart">(僅限小部件)從小部件自動啟動應用程序,無需等待點擊。</string>
<string id="SettingsEnableBatteryLevel">啟用後台服務將裝置電池電量、位置和(如果支援)活動資料傳送 Home Assistant。</string>
<string id="SettingsEnableBatteryLevel">啟用後台服務將裝置電池電量、位置和(如果支援)活動資料傳送 Home Assistant。</string>
<string id="SettingsBatteryLevelRefreshRate">後台服務應重複傳送資料的更新率(以分鐘為單位)。</string>
<string id="WebhookId">(唯讀)裝置為後台服務更新所建立的 Webhook ID。您可能需要它來進行調試。</string>
</strings>

View File

@@ -51,7 +51,7 @@
<string id="SettingsConfigUrl">URL untuk konfigurasi menu (JSON).</string>
<string id="SettingsCacheConfig">Sekiranya aplikasi cache konfigurasi menu?</string>
<string id="SettingsClearCache">Patutkah aplikasi mengosongkan cache sedia ada pada kali seterusnya ia dimulakan?</string>
<string id="SettingsVibration">Patutkah aplikasi memberikan maklum balas melalui getaran?</string>
<string id="SettingsVibration">Sekiranya aplikasi memberikan maklum balas melalui getaran?</string>
<string id="SettingsAppTimeout">Tamat masa dalam beberapa saat. Keluar dari aplikasi selepas tempoh tidak aktif ini untuk menjimatkan bateri peranti.</string>
<string id="SettingsPollDelay">Kelewatan tinjauan pendapat tambahan (dalam beberapa saat). Menambah kelewatan antara kemas kini status semua item menu.</string>
<string id="SettingsConfirmTimeout">Selepas masa ini (dalam beberapa saat), dialog pengesahan untuk tindakan ditutup secara automatik dan tindakan itu dibatalkan. Tetapkan kepada 0 untuk melumpuhkan tamat masa.</string>

View File

@@ -23,6 +23,7 @@ using Toybox.Lang;
using Toybox.Application.Properties;
using Toybox.Background;
using Toybox.System;
using Toybox.Activity;
(:background)
class BackgroundServiceDelegate extends System.ServiceDelegate {
@@ -37,99 +38,81 @@ class BackgroundServiceDelegate extends System.ServiceDelegate {
Background.exit(null);
}
function onActivityCompleted(activity as { :sport as Activity.Sport, :subSport as Activity.SubSport }) as Void {
if (!System.getDeviceSettings().phoneConnected) {
// System.println("BackgroundServiceDelegate onActivityCompleted(): No Phone connection, skipping API call.");
} else if (!System.getDeviceSettings().connectionAvailable) {
// System.println("BackgroundServiceDelegate onActivityCompleted(): No Internet connection, skipping API call.");
} else {
// Ensure we're logging completion, i.e. ignore 'activity' parameter
// System.println("BackgroundServiceDelegate onActivityCompleted(): Event triggered");
doUpdate(-1, -1);
}
}
function onTemporalEvent() as Void {
if (!System.getDeviceSettings().phoneConnected) {
// System.println("BackgroundServiceDelegate onTemporalEvent(): No Phone connection, skipping API call.");
} else if (!System.getDeviceSettings().connectionAvailable) {
// System.println("BackgroundServiceDelegate onTemporalEvent(): No Internet connection, skipping API call.");
} else {
// System.println("BackgroundServiceDelegate onTemporalEvent(): Making API call.");
var position = Position.getInfo();
// System.println("BackgroundServiceDelegate onTemporalEvent(): gps: " + position.position.toDegrees());
// System.println("BackgroundServiceDelegate onTemporalEvent(): speed: " + position.speed);
// System.println("BackgroundServiceDelegate onTemporalEvent(): course: " + position.heading + "rad (" + (position.heading * 180 / Math.PI) + "°)");
// System.println("BackgroundServiceDelegate onTemporalEvent(): altitude: " + position.altitude);
// System.println("BackgroundServiceDelegate onTemporalEvent(): battery: " + System.getSystemStats().battery);
// System.println("BackgroundServiceDelegate onTemporalEvent(): charging: " + System.getSystemStats().charging);
// System.println("BackgroundServiceDelegate onTemporalEvent(): activity: " + Activity.getProfileInfo().name);
// Don't use Settings.* here as the object lasts < 30 secs and is recreated each time the background service is run
if (position.accuracy != Position.QUALITY_NOT_AVAILABLE && position.accuracy != Position.QUALITY_LAST_KNOWN) {
var accuracy = 0;
switch (position.accuracy) {
case Position.QUALITY_POOR:
accuracy = 500;
break;
case Position.QUALITY_USABLE:
accuracy = 100;
break;
case Position.QUALITY_GOOD:
accuracy = 10;
break;
}
Communications.makeWebRequest(
(Properties.getValue("api_url") as Lang.String) + "/webhook/" + (Properties.getValue("webhook_id") as Lang.String),
{
"type" => "update_location",
"data" => {
"gps" => position.position.toDegrees(),
"gps_accuracy" => accuracy,
"speed" => Math.round(position.speed),
"course" => Math.round(position.heading * 180 / Math.PI),
"altitude" => Math.round(position.altitude),
}
},
{
:method => Communications.HTTP_REQUEST_METHOD_POST,
:headers => {
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON
},
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
},
method(:onReturnBatteryUpdate)
);
}
var data = [
{
"state" => System.getSystemStats().battery,
"type" => "sensor",
"unique_id" => "battery_level"
},
{
"state" => System.getSystemStats().charging,
"type" => "binary_sensor",
"unique_id" => "battery_is_charging"
}
];
var activity = null;
var sub_activity = null;
if ((Activity has :getActivityInfo) and (Activity has :getProfileInfo)) {
var activity = Activity.getProfileInfo().sport;
var sub_activity = Activity.getProfileInfo().subSport;
activity = Activity.getProfileInfo().sport;
sub_activity = Activity.getProfileInfo().subSport;
// We need to check if we are actually tracking any activity as the enumerated type does not include "No Sport".
if ((Activity.getActivityInfo() != null) and
((Activity.getActivityInfo().elapsedTime == null) or
(Activity.getActivityInfo().elapsedTime == 0))) {
(Activity.getActivityInfo().elapsedTime == 0))) {
// Indicate no activity with -1, not part of Garmin's activity codes.
// https://developer.garmin.com/connect-iq/api-docs/Toybox/Activity.html#Sport-module
activity = -1;
sub_activity = -1;
}
data.add({
"state" => activity,
"type" => "sensor",
"unique_id" => "activity"
});
data.add({
"state" => sub_activity,
"type" => "sensor",
"unique_id" => "sub_activity"
});
}
// System.println("BackgroundServiceDelegate onTemporalEvent(): Event triggered, activity = " + activity + " sub_activity = " + sub_activity);
doUpdate(activity, sub_activity);
}
}
private function doUpdate(activity as Lang.Number or Null, sub_activity as Lang.Number or Null) {
// System.println("BackgroundServiceDelegate onTemporalEvent(): Making API call.");
var position = Position.getInfo();
// System.println("BackgroundServiceDelegate onTemporalEvent(): gps: " + position.position.toDegrees());
// System.println("BackgroundServiceDelegate onTemporalEvent(): speed: " + position.speed);
// System.println("BackgroundServiceDelegate onTemporalEvent(): course: " + position.heading + "rad (" + (position.heading * 180 / Math.PI) + "°)");
// System.println("BackgroundServiceDelegate onTemporalEvent(): altitude: " + position.altitude);
// System.println("BackgroundServiceDelegate onTemporalEvent(): battery: " + System.getSystemStats().battery);
// System.println("BackgroundServiceDelegate onTemporalEvent(): charging: " + System.getSystemStats().charging);
// System.println("BackgroundServiceDelegate onTemporalEvent(): activity: " + Activity.getProfileInfo().name);
// Don't use Settings.* here as the object lasts < 30 secs and is recreated each time the background service is run
if (position.accuracy != Position.QUALITY_NOT_AVAILABLE && position.accuracy != Position.QUALITY_LAST_KNOWN) {
var accuracy = 0;
switch (position.accuracy) {
case Position.QUALITY_POOR:
accuracy = 500;
break;
case Position.QUALITY_USABLE:
accuracy = 100;
break;
case Position.QUALITY_GOOD:
accuracy = 10;
break;
}
Communications.makeWebRequest(
(Properties.getValue("api_url") as Lang.String) + "/webhook/" + (Properties.getValue("webhook_id") as Lang.String),
{
"type" => "update_sensor_states",
"data" => data
"type" => "update_location",
"data" => {
"gps" => position.position.toDegrees(),
"gps_accuracy" => accuracy,
"speed" => Math.round(position.speed),
"course" => Math.round(position.heading * 180 / Math.PI),
"altitude" => Math.round(position.altitude),
}
},
{
:method => Communications.HTTP_REQUEST_METHOD_POST,
@@ -141,6 +124,47 @@ class BackgroundServiceDelegate extends System.ServiceDelegate {
method(:onReturnBatteryUpdate)
);
}
var data = [
{
"state" => System.getSystemStats().battery,
"type" => "sensor",
"unique_id" => "battery_level"
},
{
"state" => System.getSystemStats().charging,
"type" => "binary_sensor",
"unique_id" => "battery_is_charging"
}
];
if (activity != null) {
data.add({
"state" => activity,
"type" => "sensor",
"unique_id" => "activity"
});
}
if (sub_activity != null) {
data.add({
"state" => sub_activity,
"type" => "sensor",
"unique_id" => "sub_activity"
});
}
Communications.makeWebRequest(
(Properties.getValue("api_url") as Lang.String) + "/webhook/" + (Properties.getValue("webhook_id") as Lang.String),
{
"type" => "update_sensor_states",
"data" => data
},
{
:method => Communications.HTTP_REQUEST_METHOD_POST,
:headers => {
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON
},
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
},
method(:onReturnBatteryUpdate)
);
}
}

View File

@@ -27,17 +27,18 @@ using Toybox.Timer;
(:glance, :background)
class HomeAssistantApp extends Application.AppBase {
private var mApiStatus as Lang.String or Null;
private var mMenuStatus as Lang.String or Null;
private var mHaMenu as HomeAssistantView or Null;
private var mQuitTimer as QuitTimer or Null;
private var mGlanceTimer as Timer.Timer or Null;
private var mUpdateTimer as Timer.Timer or Null;
private var mApiStatus as Lang.String or Null;
private var mMenuStatus as Lang.String or Null;
private var mHaMenu as HomeAssistantView or Null;
private var mQuitTimer as QuitTimer or Null;
private var mGlanceTimer as Timer.Timer or Null;
private var mUpdateTimer as Timer.Timer or Null;
// Array initialised by onReturnFetchMenuConfig()
private var mItemsToUpdate as Lang.Array<HomeAssistantToggleMenuItem or HomeAssistantTemplateMenuItem> or Null;
private var mNextItemToUpdate as Lang.Number = 0; // Index into the above array
private var mIsGlance as Lang.Boolean = false;
private var mIsApp as Lang.Boolean = false; // Or Widget
private var mItemsToUpdate as Lang.Array<HomeAssistantToggleMenuItem or HomeAssistantTemplateMenuItem> or Null;
private var mNextItemToUpdate as Lang.Number = 0; // Index into the above array
private var mIsGlance as Lang.Boolean = false;
private var mIsApp as Lang.Boolean = false; // Or Widget
private var mIsInitUpdateCompl as Lang.Boolean = false;
function initialize() {
AppBase.initialize();
@@ -204,12 +205,13 @@ class HomeAssistantApp extends Application.AppBase {
// asynchronous and affects how the views are managed.
(:glance)
function fetchMenuConfig() as Lang.Boolean {
// System.println("URL = " + Settings.getConfigUrl());
if (Settings.getConfigUrl().equals("")) {
mMenuStatus = WatchUi.loadResource($.Rez.Strings.Unconfigured) as Lang.String;
WatchUi.requestUpdate();
} else {
var menu = Storage.getValue("menu") as Lang.Dictionary;
if (menu != null and Settings.getClearCache()) {
if (menu != null and (Settings.getClearCache() || !Settings.getCacheConfig())) {
Storage.deleteValue("menu");
menu = null;
Settings.unsetClearCache();
@@ -257,6 +259,9 @@ class HomeAssistantApp extends Application.AppBase {
private function buildMenu(menu as Lang.Dictionary) {
mHaMenu = new HomeAssistantView(menu, null);
mQuitTimer.begin();
}
function startUpdates() {
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.
@@ -396,20 +401,42 @@ class HomeAssistantApp extends Application.AppBase {
function updateNextMenuItem() as Void {
var delay = Settings.getPollDelay();
if ((delay > 0) and (mNextItemToUpdate == 0)) {
if (mIsInitUpdateCompl and (delay > 0) and (mNextItemToUpdate == 0)) {
mUpdateTimer.start(method(:updateNextMenuItemInternal), delay, false);
} else {
updateNextMenuItemInternal();
}
}
// Only call this function if Settings.getPollDelay() > 0. This must be tested locally as it is then efficient to take
// alternative action if the test fails.
function forceStatusUpdates() as Void {
// Don't mess with updates unless we are using a timer.
if (Settings.getPollDelay() > 0) {
mUpdateTimer.stop();
mIsInitUpdateCompl = false;
// Start from the beginning, or we will only get a partial round of updates before mIsInitUpdateCompl is flipped.
mNextItemToUpdate = 0;
// For immediate updates
updateNextMenuItem();
}
}
// We need to spread out the API calls so as not to overload the results queue and cause Communications.BLE_QUEUE_FULL
// (-101) error. This function is called by a timer every Globals.menuItemUpdateInterval ms.
function updateNextMenuItemInternal() as Void {
var itu = mItemsToUpdate as Lang.Array<HomeAssistantToggleMenuItem>;
if (itu != null) {
// System.println("HomeAssistantApp updateNextMenuItemInternal(): Doing update for item " + mNextItemToUpdate + ", mIsInitUpdateCompl=" + mIsInitUpdateCompl);
itu[mNextItemToUpdate].getState();
mNextItemToUpdate = (mNextItemToUpdate + 1) % itu.size();
// mNextItemToUpdate = (mNextItemToUpdate + 1) % itu.size() - But with roll-over detection
if (mNextItemToUpdate == itu.size()-1) {
// Last item completed return to the start of the list
mNextItemToUpdate = 0;
mIsInitUpdateCompl = true;
} else {
mNextItemToUpdate++;
}
// } else {
// System.println("HomeAssistantApp updateNextMenuItemInternal(): No menu items to update");
}

View File

@@ -80,6 +80,7 @@ class HomeAssistantService {
case 200:
// System.println("HomeAssistantService onReturnCall(): Service executed.");
getApp().forceStatusUpdates();
var d = data as Lang.Array;
var toast = WatchUi.loadResource($.Rez.Strings.Executed) as Lang.String;
for(var i = 0; i < d.size(); i++) {

View File

@@ -83,7 +83,7 @@ class HomeAssistantTemplateMenuItem extends WatchUi.IconMenuItem {
// Terminate updating the toggle menu items via the chain of calls for a permanent network
// error. The ErrorView cancellation will resume the call chain.
//
function onReturnGetState(responseCode as Lang.Number, data as Lang.String) as Void {
function onReturnGetState(responseCode as Lang.Number, data as Null or Lang.Dictionary) as Void {
// System.println("HomeAssistantTemplateMenuItem onReturnGetState() Response Code: " + responseCode);
// System.println("HomeAssistantTemplateMenuItem onReturnGetState() Response Data: " + data);
@@ -131,7 +131,7 @@ class HomeAssistantTemplateMenuItem extends WatchUi.IconMenuItem {
case 200:
status = WatchUi.loadResource($.Rez.Strings.Available) as Lang.String;
setSubLabel(data);
setSubLabel(data.get("request"));
requestUpdate();
// Now this feels very "closely coupled" to the application, but it is the most reliable method instead of using a timer.
getApp().updateNextMenuItem();
@@ -153,19 +153,28 @@ class HomeAssistantTemplateMenuItem extends WatchUi.IconMenuItem {
// System.println("HomeAssistantTemplateMenuItem getState(): No Internet connection, skipping API call.");
ErrorView.show(WatchUi.loadResource($.Rez.Strings.NoInternet) as Lang.String + ".");
getApp().setApiStatus(WatchUi.loadResource($.Rez.Strings.Unavailable) as Lang.String);
} else if (Settings.getWebhookId().equals("")) {
getApp().updateNextMenuItem();
} else {
var url = Settings.getApiUrl() + "/template";
// https://developers.home-assistant.io/docs/api/native-app-integration/sending-data/#render-templates
var url = Settings.getApiUrl() + "/webhook/" + Settings.getWebhookId();
// System.println("HomeAssistantTemplateMenuItem getState() URL=" + url + ", Template='" + mTemplate + "'");
Communications.makeWebRequest(
url,
{ "template" => mTemplate },
{
:method => Communications.HTTP_REQUEST_METHOD_POST,
:headers => {
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON,
"Authorization" => "Bearer " + Settings.getApiKey()
"type" => "render_template",
"data" => {
"request" => {
"template" => mTemplate
}
}
},
{
:method => Communications.HTTP_REQUEST_METHOD_POST,
:headers => {
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON
},
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_TEXT_PLAIN
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
},
method(:onReturnGetState)
);

View File

@@ -196,6 +196,8 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
break;
case 200:
// System.println("HomeAssistantToggleMenuItem onReturnSetState(): Service executed.");
getApp().forceStatusUpdates();
var state;
var d = data as Lang.Array;
for(var i = 0; i < d.size(); i++) {

View File

@@ -39,7 +39,7 @@ class Settings {
private static var mPollDelay as Lang.Number = 0; // seconds
private static var mConfirmTimeout as Lang.Number = 3; // seconds
private static var mMenuAlignment as Lang.Number = WatchUi.MenuItem.MENU_ITEM_LABEL_ALIGN_LEFT;
private static var mIsBatteryLevelEnabled as Lang.Boolean = false;
private static var mIsSensorsLevelEnabled as Lang.Boolean = false;
private static var mBatteryRefreshRate as Lang.Number = 15; // minutes
private static var mIsApp as Lang.Boolean = false;
private static var mHasService as Lang.Boolean = false;
@@ -60,7 +60,7 @@ class Settings {
mPollDelay = Properties.getValue("poll_delay");
mConfirmTimeout = Properties.getValue("confirm_timeout");
mMenuAlignment = Properties.getValue("menu_alignment");
mIsBatteryLevelEnabled = Properties.getValue("enable_battery_level");
mIsSensorsLevelEnabled = Properties.getValue("enable_battery_level");
mBatteryRefreshRate = Properties.getValue("battery_level_refresh_rate");
if (System has :ServiceDelegate) {
@@ -69,19 +69,42 @@ class Settings {
// Manage this inside the application or widget only (not a glance or background service process)
if (mIsApp) {
if (mIsBatteryLevelEnabled and mHasService) {
if (mHasService) {
mWebhookManager = new WebhookManager();
if (getWebhookId().equals("")) {
mWebhookManager = new WebhookManager();
// System.println("Settings update(): Doing full webhook & sensor creation.");
mWebhookManager.requestWebhookId();
} else {
// System.println("Settings update(): Doing just sensor creation.");
// We already have a Webhook ID, so just enable or disable the sensor in Home Assistant.
// Its a multiple step process, hence starting at step 0.
mWebhookManager.registerWebhookSensor({
"device_class" => "battery",
"name" => "Battery Level",
"state" => System.getSystemStats().battery,
"type" => "sensor",
"unique_id" => "battery_level",
"unit_of_measurement" => "%",
"state_class" => "measurement",
"entity_category" => "diagnostic",
"disabled" => !Settings.isSensorsLevelEnabled()
}, 0);
}
if ((Background.getTemporalEventRegisteredTime() == null) or
(Background.getTemporalEventRegisteredTime() != (mBatteryRefreshRate * 60))) {
Background.registerForTemporalEvent(new Time.Duration(mBatteryRefreshRate * 60)); // Convert to seconds
if (mIsSensorsLevelEnabled) {
// Create the timed activity
if ((Background.getTemporalEventRegisteredTime() == null) or
(Background.getTemporalEventRegisteredTime() != (mBatteryRefreshRate * 60))) {
Background.registerForTemporalEvent(new Time.Duration(mBatteryRefreshRate * 60)); // Convert to seconds
Background.registerForActivityCompletedEvent();
}
} else if (Background.getTemporalEventRegisteredTime() != null) {
Background.deleteTemporalEvent();
Background.deleteActivityCompletedEvent();
}
} else {
// Explicitly disable the background event which persists when the application closes.
// If !mHasService disable the Settings option as user feedback
unsetIsBatteryLevelEnabled();
unsetIsSensorsLevelEnabled();
unsetWebhookId();
}
}
@@ -152,11 +175,16 @@ class Settings {
return mMenuAlignment; // Either WatchUi.MenuItem.MENU_ITEM_LABEL_ALIGN_RIGHT or WatchUi.MenuItem.MENU_ITEM_LABEL_ALIGN_LEFT
}
static function unsetIsBatteryLevelEnabled() {
mIsBatteryLevelEnabled = false;
Properties.setValue("enable_battery_level", mIsBatteryLevelEnabled);
static function isSensorsLevelEnabled() as Lang.Boolean {
return mIsSensorsLevelEnabled;
}
static function unsetIsSensorsLevelEnabled() {
mIsSensorsLevelEnabled = false;
Properties.setValue("enable_battery_level", mIsSensorsLevelEnabled);
if (mHasService and (Background.getTemporalEventRegisteredTime() != null)) {
Background.deleteTemporalEvent();
Background.deleteActivityCompletedEvent();
}
}

View File

@@ -24,6 +24,7 @@
using Toybox.Lang;
using Toybox.Communications;
using Toybox.System;
using Toybox.WatchUi;
// Can use push view so must never be run in a glance context
class WebhookManager {
@@ -52,13 +53,13 @@ class WebhookManager {
break;
case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE:
// System.println("WebhookManager onReturnRequestWebhookId() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned.");
Settings.unsetIsBatteryLevelEnabled();
Settings.unsetIsSensorsLevelEnabled();
ErrorView.show(WatchUi.loadResource($.Rez.Strings.WebhookFailed) as Lang.String + "\n" + WatchUi.loadResource($.Rez.Strings.NoJson) as Lang.String);
break;
case 404:
// System.println("WebhookManager onReturnRequestWebhookId() Response Code: 404, page not found. Check API URL setting.");
Settings.unsetIsBatteryLevelEnabled();
Settings.unsetIsSensorsLevelEnabled();
ErrorView.show(WatchUi.loadResource($.Rez.Strings.WebhookFailed) as Lang.String + "\n" + WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound) as Lang.String);
break;
@@ -77,25 +78,25 @@ class WebhookManager {
"unit_of_measurement" => "%",
"state_class" => "measurement",
"entity_category" => "diagnostic",
"disabled" => false
"disabled" => !Settings.isSensorsLevelEnabled()
}, 0);
} else {
// System.println("WebhookManager onReturnRequestWebhookId(): No webhook id in response data.");
Settings.unsetIsBatteryLevelEnabled();
Settings.unsetIsSensorsLevelEnabled();
ErrorView.show(WatchUi.loadResource($.Rez.Strings.WebhookFailed) as Lang.String);
}
break;
default:
// System.println("WebhookManager onReturnRequestWebhookId(): Unhandled HTTP response code = " + responseCode);
Settings.unsetIsBatteryLevelEnabled();
Settings.unsetIsSensorsLevelEnabled();
ErrorView.show(WatchUi.loadResource($.Rez.Strings.WebhookFailed) as Lang.String + "\n" + WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr) as Lang.String + responseCode);
}
}
function requestWebhookId() {
// System.println("WebhookManager requestWebhookId(): Requesting webhook id");
var deviceSettings = System.getDeviceSettings();
// System.println("WebhookManager requestWebhookId(): Requesting webhook id for device = " + deviceSettings.uniqueIdentifier);
Communications.makeWebRequest(
Settings.getApiUrl() + "/mobile_app/registrations",
{
@@ -153,21 +154,24 @@ class WebhookManager {
case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE:
// System.println("WebhookManager onReturnRegisterWebhookSensor() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned.");
// Webhook ID might have been deleted on Home Assistant server
Settings.unsetWebhookId();
Settings.unsetIsBatteryLevelEnabled();
ErrorView.show(WatchUi.loadResource($.Rez.Strings.WebhookFailed) as Lang.String + "\n" + WatchUi.loadResource($.Rez.Strings.NoJson) as Lang.String);
// System.println("WebhookManager onReturnRegisterWebhookSensor(): Webhook ID invalid, going full chain.");
requestWebhookId();
break;
case 404:
// System.println("WebhookManager onReturnRequestWebhookId() Response Code: 404, page not found. Check API URL setting.");
// System.println("WebhookManager onReturnRegisterWebhookSensor() Response Code: 404, page not found. Check API URL setting.");
// Webhook ID might have been deleted on Home Assistant server
Settings.unsetWebhookId();
Settings.unsetIsBatteryLevelEnabled();
ErrorView.show(WatchUi.loadResource($.Rez.Strings.WebhookFailed) as Lang.String + "\n" + WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound) as Lang.String);
// System.println("WebhookManager onReturnRegisterWebhookSensor(): Webhook ID invalid, going full chain.");
requestWebhookId();
break;
case 200:
case 201:
if ((data.get("success") as Lang.Boolean or Null) != false) {
var d = data as Lang.Dictionary;
if ((d.get("success") as Lang.Boolean or Null) != false) {
// System.println("WebhookManager onReturnRegisterWebhookSensor(): Success");
switch (step) {
case 0:
@@ -179,7 +183,7 @@ class WebhookManager {
"type" => "binary_sensor",
"unique_id" => "battery_is_charging",
"entity_category" => "diagnostic",
"disabled" => false
"disabled" => !Settings.isSensorsLevelEnabled()
}, 1);
break;
case 1:
@@ -198,12 +202,12 @@ class WebhookManager {
"state" => activity,
"type" => "sensor",
"unique_id" => "activity",
"disabled" => false
"disabled" => !Settings.isSensorsLevelEnabled()
}, 2);
break;
}
case 2:
// System.println("WebhookManager onReturnRegisterWebhookSensor(): Registering next sensor: Activity");
// System.println("WebhookManager onReturnRegisterWebhookSensor(): Registering next sensor: Sub-Activity");
if (Activity has :getProfileInfo) {
var sub_activity = Activity.getProfileInfo().subSport;
if ((Activity.getActivityInfo() != null) and
@@ -218,16 +222,18 @@ class WebhookManager {
"state" => sub_activity,
"type" => "sensor",
"unique_id" => "sub_activity",
"disabled" => false
"disabled" => !Settings.isSensorsLevelEnabled()
}, 3);
break;
}
case 3:
getApp().startUpdates();
default:
}
} else {
// System.println("WebhookManager onReturnRegisterWebhookSensor(): Failure");
Settings.unsetWebhookId();
Settings.unsetIsBatteryLevelEnabled();
Settings.unsetIsSensorsLevelEnabled();
ErrorView.show(WatchUi.loadResource($.Rez.Strings.WebhookFailed) as Lang.String);
}
break;
@@ -235,15 +241,18 @@ class WebhookManager {
default:
// System.println("WebhookManager onReturnRequestWebhookId(): Unhandled HTTP response code = " + responseCode);
Settings.unsetWebhookId();
Settings.unsetIsBatteryLevelEnabled();
Settings.unsetIsSensorsLevelEnabled();
ErrorView.show(WatchUi.loadResource($.Rez.Strings.WebhookFailed) as Lang.String + "\n" + WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr) as Lang.String + responseCode);
}
}
function registerWebhookSensor(sensor as Lang.Object, step as Lang.Number) {
var url = Settings.getApiUrl() + "/webhook/" + Settings.getWebhookId();
// System.println("WebhookManager registerWebhookSensor(): Registering webhook sensor: " + sensor.toString());
// System.println("WebhookManager registerWebhookSensor(): URL=" + url);
// https://developers.home-assistant.io/docs/api/native-app-integration/sensors/#registering-a-sensor
Communications.makeWebRequest(
Settings.getApiUrl() + "/webhook/" + Settings.getWebhookId(),
url,
{
"type" => "register_sensor",
"data" => sensor