OH 3 Examples: How to boot strap the state of an Item

Intro

There is a perennial problem that has been with us since the beginning. Sometimes an Item will have a state that is relatively static and is essentially hard coded. There are multiple ways you can deal with this problem including:

  • create a System started rule to populate the Item with it’s state; if you use restoreOnStartup you can even remove the System started rule after the first run
  • update the Item using the Karaf Console with smarthome:update
  • update the Item from the REST API Docs
  • I even wrote a script that would initialize Items based on metadata

All of these options are OK, but now in OH 3 there is a new way which is way more powerful and flexible.

NOTE: I’m going to show how to do this through MainUI. MainUI will create some metadata on the Item to tell it how to render the widget for the Item. If you want to stick to .items files, you will have to look at the code that is generated to figure out how to apply it in your .items files.

Example Problem

I’m porting my Time of Day rule from Python to JavaScript using the MainUI to create the rules. This rule relies upon a series of DateTime Items to define the start times for the various times of day as well as Item metadata to define what type of day it applies to (e.g. morning time could start later on weekends and holidays).

The rule doesn’t know nor does it care how the Item gets its states. In a typical configuration some of the DateTimes will be driven by the Astro binding. Others might be hard coded. We need a way to set the hard coded times.

The Default Widgets

MainUI tries to create a lot of the UI for you automatically based on your Items, the Model, and Item metadata. You can influence how the Item is automatically rendered by setting default widgets on the Item. One of the places where the default widgets are used, and the place we care about here, is on the Item’s page itself.

In the above you will see I have a DateTime Item named Holiday_Night. It doesn’t have a state yet (notice the NULL). So where does that “NULL” come from anyway? Can I change how that widget is rendered? The answer is “yes!” That is the “Default Standalone Widget” which you will find near the middle of the list of predefined metadata entries.

Click on that and you will be presented with a preview of the widget and a menu Item to select what sort of widget you want to use as the default.

Click on “Widget” and select “Input Widget.” If the Item were of another type you can choose the appropriate widget for that type (e.g. a knob for a thermostat setting).

This opens up a form where you can start to customize the widget. In our case we will set:

  • title: Holiday Night
  • footer: =items.Holiday_Night.state
  • input type: datetime-local
  • input mode: text
  • placeholder: hh:mm:ss
  • send button: toggled on
  • outline: toggled on
  • validate: toggled on

NOTE: input mode defaults to text so that isn’t really needed. The placeholder is a reminder of what to enter. For time of day we don’t care about the date so only the time needs to be entered using 24 hour time. Starting any field with = starts a formula where you can calculate the state based on Item’s state. In this case we just use the state. The javascript ternary operator (condition) ? true value : false value comes in handy here.

The code itself is:

value: oh-input-card
config:
  outline: true
  inputmode: text
  footer: =items.Holiday_Night.state
  placeholder: hh:mm:ss
  title: Holiday Night
  type: datetime-local
  sendButton: true
  validate: true

You will see you changes rendered in the preview at the top. Click save and you will see a live view.

Enter the time you want to initialize the Item with and click the checkmark to the right and the Item will be updated to that time. You will then see the Item’s new state in the footer of the card.

Because we didn’t specify a year/month/day it defaults to epoch. That’s fine as the rule deals with updating it to today when it runs.

Now what?

That seems like a lot of work just to initialize the Item. And that’s true. But now if you want to change it to something else in the future you can just return to the Item’s page, enter the new time and click the check to apply it. If this Item is part of the Model, you can add the Item to a Page using the “add from model” option and the widget you just defined will be used by default (if it isn’t you will have to redefine the widget as shown above).

One of the really nice features is if the Item is part of the Model, *it has already been added to your Pages." But it might have been added as a part of the List in which case you would need to define the default List widget similar to the above using the Input List Widget.

Conclusion

Not only do we now have a way to enter DateTime and text (I think Yannick is even working on a DateTime picker widget) now but if we spend a little bit of time building the model, we won’t even need to build the UI itself. Though much of that work that is saved building a sitemap will be spent creating default widgets for the relevant Items.

15 Likes

Not really :slight_smile: You can specify “date”, “time” (native controls) or even “datepicker” (Framework7 calendar) as the type in the input widget’s parameters (need a list of options for those), but I don’t think they will output dates in a format accepted by DateTime items by default…

image

image

image

1 Like

Turns out, it doesn’t work too bad, except the time picker doesn’t parse the full date properly - but setting the time works.

If you use datepicker as the type, you have a calendarParams (or calendar-params, see Input Vue f7 docs) and then you can set the calendar options) as you like. Not easy, but it works.

Here’s an example with:

component: oh-input-card
config:
  title: Date/Time Picker
  type: datepicker
  sendButton: true
  item: TestDate
  calendarParams:
    timePicker: true
    dateFormat:
      month: short
      day: numeric
      hour: numeric
      minute: numeric
slots: null

(tip: use the topic filter feature of the event monitor with for instance openhab/items/TestDate to see only those events related to this item).

1 Like

This is the UI that openhab needed!! (the whole UI, not just this widget)

Thank you @ysc for the amazing work on it and @rlkoshak for your endlessly helpful documentation

4 Likes

Clearly I was looking in the wrong place for the list of input types. I never say date or time as options nor did I see datepicker. Given that the set of possible input types is predefined and fixed is it possible to choose from a list instead of needing to look it up and type it in?

Where I seem to have run into trouble is what to put into the “Input Mode”. For example, I tried to experiment with “time” as the input type and I left the mode blank but I didn’t get the UI element to pop up as you show there. I just had --:-- -- which I would click on and type in the hour minute meridian.

Your example with the datepicker with params though works really well.

That heavily depends on your browser and OS. Mozilla has a comprehensive page on that: <input type="time"> - HTML: HyperText Markup Language | MDN
So it could be bare bones or way fancier, for instance here’s how it should look on Android:

Definitely. That’s what I tried to say with:

1 Like

Hi Rich,
trying to follow up on your solution proposal, could you please post your final solution (e.g. code) as at least for me the solution described in your first post does not work.

Br,
detond

Does not work in what way?

value: oh-input-card
config:
  outline: true
  inputmode: text
  footer: =items.Default_Night.state
  placeholder: hh:mm:ss
  title: Default Night
  type: datetime-local
  sendButton: true
  validate: true
1 Like

Sry for confusion, it’s working fine. I was just confused as the input field does not hold the value, but it’s getting resetted when you save. Thanks for quick answer anyhow!

Look at the footer of the element. That is configured to show the current state of the Item. That’s probably the best way to tell whether of not it saved the new value.

2 Likes

same here. When you hit the check mark, the value is sent to the item (can see that in the log), but the input field is cleared. Is there a way to make the input field show the item state ?

Btw, for those who still do textual configuration, this is how it “works” so far (items file only, time picker shows up in the blinds section of the UI):

DateTime nm_HoursBusiness "Business hrs start [%s]" <time> (gHaus) ["Blinds"] {
	widget="oh-input-card"[
    outline="true",
    inputmode="text",
    footer="nm_HoursBusiness",
    item="nm_HoursBusiness",
    placeholder="hh:mm",
    title="Default Night",
    type= "time",  // datetime-local= with date, time = time only.
    sendButton= "true",
    validate= "true",
    defaultValue="12:00"
],
	listWidget="oh-input-item",
	cellWidget="oh-input-cell"
}

I guess you could use the Item’s state for the placeholder text. But you will need to set the State Description metadata to only show the hours and minutes of the DateTime Item as opposed to the full date and time string. Once you set the State Desceiption then you’d use =items.nmHoursBusiness.displayState for the placeholder.

Thanks for the hint, but there are several things to fix.

  • Cant find any hint on what to use as a state description string. “hh:mm” doesn’t work.
  • The widget is not accepting accepting the default value. The input field is empty at start.
  • The input field holds a value, e.g. “06:02” when you set the time, but it is cleared as soon as the check mark is clicked.

It’s the same as Item/sitemap labels. Items | openHAB

A place holder is not a default value. It’s to provide formatting hints to you as the user. If it disappears after hitting send that may be a limitation of how these widgets work. You’ll have to do a deep dive into how F7 does this to figure out what can and cannot be done for an input field like this.

1 Like

Thanks anyway. I for sure won’t dive into F7. Gave it a glance and figured its way beyond my patience at this time. I guess my time input will have to wait until OH4 then.

Well, given all this stuff is implemented by F7, this specific way of doing the input and defaulting the value may not be supported ever. Or it may already be supported.

strange thing is that if you use

 type="date"

then the item state shows correctly as preset value in the input field. But then you can only set the date. If you use

 type="time"

that lets you pick the time, but it seems to inevitably come with that strange behavior that the field is cleared. Seems like a bug on the F7 end. But then again, the type “time” works but is not even documented here:

Maybe the time for a time picker has not yet come…

If you change the OH-item type from DateTime to String, the input field shows the correct value once set via the submit button.

1 Like

Is this expected to provide persistent initialization of an item’s state across restarts? It does seem to send the value for me, when I hit the checkmark, but that’s it. I’ve played with defaultValue as well, but it seems to have no effect (though that value is at least remembered across restarts, it does not appear to be used at all). I’m trying to get ephem_tod working in OH3 - I used item_init and ephem_tod in OH2.5 with success.

You need to set up persistence and use the restoreOnStartup strategy to have an Item’s state restored after a restart.

1 Like