mirror of
https://github.com/house-of-abbey/GarminHomeAssistant.git
synced 2026-07-08 20:03:29 +00:00
Compare commits
10 Commits
3e3f60c47c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1a2ca7c2c | ||
|
|
02a9472ac1 | ||
|
|
e0b5978406 | ||
|
|
c48d74138a | ||
|
|
3404c7f679 | ||
|
|
8c5bdbc1f8 | ||
|
|
a97440b997 | ||
|
|
17690d4349 | ||
|
|
b1fb5d9417 | ||
|
|
2fb59d2a56 |
@@ -59,3 +59,4 @@
|
||||
| 3.11 | <img src="images/Venu2_glance_default.png" width="200" title="Default Glance"/><br/>Better handling of menus larger than the Glance view can handle. As a result the Glance can no longer verify the availability of the JSON menu as fetching it might cause an _"Error: Out Of Memory Error"_. Provide two user supplied HTTP Headers. Bug fix for the numeric picker. |
|
||||
| 3.12 | Amended GPS accuracy values used by the background service. |
|
||||
| 3.13 | Added support for new devices: `d2mach2pro`, `fr170`, `fr170m`, `fr70`. |
|
||||
| 3.14 | Numeric items now support `tap_action.data` fields so service call options like `transition` are catered for. See the documentation on [Additional Action Data](https://github.com/house-of-abbey/GarminHomeAssistant/blob/main/examples/Numeric.md#additional-action-data). This features has been provided by [@StumblingGamer](https://github.com/StumblingGamer). Now prevent PIN enabled menu items from being enabled on non-touch screen devices. The PIN must be removed for the menu item to function. Fix for initialising numeric pickers with no user defined template. |
|
||||
@@ -251,11 +251,17 @@
|
||||
"$ref": "#/$defs/content"
|
||||
},
|
||||
"tap_action": {
|
||||
"$ref": "#/$defs/tap_action",
|
||||
"title": "Tap Action",
|
||||
"description": "Numeric tap action definition to include the number picker. 'confirm', 'pin' and 'exit' fields are optional.",
|
||||
"properties": {
|
||||
"action": {
|
||||
"$ref": "#/$defs/action"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"title": "Additional action data",
|
||||
"description": "Fixed Home Assistant service data. The selected picker value is merged into this object using the picker's data_attribute. Service-specific fields cannot be schema checked here."
|
||||
},
|
||||
"picker": {
|
||||
"type": "object",
|
||||
"title": "Number picker configuration",
|
||||
@@ -289,13 +295,24 @@
|
||||
"max",
|
||||
"step",
|
||||
"data_attribute"
|
||||
]
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"confirm": {
|
||||
"$ref": "#/$defs/confirm"
|
||||
},
|
||||
"pin": {
|
||||
"$ref": "#/$defs/pin"
|
||||
},
|
||||
"exit": {
|
||||
"$ref": "#/$defs/exit"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"action",
|
||||
"picker"
|
||||
]
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"enabled": {
|
||||
"$ref": "#/$defs/enabled"
|
||||
@@ -982,7 +999,7 @@
|
||||
"tap_action": {
|
||||
"type": "object",
|
||||
"title": "Tap Action",
|
||||
"description": "'confirm' and 'pin' fields are optional.",
|
||||
"description": "'confirm', 'pin' and 'exit' fields are optional.",
|
||||
"properties": {
|
||||
"confirm": {
|
||||
"$ref": "#/$defs/confirm"
|
||||
|
||||
@@ -25,6 +25,8 @@ Two simple examples using a scene and a cover as `tap` menu items.
|
||||
}
|
||||
```
|
||||
|
||||
## Confirmation
|
||||
|
||||
Any menu item with an action (`tap`, `template`, or `toggle`), may have a confirmation view added. For consistency this is always done via the `tap_action` JSON object, even though for a `toggle` menu item there will only ever be a single field inside. For the `toggle` menu item, the confirmation is presented on both `on` and `off` directions. There is no option for asymmetry, i.e. only in one direction.
|
||||
|
||||
```json
|
||||
@@ -56,6 +58,8 @@ The `confirm` field may contain a string instead of a Boolean in order to provid
|
||||
}
|
||||
```
|
||||
|
||||
## Personal Identification Number (PIN)
|
||||
|
||||
**The authors do not advise the use of this application for security sensitive devices. But we suspect users are taking that risk anyway, hence a PIN confirmation is provided that can be used for additional menu item security.**
|
||||
|
||||
This can be enabled by setting the `pin` field in the `tap_action`. The `pin` field overrides `confirm`. Explicitly setting `confirm` is not necessary.
|
||||
@@ -70,9 +74,14 @@ The 4-digit PIN is set globally for all actions in the app settings in Connect I
|
||||
|
||||
When entering an invalid PIN for the fifth time within 2 minutes, the PIN dialog will be locked for all actions for the next 10 minutes. Entering a valid PIN will always reset the failure counter.
|
||||
|
||||
<img src="../images/pin_view.png" width="200" title="Confirmation View"/>
|
||||
<img src="../images/pin_view.png" width="200" title="PIN View"/>
|
||||
|
||||
Note that for notify events, you _must_ not supply an `entity_id` or the API call will fail. There are other examples too.
|
||||
> [!IMPORTANT]
|
||||
> The PIN entry requires a touch screen enabled device.
|
||||
|
||||
## Additional Data
|
||||
|
||||
Some `action`s require additional `data` to be supplied. The following example shows how we handle this scenario. Note that for notify events, you _must not_ supply an `entity_id` or the API call will fail. There are other examples too.
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
@@ -39,6 +39,36 @@ Field | Purpose
|
||||
|
||||
It may well be the case that often `attribute` and `data_attribute` are the same attribute, as with this example.
|
||||
|
||||
## Additional Action Data
|
||||
|
||||
The `tap_action` object may also include a `data` object for fixed service call parameters. When the picker value is selected, the application merges the picker value into this `data` object using `data_attribute`.
|
||||
|
||||
For example, a light brightness picker can request a HomeAssistant transition while still using the picker value for `brightness`.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Lounge Brightness",
|
||||
"content": "{{ ((state_attr('light.lounge','brightness') | int(0) / 255) * 100) | round(0) }}%",
|
||||
"type": "numeric",
|
||||
"entity": "light.lounge",
|
||||
"tap_action": {
|
||||
"action": "light.turn_on",
|
||||
"data": {
|
||||
"transition": 2
|
||||
},
|
||||
"picker": {
|
||||
"step": 5,
|
||||
"min": 0,
|
||||
"max": 255,
|
||||
"attribute": "brightness",
|
||||
"data_attribute": "brightness"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The resulting action data sent to HomeAssistant contains both the fixed `transition` value and the selected `brightness` value.
|
||||
|
||||
## Helper
|
||||
|
||||
You might define a "helper" entity as follows in HomeAssistant:
|
||||
|
||||
@@ -112,7 +112,7 @@ class HomeAssistantMenuItemFactory {
|
||||
label as Lang.String or Lang.Symbol,
|
||||
entity_id as Lang.String?,
|
||||
template as Lang.String?,
|
||||
action as Lang.String?,
|
||||
action as Lang.String?,
|
||||
data as Lang.Dictionary?,
|
||||
options as {
|
||||
:exit as Lang.Boolean,
|
||||
@@ -163,6 +163,7 @@ class HomeAssistantMenuItemFactory {
|
||||
entity_id as Lang.String?,
|
||||
template as Lang.String?,
|
||||
action as Lang.String?,
|
||||
data as Lang.Dictionary?,
|
||||
picker as Lang.Dictionary,
|
||||
options as {
|
||||
:exit as Lang.Boolean,
|
||||
@@ -171,9 +172,12 @@ class HomeAssistantMenuItemFactory {
|
||||
:icon as WatchUi.Bitmap
|
||||
}
|
||||
) as WatchUi.MenuItem {
|
||||
var data = null;
|
||||
if (entity_id != null) {
|
||||
data = { "entity_id" => entity_id };
|
||||
if (data == null) {
|
||||
data = { "entity_id" => entity_id };
|
||||
} else {
|
||||
data["entity_id"] = entity_id;
|
||||
}
|
||||
}
|
||||
var keys = mMenuItemOptions.keys();
|
||||
for (var i = 0; i < keys.size(); i++) {
|
||||
|
||||
@@ -155,7 +155,10 @@ class HomeAssistantNumericMenuItem extends HomeAssistantMenuItem {
|
||||
//
|
||||
function onConfirm(b as Lang.Boolean) as Void {
|
||||
var dataAttribute = mPicker["data_attribute"] as Lang.String?;
|
||||
var entity_id = mData["entity_id"] as Lang.String?;
|
||||
var entity_id = null as Lang.String?;
|
||||
if (mData != null) {
|
||||
entity_id = mData["entity_id"] as Lang.String?;
|
||||
}
|
||||
|
||||
WatchUi.popView(WatchUi.SLIDE_RIGHT);
|
||||
WatchUi.requestUpdate();
|
||||
@@ -164,12 +167,18 @@ class HomeAssistantNumericMenuItem extends HomeAssistantMenuItem {
|
||||
return;
|
||||
}
|
||||
if (mAction != null) {
|
||||
var data = {} as Lang.Dictionary;
|
||||
if (mData != null) {
|
||||
var keys = mData.keys();
|
||||
for (var i = 0; i < keys.size(); i++) {
|
||||
data[keys[i]] = mData[keys[i]];
|
||||
}
|
||||
}
|
||||
data["entity_id"] = entity_id.toString();
|
||||
data[dataAttribute.toString()] = mValue;
|
||||
mHomeAssistantService.call(
|
||||
mAction,
|
||||
{
|
||||
"entity_id" => entity_id.toString(),
|
||||
dataAttribute.toString() => mValue
|
||||
},
|
||||
data,
|
||||
mExit
|
||||
);
|
||||
}
|
||||
|
||||
@@ -133,22 +133,39 @@ class HomeAssistantView extends WatchUi.Menu2 {
|
||||
));
|
||||
}
|
||||
} else if (type.equals("numeric") && action != null) {
|
||||
if (tap_action != null) {
|
||||
var picker = tap_action.get("picker") as Lang.Dictionary?;
|
||||
if (picker != null) {
|
||||
addItem(HomeAssistantMenuItemFactory.create().numeric(
|
||||
name,
|
||||
entity,
|
||||
content,
|
||||
action,
|
||||
picker,
|
||||
{
|
||||
:exit => exit,
|
||||
:confirm => confirm,
|
||||
:pin => pin
|
||||
}
|
||||
));
|
||||
if (System.getDeviceSettings().isTouchScreen) {
|
||||
// Numeric items are only actionable on touch screen devices.
|
||||
if (tap_action != null) {
|
||||
var picker = tap_action.get("picker") as Lang.Dictionary?;
|
||||
if (picker != null) {
|
||||
addItem(HomeAssistantMenuItemFactory.create().numeric(
|
||||
name,
|
||||
entity,
|
||||
content,
|
||||
action,
|
||||
data,
|
||||
picker,
|
||||
{
|
||||
:exit => exit,
|
||||
:confirm => confirm,
|
||||
:pin => pin
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addItem(HomeAssistantMenuItemFactory.create().tap(
|
||||
"PIN requires Touchscreen",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
data,
|
||||
{
|
||||
:exit => false,
|
||||
:confirm => false,
|
||||
:pin => false
|
||||
}
|
||||
));
|
||||
}
|
||||
} else if (type.equals("info") && content != null) {
|
||||
// Cannot exit from a non-actionable information only menu item.
|
||||
@@ -192,11 +209,9 @@ class HomeAssistantView extends WatchUi.Menu2 {
|
||||
}
|
||||
fullList.addAll(item.getMenuView().getItemsToUpdate());
|
||||
} else if (item instanceof HomeAssistantNumericMenuItem) {
|
||||
// Numeric items can have an optional template to evaluate
|
||||
var nmi = item as HomeAssistantNumericMenuItem;
|
||||
if (nmi.hasTemplate()) {
|
||||
fullList.add(item);
|
||||
}
|
||||
// Numeric items can have an optional template to evaluate, but they must always be included in order
|
||||
// to initialise the numeric picker's value.
|
||||
fullList.add(item);
|
||||
} else if (item instanceof HomeAssistantToggleMenuItem) {
|
||||
fullList.add(item);
|
||||
} else if (item instanceof HomeAssistantTapMenuItem) {
|
||||
|
||||
Reference in New Issue
Block a user