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
Hi guys,
Thanks again for the positive feedback. I am pleased that so many people are interested in the widget.
Hi @fibu-freak,
based on your suggestion (Heating widget - #18 by fibu-freak) with a list-card
, i have inserted two optional setting buttons. I think this fits in better with the design and has even more potential. See under the enhancements Heating-Mode- Itemand Example-Mode-Item
I hope you like the solution
The implementation of humidity will follow.
The Logo-URL can be an Web-Adress or an static-path. I define a prop for the Image-URL. More under enhancements.
Hi @doctor64,
The design should be better now for small widget. You can define the size of the widget and now the size of all fonts.
In general: The implementation of a battery indicator will follow
I hope you all like the new version v1.8. Have fun and have a nice weekend.
all the best,
Nico
v1.8
Enhancements:
- Implementation of the heating mode and an example mode placeholder.
The item must be a string item. (props: heatingModeItem and exampleModeItem)
The strings to be sent are defined in an array e.g. ,OFF, ON, VACATION, AUTOāā (props: heatingModeArray and exampleModeArray
The buttons are embedded dynamically after entering the props.
If only one item is used, only one icon is displayed. If you use two items, both icons rotate into a corresponding position.
-
Toogle item is no longer applicable in the widget. If this is required, it can also be implemented using buttons
-
The url for the logo can be defined in props and is no longer static in the code.
Tipp: Instead of an Internet address, a logo can also be saved in the folder.
Then use in the prop the follow path (eg):
http://local-IP-Adress:8080/static/folder/img.svg -
All font sizes can be defined using parameters. This means that even small widgets can be implemented responsively.
-
Animation added in the center that can be used to visualize a valve item or an alarm item
Now the item must be of the type Switch, but itās easy to switch to an Contact-Item if you want.
Bug-fixing:
- Add box-sizing: content-box to the parent container. Now the circle is really a circle too .
Here the v1.8 YAML. Too many characters for one post
Edit: please use the v1.8.1. The v1.8 YAML is removed
Hello, the widget works great! However I have a problem in my setup with the heating mode items. With one single instance of the widget, it works great but when I add a second (or more) the heating mode status wonāt be passed to the defined item.
The second widget will change last added widget heating mode item instead of their own widget item.
I have tried to figure it out myself but I lack knownlegde about YAML. I am not sure if the problem is in my setup or in the widget. I hope you can help me to get on the right track.
Below I have added information of my setup and problem.
This is my first post and could not figure out yet to add an animationā¦ so here a link to the gif to clarify my problem:
https://u.pcloud.link/publink/show?code=kZp0cjXZfNTPeH2aYSu3IRuuv8ayv4FGHQ7V
Items
String HW_BG_Heating_Mode "Verwarmings Modus [%s]" (g_HeatingMode)
String HW_EV_Heating_Mode "Verwarmings Modus [%s]" (g_HeatingMode)
String BW_Heating_Mode "Verwarmings Modus [%s]" (g_HeatingMode)
String BW_SK_Heating_Mode "Verwarmings Modus [%s]" (g_HeatingMode)
Widget configuration
- component: oh-block
config:
title: Hoofdwoning
slots:
default:
- component: oh-grid-row
config: {}
slots:
default:
- component: oh-grid-col
config: {}
slots:
default:
- component: widget:wThermostatGauge_V1.8
config:
location: Beganegrond
size: "300"
minTemp: "15"
maxTemp: "25"
setPointItem: HW_BG_Temperatuur_Setpoint
currentPointItem: gT_HW_BG
unit: Ā°C
imgUrl: http://10.0.0.30:8080/static/_empty.png
heatingModeArray: Automatisch,Handmatig,Uit
valveItem: gHA_HW_BG
fontSizeMarker: .75em
fontSizeCenter: 2.6em
fontSizeButtons: 1,8em
fontSizeFooter: 1em
heatingModeItem: HW_BG_Heating_Mode
- component: oh-grid-col
config: {}
slots:
default:
- component: widget:wThermostatGauge_V1.8
config:
location: Eerste verdieping
size: "300"
minTemp: "15"
maxTemp: "25"
setPointItem: HW_EV_Temperatuur_Setpoint
currentPointItem: gT_HW_EV
unit: Ā°C
imgUrl: http://10.0.0.30:8080/static/_empty.png
heatingModeArray: Automatisch,Handmatig,Uit
heatingModeItem: HW_EV_Heating_Mode
valveItem: gHA_HW_EV
fontSizeMarker: .75em
fontSizeCenter: 2.6em
fontSizeButtons: 1,8em
fontSizeFooter: 1em
- component: oh-grid-row
config: {}
slots:
default:
- component: oh-grid-col
config: {}
slots:
default:
- component: oh-list-card
config: {}
slots:
default:
- component: oh-slider-item
config:
item: HW_BG_Temperatuur_Setpoint
min: 15
max: 25
step: 0.5
scale: true
- component: oh-slider-item
config:
item: gT_HW_BG
min: 15
max: 25
step: 0.5
scale: true
- component: oh-label-item
config:
item: gHA_HW_BG
- component: oh-label-item
config:
item: HW_BG_Heating_Mode
- component: oh-grid-col
config: {}
slots:
default:
- component: oh-list-card
config: {}
slots:
default:
- component: oh-slider-item
config:
item: HW_EV_Temperatuur_Setpoint
min: 15
max: 25
step: 0.5
scale: true
- component: oh-slider-item
config:
item: gT_HW_EV
min: 15
max: 25
step: 0.5
scale: true
- component: oh-label-item
config:
item: gHA_HW_EV
- component: oh-label-item
config:
item: HW_EV_Heating_Mode
Hello, the widget works great. a warning message only ever comes up when the page is called up for the first time. It doesnāt matter whether I have entered items or not.
2021-02-21 10:56:35.824 [WARN ] [e.internal.SseItemStatesEventBuilder] - Attempting to send a state update of an item which doesn't exist: undefined
Hi @RowanS
sorry here is a bug in the popover code. I define a identifier to control this proplem.
Now the location props is required and this prop is the identifier if you use more than one widget.
@Tallman I cant reproduce this error. Pls try again and check all needed and referenced items.
all the best,
Nico
V1.8.1
uid: widget_HeatingCSS_1.8.1
tags: []
props:
parameters:
- description: eg. living room
label: location and widget identifier
name: location
required: true
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
- description: Control item unit eg Ā°C
label: unit
name: unit
required: false
type: TEXT
- description: URL or path to a Image (if you use a local img eg. -> http://local-IP-Adress:8080/static/folder/img.svg )
label: URL or path to image
name: imgUrl
required: false
type: TEXT
advanced: true
- description: Heating mode strings as array eg. AUTO,MANU,OFF. The string will be send to the Heating-Mode-Item [String-Item]
label: Heating Mode Array
name: heatingModeArray
required: false
type: TEXT
advanced: true
- description: Example Mode Strings as Array eg. OFF,ON,BOOST. The string will be send to the Example-Mode-Item [String-Item]
label: Example Mode Array
name: exampleModeArray
required: false
type: TEXT
advanced: true
- context: item
description: Heating Mode Item [String-Item]
label: Heating Mode Item
name: heatingModeItem
required: false
type: TEXT
advanced: true
- context: item
description: Example Mode Item [String-Item] (eg. State of heating valve)
label: Example Mode Item
name: exampleModeItem
required: false
type: TEXT
advanced: true
- context: item
description: Valve Item [Switch-Item] (eg. State of heating valve) for Animation
label: Valve Item
name: valveItem
required: false
type: TEXT
advanced: true
- label: Custom font-size current&set-point marker (eg. 1em)
name: fontSizeMarker
required: false
type: TEXT
groupName: fonts
advanced: true
- label: Custom font-Size center (eg. 2em)
name: fontSizeCenter
required: false
type: TEXT
groupName: fonts
advanced: true
- label: Custom font-Size buttons (eg. 1.8em)
name: fontSizeButtons
required: false
type: TEXT
groupName: fonts
advanced: true
- label: Custom font-Size footer (eg. 1em)
name: fontSizeFooter
required: false
type: TEXT
groupName: fonts
advanced: true
- 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
- name: fonts
label: Font-Settings
timestamp: Feb 22, 2021, 12:22:59 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 ? props.size + 'px': '100%'"
width: "=props.size ? Number(props.size)+'px' : '100%'"
background: "=props.colorThermostat ? props.colorThermostat : 'var(--f7-toggle-inactive-color)'"
border-radius: 50%
box-sizing: content-box
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
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.fontSizeFooter ? props.fontSizeFooter : '1em'"
color: "=props.colorTypo ? props.colorTypo : 'rgb(87, 84, 95)'"
z-index: 99 !important
slots:
default:
- component: Label
config:
text: Heating
- 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.fontSizeMarker ? props.fontSizeMarker : '1em'"
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.fontSizeMarker ? props.fontSizeMarker : '1em'"
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)'"
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: f7-block
config:
class: buttonContainer
style:
display: "=props.heatingModeItem ? '' : 'none'"
margin-top: 0px
position: absolute
top: 50%
left: 50%
transform: "=props.exampleModeItem ? 'translate(-50%, -50%) rotate(30deg)' : 'translate(-50%, -50%)'"
width: "=props.size ? (Number(props.size)*0.15) +'px' : '15%'"
height: 100%
text-align: center
transition: 0.7s ease
opacity: 1
z-index: 99 !important
slots:
default:
- component: oh-button
config:
popoverOpen: ='.' + props.location + '.popoverHeatingMode'
style:
width: 100%
height: 20%
position: absolute
bottom: 0%
left: 50%
transform: translate(-50%)
color: "=props.colorButton ? props.colorButton + ' !important': ''"
slots:
default:
- component: f7-icon
config:
f7: "=props.heatingModeItem ? (items[props.heatingModeItem].state == props.heatingModeArray.split(',')[0] ? 'hand_raised' : items[props.heatingModeItem].state == props.heatingModeArray.split(',')[1] ? 'arrow_2_squarepath' : items[props.heatingModeItem].state == props.heatingModeArray.split(',')[2] ? 'airplane' : 'thermometer') : ''"
style:
font-size: "=props.fontSizeButtons ? props.fontSizeButtons : '2em'"
position: absolute
transform: translate(-50%, -50%)
top: 50%
margin-top: auto
- component: f7-popover
config:
class: =props.location + ' popoverHeatingMode'
slots:
default:
- component: f7-card
config:
noShadow: true
class:
- popover-close
action: variable
actionVariable: myVar
clearVariable: true
actionVariableValue: success
slots:
default:
- component: f7-row
config: {}
slots:
default:
- component: f7-col
slots:
default:
- component: oh-repeater
config:
for: buttonlabel
in: =props.heatingModeArray.split(",")
containerStyle:
width: 100%
slots:
default:
- component: oh-button
config:
color: "=props.colorButton ? props.colorButton : ''"
class: margin
text: =loop.buttonlabel
outline: true
action: command
active: "=(items[props.heatingModeItem].state === loop.buttonlabel ? true : false)"
actionCommand: =loop.buttonlabel
actionItem: =props.heatingModeItem
- component: f7-block
config:
class: buttonContainer
style:
display: "=props.exampleModeItem ? '' : 'none'"
margin-top: 0px
position: absolute
top: 50%
left: 50%
transform: "=props.heatingModeItem ? 'translate(-50%, -50%) rotate(-30deg)' : 'translate(-50%, -50%)'"
width: "=props.size ? (Number(props.size)*0.15) +'px' : '15%'"
height: 100%
text-align: center
transition: 0.7s ease
opacity: 1
z-index: 99 !important
slots:
default:
- component: oh-button
config:
popoverOpen: ='.' + props.location + '.popoverExampleMode'
style:
width: 100%
height: 20%
position: absolute
bottom: 0%
left: 50%
transform: translate(-50%)
color: "=props.colorButton ? props.colorButton + ' !important': ''"
slots:
default:
- component: f7-icon
config:
f7: wrench
style:
font-size: "=props.fontSizeButtons ? props.fontSizeButtons : '2em'"
position: absolute
transform: translate(-50%, -50%)
top: 50%
margin-top: auto
- component: f7-popover
config:
class: =props.location + ' popoverExampleMode'
slots:
default:
- component: f7-card
config:
noShadow: true
class:
- popover-close
action: variable
actionVariable: myVar
clearVariable: true
actionVariableValue: success
slots:
default:
- component: f7-row
config: {}
slots:
default:
- component: f7-col
slots:
default:
- component: oh-repeater
config:
for: buttonlabel
in: =props.exampleModeArray.split(",")
containerStyle:
width: 100%
slots:
default:
- component: oh-button
config:
color: "=props.colorButton ? props.colorButton : ''"
class: margin
text: =loop.buttonlabel
outline: true
action: command
active: "=(items[props.exampleModeItem].state === loop.buttonlabel ? true : false)"
actionCommand: =loop.buttonlabel
actionItem: =props.exampleModeItem
- component: oh-button
config:
style:
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:
style:
font-size: "=props.fontSizeButtons ? props.fontSizeButtons : '2em'"
position: absolute
transform: translate(-50%, -50%)
top: 50%
margin-top: auto
f7: arrow_turn_left_down
- component: oh-button
config:
style:
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:
style:
font-size: "=props.fontSizeButtons ? props.fontSizeButtons : '2em'"
position: absolute
transform: translate(-50%, -50%)
top: 50%
margin-top: auto
f7: arrow_turn_right_up
- component: f7-block
config:
class: valveAnimation
style:
z-index: -100 !important
pointer-events: none
display: "=(props.valveItem && items[props.valveItem].state == 'ON' )? '' : 'none'"
background: "=props.colorSetMarker ? 'radial-gradient(' + props.colorSetMarker +' 30%, transparent 50%)' : 'radial-gradient(var(--f7-theme-color) 30%, transparent 50%)'"
margin-top: 0px
position: absolute
transform: translate(-50%, -50%)
width: 100%
height: 100%
top: 50%
left: 50%
border-radius: 50%
animation: skeleton-effect-fade 2s linear infinite
- component: f7-block
config:
class: small
style:
z-index: 100 !important
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.fontSizeCenter ? props.fontSizeCenter : '2em'"
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: "=props.imgUrl ? props.imgUrl : '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%
Nice job, but Iāve small wish: can You display .displayState (if defined) instead .state, so that proper formatting will be possible, for setPointItem and currentPointItem ? I know I can do this myself, but for each of Your great new versions, again and again ā¦
/Sas
The error message comes when the page containing the widget is opened in the browser and the Heating / Example Mode item is not linked to an item.
Hi @Tallman
thanks for the details.
Iāve found the little bug into the code. The error is by the defintion of the F7-Icon if no heatingModeItm is defined.
sorry for this.
I change the post above with version v1.8.1
I also included the array string for the icon selection.
Please give me a feedback if it works.
Change the line 510
from:
f7: "=(items[props.heatingModeItem].state == 'Manuell' ? 'hand_raised' : items[props.heatingModeItem].state == 'Auto' ? 'arrow_2_squarepath' : items[props.heatingModeItem].state == 'Vacation' ? 'airplane' : 'thermometer')"
to:
f7: "=props.heatingModeItem ? (items[props.heatingModeItem].state == props.heatingModeArray.split(',')[0] ? 'hand_raised' : items[props.heatingModeItem].state == props.heatingModeArray.split(',')[1] ? 'arrow_2_squarepath' : items[props.heatingModeItem].state == props.heatingModeArray.split(',')[2] ? 'airplane' : 'thermometer') : ''"