marvo88
(Martin)
February 26, 2025, 1:06pm
1
Hi,
I had a habpanel with my wishes that worked, meanwhile I want to change to mainUI, but I dont able to create widgets with my wishes.
Now I try to create a Heating Overview, but I didnt successful.
I attached a picture with my status and my wish and my latest code.
I hope someone can help me…
uid: Heizung
tags: []
props:
parameters:
- description: Title
label: Title
name: title
required: false
type: TEXT
- context: item
description: Temperature sensor at top
label: Temp Top
name: item_top
required: false
type: TEXT
parameterGroups: []
timestamp: Feb 26, 2025, 1:46:11 PM
component: f7-card
config:
class:
- padding
style:
background-color: "=props.bgcolor ? props.bgcolor : ''"
border-radius: var(--f7-card-expandable-border-radius)
box-shadow: 5px 5px 10px 1px rgba(0,0,0,0.1)
height: 120px
margin-left: 5px
margin-right: 5px
noShadow: false
padding: 0px
slots:
default:
- component: f7-block
config:
style:
min-height: 180px
max-height: 180px
max-width: 120px
min-width: 120px
background: url(/static/boiler.png)
background-size: cover
background-position: right bottom
display: flex
flex-direction: column
align-items: start
slots:
default:
- component: f7-row
config:
class:
- display-flex
- justify-content-space-between
- align-content-stretch
- align-items-center
slots:
default:
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
slots:
default:
- component: Label
config:
text: Puffer
style:
font-size: 12px
- component: f7-icon
config:
f7: rectangle_fill
color: '=(items[props.item_top].state.split(".")[0] < 46) ? "blue" : ((items[props.item_top].state.split(".")[0] < 60) ? "orange" : "red")'
size: 120
style:
top: 2px
left: 10px
transform: rotate(90deg)
filter: opacity(40%)
- component: oh-link
config:
text: =items[props.item_top].state + " °C"
color: '=(items[props.item_top].state.split(".")[0] < 46) ? "blue" : ((items[props.item_top].state.split(".")[0] < 60) ? "orange" : "red")'
action: analyzer
actionAnalyzerItems: =[props.item_top]
style:
top: 2px
font-size: 14px
font-weight: bold
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
slots:
default:
- component: Label
config:
text: "Vorlauf :"
style:
font-size: 12px
stue
(Matthias)
February 26, 2025, 8:37pm
2
uid: wid_Test_boiler
tags: []
props:
parameters:
- context: item
default: Test_GroupOne_NumberItem
description: item for Vorlauf
label: Item
name: itmVorlauf
required: false
type: TEXT
- context: item
default: Test_GroupOne_NumberItem
description: item for Leistung
label: Item
name: itmLeistung
required: false
type: TEXT
- default: /static/boiler.png
description: /static/myImage.jpg
label: Background image-url
name: backgroundUrl
required: false
type: TEXT
parameterGroups: []
timestamp: Feb 26, 2025, 8:22:46 PM
component: f7-card
config:
class:
#- padding
style:
background-color: "=props.bgcolor ? props.bgcolor : ''"
border-radius: var(--f7-card-expandable-border-radius)
#
box-shadow: 5px 5px 10px 1px rgba(0,0,0,0.1)
height: 120px
margin-left: 5px
margin-right: 5px
noShadow: false
display: flex
#padding: 0px
slots:
default:
- component: div
config:
style:
background-image: "='url(' + props.backgroundUrl + ')'"
#display: flex
flex-grow: 1
clip-path: ="inset( 0px round var(--f7-card-expandable-border-radius))"
#min-height: 180px
##max-height: 180px
#max-width: 120px
#min-width: 120px
#background-size: cover
#background-position: right bottom
#display: flex
#flex-direction: column
#align-items: start
#- component: f7-card-content
# config:
# style:
# display: flex
# #background: lightgreen
slots:
default:
- component: f7-row
config:
class:
#- display-flex
#- justify-content-space-between
#- align-content-stretch
#- align-items-center
style:
#display: flex
background: yellow)
filter: opacity(60%)
align-items: stretch
#flex-grow: 1
#border-radius: var(--f7-card-expandable-border-radius)
border-radius: 50px
slots:
default:
- component: f7-col
config:
class:
- display-flex
#- flex-direction-column
- align-items-center
- justify-content-center
style:
background: lightgrey
filter: opacity(60%)
slots:
default:
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
- justify-content-center
style:
background: lightgrey
filter: opacity(60%)
slots:
default:
- component: Label
config:
text: Puffer
style:
font-size: 12px
- component: f7-icon
config:
f7: rectangle_fill
color: "=(items[props.item_top].state.split('.')[0] < 46) ? 'blue' : ((items[props.item_top].state.split('.')[0] < 60) ? 'orange' : 'red')"
size: 6cqh
style:
#top: 2px
#left: 10px
transform: rotate(90deg)
filter: opacity(40%)
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
- justify-content-center
style:
background: lightgrey
filter: opacity(60%)
slots:
default:
- component: oh-link
config:
text: =items[props.item_top].state + ' °C'
color: "=(items[props.item_top].state.split('.')[0] < 46) ? 'blue' : ((items[props.item_top].state.split('.')[0] < 60) ? 'orange' : 'red')"
action: analyzer
actionAnalyzerItems: =[props.item_top]
style:
#top: 2px
#font-size: 14px
font-weight: bold
background: purple
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
- justify-content-center
style:
background: lightgreen
filter: opacity(60%)
slots:
default:
- component: Label
config:
text: "='Vorlauf: ' + items[props.itmVorlauf].state + ' °C'"
style:
font-size: 12px
- component: Label
config:
text: "='Leistung: ' + items[props.itmLeistung].state + ' W'"
style:
font-size: 12px
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
style:
background: lightblue
filter: opacity(60%)
slots:
default:
- component: oh-button
config:
class:
- display-flex
- flex-direction-column
- align-items-center
- justify-content-center
style:
flex-grow: 1
slots:
default:
- component: Label
config:
text: 'Heizung: '
style:
font-size: 12px
- component: Label
config:
text: 'ON'
style:
font-size: 12px
Hopefully you can pick up a few useful things.
I believe you, like I did, had trouble understanding CSS Flexbox. I use for every second widget I work on: CSS3 Flexbox because I just can’t keep it all in my head.
I added some background colors to clarify where each container is located. I also left your code so that you can compare and reassign it.
Of course, this is just a code suggestion and it needs to be cleaned up.
marvo88
(Martin)
February 27, 2025, 8:35am
3
Hi Matthias,
thank you very much for your help.
I was able to configure my widget with two open questions:
My switch has no changing color to red and no hand over it like the oh-button
How I can add the background picture of the water-buffer for the rectangle in your example?
uid: Heizung
tags: []
props:
parameters:
- context: item
description: item for Puffer Top
label: Item
name: item_top
required: false
type: TEXT
- context: item
description: item for Vorlauf
label: Item
name: itmVorlauf
required: false
type: TEXT
- context: item
description: item for Leistung
label: Item
name: itmLeistung
required: false
type: TEXT
- context: item
description: item for Heizung
label: Item
name: itmHeizung
required: false
type: TEXT
- default: /static/boiler.png
description: /static/myImage.jpg
label: Background image-url
name: backgroundUrl
required: false
type: TEXT
parameterGroups: []
timestamp: Feb 26, 2025, 8:22:46 PM
component: f7-card
config:
class:
#- padding
style:
background-color: "=props.bgcolor ? props.bgcolor : ''"
border-radius: var(--f7-card-expandable-border-radius)
#
box-shadow: 5px 5px 10px 1px rgba(0,0,0,0.1)
height: 120px
margin-left: 5px
margin-right: 5px
noShadow: false
display: flex
#padding: 0px
slots:
default:
- component: div
config:
style:
background-image: "='url(' + props.backgroundUrl + ')'"
#display: flex
flex-grow: 1
clip-path: ="inset( 0px round var(--f7-card-expandable-border-radius))"
#min-height: 180px
##max-height: 180px
#max-width: 120px
#min-width: 120px
#background-size: cover
#background-position: right bottom
#display: flex
#flex-direction: column
#align-items: start
#- component: f7-card-content
# config:
# style:
# display: flex
# #background: lightgreen
slots:
default:
- component: f7-row
config:
class:
#- display-flex
#- justify-content-space-between
#- align-content-stretch
#- align-items-center
style:
#display: flex
#background: yellow)
#filter: opacity(60%)
align-items: stretch
#flex-grow: 1
#border-radius: var(--f7-card-expandable-border-radius)
border-radius: 50px
slots:
default:
- component: f7-col
config:
class:
- display-flex
#- flex-direction-column
- align-items-center
- justify-content-center
style:
# background: lightgrey
# filter: opacity(60%)
slots:
default:
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
- justify-content-center
style:
#background: lightgrey
#filter: opacity(60%)
slots:
default:
- component: Label
config:
text: Puffer
style:
font-size: 12px
- component: f7-icon
config:
f7: rectangle_fill
color: "=(items[props.item_top].state.split('.')[0] < 46) ? 'blue' : ((items[props.item_top].state.split('.')[0] < 60) ? 'orange' : 'red')"
size: 10cqh
style:
#top: 2px
#left: 10px
transform: rotate(90deg)
filter: opacity(40%)
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
- justify-content-center
style:
#background: lightgrey
filter: opacity(60%)
slots:
default:
- component: oh-link
config:
text: =items[props.item_top].state + ' °C'
color: "=(items[props.item_top].state.split('.')[0] < 46) ? 'blue' : ((items[props.item_top].state.split('.')[0] < 60) ? 'orange' : 'red')"
action: analyzer
actionAnalyzerItems: =[props.item_top]
style:
#top: 2px
font-size: 20px
font-weight: bold
#background: purple
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-left
- justify-content-center
# style:
# background: lightgreen
# filter: opacity(60%)
slots:
default:
- component: Label
config:
text: "='Vorlauf: ' + items[props.itmVorlauf].state + ' °C'"
style:
font-size: 12px
- component: Label
config:
text: "='Leistung: ' + items[props.itmLeistung].state + ' W'"
style:
font-size: 12px
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
- justify-content-center
style:
#background: lightblue
#filter: opacity(60%)
slots:
default:
- component: Label
config:
text: 'Heizung: '
style:
font-size: 12px
- component: oh-icon
config:
icon: switch
action: toggle
actionItem: =props.itmHeizung
actionCommand: OFF
actionCommandAlt: ON
height: 50
style:
color: =(@props.itmHeizung == "ON") ? "green":"red"
- component: Label
config:
text: =(@props.itmHeizung == "ON") ? "ON":"OFF"
style:
color: =(@props.itmHeizung == "ON") ? "green":"red"
font-size: 12px
JustinG
(JustinG)
February 27, 2025, 3:16pm
4
By just using icon: switch
, you have selected one of the OH icons. These icons cannot be re-colored directly (there was some recent work on this, but I don’t think it is complete yet). There are a couple of different solutions: 1) find a similar or preferable icon from one of the other icon providers such as f7:power
because these icon can be recolored or 2) use the state-base variants of the OH icon you want, in this case switch-on
and switch-off
. In case #2 you would not need the color directive in the style object at all, you would move the expression up to the actual icon property itself:
icon: =(@props.itmHeizung == "ON") ? "switch-on":"switch-off"
The oh-button
becomes and html <a>
tag when it is rendered on the page, which usually automatically get the pointer cursor when hovered over. The oh-icon
, on the other hand gets rendered as an <img>
tag. So, if you want the cursor to change when over the icon you have to do that manually with the css style:
style:
cursor: pointer
You’ll have to do that with css too. The image needs to be some place OH can access it (usually this means placing it in the html
folder in your OH conf folder). Then the url to access the image will be /static/image.name
.
W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.
stue
(Matthias)
February 27, 2025, 7:11pm
5
I already did the css job by:
style:
background-image: "='url(' + props.backgroundUrl + ')'"
You only need to drop your image into /etc/openhab/html/ and either…
…adjust the default settings in the widget code.
- default: /static/boiler.png #<---- just change "boiler.png" to ...
description: /static/boiler.png
label: Background image-url
name: backgroundUrl
required: false
type: TEXT
… or change individual widget-settings (set props)
1 Like
marvo88
(Martin)
February 27, 2025, 7:49pm
6
Hi,
thank you very much, I got the switch icon and the hand-cursor, thanks.
But, if I set the picture, I have the picture in each column. I would like have the picture only behind the rectangle_fill like in the attached picture.
stue
(Matthias)
February 27, 2025, 8:25pm
7
replace…:
- component: Label
config:
text: Puffer
style:
font-size: 12px
- component: f7-icon
config:
f7: rectangle_fill
color: "=(items[props.item_top].state.split('.')[0] < 46) ? 'blue' : ((items[props.item_top].state.split('.')[0] < 60) ? 'orange' : 'red')"
size: 10cqh
style:
#top: 2px
#left: 10px
transform: rotate(90deg)
filter: opacity(40%)
…with:
- component: Label
config:
text: Puffer
style:
font-size: 12px
- component: oh-image
config:
url: =props.backgroundUrl
style:
margin: 0.3cqh
height: 8cqh
width: 5cqh
and delete the background-image from top container:
- component: div
config:
style:
#background-image: "='url(' + props.backgroundUrl + ')'" <--- delete
for your round corners play with:
border-radius
stue
(Matthias)
February 27, 2025, 9:38pm
8
uid: wid_boiler
tags: []
props:
parameters:
- context: item
default: Test_GroupOne_NumberItem
description: item with the Vorlauf temperature
label: Item
name: itmVorlauf
required: false
type: TEXT
- context: item
default: Test_GroupOne_NumberItem
description: item with the power
label: Item
name: itmLeistung
required: false
type: TEXT
- context: item
default: Test_GroupOne_NumberItem
description: item with the fill-level
label: Item
name: itmLevel
required: false
type: TEXT
- default: /static/bild.png
description: (url(/static/boiler.png))
label: Background image-url
name: backgroundUrl
required: false
type: TEXT
parameterGroups: []
timestamp: Feb 27, 2025, 9:08:58 PM
component: f7-card
config:
style:
background-color: "=props.bgcolor ? props.bgcolor : ''"
border-radius: var(--f7-card-expandable-border-radius)
box-shadow: 5px 5px 10px 1px rgba(0,0,0,0.1)
height: 120px
margin-left: 5px
margin-right: 5px
noShadow: false
display: flex
slots:
default:
- component: div
config:
style:
flex-grow: 1
clip-path: ="inset( 0px round var(--f7-card-expandable-border-radius))"
slots:
default:
- component: f7-row
config:
style:
align-items: stretch
slots:
default:
- component: f7-col
config:
class:
- display-flex
- align-items-center
- justify-content-center
style:
background: none
filter: none
slots:
default:
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
- justify-content-center
style:
background: none
filter: none
slots:
default:
- component: Label
config:
text: Puffer
style:
font-size: 12px
#______________________________________________________________________________________
#Maybe you'd like to visualize the level based on the state of an item declared in props.
- component: div
config:
style:
clip-path: ="inset( 0px round var(--f7-card-expandable-border-radius))"
margin: 0.3cqh
height: 8cqh
position: relative
slots:
default:
- component: oh-image
config:
url: =props.backgroundUrl
style:
height: 100%
- component: div
config:
style:
position: absolute
top: "=(100 - items[props.itmLevel].state) + '%'"
bottom: 0
left: 0
right: 0
background: red
filter: opacity(60%)
#______________________________________________________________________________________
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
- justify-content-center
style:
background: none
filter: none
slots:
default:
- component: oh-link
config:
text: =items[props.item_top].state + ' °C'
color: "=(items[props.item_top].state.split('.')[0] < 46) ? 'blue' :
((items[props.item_top].state.split('.')[0] <
60) ? 'orange' : 'red')"
action: analyzer
actionAnalyzerItems: =[props.item_top]
style:
font-weight: bold
background: none
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
- justify-content-center
style:
background: none
filter: none
slots:
default:
- component: Label
config:
text: "='Vorlauf: ' + items[props.itmVorlauf].state + ' °C'"
style:
font-size: 12px
- component: Label
config:
text: "='Leistung: ' + items[props.itmLeistung].state + ' W'"
style:
font-size: 12px
- component: f7-col
config:
class:
- display-flex
- flex-direction-column
- align-items-center
style:
background: none
filter: none
slots:
default:
- component: oh-button
config:
class:
- display-flex
- flex-direction-column
- align-items-center
- justify-content-center
style:
flex-grow: 1
slots:
default:
- component: Label
config:
text: "Heizung: "
style:
font-size: 12px
- component: Label
config:
text: ON
style:
font-size: 12px
marvo88
(Martin)
March 6, 2025, 7:45am
9
Hi,
Thank you very much,
I use it without the level, only a rectangle_fillwith a changing color.
The widget works, but I think I will seperate the button, because on my tablet it is not all in the box.
Thanks.