Modifying oh-locations-tab and/or linking to oh-location-card

I really like the automatically generated “location” cards, however they take up too much screen real-estate for me. Here’s a screenshot from a mobile device:

Most of this space is not used, and with over 16 locations in my model, scrolling to find the right one is difficult, slow, and not intuitive (particularly for older users). According to this topic, it seems that these location cards can’t be linked to via external source (is this still true?) and that the oh-location-card is not usable in, for example, the overview page.

Would it somehow be possible to make these cards smaller–maybe even fit them onto a grid so that they all can be navigated to from one page (without scrolling)? Something like this (HabPanel):

Here each button links directly to that location.

Thanks!

There is no setting to modify the size of the oh-location-cards. As far as I know, because of the way the the location tab page is constructed, you can’t even add a stylesheet to any of the higher elements that will impact the location cards (you can add a stylesheet within a location card to modify the elements inside the card).

If this feature is important enough to you, you’ll probably need to put in a feature request on the UI github repo.

Hm, alright. Would it instead be possible to use the navigate action in an oh-button to target a specific location card? Normal hyperlinks, eg http://localhost:8080/#card=GuestBathroom don’t work and neither does using actionPage: page:home:locations.

Any options?

Alas, not to my knowledge. Opening the card is an internal action defined through the f7 library, not something you can navigate to.

Well then, is it possible to replicate oh-location-card’s behavior using oh-repeater on a room-group?

I’ve figured out that it is possible to fetch the default list widget configuration by using fetchMetadata in oh-repeater, which gets me something like { "listWidget": { "value": "widget:temperature_control_v2", "config": { "item": "Guestbedoom_Heating_Active" } } } for each direct child of that group that has a default list item widget assigned, but I’m unsure of how to actually convert this into a display of the actual widget.

EDIT:

uid: knockoff-location-card
tags: []
props:
  parameters:
    - context: item
      description: An item to control
      label: Item
      name: item
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Dec 20, 2022, 4:27:20 PM
component: f7-card
config:
  title: '=(props.item) ? "State of " + props.item : "Set props to test!"'
  footer: =props.prop1
slots:
  default:
    - component: oh-list
      slots:
        default:
          - component: widget:list_light_v2
          - component: oh-repeater
            config:
              for: item
              fragment: false
              groupItem: =props.item
              sourceType: itemsInGroup
              fetchMetadata: listWidget
              filter: '(loop.item.tags=="Light") ? true : false'
            slots:
              default:
                - component: '=loop.item.metadata.listWidget.value'
                  config:
                    title: '=loop.item.metadata.listWidget.config.title'
                    root_item: '=loop.item.metadata.listWidget.config.root_item'
                - component: Label
                  config:
                    text: '=loop.item.metadata.listWidget.value'

For some reason this doesn’t seem to do the trick, no widgets load. Instead I just get:
image

The widget out side of the repeater shows up, but those inside don’t.

Possible: yes (mostly). Simple: not by a long shot, especially if you really want each and every feature of the location card. There are a lot of special functions that go into the location cards that are difficult to replicate with just the widget system. Off the top of my head, I would say that this requires extremely advanced widget construction and styling, several additional group items with aggregation functions, and probably a specialized rule. My personal cost/benefit analysis says a little extra scrolling on the location tab is the much better option.

My advice is, instead of thinking about trying to replicate the location cards or use them in an unintended way, try to identify what it is you need most from those cards and develop your own widget on the home screen with that reduced function. In the end, it may be an entirely different system than the location cards.

What version of OH are you using? Expressions in the component line are only supported on very recent 3.4 milestones or the new 3.4 release.

Alright, I’ve almost got the core of a “knockoff” location-card working, but and while I’m able to pass the expressions into the component line, I still can’t get the widget config into the configuration on a generalized basis. Any suggestions? Is doing so even possible?

uid: knockoff-location-card
tags: []
props:
  parameters:
    - context: item
      description: An item to control
      label: Item
      name: item
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Dec 21, 2022, 6:30:31 PM
component: f7-card
config:
  title: =props.item
slots:
  default:
    - component: oh-list
      slots:
        default:
          - component: oh-repeater
            config:
              fetchMetadata: listWidget
              for: item
              groupItem: =props.item
              filter: (['AlarmSystem','BackDoor','Battery','Blinds','Boiler','Camera','Car','CeilingFan','CellarDoor','CleaningRobot','Dishwasher','Door','Doorbell','Dryer','Equipment','Fan','Freezer','FrontDoor','GarageDoor','Gate','HVAC','InnerDoor','Inverter','KitchenHood','LawnMower','Lightbulb','LightStripe','Lock','MotionDetector','NetworkAppliance','Oven','PowerOutlet','Projector','Pump','RadiatorControl','Receiver','Refrigerator','RemoteControl','Screen','Sensor','SideDoor','Siren','Smartphone','SmokeDetector','Speaker','Television','Valve','VoiceAssistant','WallSwitch','WashingMachine','WeatherService','WebService','WhiteGood','Window'].indexOf(loop.item.tags[0]) > -1 )
              sourceType: itemsInGroup
            slots:
              default:
                - component: Label
                  config:
                    text: =loop.item.label
                - component: oh-repeater
                  config:
                    fetchMetadata: listWidget
                    for: element
                    groupItem: =loop.item.name
                    sourceType: itemsInGroup
                    filter: (loop.element.tags.length >= 1)
                  slots:
                    default:
                      - component: =loop.element.metadata.listWidget.value
                        config: =loop.element.metadata.listWidget.config     
                      - component: Label
                        config:
                          text: =loop.element.metadata.listWidget.config                          

The issue is that =loop.element.metadata.listWidget.config evaluates properly to eg. { "title": "Main", "root_item": "GuestBedroom_Lights_Main1" } or { "title": "Yard" }, this is somehow not properly formatted or skipped by the interpreter

Pretty close (except for the styling):

Yeah, I can see that. Keys within the config object are parsed by the expression parser, but the config object itself is not. That’s a tricky problem. There’s probably no way for you to make it fully generalized because of this unless you want to refactor all the custom widgets to use a single object property (which would be a tremendous hassle).

I’ve found a bit of a “hacky” workaround by simply overloading the config with every possible config option. The log complains mightily each time the widget is loaded, but it is otherwise functional :person_shrugging:

eg.

config:
  title: =loop.element.metadata.listWidget.config.title
  item: =loop.element.metadata.listWidget.config.item
  root_item: =loop.element.metadata.listWidget.config.root_item
  group_item: =loop.element.metadata.listWidget.config.group_item
  color: =loop.element.metadata.listWidget.config.color
  etc.

[WARN ] [e.internal.SseItemStatesEventBuilder] - Attempting to send a state update of an item which doesn't exist: undefined

If they bother you, you could probably eliminate most of those warnings by making each of the properties a test that only returns the value if it exists.

title: =loop.element.metadata.listWidget.config.title || ""