From a8c9085dc4a82b311e5de86fbfcf40576505031b Mon Sep 17 00:00:00 2001 From: Philip Abbey Date: Sat, 6 Jan 2024 21:16:53 +0000 Subject: [PATCH] Updated troubleshooting guide. Now includes battery level transmission debug. Co-Authored-By: Joseph Abbey --- README.md | 6 +- Troubleshooting.md | 160 ++++++++++++++++++++++++++-- images/api_test_online_battery1.png | Bin 0 -> 53880 bytes images/api_test_online_battery2.png | Bin 0 -> 69438 bytes 4 files changed, 153 insertions(+), 13 deletions(-) create mode 100644 images/api_test_online_battery1.png create mode 100644 images/api_test_online_battery2.png diff --git a/README.md b/README.md index 9af4cae..e0bd71b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ The application is designed around a simple scrollable menu where menu items hav It is important to note that your Home Assistant instance will need to be accessible via HTTPS with public SSL or all requests from the Garmin will not work. This cannot be a self-signed certificate, it must be a public certificate. You can get one for free from [Let's Encrypt](https://letsencrypt.org/) or you can pay for [Home Assistant cloud](https://www.nabucasa.com/). -**If you are struggling with getting the application to work, please consult the [trouble shooting](Troubleshooting.md) guide first.** +**If you are struggling with getting the application to work, please consult the [trouble shooting](Troubleshooting.md#menu-configuration-url) guide first.** + ## Widget or Application? @@ -267,7 +268,8 @@ The `id` attribute values are taken from the same names used in [`strings.xml`]( ## Battery Level Reporting -The application and widget both now include a background service to report your watch's battery level and charging status. This requires [significant setup](BatteryReporting.md) via YAML in Home Assistant to work. This is not for the feint hearted! We are keen to received improvements, but are reluctant to provide much in the way of support. The Home Assistant community, in particular the posts on the forum at [Bluetooth Battery Levels (Android)](https://community.home-assistant.io/t/bluetooth-battery-levels-android/661525), are your best source of support for this feature. +The application and widget both now include a background service to report your watch's battery level and charging status. This requires [significant setup](BatteryReporting.md) via YAML in Home Assistant to work. This is not for the feint hearted! We are keen to received improvements, but are reluctant to provide much in the way of support. The Home Assistant community, in particular the posts on the forum at [Bluetooth Battery Levels (Android)](https://community.home-assistant.io/t/bluetooth-battery-levels-android/661525), are your best source of support for this feature. We do however offer this [trouble shooting](Troubleshooting.md#watch-battery-level-reporting) guide. + ## Version History diff --git a/Troubleshooting.md b/Troubleshooting.md index 623150d..fa953a5 100644 --- a/Troubleshooting.md +++ b/Troubleshooting.md @@ -1,8 +1,10 @@ -# Troubleshooting Guide +# Troubleshooting Guides + +## Watch Menu and API With either of the following setups, there are inevitably some problems along the way. GarminHomeAssistant is careful to rely only on having working URLs. Getting them working is the user's responsibility. However, we have developed some fault finding tools. -## Nabu Casa Setup +### Nabu Casa Setup You can purchase cloud-based access to your Home Assistant from [Nabu Casa](https://www.nabucasa.com/), and then your setup will look something like this. @@ -13,7 +15,7 @@ You can purchase cloud-based access to your Home Assistant from [Nabu Casa](http Where `` is your personal Nabu Casa account ID. -## Do It Yourself Setup +### Do It Yourself Setup Before Nabu Casa, or if you wanted to manage your own infrastructure, you might have something like the following: @@ -38,7 +40,7 @@ http: - 172.16.0.0/12 # ``` -## Menu Configuration URL +### Menu Configuration URL This URL is very simple, you should be able to read the contents returned in a standard web browser. @@ -50,7 +52,7 @@ The browser page should then display the JSON string you saved to the file on th The menu configuration can be hosted anywhere, it does not have to be on the Home Assistant web server. Just as long as it is reachable from your phone from which you Bluetooth connect to your watch, or you watch if it has direct Internet access. -## Home Assistant API URL +### Home Assistant API URL This is slightly trickier owning to the need to supply the API key. Here are three ways you can test your API URL is correctly configured. If successful, each of these should produce a JSON string output looking like: @@ -58,7 +60,7 @@ This is slightly trickier owning to the need to supply the API key. Here are thr {"message":"API running."} ``` -### Linux, MacOS, UNIX, Cygwin etc +#### API: Linux, MacOS, UNIX, Cygwin etc Save the following as a file called `api_test.sh`, edit to include your personal values for the variables, `chmod +x api_test.sh` and then execute with `./api_test.sh`. @@ -74,11 +76,11 @@ curl -s -X GET \ ${URL}/ ``` -### MS Windows +#### API: MS Windows Save the following as a file called `api_test.cmd`, edit to include your personal values for the variables and then double click. -```shell +```cmd @echo off set API_KEY= @@ -95,13 +97,149 @@ pause ![API Test MS-DOS Output](images/api_test_dos_output.png) -### On-line +#### API: On-line There's an online way of testing the API URL too, thanks to [REQBIN](https://reqbin.com/post-online). This has less setup and it can be saved if you log into the web site. -![API Test MS-DOS Output](images/api_test_online.png) +![API Test REQBIN](images/api_test_online.png) -## Top Problems +### Top Problems 1. Failure to copy & paste keys and URLs leading to minor and hard to see errors in strings, even with protestations they are the same! (No they weren't...) 2. Accessibility of URLs, hence the above help guide. + +## Watch Battery Level Reporting + +For this you will need to have already got the main application or widget working with a menu in order to prove that the API calls are successful. We have proven this works with both our home brew infrastructure as well as Nabu Casa. Now with a script similar to one of the following two, you should be able to fake the watch API call and verify receipt by Home Assistant in the Event logging by clicking the following button. + +[![Open your Home Assistant instance and show your event developer tools.](https://my.home-assistant.io/badges/developer_events.svg)](https://my.home-assistant.io/redirect/developer_events/) + +#### Battery: Linux, MacOS, UNIX, Cygwin etc + +Assume a file called: `send_battery.bash` + +```shell +#!/bin/bash +# +# battery% charging {0|1} +# ./send_battery.bash 19 0 +# + +API_KEY="" +URL="https:///api" + +level=${1:-50} +is_charging=${2:-0} +echo "Battery Level = ${level}" +if [ ${is_charging} -eq 1 ]; then + is_charging=true +else + is_charging=false +fi +echo "Battery Charging? = ${is_charging}" +echo "" + +curl -s -X POST \ + -H "Authorization: Bearer ${API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{"level": '${level}', "is_charging": '${is_charging}', "device_id": "Bash Script"}' \ + ${URL}/events/garmin.battery_level +``` + +Execute: + +``` +$ ./send_battery.bash 45 1 +``` + +The output looks like this: + +``` +Battery Level = 45 +Battery Charging? = true + +{"message":"Event garmin.battery_level fired."} +``` + +NB. The device ID can be any string for the purposes of this testing. Your Garmin device will choose this ID for you when it submits the readings. + +#### Battery: MS Windows + +Assume a file called: `home_assistant_battery_level.cmd` + +```cmd +@echo off +rem battery% charging {0|1} +rem ./home_assistant_battery_level 19 0 +rem + +set API_KEY=FEt_fGzW_lV0xitvJPkaQHSLhGm90ADovgMbJxdHH2I +set URL=https:///api + +if [%1] == [] ( + set level=50 +) else ( + set level=%1 +) + +if [%1] == [] ( + set is_charging=0 +) else ( + set is_charging=%2 +) +echo "Battery Level = %level%" +if "%is_charging%"=="1" ( + set is_charging=true +) else ( + set is_charging=false +) +echo "Battery Charging? = %is_charging%" +echo. + +curl -s -X POST ^ + -H "Authorization: Bearer %API_KEY%" ^ + -H "Content-Type: application/json" ^ + -d "{\"level\": %level%, \"is_charging\": %is_charging%, \"device_id\": \"Batch File\"}" ^ + %URL%/events/garmin.battery_level + +echo. +pause +``` + +Execute: + +``` +> home_assistant_battery_level.cmd 41 1 +``` + +The output looks like this: + +``` +"Battery Level = 41" +"Battery Charging? = true" + +{"message":"Event garmin.battery_level fired."} +Press any key to continue . . . +``` + +NB. The device ID can be any string for the purposes of this testing. Your Garmin device will choose this ID for you when it submits the readings. + +#### Battery: On-line + +There's an online way of testing the API URL too, thanks to [REQBIN](https://reqbin.com/post-online). This has less setup and it can be saved if you log into the web site. + +URL for copy & paste: + +``` +https:///api/events/garmin.battery_level +``` + +![API Test REQBIN](images/api_test_online_battery1.png) + +JSON for copy & paste: + +```json +{"level": 19, "is_charging": true, "device_id": "REQBIN"} +``` + +![API Test REQBIN](images/api_test_online_battery2.png) diff --git a/images/api_test_online_battery1.png b/images/api_test_online_battery1.png new file mode 100644 index 0000000000000000000000000000000000000000..94696cd966a4d395c52991ca508525a50dcc0716 GIT binary patch literal 53880 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