Intergas Incomfort Lan2RF rules

I thought it was working, but the setpoint keeps changing between the new and the old. I will report back when I understand a bit more why that is. Thanks for your advice!

A timer schedules a block of code called a lambda to execute at a time in the future. The lambda is defined by [| code]. So when you reschedule the timer you are telling it to run all the code in the lambda again at the specified time.

You will in all of my examples. A lambda is a variable like any other variable. The createTimer method takes two arguments, a DateTime and a lambda. The arguments to a method are always separated by a comma.

The language upon which the Rules DSL is based allows one to take a short cut in the case where the last argument to a method is a lambda. Instead of defining the lambda normally, one and define it immediately after the method instead of between one ( ) with a comma.

The error indicates that the get http call is timing out without a return value.

1 Like

Thanks for the explanation Rich.
I have the following rules now with your suggestion of the timer. The first rule is working, but the second no longer fires.

i made an extra set of items to prevent some unwanted interaction between the rules that use them.
default.items:

Number T_WK_OH2Lan_set_lsb //For the OH2Lan-rule
Number T_WK_OH2Lan_set_msb //For the OH2Lan rule
Number WK_room_temp_set_1_lsb "Thermostaat setpoint lsb" { http="<[CV_data:10000:JSONPATH($.room_temp_set_1_lsb)]" } //receive setpoint lsb
Number WK_room_temp_set_1_msb "Thermostaat setpoint msb" { http="<[CV_data:10000:JSONPATH($.room_temp_set_1_msb)]" } //receive setpoint msb

default.sitemap:

Text item=T_WK_is
Setpoint item=T_WK_sp minValue=10 maxValue=24 step=0.5

default.rules:

// Here come the vars
var Timer Lan2RFtimer = null
var Number celsius
var String data
val String Lan2RF_ip = "192.168.0.6" //check the right IP in browser!
// Here come the rules
rule "Update Thermostat SP OH2Lan"
when
    Item T_WK_sp changed
then   
    // ignore thermostat updates if we are already running a timer
    if(Lan2RFtimer !== null) {
        logInfo("Update Thermostat SP", "waiting for setpoint from Thermostat to finish") //Wait untill new setpoint arrived
        return;
    } else {
        val twish = T_WK_sp.state as Number
        val setp = (twish - 5 ) * 10
        sendHttpGetRequest("http://192.168.0.6/data.json?heater=0&setpoint="+setp+"&thermostat=0%C3%97") //set once before timer
        Lan2RFtimer = createTimer(now.plusSeconds(30), [| // why is there a comma, I don't see that in the examples?
        // start polling the URL
            data = sendHttpGetRequest("http://192.168.0.6/data.json?heater=0&setpoint="+setp+"&thermostat=0%C3%97") //resend fter 30sec and check result
            T_WK_OH2Lan_set_lsb.sendCommand(transform("JSONPATH","$.room_temp_set_1_lsb", data)) //put in item to get string to number
            T_WK_OH2Lan_set_msb.sendCommand(transform("JSONPATH","$.room_temp_set_1_msb", data))
            val lsb = T_WK_OH2Lan_set_lsb.state as Number
            val msb = T_WK_OH2Lan_set_msb.state as Number
            celsius = (lsb + msb *256) / 100 
            if(twish != celsius){
                logInfo("Update Thermostat SP", "step x setpoint in thermostat: "+celsius+"°C, should be: "+twish+"°C" )
                Lan2RFtimer.reschedule(now.plusSeconds(10)) // try again in 10 seconds
            } else {
                // wait until timer finishes before allowing Lan2OH start
                logInfo("Update Thermostat SP", "Setting new setpoint: "+celsius+"°C Finished!")
                Lan2RFtimer = null //could I leave this out to always wait until the timer finishes?
            }
        ])        
    }
end


rule "Update Thermostat SP Lan2OH"
when
    Item WK_room_temp_set_1_lsb changed or
    Item WK_room_temp_set_1_msb changed
then
    if(Lan2RFtimer !== null) {
        logInfo("Update Thermostat SP from Thermostat", "Waiting voor Thermostat Lan2OH is finished")
        //Wait untill new setpoint arrived
        return;
    } else{
        val lsb = WK_room_temp_set_1_lsb.state as Number
        val msb = WK_room_temp_set_1_msb.state as Number
        val celsius = (lsb + msb * 256) / 100
        T_WK_sp.postUpdate(celsius)
        logInfo("Update Thermostat SP from Thermostat", "temperature setpoint recieved: "+celsius+"°C")
    }
end

I give up for today. Tomorrow I will look agaiin. if you spot whats wrong, that would be grait.
Culd I leave the line out where the timer is set to null, to always wait until the timer finishes?

To combine both rules into one, I would need to test which of the items changed that can trigger the rules. Is something like this possible? If (Item T_WK_sp changed){ do stuff} Or is there a simple way to test which of the items in the ‘when’ part of the rule caused the rule to trigger?

The timer already always finishes. If you remove the line that sets ur to null your rule will no longer run because timer will never equal null

if(triggeringItem.name == "itemName")
1 Like

Wow, that works perfectly! (couldn’t wait trying)
I also discovered I should not use too difficult names for the timer. Do you know whay that is?
For now I am happy with one single rule for the setpoint two-way communication, and one rulle for all the read-only communication (at this stage only the measured temperature and the displaycode, but I will add all documenten values at some point in time.

rule "Update Thermostat SP two-way communication"
when
    Item T_WK_sp changed or
    Item WK_room_temp_set_1_lsb changed or
    Item WK_room_temp_set_1_msb changed
then   
    // ignore thermostat updates if we are already running a timer
    if(timer !== null) {
        logInfo("Update Thermostat SP", "waiting for setpoint from Thermostat to finish") //Wait untill new setpoint arrived
        return;
    } else {
        if(triggeringItem.name == "T_WK_sp"){
            val twish = T_WK_sp.state as Number
            val setp = (twish - 5 ) * 10
            sendHttpGetRequest("http://192.168.0.6/data.json?heater=0&setpoint="+setp+"&thermostat=0%C3%97") //set once before timer
            timer = createTimer(now.plusSeconds(30), [|
                // start polling the URL
                data = sendHttpGetRequest("http://192.168.0.6/data.json?heater=0&setpoint="+setp+"&thermostat=0%C3%97") //resend fter 30sec and check result
                T_WK_OH2Lan_set_lsb.sendCommand(transform("JSONPATH","$.room_temp_set_1_lsb", data)) //put in item to get string to number
                T_WK_OH2Lan_set_msb.sendCommand(transform("JSONPATH","$.room_temp_set_1_msb", data))
                val lsb = T_WK_OH2Lan_set_lsb.state as Number
                val msb = T_WK_OH2Lan_set_msb.state as Number
                celsius = (lsb + msb *256) / 100 
                if(twish != celsius){
                    logInfo("Update Thermostat SP", "step x setpoint in thermostat: "+celsius+"°C, should be: "+twish+"°C" )
                    timer.reschedule(now.plusSeconds(10)) // try again in 10 seconds
                } else {
                    // wait until timer finishes before allowing Lan2OH start
                    logInfo("Update Thermostat SP", "Setting new setpoint: "+celsius+"°C Finished!")
                    timer = null //could I leave this out?
                }
            ])
        } else{
            val lsb = WK_room_temp_set_1_lsb.state as Number
        val msb = WK_room_temp_set_1_msb.state as Number
        val celsius = (lsb + msb * 256) / 100
        T_WK_sp.postUpdate(celsius)
        logInfo("Update Thermostat SP from Thermostat", "temperature setpoint recieved: "+celsius+"°C")
        }
    }
end

rule "Update Livingroom Thermostat real temperature"
when
    Item WK_room_temp_1_lsb changed or
    Item WK_room_temp_1_msb changed
then
    val lsb = WK_room_temp_1_lsb.state as Number
    val msb = WK_room_temp_1_msb.state as Number
    val celsius = (lsb + msb * 256) / 100
    T_WK_is.postUpdate(celsius)
    logInfo("Update Thermostat", "New temperature recieved")
end

I am now adding other values that need conversion from lsb and msb to a value. So I thought is was better to do it like the following code. But then I need the lsb and msb etc to be a var in stead of a val and put it on top of the rules file. But then I have the chance that different var-declarations interact wrongly. Now I prevent that with the if-else but this is very clumsy of course. Is there also a way to go through a predifined list of items-pairs (i.e. WK_ch_temp, T_flow for the first calculation of bit2value) and use each item from the lis to construct somethin like this:

rule "Update Livingroom Thermostat real temperature"
when
    Item WK_ch_temp_lsb changed or
    Item WK_ch_temp_msb changed or
    Item WK_tap_temp_lsb changed or
    Item WK_tap_temp_msb changed or
    Item WK_ch_pressure_lsb changed or
    Item WK_ch_pressure_msb changed or
    Item WK_room_temp_1_lsb changed or
    Item WK_room_temp_1_msb changed
then
    //ToDo: iterate through 5 bit2value calculations
    //val ArrayList<String> datalist = new ArrayList<String>("WK_ch_temp", "WK_tap_temp", "WK_ch_pressure_lsb", "WK_room_temp_1")
    //for each
    if(triggeringItem.name == "WK_temp_lsb" || triggeringItem.name == "WK_temp_msb"){
         lsb = WK_ch_temp_lsb.state as Number
         msb = WK_ch_temp_msb.state as Number
         bit2value = (lsb + msb * 256) / 100
        T_flow.postUpdate(bit2value)
    } else if(triggeringItem.name == "WK_tap_temp_lsb" || triggeringItem.name == "WK_tap_temp_msb"){
         lsb = WK_tap_temp_lsb.state as Number
         msb = WK_tap_temp_msb.state as Number
         bit2value = (lsb + msb * 256) / 100
        T_tap.postUpdate(bit2value)
    } else if(triggeringItem.name == "WK_ch_pressure_lsb" || triggeringItem.name == "WK_ch_pressure_msb"){
         lsb = WK_ch_pressure_lsb.state as Number
         msb = WK_ch_pressure_msb.state as Number
         bit2value = (lsb + msb * 256) / 100
        WK_pressure.postUpdate(bit2value)
    } else if(triggeringItem.name == "WK_room_temp_1_lsb" || triggeringItem.name == "WK_room_temp_1_msb"){
        lsb = WK_room_temp_1_lsb.state as Number
        msb = WK_room_temp_1_msb.state as Number
        bit2value = (lsb + msb * 256) / 100
        T_WK_is.postUpdate(bit2value)
        logInfo("Update Thermostat", "New data recieved")
    }
end

You will have to be more specific.

This is what lambdas are for. You just pass the Items you want to calculate.

Or you can use Design Pattern: Associated Items.

Hahaha, yes I can imagine. Sorry for that. I started with a name in ALLCAPS, but VS_Code gave it a very different collor than the other timer so I figured this was not good. Then I tried several names with underscore or ‘-’ but ended up with just lowercase lettres.

I really have to seperate the calculations cause I sometimes get crazy results from the bit2value. This can only happen in my imagination, when the lsb and msb of different items are combined, or if lsb is from the former update while msb is from the new. I may have to build in a sleep moment to be shure that all items that come from the JSON are refreshed.

Maybe it would also be better if I would give all these values a different name in stead of re-using just 3 variables. What is your idea on that?

I will definately also look into the Lambda’s. but untill now they look horifying to me. And I didn’t find an example with two variabels yet.

By convention people use all caps to indicate constants. Kuba probably added that assumption to the syntax highlighting. But it isn’t a problem.

I think underscores are ok but dashes are definitely not allowed. By convention, starting with lower case and then capitalizing every word in the name (sometimes called camel case) is used for variables.

var myComplicatedVariableName
val MY CONSTANT = 10

When in doubt, do what makes it easier for a human to read and understand. There is nothing wrong with reusing variables.

val Functions$Function2<Arg1Type, Arg2Type, ReturnType> name= [arg1, arg2 | 
     // Do stuff
     ReturnValue
]

Where you use the appropriate types for Arg1Type et al and ReturnType and ReturnValue is what you want the lambda to return.

Replace Function with Procedure and remove all the Return stuff if you don’t have a return value.

Hi Guido, i’m new to all this, installed openHab today on a Pi3 with a Razzberry everything is working… now i want to read en change the settings from my “Intergas” Lan2Rf module. This isn’t so easy for my as for a samsung tv or onkyo receiver where I can install a package. can you be more specific how to install this on the Openhabian :slight_smile:

Hi, I am fairly new to all this too, and in the mean time I changed a lot. Some for better, some for worse. But my lan2rf is not working correctly now, I am talking to the vendor about exchanging the module.
If they don’t, I am in the market for a OTGW.
So the posted work is not finished.

Anyway, you should be able to put the above content in the files as stated. (I am now on my phone, cannot scroll easily) . Best to use the samba share linking File Explorer on a winPC to the config directory of openhab.
For instance:
services/http.cfg
rules/default.rules
Tec.

Seems it is quite a while ago since the last post. Despite I probably in future will also move to the OTGW solution, I could post my code and setup (based on Guido’s) if it is helpful to anyone.

It is even a much longer time ago since your last post, but I definately am interested.
I only have time for openhab every once in a while and I never got to rewrite my Incomfort rules and items. Please do post your solution?

Guido, I am impressed with what you did. I have an Lan2RF as well and i used your files and had immediate connection with my CV.
However, though I get the current temperature fine, it seems I am unable to set the temperature. I mean my openhab application will happily ‘set’ a temperature, but my CV doesnt seem to get it.
Is there anything you can suggest I check.

The heater number you use - ```
%3C0611f022270%3E

is that actually correct for any heater.
Thanks for your help

I’m glad someone can use it!
I had it working only for a few weeks, then the responsiveness went backwards and finally I couldn’t connect to te Lan2RF module at all. At thar moment the app from Intergas could also only get part of the data. I received a new Lan2RF, but that one suffered the same after a while. I think the module cannot handle so many connections. But I didn’t want to slow down the responsiveness.
Why the domoticz users don’t suffer these problems, I don’t know.
I stopped using the device and started using the OTGW. There is also a binding for that.
The only down side of this, is that the LAN2RF also gives me water pressure independent of the thermostat, while the OTGW can only show or control the parameters that your boiler ánd thermostat can control and show. Keeping the Lan2RF alive didn’t help me there either.
For me, this means I cannot see water pressure.
There may be a solution for that using a special text command, but I never found how to do that. But that is something I might work on info a separate topic.

Oh, and @Earl_Alnot has updated my code and offered to put it online. But I never got a message. I don’t know if he is till active?

Thank you. Will give OTHW a try… but couldnt find the binding yet, other than an experimental one from a year ago. Will look further

I just discovered there is also a module which integrates to zwave, but it’s twice as expensive! See the List of shops that sell this.

The OTGW-binding I use is supposedly an experimental one, but the current version, 0.8 is working very well. See the OTG-thread.
I did have to change some things in the items they suggest and also I changed the way the room temperature setpoint is handled which I described in post 108 of the above topic.

1 Like

I found the problem setting the Setpoint: i had wrong IP in my rule. Still a bit slow

got ahold of the manual.good info too :slight_smile:
Will check OTGW
Thanks again

Congrats!
For me it took between 30 seconds and a minute to get the new setpoint.

Tnx, yes, it is not very fast.
as far as some settings go, like tapwater temp and max CV temp, I think what the json is giving back, might be a bit different from what is being set on the thermostat itself, but it surely is an interesting thing to look into
my CV and LAN2RF are intergas, thermostat is honeywell.
Anyway, will look a bit furter into it, still using the first config files you published. Will go through the suggestions made in this post to see what can be improved