Smart app to control group of lights with motion sensor and not turn on those that were off originally?


(Robert M) #1

Greetings,

I’m using the built-in smart app to control lights with a motion detector, but what would be really nice is if I could “group” bulbs and have the app remember the state of each bulb when the motion detector times out and the bulbs all turn (or become) off, then restore it to that previous state rather than turning back on all bulbs when I re-enter the room. Does that make sense?

Basically, it would need to remember “OK, this motion detector is being used on both bulbs 1 and 2. Now motion stopped and bulb 1 is on and bulb 2 is off. When motion occurs again, I’m going to turn on bulb 1 and leave off bulb 2.” If both bulbs were on originally instead of just 1, it would turn them both on again. If both bulbs were off (say the bulbs were turned off by other means), I’m not sure, but perhaps turning on both bulbs might be appropriate.

I have CoRE installed and was hoping it could do something like this, but it seems very complicated to set up and I’m not exactly sure how I’d be able to do this in there, if it is possible. I can’t imagine that someone else hasn’t wanted to do this with a group of bulbs before, so I thought I’d ask.

Thanks for any ideas!


CoRE - Get peer assistance here with setting up Pistons
#2

Grouping lights can be done, but since you want to track states individually, I really do think Core is going to be your best choice. It is complicated to set up, but fortunately there is a forum thread where people are happy to help with getting any individual rule (which core calls a piston) designed. So I would ask there and I’m sure someone can get you set up. :sunglasses:


(Robert M) #3

JDRoberts, thanks for your input. I did attempt to get some help on the CoRE thread but I’m not sure if anyone understood quite what I was asking for, and like many others I found the app difficult to use (I don’t think the difficulty stems from CoRE itself but rather the way that SmartThings makes SmartApps be written–if there were a better way to modify rules that didn’t make me navigate through multiple pages and whatnot, it would be easier to see what you’re actually doing).

Anyway, I decided to throw together a SmatApp quickly based on the “Light Follows Me” app template by SmartThings.

EDIT: I’d recommend using the GitHub link in a subsequent post instead of this code since that will be more up-to-date.

/**
 *  Copyright 2016 Robert Morris
 *  Portions of code based on "Light Follows Me" app by SmartThings, copyright 2014 SmartThings
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 *
 *  Author: Robert Morris
 */

definition(
name: “Light on Motion Plus”,
namespace: “RMoRobert”,
author: “Robert Morris”,
description: “Turn on one or more lights on when motion is detected and off after motion stops. Optionally dim before turning off and remember on/off states of invididual lights when motion stops to restore these states when turning back on rather than turning on all.”,
category: “Convenience”,
iconUrl: “https://s3.amazonaws.com/smartapp-icons/Meta/light_motion-outlet.png”,
iconX2Url: “https://s3.amazonaws.com/smartapp-icons/Meta/light_motion-outlet@2x.png
)

preferences {
section(“Turn on when there’s movement…”){
input “motion1”, “capability.motionSensor”, title: “Where?”
}
section(“Turn on/off light(s)…”){
// Really want to use the ‘dimmers’ variable below for these, but can’t seem to access their on/off
// capabilities (even though the devices support it) unless they are selected as switches, so…
// Make user select ideally the same lights for both ‘switches’ and 'dimmers’
input “switches”, “capability.switch”, multiple: true
}
section(“And off when there’s been no movement for…”){
input “minutes1”, “number”, title: “Minutes?”
}
section(“Dim before turning off…”) {
// See comment for ‘switches’ variable.
input “dimmers”, “capability.switchLevel”, multiple: true, title: "Lights to dim for 1 minute before turning off"
paragraph “If you want the lights to turn off without first dimming, select no lights here. Otherwise, you probably want to select the same lights here as you did above. (Selecting lights not chosen above will have no effect.)”
}
section(“Remember on/off state of individual lights when motion stops and restore when motion starts?”){
input “boolRemember”, “bool”, defaultValue: true, title: "Remember states?"
paragraph “By default, this app will remember the on/off state of each light chosen above and restore the lights to those on/off states when motion resumes after inactivity, rather than turning all lights back on. You can disable this below if desired, which will make this app function more like most others.”
}
section(“Only during certain times…”) {
//TODO: Would be nice to have sunset/sunrise as options here like stock app
input “starting”, “time”, title: “Starting”, required: false
input “ending”, “time”, title: “Ending”, required: false
}
}

//=========================================================================
// “Constant” declarations and value-calculator functions
//=========================================================================

// Percentage to dim lights to if dimmed (TODO: what if current level less than 10?)
def getDimToLevel() {
return 10
}

def getOffThreshold() {
return 1000 * 60 * minutes1 - 1000
}

def getDimThreshold() {
// If off threshold is <= 1, make dim threshold 30s (actually 29s) rather than zero
if (minutes1 <= 1) {
return 1000 * 30 - 1000
}
return 1000 * 60 * (minutes1 - 1) - 1000
}

//=========================================================================
// SmartApp Methoods
//=========================================================================

def installed() {
subscribe(motion1, “motion”, motionHandler)
state.mode = “unknown” // Use state.MODE to hold one of “unknown”, “on”, “dim”, or “off” depending on current situation
}

def updated() {
unsubscribe()
subscribe(motion1, “motion”, motionHandler)
state.mode = "unknown"
log.debug “****** App updated *****”

}

// Returns true if at least one switch is turned on at the moment
def isOneRealSwitchOn() {
log.trace "Running isOneRealSwitchOn()…"
def isOneOn = false
for (sw in switches) {
if (sw.currentSwitch == “on”) {
isOneOn = true
}
}
log.trace "Ran isOneRealSwitchOn(). Return value = " + isOneOn
return isOneOn
}

// Returns true if at least switch in saved switches is turned on
def isOneSavedSwitchOn() {
log.trace "Running isOneSavedSwitchOn()…"
def isOneOn = false
state.switchStates.each { key, value ->
if (value[“switch”] == “on”) {
log.debug "Saved switch is on"
isOneOn = true
}
}
log.trace "Ran isOneSavedSwitchOn(). Return value = " + isOneOn
return isOneOn
}

// Returns false if user has specified “run between” times and the current time
// is outside those times. Otherwise, returns true.
def isRunTimeOK() {
log.trace "Running isRunTimeOK()…"
def retVal = true
if (starting && ending) {
def currTime = now()
def startTime = timeToday(starting).time
def stopTime = timeToday(ending).time
retVal = startTime < stopTime ? currTime >= startTime && currTime <= stopTime : currTime <= stopTime || currTime >= startTime
}
log.trace "Exiting isRunTimeOK(). Return value = $retVal"
return retVal
}

/**

  • Returns “Switch Level” (dimmer) matching “Switch”, assuming user has selected both
    */
    def getDimmerForSwitch(sw) {
    log.debug "Running getDimmerForSwitch()… sw = ${sw}"
    for (dm in dimmers) {
    log.debug "dm.id = ${dm.id}"
    log.debug "sw.id = ${sw.id}"
    if (dm.id == sw.id) {
    log.debug "Found dimmer matching switch ${sw}!"
    log.trace "Exiting from getDimmerForSwitch(). Returning ${dm}."
    return dm
    }
    }
    log.debug "NO MATCH FOR SWITCH FOUND."
    log.trace “Exiting getDimmerForSwitch().”
    }

/**

  • Returns “Switch” matching “Switch Level” (dimmer), assuming user has selected both
    /
    def getSwitchForDimmer(dm) {
    for (sw in switches) {
    if (sw.id == dm.id) {
    log.debug " Found match for dimmer! sw = " + sw
    return sw
    }
    }
    log.debug "
    ** NO MATCH FOR DIMMER FOUND. Exiting getSwitchForDimmer()."
    }

/**

  • Saves on/off status and dimmer level of light
  • Parameter forSwitch: a Switch-capable object (supporting on/off) to remember. Will try to find same Switch as Switch Level as well
  • if possible to record dimmer status.
    */
    def saveLightState(forSwitch) {
    log.trace "Running saveLightState()…"
    if (forSwitch.currentSwitch == “on”) {
    def dm = getDimmerForSwitch(forSwitch)
    if (dm) {
    state.switchStates.put(forSwitch.id, [“switch”: “on”, “level”: dm.currentLevel])
    } else {
    state.switchStates.put(forSwitch.id, [“switch”: “on”, “level”: 100]) // Guess just store 100 for brightness if can’t tell…
    // Can’t dim bulb, so I guess don’t do anything here
    }
    } else {
    state.switchStates.put(forSwitch.id, [“switch”: “off”])
    }
    log.debug "Just saved for " + forSwitch.id + ": " + state.switchStates.get(forSwitch.id)
    log.trace “Exiting saveLightState().”
    }

/**

  • Saves on/off status only. Similar to saveLightState but does not save dimmer status.
  • Parameter forSwitch: a Switch-capable object (supporting on/off) to remember.
    */
    def saveLightOnOffState(forSwitch) {
    log.trace "Running saveLightOnOffState()…"
    log.debug "Switch ${forSwitch.id} currently saved as ${state.switchStates.(forSwitch.id)}"
    state.switchStates.(forSwitch.id).switch = forSwitch.currentSwitch
    log.debug "Just saved for " + forSwitch.id + ": " + state.switchStates.get(forSwitch.id)
    log.trace “Exiting saveLightOnOffState().”
    }

/**

  • Gets on/off status for a saved light
    */
    def getSavedLightOnOffState(forSwitch) {
    log.trace "Running getLightOnOffState()…"
    log.debug "Saved data for ${forSwitch.id} = ${state.switchStates.get(forSwitch.id)}"
    def swState = state.switchStates.get(forSwitch.id).switch ?: "off"
    log.trace "Exiting getLightOnOffState(), returning ${swState}."
    return swState
    }

/**

  • Gets dim level for a saved light
    */
    def getSavedDimLevelState(forSwitch) {
    log.trace "Running getLightOnOffState()…"
    log.debug "Saved data for ${forSwitch.id} = ${state.switchStates.get(forSwitch.id)}"
    def dmLevel = state.switchStates.get(forSwitch.id).level ?: "100"
    log.trace "Exiting getLightOnOffState(), returning ${dmLevel}."
    return dmLevel
    }

def motionHandler(evt) {
log.trace "----------------Begin handling of ${evt.name}: ${evt.value}----------------"
log.debug "state.mode = ${state.mode}"
if (!isRunTimeOK()) {
log.trace "Outside specified run time. Returning."
return
}
if (evt.value == “active”) {
log.debug "Motion active. Turn on lights (or ensure on). Calling turnOnOrRestoreLights()…"
turnOnOrRestoreLights()
} else if (evt.value == “inactive”) {
// Old code to just run scheduleCheck after ‘off’ threshold:
//runIn(minutes1 * 60, scheduleCheck, [overwrite: false]) // why not overwrite?
log.debug "Motion inactive. Deciding what to do…"
if (dimmers) {
log.debug “Dimming option has been chosen. Scheduling scheduleCheck() to run after ‘dimming’ threshold reached.”
// Run 1 minute before “off” threshold, unless offThreshold > 1 minute, then aim for 45s
runIn(minutes1 > 1 ? (minutes1 - 1) * 60 : 30, scheduleCheck)
//runIn(minutes1 > 1 ? (minutes1 - 1) * 60 : 45, scheduleCheck)
} else {
log.debug "Dimming option not chosen. Scheduling scheduleCheck() to run after ‘off’ threshold reached."
runIn(minutes1 * 60, scheduleCheck)
}
}
log.trace “----------------End handling of ${evt.name}: ${evt.value}----------------”
}

def scheduleCheck() {
log.trace "Running scheduleCheck()…"
log.debug "state.mode = ${state.mode}"
def motionState = motion1.currentState(“motion”)
if (motionState.value == “inactive”) {
def elapsed = now() - motionState.rawDateCreated.time
if (elapsed >= getDimThreshold() && elapsed < getOffThreshold() && dimmers) {
log.debug "Motion has stayed inactive for amount of time between ‘dim’ and ‘off’ thresholds ($elapsed ms). Dimming lights"
dimLights()
// Schedule to run again so can check for “off” threshold next:
runIn(minutes1 > 1 ? (minutes1 - 1) * 60 : 30, scheduleCheck)
//runIn(minutes1 > 1 ? (minutes1 - 1) * 60 : 45, scheduleCheck)
log.debug “Done dimming. Scheduled scheduleCheck() to run again in ${minutes1 > 1 ? (minutes1 - 1) * 60 : 30} seconds.”
}
if (elapsed >= getOffThreshold()) {
log.debug "Motion has stayed inactive long enough to cross ‘off’ threshold ($elapsed ms). Turning lights off."
turnOffLights()
} else {
log.debug “Motion has not stayed inactive long enough since last check ($elapsed ms). Doing nothing”
}
} else {
log.debug “Motion is active. Do nothing and wait for inactive.”
}
log.debug "state.mode = ${state.mode}"
log.trace “Exiting scheduleCheck().”
}

/**

  • If configured to save previous light states, attemps to restore those. If can’t find, simply turns on light.
  • Intended to be called when motion is detected after period of no motion (i.e., when lights are off or dimmed).
    */
    def turnOnOrRestoreLights() {
    log.trace "Running turnOnOrRestoreLights()…"
    log.debug "state.mode = ${state.mode}"
    if (!isRunTimeOK()) {
    log.trace "Outside specified run time. Returning."
    return
    }
    if (state.mode != “dim” && isOneRealSwitchOn()) {
    log.debug "Current mode is not ‘dim’ and at least on swtich is on. Assume this is desired state."
    log.debug "Setting mode to ‘on’ in case it isn’t."
    state.mode = “on”
    }
    else if (state.mode == “dim” || state.mode == “off”) {
    if (!isOneSavedSwitchOn) {
    log.debug "No switches were saved as ‘on’ when motion last stopped. Turning all on."
    switches.on
    state.mode = “on”
    } else {
    log.debug "Mode is either ‘dim’ or ‘off,’ so restore lights to last known state."
    switches.each {
    def savedLightState = getSavedLightOnOffState(it)
    if (savedLightState != “off”) {
    log.debug "${it} was saved as on. Turning on."
    it.on()
    def dm = getDimmerForSwitch(it)
    if (dm) {
    def prevLevel = getSavedDimLevelState(it)
    log.debug "Dimmer found for ${it}. Previous level: ${prevLevel}. Setting."
    dm.setLevel(prevLevel)
    } else {
    log.debug "No dimmer found for ${it}. Turning on switch but cannot restore dim level."
    it.on()
    }
    } else {
    log.debug “${it} was saved as off. Not turning on.”
    }
    }
    }
    }
    if (state.mode == “unknown”) {
    log.debug "State unknown. Turning on all switches."
    switches.on()
    }
    state.mode = "on"
    log.debug "state.mode = ${state.mode}"
    log.trace “Exiting turnOnOrRestoreLights().”
    }

/**

  • Dims lights (those configured to be dimmed, which for most users is probably all of them).
  • Intended to be called when motion has been inactive for a period of time between the “dim” and “off” thresholds.
    */
    def dimLights() {
    log.trace "Running dimLights()…"
    log.debug "state.mode = ${state.mode}"
    if (!isRunTimeOK()) {
    log.trace "Outside specified run time. Returning."
    return
    }
    state.switchStates = [:]
    for (sw in switches) {
    log.debug "Saving light state for ${sw}"
    saveLightState(sw)
    log.debug "Dimming ${sw}"
    def dm = getDimmerForSwitch(sw)
    if (dm) {
    log.debug "Found ${dm}, currently at level ${dm.currentLevel}"
    if (sw.currentSwitch != “off”) {
    def toLevel = dimToLevel
    if (dm.currentLevel <= toLevel) {
    // If light is currently at or less than “dim to” level, dim it as low as possible
    toLevel = 1
    }
    dm.setLevel(toLevel)
    log.debug “Dimmed ${dm} to ${toLevel}”
    } else {
    log.debug “Not dimming ${sw} because is off.”
    }
    log.debug “${dm} now at level ${dm.currentLevel}”
    } else {
    log.debug “No dimmer found for ${sw}”
    }
    }
    state.mode = "dim"
    log.debug "state.mode = ${state.mode}"
    log.trace “Exiting dimLights().”
    }

/**

  • Turns off all lights.
  • Intended to be called when motion has been inactive for a period of time greater than or equal to the “off” threshold.
    */
    def turnOffLights() {
    log.trace "Running turnOffLights()…"
    log.debug "state.mode = ${state.mode}"
    if (!isRunTimeOK()) {
    log.trace "Outside specified run time. Returning."
    return
    }
    switches.each {
    log.debug "Saving on/off state then turning off: ${it}"
    saveLightOnOffState(it)
    it.off()
    }
    state.mode = "off"
    log.debug "Turned off all lights."
    log.debug "state.mode = ${state.mode}"
    log.trace “Exiting turnOffLights().”
    }

This was hastily thrown together and seems to work fine for my use cases, but I haven’t tested every possible scenario (or code path) and I can’t guarantee that it will work for everyone. I’ll keep working on it for myself but I’m not sure if anyone else might be interested in this.

Also, there are some oddities in my code: this is intended to be used with Philips Hue bulbs, which support both “level” (via Switch Level capability) and “on”/“off” (via Switch capability). However, in order to access level from Switch Level, I have to have the user select them as a Switch Level, but I also have to have them select them as Switch devices in order to be able to use on/off. I’m sure there’s a better way to do this, but right now it really only works as intended if you choose the same bulbs for both (or just don’t use the dimming feature, in which case it doesn’t matter). I’m also not sure if this would be a good candidate for a parent/child app situation or what the advantages or disadvantages of that model would be.

Suggestions welcome, or feel free to modify for your own use.

EDIT: Rewrote large portions of code with some bug fixes 10/7/16–still haven’t tested this much in the real world, so feel free to give feedback.


(Don) #4

Since your making your own code. Possibly you could get some helpful guide looking at the Smart app that uses a canary bulb state to turn off or restore bulbs to their saved state.
It was originally written to reset smart bulbs after a power loss / restore event. Something in its code might help you write the saving and restoring your looking for. I can’t seem to find the link for it right now. I’m sure @JDRoberts will chime in. He is very good and finding helpful links.


(Robert M) #5

Thanks for the suggestion! I didn’t know such an app existed. Right now, I’m using the “state” map object provided by ST to store bulb states (on/off status and dim level) before either dimming them or turning them off, then retrieving these states from that map when motion resumes. That’s the only way I can think of to persist such information between executions of a SmartApp, but perhaps there are better thought-out ways to store particular information.

For anyone who wants to know more about why I wrote this: my particular use case is that I have two Hue bulbs in in each of my bedrooms, only one of which I usually want on. They are in the same fixture controlled by the same physical switch. The default “Smart Lighting” app (or whatever it’s called) will turn on/off both of them with motion, but I usually prefer to only have one of them turned on at a time, though occasionally I’ll use both if I want extra light. If I do have both of them on, I want the behavior the stock app provides, but if I have one of them off I don’t want the second one to keep turning back on when motion is detected. I think I have this behavior covered with my SmartApp, which does:

  • If no lights are on and motion is detected, then either (1) turn on only those lights that the app knows were on when motion was last inactive for a period of time long enough to dim or turn off the bulbs, or (2) turn on all lights if the app does not know the previous state of any lights (e.g., if you just installed it) or if all lights were off when motion was last inactive for long enough. (This last condition is designed to still turn on lights in the event that the lights were manually turned off by other means before the inactivity timeout was reached–I don’t think it’s desirable to restore all bulbs to "off’ when motion resumes.)
  • If lights are on and motion has stayed inactive for long enough, then (save the on/off status of each light and) turn off all lights.
  • Optionally, one minute before the above “off” threshold is reached, dim for 1 minute any lights that are on (after saving their previous dim level and on/off state for all lights so they can be restored when motion resumes)–this will attempt to dim them for 30 seconds instead if the user sets the “off” time to 1 minute of inactivity, though ST doesn’t guarantee accuracy here.

The last thing was just something I though would be nice to have–both to serve as a “warning” that the lights are about to turn off, and because Philips has new Hue motion sensors that do something similar, and I didn’t want to feel like I was missing out by not having them. :slight_smile: It is optional and won’t happen if you don’t choose to dim those lights in the app. (I really don’t like that the lights have to be selected twice in the app’s preferences, but there doesn’t seem to be a way to ask the user to choose devices that support both “switch” (e.g., lights) and “switch level” (i.e., dimmable) capabilities, so they have to be chosen twice so I can access both of those properties. I guess this does provide the option of only dimming certain lights if you want to apply this feature to some but not all.)


(Coffe) #6

Is it possible to ad a tun on when lux is to low to this app instead of time?
And a turn on state like a set level on first motion


(Robert M) #7

@Effoc, yes! I don’t use it, so I haven’t tested it much, but I added code a while back that should be able to turn the light on only when a lux sensor is below a certain level (you can use this in addition to or instead of time, mode, or status of other switch). You’ll find this under the “Only when illuminance is less than…” section on the first page of the SmartApp’s configuration pages.

If you know of a good lux sensor, I’d like to hear about that as well. :slight_smile: The Zooz Multi worked poorly for me as a motion detector but might be accurate enough for lux, and I know Aeon has one (or a few generations of it) that might work, too, but again, I haven’t tested this much.

EDIT: Sorry, I guess I should provide the code for this. I have this project in a GitHub repository now: https://github.com/RMoRobert/STLightsOnMotionPlus (the code above is probably old and might not have this feature). Again, this is just something I’m working on in my free time and there are a few minor issues, but it’s working pretty well for my cases. Feel free to modify it for yours.


(Coffe) #8

I have 3 different motions sensors whit lux
Fibaro aeotec and a china copy of the fibaro and i like everyone but i don’t know how accurate they show the lux.
Celebrate the settings after what they show. take a look in the room and think aaaa now it should light up the room and take a look in ST and see how much the lux is on and edit the settings after it.

Have tested the app now and good i love it.
Some ideas
% possibility to add more motion sensors per settings instead of one.
% The ability to edit turn on stage. Like between 00.00 and 06.00 like in room toilet the turn on stage is dimmed yellow from start and from 06.00 and 00.00 bright white.


(Coffe) #9

I would if i could help you coding but im really new into this but i like your smal notes to yourself in the coding :slight_smile:


(Robert M) #10

@Effoc, I like those ideas! I was definitely thinking about the second one (adding the ability to automatically set the dim level and/or color temperature based on time of day, mode, or similar setting), but that gets tricky with multiple bulbs since the point of my app is to “remember” their individual states and restore those. In this case, would you “remember” what the user had previously unless the mode has changed or the time has passed one of the thresholds, in which case you retrieve a preference they set in the app? That gets tricky, as does writing a user interface that would let you control all of that with multiple bulbs, I think.

I’ve managed to work around this in a one-bulb scenario by using my app during certain modes and the stock SmartLighting app (or whatever it’s called; it does let you set a dim level) when my “Night” mode is activated. This should also work if you have multiple bulbs but don’t care to set them individually. While I’m using modes, I think it should also be possible to use with time-based constraints as well. (But, by the way, I’m starting to prefer modes instead. I wasn’t using them for anything else before, and now if the weather is bad and it gets dark earlier than it usually does, I can manually turn on my “evening” mode when I want rather than waiting for sunset or a specific time; I can also change it to–and this is different for me–“night” mode when I go to bed and no longer want most motion sensors to turn on light.)


(Coffe) #11

I use hue advance connect and gouped all my rooms so your app thinks it only turn on one light and if i change the light when it have turned it on it stays that way. but im interested in when i have left the room and everything is of again i want it to turn on “white” again or some other base color.

Changed a line in yore code so u can chose multiple motion sensor and it works have tried it now.

preferences {
page(name: “pageBasic”, title: “When there’s activity on sensor”, nextPage: “pageAdvanced”, uninstall: true) {
section(“Choose a motion sensor(s)…”) {
input “motion1”, “capability.motionSensor”, title: “Which motion sensor(s)?” , multiple: true


(Robert M) #12

I’ve tried Hue Advanced Connect myself but found it didn’t work very well with my app because unlike the stock Hue Connect app, Hue Advanced took a while (a few minutes?) to “sync” a change made directly via the Hue Hub with the corresponding Things in SmartThings. This may be OK if you use my app to dim/turn off lights after several minutes, but if you have a very short time (personally, one of my rooms is 1 minute), then my app won’t be able to properly “remember” the bulbs’ states since they won’t be accurately represented in ST (unless you keep motion going for a few minutes). I think Hue Advanced is supposed to be just as fast as the stock Hue Connect, but I had to switch back because it wasn’t working for me.

As for “groups,” I again am not using them since I’m no longer on Hue Advanced Connect, but my understanding is that my app (and any other) would see them as one bulb. If you want a specific brightness or color setting when motion is detected, the stock SmartLighting (or whatever it’s called) app can do that. If you don’t care about remembering the state of individual bulbs, I think the only advantage my app has over the stock app is the ability to dim the lights for a minute or so before actually turning them off. If I had more time, I’d definitely add the ability to set a specific brightness and/or color temperature when in certain modes (or times, etc.) to my app.

Anyway, I’m glad my app is useful for you! I haven’t tested it with multiple motion sensors (I can’t remember how the code that runs with the motion events fire would respond in such a case), but I’m glad it’s working!