Hi @Nico_R
thank you for your great work on the widget.
Can you give me a hint as to what I have to change so that instead of the openhab logo I get a label field for the switch below.
Hi @Nico_R
thank you for your great work on the widget.
Can you give me a hint as to what I have to change so that instead of the openhab logo I get a label field for the switch below.
Hi @Tallman ,
if you want only show a simple text label i can suggest the follow solution.
Change the oh-image
component to a Label
component at the same position.
- component: Label
config:
text: Your Text
style:
position: absolute
transform: translate(-50%)
left: 50%
width: 40%
#- component: oh-image
#config:
#url: https://community-openhab-org.s3-eu-central-1.amazonaws.com/original/2X/7/7d388a86c95471f89b1bb911d96d7609a3e3a059.svg
#style:
#position: absolute
#transform: translate(-50%)
#left: 50%
#width: 40%
The result:
all the best,
Nico
look at the first post. I’ve updated the yaml.
The widget in v1.7 is now more responsive.
Cool looking and good working widget, thank you for that!
Hi Nico,
great work. I’m using the widget for all my AVM-thermostats.
As you can see I’m using a List-Card-Widget to get some other information and to rule several modes. Are these information interesting enough to you too, to integrate it in your widget ???
Another point is that you have written above something about
Is it part of the widget, as I didn’t find anything in the widget ?
Thx again, and
Cheers,
Peter
Hi @fibu-freak
thanks for the positive feedback.
Please post the little yaml extract of your list-component under the widget.
I will looking for a good solution.
best,
Nico
First of all, i wish to say big Thank You for you excellent work! Widget just beautiful!
I use it with MAX! thermostats and it get big thumbs up, especially from my wife .
I made few improvements, may be it will be useful for someone.
First, operations of my thermostats linked to windows open state, so I added icon representing window state. It accept ether item or group and expect states OPEN or CLOSED. Unfortunately, f7 icon set does not include windows icons, so I use icons from openhab classic set.
Next, I added ability to display thermostat mode. It expect string item and display it as is. Maybe it need to be made as a menu, but I’m almost never switch thermostat mode manually.
Last but not least I added ability to display heating status, like it is done in OH locations badges. But I’m don’t like default OH HVAC icon, so instead string “HEATING” change color then heating active. Expect simple binary item with ON/OFF state.
Screenshots:
uid: HeatingCSS_1.8
tags:
- heating
props:
parameters:
- description: eg. living room
label: location
name: location
required: false
type: TEXT
- description: Visual size of the control in px (default 400px), without a size the design is responsive
label: size [px]
name: size
required: false
type: TEXT
- description: Minimum value
label: minTemp
name: minTemp
required: true
type: TEXT
- description: Maximum value
label: maxTemp
name: maxTemp
required: true
- context: item
description: Item to control
label: Set point Item
name: setPointItem
required: true
type: TEXT
- context: item
label: Item for current temperature
name: currentPointItem
required: true
type: TEXT
- context: item
label: Item to toggle something
name: toggleItem
required: false
type: TEXT
- context: item
label: Item to display window state
name: windowItem
required: false
type: TEXT
- context: item
label: Item to display thermostat mode
name: modeItem
required: false
type: TEXT
- context: item
label: Item to display heater state
name: heaterItem
required: false
type: TEXT
- description: Control item unit eg °C
label: unit
name: unit
required: false
type: TEXT
- label: Main-Color Thermostat
name: colorThermostat
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color control ring
name: colorControlRing
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color buttons
name: colorButton
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color center
name: colorCenter
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color Typo
name: colorTypo
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color setPoint Marker
name: colorSetMarker
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color currentPoint Marker
name: colorCurrentMarker
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color bar linear gradient startPoint
name: colorBarStartPoint
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color bar linear gradient endPoint
name: colorBarEndPoint
required: false
type: TEXT
groupName: colors
advanced: true
parameterGroups:
- name: colors
label: Color-Settings
timestamp: Feb 12, 2021, 4:56:28 PM
component: f7-card
config:
title: "=(props.location) ? 'Klima ' + props.location : ''"
slots:
default:
- component: f7-card-content
slots:
default:
- component: f7-row
config:
resizableFixed: true
resizable-absolute: true
class:
- justify-content-center
slots:
default:
- component: f7-block
config:
class: thermostat
style:
flex-shrink: 0
--f7-block-margin-vertical: 0px
--f7-block-padding-vertical: 0px
--f7-block-padding-horizontal: 0px
padding-left: 0px
padding-top: "=props.size ? '': '100%'"
width: "=props.size ? Number(props.size)+'px' : '100%'"
height: "=props.size ? Number(props.size)+'px' : '100%'"
background: "=props.colorThermostat ? props.colorThermostat : 'var(--f7-toggle-inactive-color)'"
border-radius: 50%
border: 2px solid rgb(64, 60, 77)
slots:
default:
- component: f7-block
config:
class: bar
style:
margin-top: 0px
position: absolute
width: "=props.size ? (Number(props.size)*0.89) +'px' : '89%'"
height: "=props.size ? (Number(props.size)*0.89) +'px' : '89%'"
top: 50%
left: 50%
transform: translate(-50%, -50%)
border-radius: 50%
slots:
default:
- component: f7-block
config:
class: inner_bar
style:
margin-top: 0
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
width: "=props.size ? (Number(props.size)*0.86) +'px' : '97%'"
height: "=props.size ? (Number(props.size)*0.86) +'px' : '97%'"
border-radius: 100%
background-color: "=props.colorThermostat ? props.colorThermostat : 'var(--f7-toggle-inactive-color)'"
z-index: 4 !important
slots:
default:
- component: f7-block
config:
style:
background: "='conic-gradient(transparent 0deg 160deg, ' + (props.colorThermostat ? props.colorThermostat : 'var(--f7-toggle-inactive-color)') + ' 160deg 200deg, transparent 200deg 360deg)'"
content: ""
display: block
position: absolute
width: 100%
height: 100%
bottom: "=props.size ? '-7px' : '-7px'"
left: 50%
transform: translate(-50%)
- component: f7-block
config:
class: hold left
style:
margin-top: 0px
position: absolute
width: 100%
height: 100%
clip-path: "=props.size ? 'inset(0px 0px 0px ' + (Number(props.size)*0.89/2) + 'px)' : 'inset(0% 0% 0% 50%)'"
border-radius: 100%
background-color: rgb(58, 55, 73)
slots:
default:
- component: f7-block
config:
class: fill fill1
style:
margin-top: 0px
position: absolute
width: 100%
height: 100%
border-radius: 100%
clip-path: "=props.size ? 'inset(0px ' + (Number(props.size)*0.89/2) + 'px 0px 0px)' : 'inset(0% 50% 0% 0%)'"
background: "=props.colorBarStartPoint && props.colorBarEndPoint ? '-webkit-linear-gradient(top, ' + props.colorBarEndPoint + ' 20%,' + props.colorBarEndPoint + ' 100%)' : '-webkit-linear-gradient(top, rgb(255, 73, 0) 20%,rgb(255, 73, 0) 100%)'"
z-index: 1 !important
animation: left 0.3s linear both
animation-delay: 1s
transition: transform 0.6s
transform: "=(items[props.setPointItem].state.split(' ')[0] >= (((Number(props.maxTemp) - Number(props.minTemp)) / 2) + Number(props.minTemp)) && items[props.setPointItem].state.split(' ')[0] <= Number(props.maxTemp) ? 'rotate('+(320/(Number(props.maxTemp)-Number(props.minTemp))*(items[props.setPointItem].state.split(' ')[0]-Number(props.minTemp))-160)+'deg)' : (items[props.setPointItem].state.split(' ')[0] > Number(props.maxTemp)) ? 'rotate(180deg)' : '')"
- component: f7-block
config:
class: hold right
style:
margin-top: 0px
position: absolute
width: 100%
height: 100%
clip-path: "=props.size ? 'inset(0px 0px 0px ' + (Number(props.size)*0.89/2) + 'px)' : 'inset(0% 0% 0% 50%)'"
border-radius: 100%
background-color: rgb(58, 55, 73)
z-index: 3 !important
transform: rotate(180deg)
slots:
default:
- component: f7-block
config:
class: fill
style:
margin-top: 0px
position: absolute
width: 100%
height: 100%
border-radius: 100%
z-index: 3 !important
animation: right 1s linear both
transition: transform 0.6s
- component: f7-block
config:
class: fill fill2
style:
position: absolute
margin-top: 0px
width: 100%
height: 100%
border-radius: 50%
z-index: 3 !important
clip-path: "=props.size ? 'inset(0px '+ (Number(props.size)*0.89/2) + 'px 0px 0px)' : 'inset(0% 50% 0% 0%)'"
background: "=props.colorBarStartPoint && props.colorBarEndPoint ? '-webkit-linear-gradient(top, ' + props.colorBarEndPoint + ' 40%,' + props.colorBarStartPoint + ' 100%)' : '-webkit-linear-gradient(top, rgb(255, 73, 0) 40%,rgb(255, 158, 35) 100%)'"
transform: "=(items[props.setPointItem].state.split(' ')[0] <= (((Number(props.maxTemp) - Number(props.minTemp)) / 2) + Number(props.minTemp)) && items[props.setPointItem].state.split(' ')[0] >= Number(props.minTemp) ? 'rotate('+(320/(Number(props.maxTemp)-Number(props.minTemp))*(items[props.setPointItem].state.split(' ')[0]-Number(props.minTemp))+20)+'deg)' : (items[props.setPointItem].state.split(' ')[0] > (((Number(props.maxTemp) - Number(props.minTemp)) / 2) + Number(props.minTemp))) ? 'rotate(180deg)' : '')"
- component: f7-block
config:
class: span
style:
margin-top: 0px
width: "=props.size ? (Number(props.size)*0.89) +'px' : '100%'"
font-weight: "=props.size ? (Number(props.size)*2) +'px' : 'calc(var(--f7-list-item-title-font-weight)*2)'"
position: absolute
bottom: 0px
text-align: center
text-transform: uppercase
font-size: "=props.size ? (Number(props.size)*0.0375) +'px' : '1em'"
color: "=props.colorTypo ? props.colorTypo : 'rgb(87, 84, 95)'"
z-index: 99 !important
slots:
default:
- component: Label
config:
text: Heating
style:
color: "=(items[props.heaterItem].state === 'ON') ? 'orange' : 'black'"
- component: f7-block
config:
class: shadow
style:
margin-top: 0px
position: absolute
top: 50%
left: 50%
transform: "=(items[props.setPointItem].state.split(' ')[0] >= Number(props.minTemp) && items[props.setPointItem].state.split(' ')[0] <= Number(props.maxTemp) ? 'translate(-50%, -50%) rotate('+(320/(Number(props.maxTemp)-Number(props.minTemp))*(items[props.setPointItem].state.split(' ')[0]-Number(props.minTemp))-160)+'deg)' : 'translate(-50%, -50%) rotate(0deg)')"
width: "=props.size ? (Number(props.size)*0.0625) +'px' : '6.25%'"
height: 86%
text-align: center
transition: 0.7s ease
animation: shadow 1.4s ease-out both
slots:
default:
- component: f7-block
config:
class: shadow-cube
style:
margin-top: 0px
position: absolute
top: 0
width: "=props.size ? (Number(props.size)*0.0625) +'px' : '100%'"
height: 0px
box-shadow: "=props.size ? '0 0 ' + (Number(props.size)*0.1125) +'px ' + (Number(props.size)*0.0325) + 'px ' + (props.colorSetMarker ? props.colorSetMarker : 'rgba(255, 158, 35, 0.5)'): '0 0 45px 13px rgba(255, 158, 35, 0.5)'"
- component: f7-block
config:
class: markerContainer
style:
pointer-events: none
margin-top: 0px
position: absolute
top: 50%
left: 50%
transform: "=(items[props.currentPointItem].state.split(' ')[0] >= Number(props.minTemp) && items[props.currentPointItem].state.split(' ')[0] <= Number(props.maxTemp) ? 'translate(-50%, -50%) rotate('+(320/(Number(props.maxTemp)-Number(props.minTemp))*(items[props.currentPointItem].state.split(' ')[0]-Number(props.minTemp))-160)+'deg)' : 'translate(-50%, -50%) rotate(0deg)')"
width: "=props.size ? (Number(props.size)*0.1) +'px' : '10%'"
height: 100%
text-align: center
transition: 0.7s ease
opacity: 1
z-index: 99 !important
slots:
default:
- component: f7-block
config:
class: markerCurrent
style:
margin-top: 0px
width: "=props.size ? (Number(props.size)*0.1) +'px' : '100%'"
height: "=props.size ? (Number(props.size)*0.1) +'px' : ''"
padding-top: "=props.size ? '' : '100%'"
background: "=props.colorCurrentMarker ? props.colorCurrentMarker : 'rgb(33, 150, 243)'"
position: absolute
transform: translate(-50%,-50%) rotate(45deg)
left: 50%
top: "=props.size ? (Number(props.size)*0.14) +'px' : '15%'"
border-radius: 0% 50% 50% 50%
box-shadow: 0 0 5px 1px rgb(48, 46, 56)
slots:
default:
- component: f7-block
config:
class: number
style:
margin-top: 0px
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%) rotate(-45deg)
text-align: center
slots:
default:
- component: Label
config:
text: =items[props.currentPointItem].state.split(' ')[0]
style:
font-size: "=props.size ? (Number(props.size)*0.04) +'px' : '14px'"
color: white
font-weight: bold
- component: f7-block
config:
class: markerContainer
style:
pointer-events: none
margin-top: 0px
position: absolute
top: 50%
left: 50%
transform: "=(items[props.setPointItem].state.split(' ')[0] >= Number(props.minTemp) && items[props.setPointItem].state.split(' ')[0] <= Number(props.maxTemp) ? 'translate(-50%, -50%) rotate('+(320/(Number(props.maxTemp)-Number(props.minTemp))*(items[props.setPointItem].state.split(' ')[0]-Number(props.minTemp))-160)+'deg)' : 'translate(-50%, -50%) rotate(0deg)')"
width: "=props.size ? (Number(props.size)*0.1) +'px' : '10%'"
height: 100%
text-align: center
transition: 0.7s ease
opacity: 1
z-index: 99 !important
slots:
default:
- component: f7-block
config:
class: markerSet
style:
margin-top: 0px
width: "=props.size ? (Number(props.size)*0.1) +'px' : '100%'"
height: "=props.size ? (Number(props.size)*0.1) +'px' : ''"
padding-top: "=props.size ? '' : '100%'"
background: "=props.colorSetMarker ? props.colorSetMarker : 'rgb(230, 74, 25)'"
position: absolute
transform: translate(-50%,-50%) rotate(-45deg)
left: 50%
top: "=props.size ? (Number(props.size)*Number(-0.0125)) +'px': '-2%'"
border-radius: 50% 50% 50% 0
box-shadow: 0 0 5px 1px rgb(48, 46, 56)
z-index: 100 !important
slots:
default:
- component: f7-block
config:
class: number
style:
margin-top: 0px
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%) rotate(45deg)
text-align: center
slots:
default:
- component: Label
config:
text: =items[props.setPointItem].state.split(' ')[0]
style:
font-size: "=props.size ? (Number(props.size)*0.04) +'px' : '14px'"
color: white
font-weight: bold
- component: f7-block
config:
class: center
style:
margin-top: 0px
position: absolute
width: "=props.size ? (Number(props.size)*0.65) +'px' : '65%'"
height: "=props.size ? (Number(props.size)*0.65) +'px' : '65%'"
background: "=props.colorControlRing ? props.colorControlRing : 'rgb(227, 228, 237)'"
animation: bound-in 0.6s ease forwards
top: 50%
left: 50%
transform: translate(-50%, -50%)
border-radius: 50%
box-shadow: 0px 15px 35px 11px rgba(46, 44, 58,0.60)
slots:
default:
- component: oh-toggle
config:
visible: "=props.toggleItem ? true : false"
item: =props.toggleItem
style:
position: absolute
bottom: 0%
left: 50%
transform: translate(-50%,-50%)
color: "=props.colorButton ? props.colorButton + ' !important': ''"
- component: oh-icon
config:
visible: "=props.windowItem ? true : false"
icon: "=(items[props.windowItem].state === 'OPEN') ? 'window-open' : 'window-closed'"
style:
position: absolute
bottom: 40%
left: 50%
transform: translate(-50%,-50%)
width: 20%
height: 50%
- component: oh-button
config:
visible: "=props.modeItem ? true : false"
item: =props.toggleItem
text: =items[props.modeItem].state
style:
position: absolute
bottom: 5%
left: 50%
transform: translate(-50%,-50%)
color: "=props.colorButton ? props.colorButton + ' !important': ''"
- component: oh-button
config:
style:
--f7-button-hover-bg-color: transparent
--f7-button-pressed-bg-color: transparent
width: 30%
height: 50%
position: absolute
margin-top: 0px
top: 50%
left: 10%
transform: translate(-50%, -50%)
color: "=props.colorButton ? props.colorButton : ''"
action: command
actionItem: =props.setPointItem
actionCommand: "=Number(items[props.setPointItem].state.split(' ')[0]) > Number(props.minTemp) ? Number(items[props.setPointItem].state.split(' ')[0]) - 0.5 : ''"
slots:
default:
- component: f7-icon
config:
size: "=props.size ? (Number(props.size)*0.075) : '30'"
style:
position: absolute
transform: translate(-50%, -50%)
top: 50%
margin-top: auto
f7: arrow_turn_left_down
- component: oh-button
config:
style:
--f7-button-hover-bg-color: transparent
--f7-button-pressed-bg-color: transparent
width: 30%
height: 50%
position: relative
margin-top: 0px
top: 50%
left: 90%
transform: translate(-50%, -50%)
color: "=props.colorButton ? props.colorButton : ''"
action: command
actionItem: =props.setPointItem
actionCommand: "=Number(items[props.setPointItem].state.split(' ')[0]) < Number(props.maxTemp) ? Number(items[props.setPointItem].state.split(' ')[0]) + 0.5 : ''"
slots:
default:
- component: f7-icon
config:
size: "=props.size ? (Number(props.size)*0.075) : '30'"
style:
position: absolute
transform: translate(-50%, -50%)
top: 50%
margin-top: auto
f7: arrow_turn_right_up
- component: f7-block
config:
class: small
style:
margin-top: 0px
position: absolute
width: "=props.size ? (Number(props.size)*0.375) +'px' : '57.6%'"
height: "=props.size ? (Number(props.size)*0.375) +'px' : '57.6%'"
background: "=props.colorCenter ? props.colorCenter : 'rgb(248, 249, 250)'"
text-align: center
animation: bound-in-small 0.6s ease forwards
top: 50%
left: 50%
transform: translate(-50%, -50%)
border-radius: 50%
box-shadow: 0px 5px 10px 5px rgba(96, 93, 111,0.19)
slots:
default:
- component: f7-block
config:
class: heat
style:
font-size: "=props.size ? (Number(props.size)*0.0375) +'px' : '14px'"
color: "=props.colorTypo ? props.colorTypo : 'rgb(87, 84, 95)'"
font-weight: 300
slots:
default:
- component: Label
config:
text: =props.location
- component: f7-block
config:
class: heat
style:
font-size: "=props.size ? (Number(props.size)*0.1125) +'px' : '2.5em'"
color: "=props.colorTypo ? props.colorTypo : 'rgb(87, 84, 95)'"
font-weight: 300
slots:
default:
- component: Label
config:
text: "=props.unit ? items[props.setPointItem].state.split(' ')[0] + '' + props.unit : items[props.setPointItem].state.split(' ')[0]"
- component: oh-image
config:
url: https://community-openhab-org.s3-eu-central-1.amazonaws.com/original/2X/7/7d388a86c95471f89b1bb911d96d7609a3e3a059.svg
style:
position: absolute
transform: translate(-50%)
left: 50%
width: 40%
Unfortunately, this is my first post and forum software does not allow me to include second screenshot in same post - see it here:
first, thx for reply.
Here is the yaml of the list-card:
component: oh-list-card
config: {}
slots:
default:
- component: oh-label-item
config:
item: radiator_valve_01_Mode
title: Temperatur Modus
icon: oh:heating2
iconUseState: true
action: options
actionItem: radiator_valve_01_Mode
- component: oh-label-item
config:
item: radiator_valve_01_ModeX
title: Automatic Modus
iconUseState: true
action: options
actionItem: radiator_valve_01_ModeX
icon: oh:temperature
- component: oh-label-item
config:
item: radiator_valve_01_Battery
title: Batteriezustand
icon: oh:lowbattery1
iconUseState: true
I’m using now Version 1.7 of your Widget, therefore I made a little change in the code to see directly which Version I’m using:
I’m also wondering what would happen with the openHAB-Label, when the Internet-Connection is broken, as I understand that the image comes from an external internet-adress.
Again thx, for this great widget. I was several times asked for this awesome widget in the german community and I hope you don’t mind if I recommend this site to others.
Cheers
Peter
Edit: I forgot to say that it would nice if the information could be shown/changed in the corners of the widget, so no extra place is needed (only a brain-fart )
Your changes look similar that I do. You can replace window icon with battery information. Something like
- component: oh-icon
config:
visible: "=props.lowbatteryItem ? true : false"
icon: "=(items[props.Item].state === 'ON') ? 'lowbattery-on' : 'lowbattery-off'"
style:
position: absolute
bottom: 40%
left: 50%
transform: translate(-50%,-50%)
width: 20%
height: 50%
And if you not need toggleItem support you can put second status line below
- component: oh-button
config:
visible: "=props.modeItem ? true : false"
item: =props.toggleItem
text: =items[props.modeItem].state
style:
position: absolute
bottom: 5%
left: 50%
transform: translate(-50%,-50%)
color: "=props.colorButton ? props.colorButton + ' !important': ''"
Only problem what I don’t know how to make status line switchable.
Hi Alex, thx for reply and your hints.
I think your ideawith the window is nice and very practically.
Some side-information:
The battery-low info is more or less from a Switch-Item(Channel is read-only).
The Mode-Items are Type “String” with “Setpoint” with several options. So the result looks:
and
I think the information comes from the Binding-Channels, so a Switch-Item can’t help in this case.
As I’m not very good in coding and programming, I will wait if Nico find a solution, but I will have a look at your code, maybe I can learn a bit for future purposes.
Cheers,
Peter
MEGA JOB!
siting in this moment on integrate my AVM-thermostats and find that great solution ,
thank you all for that!
Hello!
I implemented (i hope) what you needed. See screenshots:
Few notes:
removed toggleItem (I think this functionality can be covered with buttons)
modeItem now display popup for setting
added mode2Item, also with popup. Because my thermostat have only one mode switch setting, I use same for both switches in demo (unfortunately, if enabled replacing openhab logo, I unable to find better place for it, blame my lack of designer skills here)
added batteryItem to display battery status. Expects OPEN/CLOSED state, but can be easily adapted for other reporting, I hope.
Below 300 px looks rather ugly, sorry
Code:
uid: HeatingCSS_1.9
tags:
- heating
props:
parameters:
- description: eg. living room
label: location
name: location
required: false
type: TEXT
- description: Visual size of the control in px (default 400px), without a size the design is responsive
label: size [px]
name: size
required: false
type: TEXT
- description: Minimum value
label: minTemp
name: minTemp
required: true
type: TEXT
- description: Maximum value
label: maxTemp
name: maxTemp
required: true
- context: item
description: Item to control
label: Set point Item
name: setPointItem
required: true
type: TEXT
- context: item
label: Item for current temperature
name: currentPointItem
required: true
type: TEXT
- context: item
label: Item to display window state
name: windowItem
required: false
type: TEXT
- context: item
label: Item to display thermostat mode
name: modeItem
required: false
type: TEXT
- context: item
label: Item to display thermostat mode
name: mode2Item
required: false
type: TEXT
- context: item
label: Item to display heater state
name: heaterItem
required: false
type: TEXT
- context: item
label: Item to display low battery status
name: batteryItem
required: false
type: TEXT
- description: Control item unit eg °C
label: unit
name: unit
required: false
type: TEXT
- label: Main-Color Thermostat
name: colorThermostat
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color control ring
name: colorControlRing
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color buttons
name: colorButton
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color center
name: colorCenter
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color Typo
name: colorTypo
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color setPoint Marker
name: colorSetMarker
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color currentPoint Marker
name: colorCurrentMarker
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color bar linear gradient startPoint
name: colorBarStartPoint
required: false
type: TEXT
groupName: colors
advanced: true
- label: Color bar linear gradient endPoint
name: colorBarEndPoint
required: false
type: TEXT
groupName: colors
advanced: true
parameterGroups:
- name: colors
label: Color-Settings
timestamp: Feb 14, 2021, 2:11:18 AM
component: f7-card
config:
title: "=(props.location) ? 'Klima ' + props.location : ''"
slots:
default:
- component: f7-card-content
slots:
default:
- component: f7-row
config:
resizableFixed: true
resizable-absolute: true
class:
- justify-content-center
slots:
default:
- component: f7-block
config:
class: thermostat
style:
flex-shrink: 0
--f7-block-margin-vertical: 0px
--f7-block-padding-vertical: 0px
--f7-block-padding-horizontal: 0px
padding-left: 0px
padding-top: "=props.size ? '': '100%'"
width: "=props.size ? Number(props.size)+'px' : '100%'"
height: "=props.size ? Number(props.size)+'px' : '100%'"
background: "=props.colorThermostat ? props.colorThermostat : 'var(--f7-toggle-inactive-color)'"
border-radius: 50%
border: 2px solid rgb(64, 60, 77)
slots:
default:
- component: f7-block
config:
class: bar
style:
margin-top: 0px
position: absolute
width: "=props.size ? (Number(props.size)*0.89) +'px' : '89%'"
height: "=props.size ? (Number(props.size)*0.89) +'px' : '89%'"
top: 50%
left: 50%
transform: translate(-50%, -50%)
border-radius: 50%
slots:
default:
- component: f7-block
config:
class: inner_bar
style:
margin-top: 0
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
width: "=props.size ? (Number(props.size)*0.86) +'px' : '97%'"
height: "=props.size ? (Number(props.size)*0.86) +'px' : '97%'"
border-radius: 100%
background-color: "=props.colorThermostat ? props.colorThermostat : 'var(--f7-toggle-inactive-color)'"
z-index: 4 !important
slots:
default:
- component: f7-block
config:
style:
background: "='conic-gradient(transparent 0deg 160deg, ' + (props.colorThermostat ? props.colorThermostat : 'var(--f7-toggle-inactive-color)') + ' 160deg 200deg, transparent 200deg 360deg)'"
content: ""
display: block
position: absolute
width: 100%
height: 100%
bottom: "=props.size ? '-7px' : '-7px'"
left: 50%
transform: translate(-50%)
- component: f7-block
config:
class: hold left
style:
margin-top: 0px
position: absolute
width: 100%
height: 100%
clip-path: "=props.size ? 'inset(0px 0px 0px ' + (Number(props.size)*0.89/2) + 'px)' : 'inset(0% 0% 0% 50%)'"
border-radius: 100%
background-color: rgb(58, 55, 73)
slots:
default:
- component: f7-block
config:
class: fill fill1
style:
margin-top: 0px
position: absolute
width: 100%
height: 100%
border-radius: 100%
clip-path: "=props.size ? 'inset(0px ' + (Number(props.size)*0.89/2) + 'px 0px 0px)' : 'inset(0% 50% 0% 0%)'"
background: "=props.colorBarStartPoint && props.colorBarEndPoint ? '-webkit-linear-gradient(top, ' + props.colorBarEndPoint + ' 20%,' + props.colorBarEndPoint + ' 100%)' : '-webkit-linear-gradient(top, rgb(255, 73, 0) 20%,rgb(255, 73, 0) 100%)'"
z-index: 1 !important
animation: left 0.3s linear both
animation-delay: 1s
transition: transform 0.6s
transform: "=(items[props.setPointItem].state.split(' ')[0] >= (((Number(props.maxTemp) - Number(props.minTemp)) / 2) + Number(props.minTemp)) && items[props.setPointItem].state.split(' ')[0] <= Number(props.maxTemp) ? 'rotate('+(320/(Number(props.maxTemp)-Number(props.minTemp))*(items[props.setPointItem].state.split(' ')[0]-Number(props.minTemp))-160)+'deg)' : (items[props.setPointItem].state.split(' ')[0] > Number(props.maxTemp)) ? 'rotate(180deg)' : '')"
- component: f7-block
config:
class: hold right
style:
margin-top: 0px
position: absolute
width: 100%
height: 100%
clip-path: "=props.size ? 'inset(0px 0px 0px ' + (Number(props.size)*0.89/2) + 'px)' : 'inset(0% 0% 0% 50%)'"
border-radius: 100%
background-color: rgb(58, 55, 73)
z-index: 3 !important
transform: rotate(180deg)
slots:
default:
- component: f7-block
config:
class: fill
style:
margin-top: 0px
position: absolute
width: 100%
height: 100%
border-radius: 100%
z-index: 3 !important
animation: right 1s linear both
transition: transform 0.6s
- component: f7-block
config:
class: fill fill2
style:
position: absolute
margin-top: 0px
width: 100%
height: 100%
border-radius: 50%
z-index: 3 !important
clip-path: "=props.size ? 'inset(0px '+ (Number(props.size)*0.89/2) + 'px 0px 0px)' : 'inset(0% 50% 0% 0%)'"
background: "=props.colorBarStartPoint && props.colorBarEndPoint ? '-webkit-linear-gradient(top, ' + props.colorBarEndPoint + ' 40%,' + props.colorBarStartPoint + ' 100%)' : '-webkit-linear-gradient(top, rgb(255, 73, 0) 40%,rgb(255, 158, 35) 100%)'"
transform: "=(items[props.setPointItem].state.split(' ')[0] <= (((Number(props.maxTemp) - Number(props.minTemp)) / 2) + Number(props.minTemp)) && items[props.setPointItem].state.split(' ')[0] >= Number(props.minTemp) ? 'rotate('+(320/(Number(props.maxTemp)-Number(props.minTemp))*(items[props.setPointItem].state.split(' ')[0]-Number(props.minTemp))+20)+'deg)' : (items[props.setPointItem].state.split(' ')[0] > (((Number(props.maxTemp) - Number(props.minTemp)) / 2) + Number(props.minTemp))) ? 'rotate(180deg)' : '')"
- component: f7-block
config:
class: span
style:
margin-top: 0px
width: "=props.size ? (Number(props.size)*0.89) +'px' : '100%'"
font-weight: "=props.size ? (Number(props.size)*2) +'px' : 'calc(var(--f7-list-item-title-font-weight)*2)'"
position: absolute
bottom: 0px
text-align: center
text-transform: uppercase
font-size: "=props.size ? (Number(props.size)*0.0375) +'px' : '1em'"
color: "=props.colorTypo ? props.colorTypo : 'rgb(87, 84, 95)'"
z-index: 99 !important
slots:
default:
- component: Label
config:
text: Heating
style:
color: "=(items[props.heaterItem].state === 'ON') ? 'orange' : 'black'"
- component: f7-block
config:
class: shadow
style:
margin-top: 0px
position: absolute
top: 50%
left: 50%
transform: "=(items[props.setPointItem].state.split(' ')[0] >= Number(props.minTemp) && items[props.setPointItem].state.split(' ')[0] <= Number(props.maxTemp) ? 'translate(-50%, -50%) rotate('+(320/(Number(props.maxTemp)-Number(props.minTemp))*(items[props.setPointItem].state.split(' ')[0]-Number(props.minTemp))-160)+'deg)' : 'translate(-50%, -50%) rotate(0deg)')"
width: "=props.size ? (Number(props.size)*0.0625) +'px' : '6.25%'"
height: 86%
text-align: center
transition: 0.7s ease
animation: shadow 1.4s ease-out both
slots:
default:
- component: f7-block
config:
class: shadow-cube
style:
margin-top: 0px
position: absolute
top: 0
width: "=props.size ? (Number(props.size)*0.0625) +'px' : '100%'"
height: 0px
box-shadow: "=props.size ? '0 0 ' + (Number(props.size)*0.1125) +'px ' + (Number(props.size)*0.0325) + 'px ' + (props.colorSetMarker ? props.colorSetMarker : 'rgba(255, 158, 35, 0.5)'): '0 0 45px 13px rgba(255, 158, 35, 0.5)'"
- component: f7-block
config:
class: markerContainer
style:
pointer-events: none
margin-top: 0px
position: absolute
top: 50%
left: 50%
transform: "=(items[props.currentPointItem].state.split(' ')[0] >= Number(props.minTemp) && items[props.currentPointItem].state.split(' ')[0] <= Number(props.maxTemp) ? 'translate(-50%, -50%) rotate('+(320/(Number(props.maxTemp)-Number(props.minTemp))*(items[props.currentPointItem].state.split(' ')[0]-Number(props.minTemp))-160)+'deg)' : 'translate(-50%, -50%) rotate(0deg)')"
width: "=props.size ? (Number(props.size)*0.1) +'px' : '10%'"
height: 100%
text-align: center
transition: 0.7s ease
opacity: 1
z-index: 99 !important
slots:
default:
- component: f7-block
config:
class: markerCurrent
style:
margin-top: 0px
width: "=props.size ? (Number(props.size)*0.1) +'px' : '100%'"
height: "=props.size ? (Number(props.size)*0.1) +'px' : ''"
padding-top: "=props.size ? '' : '100%'"
background: "=props.colorCurrentMarker ? props.colorCurrentMarker : 'rgb(33, 150, 243)'"
position: absolute
transform: translate(-50%,-50%) rotate(45deg)
left: 50%
top: "=props.size ? (Number(props.size)*0.14) +'px' : '15%'"
border-radius: 0% 50% 50% 50%
box-shadow: 0 0 5px 1px rgb(48, 46, 56)
slots:
default:
- component: f7-block
config:
class: number
style:
margin-top: 0px
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%) rotate(-45deg)
text-align: center
slots:
default:
- component: Label
config:
text: =items[props.currentPointItem].state.split(' ')[0]
style:
font-size: "=props.size ? (Number(props.size)*0.04) +'px' : '14px'"
color: white
font-weight: bold
- component: f7-block
config:
class: markerContainer
style:
pointer-events: none
margin-top: 0px
position: absolute
top: 50%
left: 50%
transform: "=(items[props.setPointItem].state.split(' ')[0] >= Number(props.minTemp) && items[props.setPointItem].state.split(' ')[0] <= Number(props.maxTemp) ? 'translate(-50%, -50%) rotate('+(320/(Number(props.maxTemp)-Number(props.minTemp))*(items[props.setPointItem].state.split(' ')[0]-Number(props.minTemp))-160)+'deg)' : 'translate(-50%, -50%) rotate(0deg)')"
width: "=props.size ? (Number(props.size)*0.1) +'px' : '10%'"
height: 100%
text-align: center
transition: 0.7s ease
opacity: 1
z-index: 99 !important
slots:
default:
- component: f7-block
config:
class: markerSet
style:
margin-top: 0px
width: "=props.size ? (Number(props.size)*0.1) +'px' : '100%'"
height: "=props.size ? (Number(props.size)*0.1) +'px' : ''"
padding-top: "=props.size ? '' : '100%'"
background: "=props.colorSetMarker ? props.colorSetMarker : 'rgb(230, 74, 25)'"
position: absolute
transform: translate(-50%,-50%) rotate(-45deg)
left: 50%
top: "=props.size ? (Number(props.size)*Number(-0.0125)) +'px': '-2%'"
border-radius: 50% 50% 50% 0
box-shadow: 0 0 5px 1px rgb(48, 46, 56)
z-index: 100 !important
slots:
default:
- component: f7-block
config:
class: number
style:
margin-top: 0px
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%) rotate(45deg)
text-align: center
slots:
default:
- component: Label
config:
text: =items[props.setPointItem].state.split(' ')[0]
style:
font-size: "=props.size ? (Number(props.size)*0.04) +'px' : '14px'"
color: white
font-weight: bold
- component: f7-block
config:
class: center
style:
margin-top: 0px
position: absolute
width: "=props.size ? (Number(props.size)*0.65) +'px' : '65%'"
height: "=props.size ? (Number(props.size)*0.65) +'px' : '65%'"
background: "=props.colorControlRing ? props.colorControlRing : 'rgb(227, 228, 237)'"
animation: bound-in 0.6s ease forwards
top: 50%
left: 50%
transform: translate(-50%, -50%)
border-radius: 50%
box-shadow: 0px 15px 35px 11px rgba(46, 44, 58,0.60)
slots:
default:
- component: oh-icon
config:
visible: "=props.batteryItem ? true : false"
item: =props.batteryItem
icon: "=(items[props.windowItem].state === 'OPEN') ? 'batterylevel-10' : 'batterylevel-70'"
style:
position: absolute
bottom: 40%
left: 65%
transform: translate(-50%,-50%)
width: 10%
height: 50%
color: "=props.colorButton ? props.colorButton + ' !important': ''"
- component: oh-icon
config:
visible: "=props.windowItem ? true : false"
icon: "=(items[props.windowItem].state === 'OPEN') ? 'window-open' : 'window-closed'"
style:
position: absolute
bottom: 40%
left: 50%
transform: translate(-50%,-50%)
width: 20%
height: 50%
- component: oh-button
config:
visible: "=props.modeItem ? true : false"
item: =props.modeItem
text: =items[props.modeItem].state
small: true
outline: true
raised: false
action: options
actionItem: =props.modeItem
style:
font-size: "=props.size ? (Number(props.size)*0.0375) +'px' : '12px'"
position: absolute
bottom: 0%
left: 50%
transform: translate(-50%,-50%)
color: "=props.colorButton ? props.colorButton + ' !important': ''"
- component: oh-button
config:
style:
--f7-button-hover-bg-color: transparent
--f7-button-pressed-bg-color: transparent
width: 30%
height: 50%
position: absolute
margin-top: 0px
top: 50%
left: 10%
transform: translate(-50%, -50%)
color: "=props.colorButton ? props.colorButton : ''"
action: command
actionItem: =props.setPointItem
actionCommand: "=Number(items[props.setPointItem].state.split(' ')[0]) > Number(props.minTemp) ? Number(items[props.setPointItem].state.split(' ')[0]) - 0.5 : ''"
slots:
default:
- component: f7-icon
config:
size: "=props.size ? (Number(props.size)*0.075) : '30'"
style:
position: absolute
transform: translate(-50%, -50%)
top: 50%
margin-top: auto
f7: arrow_turn_left_down
- component: oh-button
config:
style:
--f7-button-hover-bg-color: transparent
--f7-button-pressed-bg-color: transparent
width: 30%
height: 50%
position: relative
margin-top: 0px
top: 50%
left: 90%
transform: translate(-50%, -50%)
color: "=props.colorButton ? props.colorButton : ''"
action: command
actionItem: =props.setPointItem
actionCommand: "=Number(items[props.setPointItem].state.split(' ')[0]) < Number(props.maxTemp) ? Number(items[props.setPointItem].state.split(' ')[0]) + 0.5 : ''"
slots:
default:
- component: f7-icon
config:
size: "=props.size ? (Number(props.size)*0.075) : '30'"
style:
position: absolute
transform: translate(-50%, -50%)
top: 50%
margin-top: auto
f7: arrow_turn_right_up
- component: f7-block
config:
class: small
style:
margin-top: 0px
position: absolute
width: "=props.size ? (Number(props.size)*0.375) +'px' : '57.6%'"
height: "=props.size ? (Number(props.size)*0.375) +'px' : '57.6%'"
background: "=props.colorCenter ? props.colorCenter : 'rgb(248, 249, 250)'"
text-align: center
animation: bound-in-small 0.6s ease forwards
top: 50%
left: 50%
transform: translate(-50%, -50%)
border-radius: 50%
box-shadow: 0px 5px 10px 5px rgba(96, 93, 111,0.19)
slots:
default:
- component: f7-block
config:
class: heat
style:
font-size: "=props.size ? (Number(props.size)*0.0375) +'px' : '14px'"
color: "=props.colorTypo ? props.colorTypo : 'rgb(87, 84, 95)'"
font-weight: 300
slots:
default:
- component: Label
config:
text: =props.location
- component: f7-block
config:
class: heat
style:
font-size: "=props.size ? (Number(props.size)*0.1125) +'px' : '2.5em'"
color: "=props.colorTypo ? props.colorTypo : 'rgb(87, 84, 95)'"
font-weight: 300
slots:
default:
- component: Label
config:
text: "=props.unit ? items[props.setPointItem].state.split(' ')[0] + '' + props.unit : items[props.setPointItem].state.split(' ')[0]"
- component: oh-image
config:
url: https://community-openhab-org.s3-eu-central-1.amazonaws.com/original/2X/7/7d388a86c95471f89b1bb911d96d7609a3e3a059.svg
visible: "=props.mode2Item ? false : true"
style:
position: absolute
transform: translate(-50%)
left: 50%
width: 40%
- component: oh-button
config:
visible: "=props.mode2Item ? true : false"
item: =props.mode2Item
text: =items[props.mode2Item].state
small: true
outline: true
raised: false
action: options
actionItem: =props.mode2Item
style:
font-size: "=props.size ? (Number(props.size)*0.0375) +'px' : '12px'"
position: absolute
bottom: 0%
left: 50%
transform: translate(-50%,-50%)
color: "=props.colorButton ? props.colorButton + ' !important': ''"
Hi Alex,
many thx for your ideas and the efforts to realise this. The result looks very good even I made some changes.
In Line 445 I changed:
Line: 445 Battery - it's "LOWBAT" (Switch) -Normal ="OFF" and when low -> "ON" (I use a selvmade Icon) and Name from windowItem to batteryItem
old: icon: "=(items[props.windowItem].state === 'OPEN') ? 'batterylevel-10' : 'batterylevel-70'"
new: icon: "=(items[props.batteryItem].state === 'OFF') ? 'lowbattery1-off' : 'lowbattery1-on'"
and I also tested this code with f7:icons baut it doesen’t work
I also tried this code, but it seems not to work
new: icon: "=(items[props.batteryItem].state === 'OFF') ? 'f7:battery_100' : 'f7:battery_0'"
iconColor: "=(items[props.batteryItem].state === 'OFF') ? 'green' : 'red'"
To Display the Modes as they are translated by the Binding I changed this lines:
Line: 591
old: text: =items[props.mode2Item].state
new: text: =items[props.mode2Item].displayState
Line: 469
old: text: =items[props.modeItem].state
new: text: =items[props.modeItem].displayState
I also deleted one line as I don’t want to see the location twice:
Line: 126 I deleted this Line as I can see the Location in the Thermostat itself
old: title: "=(props.location) ? 'Klima ' + props.location : ''"
new: Line deleted
And last but not least I changed this line (only for my personal numeration):
Line: 283
old: text: Heating
new: text: Rel.V1.7_na
which means: Base is Release 1.7 from _n (Nico) with the extensions from a (Alex)
And as a result:
Btw: The heaterItem is also a nice feature and as I have no electric heating I use it in combination with a wall-switch(just for testing) and I think there are a lot more possibilities.
Thx again to Nico and you for your work.
Cheers
Peter
Edit: I forgot to say that I’m using AVM-Fritz Thermostats and Homematic-Window-/Door_Sensors
Hey guys,
I’m not a programmer, I tried to change it for half the day, but failed.
Would it be possible to separate the large displayed temperature in the input?
(a selection which is displayed)
I would prefer to see the current temperature than the set target temperature.
I mean in this example it would now be 18,5 instead of 6 in the middle
Thx !!!
sy - Google translated
Hey guys, @fibu-freak , @doctor64 , @Peters_Bastelecke
I’am in progress to implement the some enhancements.
Thanks for the posts, the good feedback and the patience.
It will take a little bit time.
all the best,
Nico
Yes, of course some local modification sometimes needed. I, for example, use MAX! EQ-3 thermostats and zigbee Xiaomi window sensors.
About heater item - i also don’t use electric heating and my thermostat does not return heated state, but it can report valve open state. So I create additional item make simple rule:
Number GF_Living_Radiator_Valve "Valve position [%d %%]" <flowpipe> (GF_Living_Thermostat, MaxValve) ["OpenLevel"] {channel="max:thermostat:NEQ1208352:thermostatLiving:valve"}
String GF_Living_Radiator_Heated "Heated [%s]" <heating> (GF_Living_Thermostat) ["Status"]
rule "Heating indication"
when
Member of gMaxValve changed
then
val changedValve = triggeringItem
val String[] thermostatNameArr=changedValve.name.split("_")
val String thermostatIndicator=thermostatNameArr.get(0)+"_"+thermostatNameArr.get(1)+"_"+thermostatNameArr.get(2)+"_"+"Heated"
logInfo("HeatingUpdate", "triggered=" + changedValve + " Indicator name:" + thermostatIndicator)
if (changedValve.state > 0 ) thermostatIndicator.sendCommand("ON") else thermostatIndicator.sendCommand("OFF")
end
And it gives me fancy icon on location card and on heating widget.
May be it will be useful, I don’t know is your thermostat able to return valve open status.
Sorry, can not check right now, but looks like you need to change line
from: text: "=props.unit ? items[props.setPointItem].state.split(' ')[0] + '' + props.unit : items[props.setPointItem].state.split(' ')[0]"
to: text: "=props.unit ? items[props.currentPointItem].state.split(' ')[0] + '' + props.unit : items[props.currentPointItem].state.split(' ')[0]"
It’s difficult to say correct line number because i have modified widget source at hand, but it near end of widget code. Hope this helps.
Hi Alex,
thx for this tip, - it works