Automatic light dimming

  1. Is indeed a mistake. I remember writing the lock but must have weed it out when I copied and pasted. One of the problems of wiring coffee on a phone.

  2. Based on experience, at least from 1.8 I’ve seen inconsistent behavior with finally NOT being executed when an exception actually occurs. This may be fixed now but I got in the habit of unlocking in both because of things experience. That is how finally is supposed to work but that isn’t how it worked in the Rules DSL at some point. I spent about a man week figuring this out the hard way.

  3. Indeed in normal Java One shouldn’t catch Error, but I do this so that I will at least get a chance to see what rule caused the Error. Otherwise there is nothing in the log to let you correlate the Error with the rule. This is all theoretical of course as I’ve never seen an Error in OH. I will agree that if a Error is caught it should be rethrown. However that again brings 2 to the for as, at in my experience, the finally will not execute as it should.

1 Like

a.) Regarding the “Generic Presence Detection”:

Rule (identical to your example tutorial apart from && replacing “and” in the else if statement):

rule "System started"
when
    System started
then
    Present.sendCommand(OFF) // assume no one is home on startup
end

rule "gPresent updated, at least one sensor changed state"
when
    Item gPresent received update
then
    // someone came home
    if(gPresent.state == ON && Present.state != ON) {
        Present_Timer.postUpdate(OFF) // cancel the timer if necessary
        Present.sendCommand(ON)
    }

    // no one is home
    else if(gPresent.state == OFF && Present.state != OFF){
        Present_Timer.sendCommand(ON) // start the timer
    }
end

rule "Present_Timer expired"
when
    Item Present_Timer received command OFF
then
    Present.sendCommand(OFF)
end

Items:

Switch Present "Someone is Present" <present> // master presence switch
Group:Switch:OR(OFF,ON) gPresent <present> // all presence sensors belong to this group
Switch Present_Timer { expire="1m,command=OFF" }


Switch Presence_Mobile_Mike "Mikes Mobile" <network> (gPresent) { channel="network:device:192_168_2_163:online" }

Switch Presence_Iris_Saxion "Iris Mobile" <network> (gPresent) { channel="network:device:192_168_2_191:online" }

Switch Presence_Diamant_Saxion "Diamant Mobile"  <network> (gPresent) { channel="network:device:192_168_2_146:online" }

Switch Presence_Pepijn_Saxion "Pip Mobile" <network> (gPresent) { channel="network:device:192_168_2_150:online" }

Switch Presence_Euan_Saxion "Euan Mobile" <network> (gPresent) { channel="network:device:192_168_2_117:online" }

My understanding is that the switch “Present” should be ON if anyone of the WiFi connections in the group (gPresent) are connected right? At the moment, there are two main issues;

  1. The switch “Present” is only ON when all the WiFi connections in the gPresent group are connected, thus it is acting as an AND switch rather than an OR switch

  2. The switch “Present” does not switch OFF when all WiFi connections are off, in fact it only switches OFF on restart (as per the rule)

However, while checking the log (events.log) the group gPresent receives the ON/OFF commands correctly (e.g. `gPresent changed from ON to OFF through Presence_Mobile_Mike``) and the Timer is also sent the ON command correctly, but it does not change the state of the switch after the 1 minute.

Any ideas?

Update: Infact according to the log it appears that the the item “Present_Timer” receives the ON command multiple times once all WiFi connections are off:

2017-06-28 12:31:12.427 [ItemCommandEvent          ] - Item 'Present_Timer' received command ON
2017-06-28 12:31:16.409 [ItemStateChangedEvent     ] - Presence_Mobile_Mike changed from ON to OFF
2017-06-28 12:31:16.423 [ItemStateChangedEvent     ] - network_device_192_168_2_163_online changed from ON to OFF
2017-06-28 12:31:16.429 [ItemStateChangedEvent     ] - network_device_192_168_2_163_time changed from 304.38349599999997963095665909349918365478515625 to -1
2017-06-28 12:31:16.437 [ItemCommandEvent          ] - Item 'Present_Timer' received command ON
2017-06-28 12:32:06.401 [ItemStateChangedEvent     ] - network_device_192_168_2_164_time changed from 1.0822860000000000813002998256706632673740386962890625 to 0.4622370000000000089812601800076663494110107421875
2017-06-28 12:32:12.430 [ItemCommandEvent          ] - Item 'Present_Timer' received command ON
2017-06-28 12:32:12.442 [ItemCommandEvent          ] - Item 'Present_Timer' received command ON

However the timer never receives the OFF command and thus Presence does not switch OFF either. I am thinking the error is related to the expire binding at this point? Is there anything that has to be configured for this binding?

The Group gPresent should be either OR(ON,OFF) or AND(OFF,ON). OR(OFF,ON) means if any one Switch is OFF, gPresent is OFF.

Do you have the Expire binding installed?

Thanks for the clarification of the OR.

Indeed the expire binding is installed (via paper UI)

Hi,

First thing I would do (not being an authority of any sort) is to analyze the setup. Z-wave networks can sometimes create a lot of delay in terms of actual response (depending on the routing nodes).
Second thing I would think about is as @rlkoshak and @rossko57 stated, triggered rule execution.
Third thing I am thinking about is that the way you are trying to achieve a constant lighting setup. The way you have written the rule will for sure expose your measured light level values to a lot of unsatisfying values! The control method is purely wrong (at least in my opinion). If it works for you, then keep it as it is, if not, find a control method that can fulfill the need, like PID control!

Best regards,
George

I’m not sure what could be wrong. There is no additional setup required for the Expire binding.

Thanks for the feedback. In regards to the control system; indeed I agree it is rather rudimentary (simple negative feedback loop) - however implementing a control system such as PID would involve finding the transfer function and then tuning the various parameters with unit step response etc. which to be done efficiently requires software (such as 20sim) and/or matlab and at the moment I simply do not have the time for it - furthermore, how would the PID actions be implemented in OpenHAB rules? is there an in built function in the rules or something similar? If you have a link to some good content regarding PID and OpenHab I would be very interested in reading further upon it. Cheers!

Hi @miccio,

A few months ago I pull requested a PID controller binding. Take a look here.
I have tested it with constant lighting, ambient temperature control, and other relatively fast processes (loop time less than 200ms) - for my setups it worked like a charm!.
I am glad I find someone to be interested in PID control, I can provide the jar when requested (momentarily I am trying to keep the tests of the binding applied to my existing running projects, that is why I am not publicly promoting this).

Best regards,

George

3 Likes

Hi there,

I was wondering if you have any ideas why the following code is not working as intended. From what I can tell the, entranceLock never unclocks ; what happens is that the dimmers increase once, then nothing happens anymore.

import java.util.concurrent.locks.ReentrantLock

var java.util.concurrent.locks.ReentrantLock entranceLock  = new java.util.concurrent.locks.ReentrantLock()
var Number Dimmer_1_Value = 0
var Number Dimmer_2_Value = 0
var Number Dimmer_3_Value = 0
var Number Dimmer_4_Value = 0


rule "Dimming UP: Entrance"
when
    Item ZwaveEye1Lux changed
then
    if(!entranceLock.isLocked) {
	entranceLock.lock()
        try {
            if(ZwaveEye1Lux.state as DecimalType <= LuxSetpoint.state as DecimalType &&
               Standard_ALD.state == ON &&
               Present.state == ON){
                Dimmer_1_Value = Dimmer_1.state as PercentType
		Dimmer_1_Value = Dimmer_1_Value + 3
		Dimmer_2_Value = Dimmer_2.state as PercentType
		Dimmer_2_Value = Dimmer_2_Value + 3
		Thread::sleep(1000)
		sendCommand(Dimmer_1,Dimmer_1_Value)
                sendCommand(Dimmer_2, Dimmer_2_Value)
		
            }
        } 
        
	catch(Throwable t) { entranceLock.unlock() }
        finally { entranceLock.unlock() }
    }
end

Any insight would be greatly appreciated!

What is in your logs? Add some logInfos to trace progress and expected values. Errors in try blocks don’t always seem to end up at the catch or finally blocks in rules.

Absolutely add some logging to the main try, the catch, and the finally. In the catch, log out t.toString so we can see what is being thrown.

Try loading it in Eclispe Smarthome Designer to see if there is some syntax problem that is not apparent.

Finally, this isn’t the cause of an error, but when you import java.util.concurrent.locks.ReentrantLock, you only need to refer to it as ReentrantLock in your code. That is the main purpose of imports.

Hello, I will add the logs as soon as I can. Yes I tried various options to make the code work including the import declaration you mention (I saw it in some example code), I did think it didn’t make sense but I still tried it! Anyway, regarding this line of code:

   if(ZwaveEye1Lux.state as DecimalType <= LuxSetpoint.state as DecimalType &&
               Standard_ALD.state == ON &&
               Present.state == ON){
                Dimmer_1_Value = Dimmer_1.state as PercentType
		Dimmer_1_Value = Dimmer_1_Value + 3
		Dimmer_2_Value = Dimmer_2.state as PercentType
		Dimmer_2_Value = Dimmer_2_Value + 3
		Thread::sleep(1000)
		sendCommand(Dimmer_1,Dimmer_1_Value)
                sendCommand(Dimmer_2, Dimmer_2_Value)
		
            }
        } 

If the virtual switch (Standard_ALD ) is switched OFF while the rule is running, then technically the rule should not execute the next time the if statement is cheked, as the dimmers keep on receiving commands even if the switch is turned OFF. The rule initially responds to the switch, as the dimmers only start receiving commands once the switch is turned ON. Any ideas? I wouldn’t think this should happen regardless of the lock/unlock issue?

Like has been suggested, you need to add log statements all over the place in this rule to see exactly where it is getting to, the states of your Items, at each part of the rule.

Dealing with concurrency is really hard and doing it blind is all but impossible.

Hi @miccio,

Do not lose hope, take things to be done step by step. As Rich is always stating, posting logs is most of the times the only way to go!

Best regards,

George

Fair enough, it makes sense! I will post an update once I can. I just thought a switch being OFF (thus the IF condition not being met) would cause the rule to stop running! Anyway thanks for the support everyone, this community is really great!

That is ambiguous.
Is it (A <= B) && C , or is it A <= (B && C) ?
I’m sure it evaluates in a predictable way (if you know the rules - I don’t), but that may not be what you intended.
This is probably another place to go step by step - multiple if() until you can confirm things are happening just the way you want.

Well when it was coded as per below the behaviour was the same, when @rlkoshak suggested a cleaned up version of my code he removed all the extra brackets, thus I assumed they did not make a difference:

if (((ZwaveEye1Lux.state as DecimalType) <= ( LuxSetpoint.state as DecimalType - 30)) && (Standard_ALD.state == ON) && (Presence_Mobile_Mike.state == ON || Presence_Iris_Saxion.state == ON || Presence_Pepijn_Saxion.state == ON || Presence_Diamant_Saxion.state == ON || Presence_Euan_Saxion.state == ON ))

It evaluates the <= first and then the && so it is (A <= B) && C

Here is a handy cheet sheet.

I completely agree though, when debugging separate if statements for each can be very revealing, expecially when you drop a log statement in each one so you know how far you get down the evaluations.

It depends on the context as to whether they make a difference. To elaborate on rossko’s example:

`(A <= B) && C` is the same as A <= B && C`

So in this case the parens are supurfluous. However, if you want the B && C to evaluate first you must use the parens:

`A <= (B && C)`

The parens are a way for you to somewhat control the order things are evaluated in the if statements. It also isn’t always a bad thing to put in supurflous parens because it helps document the order that everything is evaluated (for example, by putting (ZwaveEye1Lux.state as DecimalType) in parens you are forcing it to evaluate first before the <=. However, in this case it is superflous because the as evaluates before the <= anyway.

So, in the above, the only parens that are actually functionally doing anything (besides the outer parens for the if statement itself) are the ones around all the || checks on Presence. So the following is functionally equavalent to your example:

if(ZwaveEye1Lux.state as DecimalType <= LuxSetpoint.state as DecimalType - 30 &&
   Standard_ALD.state == ON && (Presence_Mobile_Mike.state == ON ||
   Presence_Iris_Saxion.state == ON || Presence_Pepijn_Saxion.state == ON ||
   Presence_Diamant_Saxion.state == ON || Presence_Euan_Saxion.state == ON))

I might add a parens around the LuxSetpoint as DecimalType - 30 just to emphasize that there is some math going on in that part before the boolean evaluations. But it is not necessary.

The parens around the Presence checks ARE required though because you want to evaluate all the presence switches at once and the parens force them to be evaluated first and then the result compared with the rest.

All that being said, I would recommend using a Group:

    Group:SwitchOR(ON,OFF) gPresence
    Switch Presence_Mobile_Mike ... (gPresence) ...
    ...
    if (ZwaveEye1Lux.state as DecimalType <= LuxSetpoint.state as DecimalType - 30 &&
       Standard_ALD.state == ON && gPresence.state == ON)

Thanks alot for the clarification, at this point I am going to have to provide log files and/or use separate IF statemements to pinpoint the isse. That being said I have also coded it using the group exactly how you outlined (see code below), and still the lights were still being dimmed when the virtual switch Standard_ALD was switched OFF once the rule was running:

 if (ZwaveEye1Lux.state as DecimalType <= LuxSetpoint.state as DecimalType - 30 &&
           Standard_ALD.state == ON && gPresence.state == ON)

It’s invariably quicker to do the diagnostics than flail around hoping.

1 Like