[semantic,ui] Using enriched semantic to ease UI creation

Hi mates,
I’m happy that you gave the concept a try :slight_smile:
I’ve just evolved the above a tiny bit even more …

Some of you may have seen my oh-repeater stuff for timestamps here:

To not spread related content via multiple threads, I’d like to share it here:

Dynamic warning timeouts

In the thread linked above, I’ve created a list which hilights outstanding heartbeats from wireles sensors:

The initial attempt used a fixed timeout (1h) for warnings and another (1day) for errors.

This leads to some false negativ presentation:
While most wireless sensors report something every some seconds/minutes, I do have some sensors too which need quite very long periods of deep sleep to reach an acceptable battery lifetime:

  • Xiaomi Lumi Zigbee temp/hum/pressure sensors
  • Shelly Flood water sensors
  • Shelly Door Window sensors

See them in the above picture shown with orange or red badges…

To overcome this limitation, I’ve extended my uiSemantics namespace by additional keys for warning/failure timeouts:

  "metadata": {
    "uiSemantics": {
      "config": {
        "warn": -1440,
        "fail": -2160,
        "icon": "f7:waveform_path_ecg",
        "preposition": " im ",
        "equipment": "Wassermelder",
        "location": "Technikraum"
      }

Notice the warn/fail keys here. There I’ve added the specific timeout in minutes for that item.

Sure, you’ll certainly ask for the negative values there - right?
Answer: in the dayjs() calculation in the widget I was using negative offsets. So putting negatives here already saved me some rewrite in my widgets. :wink:

As in the OP, I don’t populate the key’s by hand. It’s again in a supporting script:

var enrichMetadata = function(item, icon) {
  
  logger.info("Item tested: "+item)
  var prepositionFor = ["Küche", "Werkstatt", "Waschküche", "Bibliothek", "Garage"]
  var uiSemanticsKeys = { "equipment" : "" , "location" : "", "prepositon" : "" , "icon" : "" , "warn" : -30, "fail" : -45}
  var isPointOf = getValue(item, "semantics", "isPointOf");
  logger.info("Item isPointOf: "+ isPointOf );
  
  var equipmentItem = isPointOf === undefined ? ir.getItem(item) : ir.getItem( 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 ";
  uiSemanticsKeys.icon = icon;
  
  var warnTimeoutFor = {"LUMITH" : -720 , "SHELLYDW" : -240 , "SHELLYFLOOD" : -1440 };
  for (var s in warnTimeoutFor) {
    if (item.toUpperCase().indexOf(s) > -1 ) { 
      uiSemanticsKeys.warn = warnTimeoutFor[s];
      break;
    }
  }
  uiSemanticsKeys.fail= uiSemanticsKeys.warn * 1.5;
  
  if ( getValue(item, UI_NAMESPACE, "location" ) !== null ) {
        logger.info( "Item: "+ item +" UPDATE Metadata in "+ UI_NAMESPACE + ": " + uiSemanticsKeys.equipment  + uiSemanticsKeys.preposition + uiSemanticsKeys.location );
        MetadataRegistry.update(new Metadata(new MetadataKey( UI_NAMESPACE, item), null , uiSemanticsKeys ));
  } else {
        logger.info( "Item: "+ item +" ADD Metadata in "+ UI_NAMESPACE + ": " + uiSemanticsKeys.equipment  + uiSemanticsKeys.preposition + uiSemanticsKeys.location );
        MetadataRegistry.add(new Metadata(new MetadataKey( UI_NAMESPACE, item), null , uiSemanticsKeys ));
  }
  return null;
}

The scripts makes some assumption on the item name to filter the long-sleeping deivices (items). I did this because I didn’t found a way to determine, what thing type an item is linked to from within a rule.
IF SOMEONE HAS GOT AN IDEA ON THIS, please let me know :wink:

Once we have the additional timeout set in our metadata, we can change the oh-repeater loop to use the specific timeouts instead of the fixed for filtering and coloring:

  - component: oh-repeater
    config:
      for: i
      sourceType: itemsInGroup
      groupItem: =props.mainItem
      fetchMetadata: semantics,widgetOrder,uiSemantics
      filter: '( loop.i.state < dayjs().add(loop.i.metadata.uiSemantics.config.warn,"m").format() ) ? true : vars.detailsOn '
      style:
        highlightColor: blue
    slots:
      default:
        - component: oh-list-item
          config:
            icon: ="f7:"+props.icon
            iconColor: '=dayjs(items[loop.i.name].state).isAfter(dayjs().add(loop.i.metadata.uiSemantics.config.warn,"m")) ? "green" : dayjs(items[loop.i.name].state).isAfter(dayjs().add(loop.i.metadata.uiSemantics.config.fail,"m")) ? "orange" : "red"'
            footer: =loop.i.metadata.uiSemantics.config.preposition + loop.i.metadata.uiSemantics.config.location
            title: =loop.i.metadata.uiSemantics.config.equipment
            item: =loop.i.name
            badge: =dayjs(items[loop.i.name].state).fromNow()
            badgeColor: '=dayjs(items[loop.i.name].state).isAfter(dayjs().add(loop.i.metadata.uiSemantics.config.warn,"m")) ? "green" : dayjs(items[loop.i.name].state).isAfter(dayjs().add(loop.i.metadata.uiSemantics.config.fail,"m")) ? "orange" : "red"'

This brings us:

Notice the Shelly Flood “Wassermelder im Technikraum”. This guy was marked orange formerly. BUT: Since it is absolutely fine, if it sleeps for a whole day if no water alarm is to be issued, the widget should not complain about it…

Have fun … :wink:

1 Like