Expandable Lighting Widget
I’ve been hacking this together for a while now. I started with an expandable widget I found on the forums (if I can find it again I will link it here) and tweaked it into something more suibable for my needs.
I have a few different types of lights: Switch on/off, dimmer/CCT bulbs, and some with motion detectors.
This widget will adjust itself to be suitable for all of these light types. Just leave some of the props empty, and the widget will know what type of light you have.
I have also designed it to fit nicely on my iPhone, tablet, and desktop nicely without over lapping text and graphics.
There are icons to show; Motion detection, Timer status, Illuminance, and Illuminace Threshold.
When expanded, there are more detailed controls - Scene Brightness, timer settings and Motion detector light threshold.
Here are some screenshots-
Here is the widget code:
props:
parameters:
- description: Location
label: Location
name: location
required: false
type: TEXT
- context: item
label: Brightness
name: bright
required: false
type: TEXT
- context: item
label: Motion Detection
name: motion
required: false
type: TEXT
- context: item
label: Illuminance threshold
name: illumt
required: false
type: TEXT
- context: item
label: Illuminance
name: illum
required: false
type: TEXT
- context: item
label: Scene brightness
name: sbright
required: false
type: TEXT
- context: item
label: Motion Timer
name: mtimer
required: false
type: TEXT
- context: item
label: "'On Time' Timer"
name: oTtimer
required: false
type: TEXT
- context: item
label: Motion Detection On/Off
name: motionOnOff
required: false
type: TEXT
timestamp: Jun 21, 2021, 11:03:01 PM
component: f7-card
config:
expandable: true
swipeToClose: true
backdrop: true
class:
- card-expandable-animate-width
style:
background: '=(items[props.bright].state > 0 || items[props.bright].state == "ON") ? "linear-gradient(to bottom, hsla(48, 90%, 54%, 1), hsla(48, 90%, 95%, 1), 10% , hsla(0, 0%, 100%, 1) )": "white"'
height: 170px
margin: 5px
margin-top: 10px
slots:
default:
- component: oh-button
config:
iconF7: ellipsis
iconSize: 30px
color: gray
style:
position: absolute
top: 0
right: 0
padding-top: 10px
padding-right: 15px
padding-bottom: 40px
z-index: 999
class:
- cell-open-button
- card-opened-fade-out
- component: f7-card-content
config:
style:
width: 100%
padding-top: 30px
slots:
default:
- component: f7-icon
config:
material: lightbulb
size: '=(items[props.bright].state > 0 || items[props.bright].state == "ON") ? "120px": "90px"'
color: '=(items[props.bright].state > 0 || items[props.bright].state == "ON") ? "yellow": "gray"'
style:
opacity: '=(items[props.bright].state > 0 || items[props.bright].state == "ON") ? "90%": "10%"'
position: absolute
top: '=(items[props.bright].state > 0 || items[props.bright].state == "ON") ? "45px": "60px"'
right: '=(items[props.bright].state > 0 || items[props.bright].state == "ON") ? "-15px": "0px"'
- component: oh-button
config:
iconF7: xmark_circle_fill
iconSize: 30px
color: black
style:
position: absolute
top: 0
right: 0
padding-top: 10px
padding-bottom: 35px
z-index: 999
class:
- card-opened-fade-in
- cell-close-button
- card-close
- component: oh-link
config:
action: toggle
actionItem: =props.bright
actionCommand: '=(props.sbright) ? items[props.sbright].state: "ON"'
actionCommandAlt: OFF
class:
- card-prevent-open
style:
width: 100%
height: 100%
position: absolute
top: 0
left: 0
z-index: 0
- component: f7-block
config:
class:
- no-padding
style:
margin: 0px
height: 200px
slots:
default:
- component: f7-row
config:
style:
height: 65px
width: auto
white-space: nowrap
flex-wrap: nowrap
slots:
default:
- component: f7-col
slots:
default:
- component: Label
config:
text: =props.location
style:
font-weight: 600
text-overflow: ellipsis
overflow: hidden
white-space: nowrap
- component: f7-chip
config:
text: '=(items[props.bright].state > 0) ? items[props.bright].state + " %": (items[props.bright].state == "ON") ? "ON": "OFF"'
color: '=(items[props.bright].state > 0) ? "yellow": (items[props.bright].state == "ON") ? "yellow": "gray"'
- component: f7-row
config:
style:
white-space: nowrap
flex-wrap: nowrap
height: auto
class:
- justify-content-flex-start
slots:
default:
- component: f7-icon
config:
visible: '=(props.motionOnOff) ? "true": "false"'
f7: dot_radiowaves_right
size: 20px
color: '=(items[props.motion].state == "OFF" && items[props.motionOnOff].state == "ON") ? "blue" : (items[props.motion].state == "ON") ? "red" : (items[props.motionOnOff].state == "OFF") ? "gray" : "gray"'
style:
margin-right: 5px
- component: f7-icon
config:
f7: timer
size: 20px
color: '=(items[props.oTtimer].state != "0" && (items[props.bright].state == 0 || items[props.bright].state == "OFF")) ? "blue": (items[props.oTtimer].state != "0" && (items[props.bright].state > 0 || items[props.bright].state != "OFF")) ? "red": "gray"'
visible: '=(props.oTtimer) ? "true": "false"'
style:
margin-right: 5px
- component: f7-row
config:
visible: '=(props.illum) ? "true": "false"'
style:
height: auto
width: 100%
overflow: hidden
slots:
default:
- component: f7-col
config:
style:
flex-wrap: nowrap
align-self: flex-end
slots:
default:
- component: f7-row
config:
class:
- justify-content-flex-start
style:
margin-top: 5px
flex-wrap: nowrap
slots:
default:
- component: f7-icon
config:
f7: light_max
color: yellow
size: 18px
style:
margin-top: 0px
margin-left: 0px
- component: Label
config:
text: =items[props.illum].displayState
style:
margin-left: 8px
font-size: 12px
color: gray
text-overflow: ellipsis
overflow: hidden
white-space: nowrap
- component: f7-row
config:
visible: '=(props.illumt) ? "true": "false"'
style:
height: 20px
width: 100%
overflow: hidden
slots:
default:
- component: f7-col
config:
style:
flex-wrap: nowrap
align-self: flex-end
slots:
default:
- component: f7-row
config:
class:
- justify-content-flex-start
style:
margin-top: 5px
flex-wrap: nowrap
slots:
default:
- component: f7-icon
config:
f7: increase_indent
color: '=(items[props.illumt].state < (items[props.illum].state | ".0")) ? "gray": (items[props.motionOnOff].state == "OFF") ? "gray": "green"'
size: 18px
style:
margin-top: 0px
margin-left: 0px
- component: Label
config:
text: =items[props.illumt].displayState
style:
margin-left: 8px
font-size: 12px
color: gray
text-overflow: ellipsis
overflow: hidden
white-space: nowrap
- component: f7-block
config:
class:
- card-prevent-open
- card-content-padding
slots:
default:
- component: oh-list
config:
class:
- padding
slots:
default:
- component: oh-toggle-item
config:
title: On/Off
item: =props.bright
icon: f7:power
color: yellow
actionCommand: '=(props.sbright) ? items[props.sbright].state: "ON"'
actionCommandAlt: OFF
- component: oh-stepper-item
config:
title: Brightness
item: =props.bright
icon: oh:slider
iconUseState: true
color: '=(items[props.bright].state > 0) ? "yellow" : "gray"'
visible: '=(props.sbright) ? "true": "false"'
min: 0
max: 100
- component: oh-stepper-item
config:
title: Scene Brightness
item: =props.sbright
icon: oh:slider
iconUseState: true
color: blue
min: 0
max: 100
visible: '=(props.sbright) ? "true": "false"'
- component: oh-list-item
config:
title: Motion detection
icon: f7:dot_radiowaves_right
badge: '=(items[props.motionOnOff].state == "ON" && items[props.illumt].state > (items[props.illum].state | ".0")) ? "AUTO": (items[props.motionOnOff].state == "OFF") ? "OFF": (items[props.motionOnOff].state == "ON") ? "AUTO": (items[props.motionOnOff].state == "ON" && items[props.illumt].state < (items[props.illum].state | ".0")) ? "TOO BRIGHT": items[props.motionOnOff].displayState'
badge-color: '=(items[props.motionOnOff].state == "ON" && items[props.illumt].state > (items[props.illum].state | ".0") && items[props.motion].state == "OFF") ? "blue": (items[props.motionOnOff].state == "ON") ? "blue" : (items[props.motionOnOff].state == "OFF") ? "black": (items[props.motionOnOff].state == "ON" && items[props.illumt].state < (items[props.illum].state | ".0") ) ? "yellow": (items[props.motion].state == "ON" && items[props.motionOnOff].state == "ON" && items[props.illumt].state > (items[props.illum].state | ".0") ) ? "green": "red"'
action: toggle
actionItem: =props.motionOnOff
actionCommand: ON
actionCommandAlt: OFF
visible: '=(props.motionOnOff) ? "true": "false"'
- component: oh-stepper-item
config:
title: Motion Timer
item: =props.mtimer
footer: in Minutes
color: '=(items[props.motionOnOff].state == "ON") ? "blue": "gray"'
fill: true
round: true
autorepeat: true
autorepeatDynamic: true
small: true
min: 1
max: 600
icon: f7:timer
visible: "=(props.mtimer) ? true: false"
- component: oh-stepper-item
config:
title: lux Threshold
item: =props.illumt
color: '=(items[props.illumt].state < (items[props.illum].state | ".0")) ? "gray": (items[props.motionOnOff].state == "OFF") ? "gray": "green"'
fill: true
round: true
autorepeat: true
autorepeatDynamic: true
small: true
max: 600
icon: f7:light_max
footer: ="Currently " + items[props.illum].displayState
visible: "=(props.illumt) ? true: false"
- component: oh-stepper-item
config:
title: Auto Off
item: =props.oTtimer
footer: in Minutes
color: '=(items[props.oTtimer].state == "0") ? "gray": "blue"'
fill: true
round: true
autorepeat: true
autorepeatDynamic: true
small: true
min: 0
max: 600
icon: f7:timer
visible: "=(props.oTtimer) ? true: false"
The motion detection and Auto Off time should never be operating at the same time, so I have a rule to turn off the appropriate timer when the other one is interacted with -
rule "Lights, Kitchen Sink - 'On Time' turns OFF 'Motion Detection'"
when
Item Kitchen_Sink_Ceiling_Light_OnTime changed from 0
then
if (newState > 0 && Kitchen_Sink_Ceiling_Light_MotionOnOff.state == ON) {
Kitchen_Sink_Ceiling_Light_MotionOnOff.sendCommand(OFF)
logInfo("Lights - Kitchen Sink", "'On Time' turned ON, so Motion Detection is turning OFF")
}
end
rule "Lights, Kitchen Sink - 'Motion Detection' turns OFF 'On Time'"
when
Item Kitchen_Sink_Ceiling_Light_MotionOnOff changed to ON
then
if (Kitchen_Sink_Ceiling_Light_OnTime.state != 0) {
Kitchen_Sink_Ceiling_Light_OnTime.sendCommand(0)
logInfo("Lights - Kitchen Sink", "'Motion Detection' turned ON, so 'On Time' set to 0 min")
}
end
rule "Lights, Understairs - 'On Time' turns OFF 'Motion Detection'"
when
Item Hall_Understairs_Lamp_OnTime changed from 0
then
if (Understairs_MotionLightSensor_OnOff.state == ON) {
Understairs_MotionLightSensor_OnOff.sendCommand(OFF)
logInfo("Lights - Understairs", "'On Time' turned ON, so Motion Detection is turning OFF")
}
end
rule "Lights, Understairs - 'Motion Detection' turns OFF 'On Time'"
when
Item Understairs_MotionLightSensor_OnOff changed to ON
then
if (Hall_Understairs_Lamp_OnTime.state != 0) {
Hall_Understairs_Lamp_OnTime.sendCommand(0)
logInfo("Lights - Understairs", "'Motion Detection' turned ON, so 'On Time' set to 0 min")
}
end
rule "Lights, Kitchen Endboard - 'On Time' turns OFF 'Motion Detection'"
when
Item Kitchen_Endboard_Ceiling_Light_OnTime changed from 0
then
if (newState != 0 && Kitchen_Endboard_Ceiling_Light_MotionOnOff.state == ON) {
Kitchen_Endboard_Ceiling_Light_MotionOnOff.sendCommand(OFF)
logInfo("Lights - Kitchen Endboard", "'On Time' turned ON, so Motion Detection is turning OFF")
}
end
rule "Lights, Kitchen Endboard - 'Motion Detection' turns OFF 'On Time'"
when
Item Kitchen_Endboard_Ceiling_Light_MotionOnOff changed to ON
then
if (Kitchen_Endboard_Ceiling_Light_OnTime.state != 0) {
Kitchen_Endboard_Ceiling_Light_OnTime.sendCommand(0)
logInfo("Lights - Kitchen Endboard", "'Motion Detection' turned ON, so 'On Time' set to 0 min")
}
end
rule "Lights, Hall - 'On Time' turns OFF 'Motion Detection'"
when
Item Hall_Ceiling_Light_OnTime changed from 0
then
if (newState != 0 && Hall_Ceiling_Light_MotionOnOff.state == ON) {
Hall_Ceiling_Light_MotionOnOff.sendCommand(OFF)
logInfo("Lights - Hall", "'On Time' turned ON, so Motion Detection is turning OFF")
}
end
rule "Lights, Hall - 'Motion Detection' turns OFF 'On Time'"
when
Item Hall_Ceiling_Light_MotionOnOff changed to ON
then
if (Hall_Ceiling_Light_OnTime.state != 0) {
Hall_Ceiling_Light_OnTime.sendCommand(0)
logInfo("Lights - Hall", "'Motion Detection' turned ON, so 'On Time' set to 0 min")
}
end
rule "Lights, Back Hall - 'On Time' turns OFF 'Motion Detection'"
when
Item BackHall_Ceiling_Light_OnTime changed from 0
then
if (newState != 0 && BackHall_Ceiling_Light_MotionOnOff.state == ON) {
BackHall_Ceiling_Light_MotionOnOff.sendCommand(OFF)
logInfo("Lights - Back Hall", "'On Time' turned ON, so Motion Detection is turning OFF")
}
end
rule "Lights, Back Hall - 'Motion Detection' turns OFF 'On Time'"
when
Item BackHall_Ceiling_Light_MotionOnOff changed to ON
then
if (BackHall_Ceiling_Light_OnTime.state != 0) {
BackHall_Ceiling_Light_OnTime.sendCommand(0)
logInfo("Lights - Back Hall", "'Motion Detection' turned ON, so 'On Time' set to 0 min")
}
end
rule "Lights, Kitchen Under Cabinet - 'Motion Detection' turns OFF 'On Time'"
when
Item Kitchen_UnderCabinet_Light_MotionOnOff changed to ON
then
if (Kitchen_UnderCabinet_Light_OnTime.state != 0) {
Kitchen_UnderCabinet_Light_OnTime.sendCommand(0)
logInfo("Lights - Kitchen Under Cabinet", "'Motion Detection' turned ON, so 'On Time' set to 0 min")
}
end
rule "Lights, Kitchen Under Cabinet - 'On Time' turns OFF 'Motion Detection'"
when
Item Kitchen_UnderCabinet_Light_OnTime changed from 0
then
if (newState != 0 && Kitchen_UnderCabinet_Light_MotionOnOff.state == ON) {
Kitchen_UnderCabinet_Light_MotionOnOff.sendCommand(OFF)
logInfo("Lights - Kitchen Under Cabinet", "'On Time' turned ON, so Motion Detection is turning OFF")
}
end
These are the rules that make ‘On Time’ work -
var Timer timer_backhall = null
var Timer timer_bathroom = null
var Timer timer_hall = null
var Timer timer_frontdoor = null
var Timer timer_kEndboard = null
var Timer timer_kSink = null
var Timer timer_landing = null
var Timer timer_jBed = null
var Timer timer_jCeiling = null
rule "Timer Light - Back Hall"
when
Item BackHall_Ceiling_Light_Brightness changed from OFF to ON
then
val bright = BackHall_Ceiling_Light_Brightness
val timerItem = BackHall_Ceiling_Light_OnTime
if (timerItem.state > 0) {
if (timer_backhall === null) {
// logInfo("Timer Lights - " + getLocation(bright).label, "Motion detected")
timer_backhall = createTimer(now.plusMinutes(Integer::parseInt(timerItem.state.toString)), [ |
bright.sendCommand(OFF)
timer_backhall.cancel()
timer_backhall = null
logInfo("Timer Lights - " + getLocation(bright).label, "Timer elapsed. " + getLocation(bright).label + " " + getEquipment(bright).label + " turned OFF")
])
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer started")
} else if (timer_backhall !== null) {
timer_backhall.reschedule(now.plusMinutes(Integer::parseInt(timerItem.state.toString)))
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer rescheduled")
}
}
end
rule "Timer Light - Bath Room"
when
Item BathRoom_Ceiling_Light_Brightness changed from OFF to ON
then
val bright = BathRoom_Ceiling_Light_Brightness
val timerItem = BathRoom_Ceiling_Light_OnTime
if (timerItem.state > 0) {
if (timer_bathroom === null) {
// logInfo("Timer Lights - " + getLocation(bright).label, "Motion detected")
timer_bathroom = createTimer(now.plusMinutes(Integer::parseInt(timerItem.state.toString)), [ |
bright.sendCommand(OFF)
timer_bathroom.cancel()
timer_bathroom = null
logInfo("Timer Lights - " + getLocation(bright).label, "Timer elapsed. " + getLocation(bright).label + " " + getEquipment(bright).label + " turned OFF")
])
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer started")
} else if (timer_bathroom !== null) {
timer_bathroom.reschedule(now.plusMinutes(Integer::parseInt(timerItem.state.toString)))
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer rescheduled")
}
}
end
rule "Timer Light - Front Door"
when
Item Hall_FrontDoor_Light_Brightness changed from OFF to ON
then
val bright = Hall_FrontDoor_Light_Brightness
val timerItem = Hall_FrontDoor_Light_OnTime
if (timerItem.state > 0) {
if (timer_frontdoor === null) {
// logInfo("Timer Lights - " + getLocation(bright).label, "Motion detected")
timer_frontdoor = createTimer(now.plusMinutes(Integer::parseInt(timerItem.state.toString)), [ |
bright.sendCommand(OFF)
timer_frontdoor.cancel()
timer_frontdoor = null
logInfo("Timer Lights - " + getLocation(bright).label, "Timer elapsed. " + getLocation(bright).label + " " + getEquipment(bright).label + " turned OFF")
])
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer started")
} else if (timer_frontdoor !== null) {
timer_frontdoor.reschedule(now.plusMinutes(Integer::parseInt(timerItem.state.toString)))
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer rescheduled")
}
}
end
rule "Timer Light - Hall Ceiling Light"
when
Item Hall_Ceiling_Light_Brightness changed from OFF to ON
then
val bright = Hall_Ceiling_Light_Brightness
val timerItem = Hall_Ceiling_Light_OnTime
if (timerItem.state > 0) {
if (timer_hall === null) {
// logInfo("Timer Lights - " + getLocation(bright).label, "Motion detected")
timer_hall = createTimer(now.plusMinutes(Integer::parseInt(timerItem.state.toString)), [ |
bright.sendCommand(OFF)
timer_hall.cancel()
timer_hall = null
logInfo("Timer Lights - " + getLocation(bright).label, "Timer elapsed. " + getLocation(bright).label + " " + getEquipment(bright).label + " turned OFF")
])
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer started")
} else if (timer_hall !== null) {
timer_hall.reschedule(now.plusMinutes(Integer::parseInt(timerItem.state.toString)))
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer rescheduled")
}
}
end
rule "Timer Light - Landing Ceiling Light"
when
Item Landing_Ceiling_Light_Brightness changed from OFF to ON
then
val bright = Landing_Ceiling_Light_Brightness
val timerItem = Landing_Ceiling_Light_OnTime
if (timerItem.state > 0) {
if (timer_landing === null) {
// logInfo("Timer Lights - " + getLocation(bright).label, "Motion detected")
timer_landing = createTimer(now.plusMinutes(Integer::parseInt(timerItem.state.toString)), [ |
bright.sendCommand(OFF)
timer_landing.cancel()
timer_landing = null
logInfo("Timer Lights - " + getLocation(bright).label, "Timer elapsed. " + getLocation(bright).label + " " + getEquipment(bright).label + " turned OFF")
])
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer started")
} else if (timer_landing !== null) {
timer_landing.reschedule(now.plusMinutes(Integer::parseInt(timerItem.state.toString)))
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer rescheduled")
}
}
end
rule "Timer Light - Jimmy's Bed Lamp"
when
Item JimmysRoom_Bedside_Lamp_OnOff changed from OFF to ON
then
val bright = JimmysRoom_Bedside_Lamp_OnOff
val timerItem = JimmysRoom_Bedside_Lamp_OnTime
if (timerItem.state > 0) {
if (timer_jBed === null) {
// logInfo("Timer Lights - " + getLocation(bright).label, "Motion detected")
timer_jBed = createTimer(now.plusMinutes(Integer::parseInt(timerItem.state.toString)), [ |
bright.sendCommand(OFF)
timer_jBed.cancel()
timer_jBed = null
logInfo("Timer Lights - " + getLocation(bright).label, "Timer elapsed. " + getLocation(bright).label + " " + getEquipment(bright).label + " turned OFF")
])
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer started")
} else if (timer_jBed !== null) {
timer_jBed.reschedule(now.plusMinutes(Integer::parseInt(timerItem.state.toString)))
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer rescheduled")
}
}
end
rule "Timer Light - Jimmy's Ceiling Light"
when
Item JimmysRoom_Ceiling_Light_Brightness changed from OFF to ON
then
val bright = JimmysRoom_Ceiling_Light_Brightness
val timerItem = JimmysRoom_Ceiling_Light_OnTime
if (timerItem.state > 0) {
if (timer_jCeiling === null) {
// logInfo("Timer Lights - " + getLocation(bright).label, "Motion detected")
timer_jCeiling = createTimer(now.plusMinutes(Integer::parseInt(timerItem.state.toString)), [ |
bright.sendCommand(OFF)
timer_jCeiling.cancel()
timer_jCeiling = null
logInfo("Timer Lights - " + getLocation(bright).label, "Timer elapsed. " + getLocation(bright).label + " " + getEquipment(bright).label + " turned OFF")
])
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer started")
} else if (timer_jCeiling !== null) {
timer_jCeiling.reschedule(now.plusMinutes(Integer::parseInt(timerItem.state.toString)))
logInfo("Timer Lights - " + getLocation(bright).label, timerItem.state + " min Timer rescheduled")
}
}
end
These are the rules that make the Motion detection work -
var Timer timer_backhall = null
var Timer timer_hall = null
var Timer timer_kEndboard = null
var Timer timer_kSink = null
var Timer timer_kCabinets = null
rule "Motion Light - Back Hall"
when
Item BackHall_MotionLightSensor_Motion received update ON
then
val bright = BackHall_Ceiling_Light_Brightness
val sceneB = BackHall_Ceiling_Light_SceneBrightness
val ctemp = BackHall_Ceiling_Light_ColorTemperature
val illum = BackHall_MotionLightSensor_Illuminance
val illumt = BackHall_Ceiling_Light_IlluminanceThreshold
val timerItem = BackHall_MotionLightSensor_Timer
val onOff = BackHall_Ceiling_Light_MotionOnOff
if (onOff.state == ON) {
if (timer_backhall === null) {
logInfo("Motion Lights - " + getLocation(bright).label, "Motion detected")
if ((illum.state as Number) <= (illumt.state as Number)) {
logInfo("Motion Lights - " + getLocation(bright).label, "Illuminance (" + illum.state + ") is below Threshold (" + illumt.state + "). Turning " + getLocation(bright).label + " " + getEquipment(bright).label + " ON")
ctemp.sendCommand(Calculated_ColorTemperature.state.toString)
if (bright.state != sceneB.state) {
bright.sendCommand(sceneB.state.toString)
}
timer_backhall = createTimer(now.plusMinutes(Integer::parseInt(timerItem.state.toString)), [ |
bright.sendCommand(OFF)
timer_backhall.cancel()
timer_backhall = null
logInfo("Motion Lights - " + getLocation(bright).label, "Timer elapsed. " + getLocation(bright).label + " " + getEquipment(bright).label + " turned OFF")
])
logInfo("Motion Lights - " + getLocation(bright).label, timerItem.state + " min Timer started")
} else {
logInfo("Motion Lights - " + getLocation(bright).label, "Illuminance (" + illum.state + ") is above Threshold (" + illumt.state + "). Not turning " + getLocation(bright).label + " " + getEquipment(bright).label + " ON")
}
} else if (timer_backhall !== null) {
timer_backhall.reschedule(now.plusMinutes(Integer::parseInt(timerItem.state.toString)))
logInfo("Motion Lights - " + getLocation(bright).label, timerItem.state + " min Timer rescheduled")
}
Kitchen_Endboard_MotionLightSensor_Motion.sendCommand(ON)
Kitchen_Endboard_MotionLightSensor_Motion.sendCommand(OFF)
}
end
rule "Motion Light - Hall Ceiling Light"
when
Item Hall_MotionLightSensor_Motion received update ON
then
val bright = Hall_Ceiling_Light_Brightness
val sceneB = Hall_Ceiling_Light_SceneBrightness
val ctemp = Hall_Ceiling_Light_ColorTemperature
val illum = Hall_MotionLightSensor_Illuminance
val illumt = Hall_Ceiling_Light_IlluminanceThreshold
val motion = Hall_MotionLightSensor_Motion
val timerItem = Hall_MotionLightSensor_Timer
val onOff = Hall_Ceiling_Light_MotionOnOff
if (onOff.state == ON) {
if (timer_hall === null) {
logInfo("Motion Lights - " + getLocation(bright).label, "Motion detected")
if ((illum.state as Number) <= (illumt.state as Number)) {
logInfo("Motion Lights - " + getLocation(bright).label, "Illuminance (" + illum.state + ") is below Threshold (" + illumt.state + "). Turning " + getLocation(bright).label + " " + getEquipment(bright).label + " ON")
ctemp.sendCommand(Calculated_ColorTemperature.state.toString)
if (bright.state != sceneB.state) {
bright.sendCommand(sceneB.state.toString)
}
timer_hall = createTimer(now.plusMinutes(Integer::parseInt(timerItem.state.toString)), [ |
bright.sendCommand(OFF)
timer_hall.cancel()
timer_hall = null
logInfo("Motion Lights - " + getLocation(bright).label, "Timer elapsed. " + getLocation(bright).label + " " + getEquipment(bright).label + " turned OFF")
if (motion.state == ON) {
motion.sendCommand(OFF)
}
])
logInfo("Motion Lights - " + getLocation(bright).label, timerItem.state + " min Timer started")
} else {
logInfo("Motion Lights - " + getLocation(bright).label, "Illuminance (" + illum.state + ") is above Threshold (" + illumt.state + "). Not turning " + getLocation(bright).label + " " + getEquipment(bright).label + " ON")
}
} else if (timer_hall !== null) {
timer_hall.reschedule(now.plusMinutes(Integer::parseInt(timerItem.state.toString)))
logInfo("Motion Lights - " + getLocation(bright).label, timerItem.state + " min Timer rescheduled")
}
}
end
rule "Motion Light - Kitchen Endboard"
when
Item Kitchen_Endboard_MotionLightSensor_Motion received update ON
then
val bright = Kitchen_Endboard_Ceiling_Light_Brightness
val sceneB = Kitchen_Endboard_Ceiling_Light_SceneBrightness
val ctemp = Kitchen_Endboard_Ceiling_Light_ColorTemperature
val illum = Kitchen_Endboard_MotionLightSensor_Illuminance
val illumt = Kitchen_Endboard_Ceiling_Light_IlluminanceThreshold
val timerItem = Kitchen_Endboard_MotionLightSensor_Timer
val onOff = Kitchen_Endboard_Ceiling_Light_MotionOnOff
if (onOff.state == ON) {
if (timer_kEndboard === null) {
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, "Motion detected")
if ((illum.state as Number) <= (illumt.state as Number)) {
logInfo("Motion Lights - " + getLocation(bright).label + getEquipment(illum).label, "Illuminance (" + illum.state + ") is below Threshold (" + illumt.state + "). Turning " + getLocation(bright).label + " " + getEquipment(bright).label + " ON")
ctemp.sendCommand(Calculated_ColorTemperature.state.toString)
if (bright.state != sceneB.state) {
bright.sendCommand(sceneB.state.toString)
}
timer_kEndboard = createTimer(now.plusMinutes(Integer::parseInt(timerItem.state.toString)), [ |
bright.sendCommand(OFF)
timer_kEndboard.cancel()
timer_kEndboard = null
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, "Timer elapsed. " + getLocation(bright).label + " " + getEquipment(bright).label + " turned OFF")
])
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, timerItem.state + " min Timer started")
} else {
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(illum).label, "Illuminance (" + illum.state + ") is above Threshold (" + illumt.state + "). Not turning " + getLocation(bright).label + " " + getEquipment(bright).label + " ON")
}
} else if (timer_kEndboard !== null) {
timer_kEndboard.reschedule(now.plusMinutes(Integer::parseInt(timerItem.state.toString)))
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, timerItem.state + " min Timer rescheduled")
}
}
end
rule "Motion Light - Kitchen Sink"
when
Item Kitchen_Sink_MotionLightSensor_Motion received update ON
then
val bright = Kitchen_Sink_Ceiling_Light_Brightness
val sceneB = Kitchen_Sink_Ceiling_Light_SceneBrightness
val ctemp = Kitchen_Sink_Ceiling_Light_ColorTemperature
val illum = Kitchen_Sink_MotionLightSensor_Illuminance
val illumt = Kitchen_Sink_Ceiling_Light_IlluminanceThreshold
val timerItem = Kitchen_Sink_MotionLightSensor_Timer
val onOff = Kitchen_Sink_Ceiling_Light_MotionOnOff
if (onOff.state == ON) {
if (timer_kSink === null) {
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, "Motion detected")
if ((illum.state as Number) <= (illumt.state as Number)) {
logInfo("Motion Lights - " + getLocation(bright).label + getEquipment(illum).label, "Illuminance (" + illum.state + ") is below Threshold (" + illumt.state + "). Turning " + getLocation(bright).label + " " + getEquipment(bright).label + " ON")
ctemp.sendCommand(Calculated_ColorTemperature.state.toString)
if (bright.state != sceneB.state) {
bright.sendCommand(sceneB.state.toString)
}
timer_kSink = createTimer(now.plusMinutes(Integer::parseInt(timerItem.state.toString)), [ |
bright.sendCommand(OFF)
timer_kSink.cancel()
timer_kSink = null
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, "Timer elapsed. " + getLocation(bright).label + " " + getEquipment(bright).label + " turned OFF")
])
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, timerItem.state + " min Timer started")
} else {
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, "Illuminance (" + illum.state + ") is above Threshold (" + illumt.state + "). Not turning " + getLocation(bright).label + " " + getEquipment(bright).label + " ON")
}
} else if (timer_kSink !== null) {
timer_kSink.reschedule(now.plusMinutes(Integer::parseInt(timerItem.state.toString)))
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, timerItem.state + " min Timer rescheduled")
}
}
end
rule "Motion Light - Kitchen Under Cabinet"
when
Item Kitchen_Sink_MotionLightSensor_Motion received update ON
then
val bright = Kitchen_UnderCabinet_Light_Brightness
val sceneB = Kitchen_UnderCabinet_Light_SceneBrightness
val ctemp = Kitchen_UnderCabinet_Light_ColorTemperature
val illum = Kitchen_Sink_MotionLightSensor_Illuminance
val illumt = Kitchen_UnderCabinet_Light_IlluminanceThreshold
val timerItem = Kitchen_Sink_MotionLightSensor_Timer
val onOff = Kitchen_UnderCabinet_Light_MotionOnOff
if (onOff.state == ON) {
if (timer_kCabinets === null) {
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, "Motion detected")
if ((illum.state as Number) <= (illumt.state as Number)) {
logInfo("Motion Lights - " + getLocation(bright).label + getEquipment(illum).label, "Illuminance (" + illum.state + ") is below Threshold (" + illumt.state + "). Turning " + getLocation(bright).label + " " + getEquipment(bright).label + " ON")
ctemp.sendCommand(Calculated_ColorTemperature.state.toString)
if (bright.state != sceneB.state) {
bright.sendCommand(sceneB.state.toString)
}
timer_kCabinets = createTimer(now.plusMinutes(Integer::parseInt(timerItem.state.toString)), [ |
bright.sendCommand(OFF)
timer_kCabinets.cancel()
timer_kCabinets = null
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, "Timer elapsed. " + getLocation(bright).label + " " + getEquipment(bright).label + " turned OFF")
])
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, timerItem.state + " min Timer started")
} else {
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, "Illuminance (" + illum.state + ") is above Threshold (" + illumt.state + "). Not turning " + getLocation(bright).label + " " + getEquipment(bright).label + " ON")
}
} else if (timer_kCabinets !== null) {
timer_kCabinets.reschedule(now.plusMinutes(Integer::parseInt(timerItem.state.toString)))
logInfo("Motion Lights - " + getLocation(bright).label + " " + getEquipment(bright).label, timerItem.state + " min Timer rescheduled")
}
}
end
PROBLEMS
It’s working quite well but there is a few things I can’t get right:
1-
The two slider items hit 100% only about 1/4 of the total length of the slider ** I have temporarily changed my widget to use steppers until I can figure this out.
I’m sure it has something to do with the column width of something above, but I can’t figure it out.
2-
When the window expands on my iPhone 12, because of the way the fancy screen goes up into the very top of the phone, the closing X button is obscured by my iPhone time and other icons that live in this space.