Hi Folks,
I’d like to share the idea of improving custom widget configuration by leveraging yet-existing information which can be derived from the semantics model.
Currently, this is not yet a turn-key solution but more a proof of concept to be discussed and improved. So yes: feel invited to adopt and suggest improvements …
Let’s start…
The Problem
In a setup, we may have multiple equipment
with similar points
. So all battery-powered room sensors may have channels
for
- temperature
- humidity
- battery low
- …
When linking them to items, what *label*
should we use?
- “Temperature Kitchen Ground Floor”
- “Humidity Kitchen Ground Floor”
- “Battery Low Kitchen Ground Floor”
or simply:
- “Temperature”
- “Humidity”
- “Battery Low”
With openHAB3 the latter would be sufficent since we have the semantic model.
We put the relevant items into the hierarchy. So from the model’s perspective it’s clear to what equipment in which room a temperature reading belongs to.
But what if we query “all temperatures” throught the models’s temperature property? We’ll get something like that:
Wouldn’t it be nice to leverage the model’s semantic relations here too?
Shouldn’t we be able to show the room and the equipment where these readings came from in our custom widgets?
Answer: Not out of the box (yet).
Solution idea
We already have all the needed information, the association to a equipment and the position in a location in the semantics metadata:
- isPointOf
- hasLocation
Unfortunately, in custom widgets we can’t follow these “pointers” to derive information from the parent groups.
But in rules: We can!
So why not collecting the label information from the parent groups (equipment and location) and simply store them as config date in an additional metadata namespace?
Let us start…
Example
We want to create a UI widget which shows us empty batteries which shoul be replaced. Since all items tagged with LowBattery have the same label, we like to add the Information to our widget where these batteries belong to.
As said above, we introduce a custom namespace “uiSemantics” and put that information there:
"metadata": {
"uiSemantics": {
"config": {
"preposition": " im ",
"equipment": "Bewegungsmelder",
"location": "Büro"
}
},
"semantics": {
"value": "Point_Status_LowBattery",
"config": {
"relatesTo": "Property_Energy",
"isPointOf": "ZIGTIO1PhilipsSML001"
}
As you see, I even opted for putting the correct German preposition ("im
" vs. "in der"
) to form correct expressions later in the UI like:
"Bewegungsmelder im Büro"
"Kühlschrank in der Küche"
Since we don’t want to add all those metadata by hand, I’ve created a tiny script to derive the needed parent labels and put them into “uiSemantics”. This script may run daily (with adopted to MetadataRegistry.update… )
var UI_NAMESPACE = "uiSemantics";
var enrichMetadata = function(item) {
logger.info("Item enriched: "+item)
var prepositionFor = ["Küche", "Werkstatt", "Waschküche", "Bibliothek", "Garage"]
var uiSemanticsKeys = { "equipment" : "" , "location" : "", "prepositon" : ""}
var equipmentItem=ir.getItem(getValue(item, "semantics", "isPointOf"));
var locationItem=ir.getItem(getValue(equipmentItem.name, "semantics", "hasLocation"));
uiSemanticsKeys.equipment = equipmentItem.label;
uiSemanticsKeys.location = locationItem.label;
uiSemanticsKeys.preposition = (prepositionFor.indexOf( uiSemanticsKeys.location) > -1 ) ? " in der " : " im ";
logger.info( "Item: "+ item +" Equipment: "+ uiSemanticsKeys.equipment + uiSemanticsKeys.preposition + uiSemanticsKeys.location );
MetadataRegistry.add(new Metadata(new MetadataKey( UI_NAMESPACE, item), null , uiSemanticsKeys ));
return null;
}
logger.info("Starting: Collecting semantics ...")
var lowBattItems = ir.getItem("gLowBattery").getMembers();
// Check the metadata for all the relevant Items
for each (var item in lowBattItems) {
enrichMetadata(item.name);
}
Now that we have have the labels of the parents in the metadata, we can simply use them e.g. in the beloved oh-repeater (A couple of simple oh-repeater examples):
- component: oh-repeater
config:
for: i
sourceType: itemsWithTags
itemTags: LowBattery
fetchMetadata: semantics,widgetOrder,uiSemantics
filter: loop.i.state != "OFF"
slots:
default:
- component: oh-label-card
config:
icon: f7:battery_25
title: =loop.i.label
footer: =loop.i.metadata.uiSemantics.config.equipment + loop.i.metadata.uiSemantics.config.preposition + loop.i.metadata.uiSemantics.config.location
item: =loop.i.name
This snippet iterates through all items tagged with LowBattery if the state not “OFF”. Notice the fetchMetadata
line: There we query our label information to be used in the footer
below.
This gives:
As I said: The equipment
information as well as the location
is available in the model and accessible from the rules - but currently simply not accessible from within widget code eg. via
// NOT WORKING!!!
= items[loop.i.metadata.semantics.config.isPointOf].label
Therefore I came up with this concept …