kimifish
(kimifish)
November 27, 2025, 5:33pm
1
I want to create a widget with a schedule. The schedule itself is stored in a StringItem in JSON format like {“monday”: {“on”: “08:00”, “off”: “22:00”}, …}.
The widget should allow editing any value for any day of the week.
Something is clearly going wrong in the widget’s code, but I can’t figure out what. I’d appreciate any advice.
uid: WAN_schedule_editor
tags: []
props:
parameters:
- description: Terminal Name (e.g. kimiphone2)
label: Terminal Name
name: terminal
required: true
type: text
- description: Item Postfix (default _autoWAN_schedule)
label: Item Postfix
name: postfix
required: false
type: text
default: _autoWAN_schedule
timestamp: Nov 26, 2025, 12:30:00 PM
component: f7-card
config:
title: ='Schedule ' + props.terminal
outline: true
slots:
content:
- component: oh-context
config:
constants:
targetItemName: =props.terminal + props.postfix
variables:
mySchedule: >
=(items[props.terminal + props.postfix] && items[props.terminal + props.postfix].state !== 'NULL' && items[props.terminal + props.postfix].state !== 'UNDEF')
? JSON.parse(items[props.terminal + props.postfix].state.toString()) :
JSON.parse("{'monday':{'on':'08:00','off':'22:00'}, 'tuesday':{'on':'08:00','off':'22:00'}, 'wednesday':{'on':'08:00','off':'22:00'}, 'thursday':{'on':'08:00','off':'22:00'}, 'friday':{'on':'08:00','off':'23:00'}, 'saturday':{'on':'10:00','off':'22:00'}, 'sunday':{'on':'10:00','off':'22:00'}}")
slots:
default:
# DEBUG BLOCK
- component: f7-block
config:
visible: true
style:
color: red
slots:
default:
- component: Label
config:
text: =vars.mySchedule.monday.on
# DEBUG BLOCK END
- component: f7-block
config:
visible: =items[const.targetItemName] === undefined
style:
color: red
text-align: center
slots:
default:
- component: Label
config:
text: ="Item " + constants.targetItemName + " not found!"
- component: f7-list
config:
accordionList: true
visible: =items[const.targetItemName] !== undefined
slots:
default:
- component: oh-repeater
config:
fragment: true
for: dayCfg
sourceType: array
in:
- day: monday
label: Monday
- day: tuesday
label: Tuesday
- day: wednesday
label: Wednesday
- day: thursday
label: Thursday
- day: friday
label: Friday
- day: saturday
label: Saturday
- day: sunday
label: Sunday
slots:
default:
- component: f7-list-item
config:
title: =loop.dayCfg.label
accordionItem: true
slots:
default:
- component: f7-accordion-content
slots:
default:
- component: f7-block
config:
class:
- display-flex
- justify-content-space-between
- align-items-center
slots:
default:
- component: oh-input
config:
type: time
#type: text
label: On
style:
width: 45%
variable: vars.mySchedule
variableKey: =[loop.dayCfg.day].on
- component: oh-input
config:
type: time
label: Off
style:
width: 45%
variable: vars.mySchedule #vars[loop.dayCfg.day].on
variableKey: monday.off
#variableKey: =[loop.dayCfg.day].off
- component: f7-block
config:
visible: =items[constants.targetItemName] !== undefined
slots:
default:
- component: f7-button
config:
text: Save
fill: true
action: command
actionItem: =constants.targetItemName
actionCommand: vars.mySchedule
Sorry for providing the code in two parts – I couldn’t get around the site’s parser. The second part is the button that saves the schedule back to the item.
JustinG
(JustinG)
November 28, 2025, 4:51pm
2
Can you be more specific about what is going wrong. I see a couple of issues, but I don’t know if they address the problem you are seeing.
This is most likely what you are referring to. This will not work because the actions are not an f7 feature, they are specific to OH. You need to use the oh-button here not the f7-button.
kimifish
(kimifish)
November 28, 2025, 5:29pm
3
Yes, thank you. I have already noticed and fixed this, as well as a few other points. But the main problem is something else, of course: the input fields do not pick up the initial time values loaded from the JSON (see screenshot), and they also do not overwrite them with what I select. When the button is pressed, the same JSON that was loaded is written back to the item.
Fixed code:
uid: WAN_schedule_editor_time
tags: []
props:
parameters:
- description: Terminal Name (e.g. kimiphone)
label: Terminal Name
name: terminal
required: true
type: text
- description: Item Postfix (default _autoWAN_schedule)
label: Item Postfix
name: postfix
required: false
type: text
default: _autoWAN_schedule
timestamp: Nov 28, 2025, 18:30:00 PM
component: f7-card
config:
title: =props.terminal + " schedule"
outline: true
slots:
content:
- component: oh-context
config:
constants:
targetItemName: =props.terminal + props.postfix
variables:
mySchedule: >
=(items[props.terminal + props.postfix] && items[props.terminal + props.postfix].state !== 'NULL' && items[props.terminal + props.postfix].state !== 'UNDEF')
? JSON.parse(items[props.terminal + props.postfix].state.toString()) :
JSON.parse("{'monday':{'on':'08:00','off':'22:00'}, 'tuesday':{'on':'08:00','off':'22:00'}, 'wednesday':{'on':'08:00','off':'22:00'}, 'thursday':{'on':'08:00','off':'22:00'}, 'friday':{'on':'08:00','off':'23:00'}, 'saturday':{'on':'10:00','off':'22:00'}, 'sunday':{'on':'10:00','off':'22:00'}}")
slots:
default:
# DEBUG BLOCK
- component: f7-block
config:
visible: true
style:
color: red
slots:
default:
- component: Label
config:
text: =vars.mySchedule.monday.on
# DEBUG BLOCK END
- component: f7-block
config:
visible: =items[const.targetItemName] === undefined
style:
color: red
text-align: center
slots:
default:
- component: Label
config:
text: ="Item " + const.targetItemName + " not found!"
- component: f7-list
config:
accordionList: true
visible: =items[const.targetItemName] !== undefined
slots:
default:
- component: oh-repeater
config:
fragment: true
for: dayCfg
sourceType: array
in:
- day: monday
label: Monday
- day: tuesday
label: Tuesday
- day: wednesday
label: Wednesday
- day: thursday
label: Thursday
- day: friday
label: Friday
- day: saturday
label: Saturday
- day: sunday
label: Sunday
slots:
default:
- component: f7-list-item
config:
title: =loop.dayCfg.label
accordionItem: true
slots:
default:
- component: f7-accordion-content
slots:
default:
- component: f7-block
config:
class:
- display-flex
- justify-content-space-between
- align-items-center
slots:
default:
- component: oh-input
config:
type: time
label: On
style:
width: 45%
variable: vars.mySchedule
variableKey: =loop.dayCfg.day + '.on'
- component: oh-input
config:
type: time
label: Off
style:
width: 45%
variable: vars.mySchedule
variableKey: =loop.dayCfg.day + '.off'
- component: f7-block
config:
visible: =items[constants.targetItemName] !== undefined
slots:
default:
- component: oh-button
config:
text: Save
fill: true
action: command
actionItem: =const.targetItemName
actionCommand: =JSON.stringify(vars.mySchedule)
I suspect that oh-input with type: time does not actually understand the HH:mm format at all, and I do not know how to parse a string into the DateTime or whatever it expects. And even if that works, does type: time even work with variables at all, or does it require a DateTime Item only?
JustinG
(JustinG)
November 30, 2025, 5:09pm
4
You could be correct about that, there is a bit of specialized code in the oh-input for processing date data, and I have never tried to work with just time values. The only widget I have ever created that work with time values I’ve split up into separate hour, minute, and second strings.
I do know that the input works with full date-time values so you could also try to work around the issue by manipulating dull date-times. It would add a deal of complexity, but, since you already have an oh-context, you could easily add a couple of functions that take care of much of that complexity.
kimifish
(kimifish)
December 2, 2025, 4:26pm
5
Yes, in the end the full date format worked. The main issue, as it turned out, was completely non-obvious from a syntax standpoint — the variable name in the oh-input: variable: field shouldn’t include vars.. Because of that, I probably skipped several working versions. In the end, I added a couple of functions and had to introduce two layers of oh-context, since variables and funcs defined higher up in the same context aren’t recognized, but it seems to be working now.
It would be great if someone with more experience could take a look and point out places where the code could be simplified.
uid: WAN_schedule_editor_time
tags: []
props:
parameters:
- description: Terminal Name (e.g. kimiphone)
label: Terminal Name
name: terminal
required: true
- default: _autoWAN_schedule
description: Item Postfix (default _autoWAN_schedule)
label: Item Postfix
name: postfix
required: false
timestamp: Dec 2, 2025, 7:10:10 PM
component: f7-card
config:
title: =props.terminal + " schedule"
outline: true
slots:
content:
- component: oh-context
config:
constants:
targetItemName: =props.terminal + props.postfix
variables:
schedule: >
=(items[props.terminal + props.postfix] && items[props.terminal +
props.postfix].state !== 'NULL' && items[props.terminal +
props.postfix].state !== 'UNDEF') ? JSON.parse(items[props.terminal
+ props.postfix].state.toString()) : JSON.parse('{"monday": {"on":
"07:00", "off": "23:00"}, "tuesday": {"on": "07:00", "off":
"23:00"}, "wednesday": {"on": "07:00", "off": "23:00"}, "thursday":
{"on": "07:00", "off": "23:00"}, "friday": {"on": "07:00", "off":
"23:00"}, "saturday": {"on": "07:00", "off": "23:00"}, "sunday":
{"on": "07:00","off": "23:00"}}')
functions:
toDT: =(x) => ("2020-01-01T" + x.toString() + ":00.000")
fromDT: =(x) => x.split("T")[1].substring(0,5)
slots:
default:
- component: oh-context
config:
variables:
sched:
monday:
on: =fn.toDT(vars.schedule.monday.on)
off: =fn.toDT(vars.schedule.monday.off)
tuesday:
on: =fn.toDT(vars.schedule.tuesday.on)
off: =fn.toDT(vars.schedule.tuesday.off)
wednesday:
on: =fn.toDT(vars.schedule.wednesday.on)
off: =fn.toDT(vars.schedule.wednesday.off)
thursday:
on: =fn.toDT(vars.schedule.thursday.on)
off: =fn.toDT(vars.schedule.thursday.off)
friday:
on: =fn.toDT(vars.schedule.friday.on)
off: =fn.toDT(vars.schedule.friday.off)
saturday:
on: =fn.toDT(vars.schedule.saturday.on)
off: =fn.toDT(vars.schedule.saturday.off)
sunday:
on: =fn.toDT(vars.schedule.sunday.on)
off: =fn.toDT(vars.schedule.sunday.off)
slots:
default:
- component: f7-block
config:
visible: =items[const.targetItemName] === undefined
style:
color: red
text-align: center
slots:
default:
- component: Label
config:
text: ="Item " + const.targetItemName + " not found!"
- component: f7-list
config:
style:
padding: 10px 10px
accordionList: true
visible: =items[const.targetItemName] !== undefined
slots:
default:
- component: oh-repeater
config:
fragment: true
for: dayCfg
sourceType: array
in:
- day: monday
label: Monday
- day: tuesday
label: Tuesday
- day: wednesday
label: Wednesday
- day: thursday
label: Thursday
- day: friday
label: Friday
- day: saturday
label: Saturday
- day: sunday
label: Sunday
slots:
default:
- component: f7-list-item
config:
title: =loop.dayCfg.label
accordionItem: true
slots:
default:
- component: f7-accordion-content
slots:
default:
- component: f7-block
config:
class:
- display-flex
- justify-content-space-between
- align-items-center
slots:
default:
- component: oh-input
config:
type: time
label: On
style:
width: 45%
variable: sched
variableKey: =loop.dayCfg.day + '.on'
- component: oh-input
config:
type: time
label: Off
style:
width: 45%
variable: sched
variableKey: =loop.dayCfg.day + '.off'
- component: f7-block
config:
style:
padding: 10px 10px
visible: =items[const.targetItemName] !== undefined
slots:
default:
- component: oh-button
config:
text: "Save"
fill: true
action: command
actionItem: =const.targetItemName
actionCommand: >
='{"monday":{"on":"' +
fn.fromDT(vars.sched.monday.on) +
'","off":"' +
fn.fromDT(vars.sched.monday.off) +
'"}, "tuesday": {"on":"' +
fn.fromDT(vars.sched.tuesday.on) +
'","off":"' +
fn.fromDT(vars.sched.tuesday.off) +
'"}, "wednesday": {"on":"' +
fn.fromDT(vars.sched.wednesday.on) +
'","off":"' +
fn.fromDT(vars.sched.wednesday.off) +
'"}, "thursday": {"on":"' +
fn.fromDT(vars.sched.thursday.on) +
'","off":"' +
fn.fromDT(vars.sched.thursday.off) +
'"}, "friday": {"on":"' +
fn.fromDT(vars.sched.friday.on) +
'","off":"' +
fn.fromDT(vars.sched.friday.off) +
'"}, "saturday": {"on":"' +
fn.fromDT(vars.sched.saturday.on) +
'","off":"' +
fn.fromDT(vars.sched.saturday.off) +
'"}, "sunday": {"on":"' +
fn.fromDT(vars.sched.sunday.on) +
'","off":"' +
fn.fromDT(vars.sched.sunday.off) +
'"}}'
I tested your widget in openHAB 5.1 Milestone 3 . I can successfully save values to a string item, but the time does not display within the widget itself.
I suspect this is an issue with the underlying oh-input component. I attempted to use f7-input instead, which successfully displays the time, but this prevents the saving function from working.f7-input does not appear to support the necessary variable and variableKey parameters for data binding/saving.
What is the openHAB version you are currently using?