Uponor Smatrix binding request

Looks very cool! Will try this next week for sure :grinning:

I have made the rule a bit easier to use. Now all you have to do is update the hashmap with the id of the field and the item that should hold the value:

EDIT: Cleaned up the code.

import java.util.HashMap

//Create a map that map from uponor id to the item that should be updated:
val HashMap<String, GenericItem> itemMap  = newHashMap(
    '105' -> Room0Temp,
    '109' -> Room0Name,
    '145' -> Room1Temp,
    '149' -> Room1Name,
    '185' -> Room2Temp,
    '189' -> Room2Name,
    '225' -> Room3Temp,
    '229' -> Room3Name,
    '265' -> Room4Temp,
    '269' -> Room4Name,
    '305' -> Room5Temp,
    '309' -> Room5Name
)

rule "Read Uponor values"
when
    Time cron "0 0/1 * * * ?"
then
    var url = "http://<ip to uponor gateway>/api";
    var contenttype = "application/json";

    var POSTrequest = '{"jsonrpc":"2.0", "id":8, "method":"read", "params":{ "objects":[%s]}}'
    val itemQuery = '{"id":"%s","properties":{"85":{}}}'
    val itemQueryList = newArrayList()
    val idSet = itemMap.keySet
    idSet.forEach[ key | itemQueryList.add(String.format(itemQuery, key)) ]
    POSTrequest = String.format(POSTrequest, itemQueryList.join(','))

    var json = sendHttpPostRequest(url, contenttype, POSTrequest);
    var count = Integer::parseInt(transform("JSONPATH", "$.result.objects.length()", json));

    for(var i = 0; i < count; i++) {
        val id = transform("JSONPATH", "$.result.objects[" +i+ "].id", json);
        val value = transform("JSONPATH", "$.result.objects[" +i+ "].properties.85.value", json);
        val item = itemMap.get(id);
        item.postUpdate(value);
    }
end

Just got home and tried it. Seems to work fine :).
Is there a way of retrieving “everything”, so we can poke around the different values?

As a side note, I took mine apart and found a nice serial interface with login prompt. Didn’t get much further than that. I’d like to see if the FTP server could be disabled / used.

There is no good way to get all values.
I made a rule that can print all values in the list of keys above to the log but you have to map them to the correct key manually.
It will only list key value pairs if the key actually has a value.
There also seem to be a limit on how big queries can be. I tried to add all id:s to one query but that failed so I split it up into multiple queries.

EDIT: Cool about the serial interface. Let me know if you get something usefull out of it. It would be nice to be able to interface it directtly without the U@home gateway.

val numRooms = 6
val numModules = 1

val Procedures$Procedure1 processRequest = [ itemQueryList |
    val url = "http://192.168.0.117/api"
    val contenttype = "application/json"
    var POSTrequest = '{"jsonrpc":"2.0", "id":8, "method":"read", "params":{ "objects":[%s]}}'
    val request = String.format(POSTrequest, itemQueryList.join(','))
    val json = sendHttpPostRequest(url, contenttype, request);
    val count = Integer::parseInt(transform("JSONPATH", "$.result.objects.length()", json));
    for(var i = 0; i < count; i++) {
        if (transform("JSONPATH", "$.result.objects[" +i+ "]", json).contains("value")) {
            val id = transform("JSONPATH", "$.result.objects[" +i+ "].id", json)
            val value = transform("JSONPATH", "$.result.objects[" +i+ "].properties.85.value", json)
            logWarn("Uponor", "id  " + id + ": value = " + value)
        }
    }
]

rule "Read Uponor values"
when
    Time cron "0 0/1 * * * ?"
then
    val itemQuery = '{"id":"%s","properties":{"85":{}}}'
    val itemQueryList = newArrayList()
    //Add global keysto query
    for (var i = 20; i < 41; i++) {
        itemQueryList.add(String.format(itemQuery, i))
    }
    //Add module keys to query
    for (var j = 0; j < numModules; j++) {
        for (var i = 60; i < 71; i++) {
            itemQueryList.add(String.format(itemQuery, i + j*500))
        }
    }
    processRequest.apply(itemQueryList)

    //Query room keys
    for (var j = 0; j < numModules; j++) {
        for (var k = 0; k < numRooms; k++) {
            itemQueryList = newArrayList()
            for (var i = 80; i < 115; i++) {
                itemQueryList.add(String.format(itemQuery, i + k*40 + j*500))
            }
            processRequest.apply(itemQueryList)
        }
    }
end

It’s actually on the U@Home module, so it doesn’t help much. I also discovered that I cannot use U@Home without the display (I-167). If it’s absent, then I don’t get any values via U@Home at all.

Is it possible to do a kind of mapping between keys and descriptions in this ‘print all’ rule, so we get an overview of what’s what?

I’m thinking something in the lines of:

General
Id Description
20 Serial number
23 Home/Away status
26 TS SW version
etc.

Rooms
Id-offset Description
10 Temperature setpoint
24 Current temperature
26 Humidity (%)
28 Room description
29 Utilization (%)
etc.

When the overview is in place, then it’s easier to produce the items & rule.

I also assume that the alarms are there somewhere? Just like the data for the graphs.

This prints out the data in the format:
field name : value : room number : module number

I will see if I can find the alarms.

import java.util.HashMap

val numRooms = 6
val numModules = 1

val Procedures$Procedure1 processRequest = [ itemQueryList |

    val HashMap<String, String> idMap = newHashMap(
        "20" -> "module_id",
        "21" -> "cooling_available",
        "22" -> "holiday_mode",
        "23" -> "forced_eco_mode",
        "24" -> "hc_mode",
        "25" -> "hc_masterslave",
        "26" -> "ts_sv_version",
        "27" -> "holiday_setpoint",
        "28" -> "average_temp_low",
        "29" -> "low_temp_alarm_limit",
        "30" -> "low_temp_alarm_hysteresis",
        "31" -> "remote_access_alarm",
        "32" -> "device_lost_alarm",
        "33" -> "no_comm_controller1",
        "34" -> "no_comm_controller2",
        "35" -> "no_comm_controller3",
        "36" -> "no_comm_controller4",
        "37" -> "average_room_temperature",
        "38" -> "controller_presence",
        "39" -> "allow_hc_mode_change",
        "40" -> "hc_master_type",

        "60" -> "output_module",
        "61" -> "rh_deadzone",
        "62" -> "controller_sv_version",
        "63"-> "thermostat_presence",
        "64" -> "supply_high_alarm",
        "65" -> "supply_low_alarm",
        "66" -> "average_room_temperature_NO",
        "67" -> "measured_outdoor_temperature",
        "68" -> "supply_temp",
        "69" -> "dehumidifier_status",
        "70" -> "outdoor_sensor_presence",

        "80" -> "eco_profile_active_cf",
        "81" -> "dehumidifier_control_activation",
        "82" -> "rh_control_activation",
        "83" -> "eco_profile_number",
        "84" -> "setpoint_write_enable",
        "85" -> "cooling_allowed",
        "86" -> "rh_setpoint",
        "87" -> "min_setpoint",
        "88" -> "max_setpoint",
        "89" -> "min_floor_temp",
        "90" -> "max_floor_temp",
        "91" -> "room_setpoint",
        "92" -> "eco_offset",
        "93" -> "eco_profile_active",
        "94" -> "home_away_mode_status",
        "95" -> "room_in_demand",
        "96" -> "rh_limit_reached",
        "97" -> "floor_limit_status",
        "98" -> "technical_alarm",
        "99" -> "tamper_indication",
        "100" -> "rf_alarm",
        "101" -> "battery_alarm",
        "102" -> "rh_sensor",
        "103" -> "thermostat_type",
        "104" -> "regulation_mode",
        "105" -> "room_temperature",
        "106" -> "room_temperature_ext",
        "107" -> "rh_value",
        "108" -> "ch_linked_to_th",
        "109" -> "room_name",
        "110" -> "utilization_factor_24h",
        "111" -> "utilization_factor_7d",
        "112" -> "reg_mode",
        "113" -> "channel_average",
        "114" -> "radiator_heating")

    val url = "http://<ip to uponor gateway>/api"
    val contenttype = "application/json"
    var POSTrequest = '{"jsonrpc":"2.0", "id":8, "method":"read", "params":{ "objects":[%s]}}'
    val request = String.format(POSTrequest, itemQueryList.join(','))
    val json = sendHttpPostRequest(url, contenttype, request);
    val count = Integer::parseInt(transform("JSONPATH", "$.result.objects.length()", json));
    for(var i = 0; i < count; i++) {
        if (transform("JSONPATH", "$.result.objects[" +i+ "]", json).contains("value")) {
            val Number id = Integer::parseInt(transform("JSONPATH", "$.result.objects[" +i+ "].id", json))
            val value = transform("JSONPATH", "$.result.objects[" +i+ "].properties.85.value", json)
            val Number module = id/500
            var tmp = id.intValue() % 500;
            if ((tmp - 80) >= 0) {
                val Number room = (tmp - 80)/40
                val Number realId = (tmp % 40) + 80
	        val printString = "%1$-35s : %2$10s : %3$2d : %4$2d"
                val name = idMap.get("" + realId)
                logWarn("Uponor", String.format(printString, name, ""+value, room.intValue(), module.intValue()))
	    }
            else {
	    val printString = "%1$-35s : %2$10s : -- : %3$2d"
            val name = idMap.get("" + tmp)
            logWarn("Uponor", String.format(printString, name, ""+value,  module.intValue()))
            }
        }
    }
]

rule "Read Uponor values 2"
when
    Time cron "0 0/1 * * * ?"
then
    val itemQuery = '{"id":"%s","properties":{"85":{}}}'
    val itemQueryList = newArrayList()
    //Add global keysto query
    for (var i = 20; i < 41; i++) {
        itemQueryList.add(String.format(itemQuery, i))
    }
    processRequest.apply(itemQueryList)
    //Add module keys to query
    for (var j = 0; j < numModules; j++) {
        itemQueryList = newArrayList()
        for (var i = 60; i < 71; i++) {
            itemQueryList.add(String.format(itemQuery, i + j*500))
	}
        processRequest.apply(itemQueryList)
    }

    //Query room keys
    for (var j = 0; j < numModules; j++) {
        for (var k = 0; k < numRooms; k++) {
            itemQueryList = newArrayList()
            for (var i = 80; i < 115; i++) {
                itemQueryList.add(String.format(itemQuery, i + k*40 + j*500))
            }
            processRequest.apply(itemQueryList)
        }
    }
end

Found it.
This rule will write the active alarms in the log.
EDIT: This reads all active alarms. They can also be read like the other values if you change the standard property “85” to “77” for the name and “662” for the state.

example:

2018-08-01 22:13:00.140 [WARN ] [clipse.smarthome.model.script.Uponor] - Average temp  low_u0_z0_cmd0 (id = 28) with state true
rule "Read Uponor alarms"
when
    Time cron "0 0/1 * * * ?"
then
    val url = "http://<ip>/api";
    val contenttype = "application/json";
    var POSTrequest = '{"jsonrpc":"2.0","id":2,"method":"readactivealarms","params":{}}'
    val json = sendHttpPostRequest(url, contenttype, POSTrequest);

    val count = Integer::parseInt(transform("JSONPATH", "$.result.objects.length()", json));

    for(var i = 0; i < count; i++) {
        val id = transform("JSONPATH", "$.result.objects[" +i+ "].id", json)
        val alarm = transform("JSONPATH", "$.result.objects[" +i+ "].properties.77.value", json)
        val state = transform("JSONPATH", "$.result.objects[" +i+ "].properties.662.value", json)
        if (transform("JSONPATH", "$.result.objects[" +i+ "].id", json).contains("663")) {
            val acced = transform("JSONPATH", "$.result.objects[" +i+ "].properties.663.value", json)
            logWarn("Uponor",  alarm + " (id = " + id + ") with state " + (state!=0) + " and acced " + (acced!=0))
        }
        else {
            logWarn("Uponor",  alarm + " (id = " + id + ") with state " + (state!=0))
        }

    }
end

I made a new rule to read the alarms regardless if they have triggered. That is most likely more useful.
It only reads the state and assumes that the item is a switch but that should be easy to change if you want to.

As you can see it is almost identical to the other one. So if you find other property values that makes sense it should be easy to create new rules for those.

val HashMap<String, GenericItem> alarmItemMap  = newHashMap(
    '28' -> TempAlarm
)

rule "Read Uponor alarms"
when
    Time cron "0 0/1 * * * ?"
then
    val url = "http://<ip>/api";
    val contenttype = "application/json";

    var POSTrequest = '{"jsonrpc":"2.0", "id":8, "method":"read", "params":{ "objects":[%s]}}'
    val itemQuery = '{"id":"%s","properties":{"77":{}, "662":{}}}'
    val itemQueryList = newArrayList()
    val idSet = alarmItemMap.keySet
    idSet.forEach[ key | itemQueryList.add(String.format(itemQuery, key)) ]
    POSTrequest = String.format(POSTrequest, itemQueryList.join(','))

    val json = sendHttpPostRequest(url, contenttype, POSTrequest);
    val count = Integer::parseInt(transform("JSONPATH", "$.result.objects.length()", json));

    for(var i = 0; i < count; i++) {
        val id = transform("JSONPATH", "$.result.objects[" +i+ "].id", json)
        val state = transform("JSONPATH", "$.result.objects[" +i+ "].properties.662.value", json)
        val item = alarmItemMap.get(id);
        if (state.equals("0") {
            item.postUpdate('OFF')
        }
        else {
            item.postUpdate('ON')
        }
    }
end

You are indeed insane :smiley:. Really admire your skills in finding these things. Will test tomorrow, thanks for your work so far!

Hi,
I’ve tried this, and it’s nice to get an overview of the different data. I have 12 zones, but the last two gives other results than the first 10 (have added separation lines for the output):

2018-08-02 08:42:01.440 [WARN ] [clipse.smarthome.model.script.Uponor] - ****** Room: 9
2018-08-02 08:42:01.564 [WARN ] [clipse.smarthome.model.script.Uponor] - eco_profile_active_cf               :          0 :  9 :  0
2018-08-02 08:42:01.565 [WARN ] [clipse.smarthome.model.script.Uponor] - dehumidifier_control_activation     :          0 :  9 :  0
2018-08-02 08:42:01.566 [WARN ] [clipse.smarthome.model.script.Uponor] - rh_control_activation               :          0 :  9 :  0
2018-08-02 08:42:01.566 [WARN ] [clipse.smarthome.model.script.Uponor] - eco_profile_number                  :        0.0 :  9 :  0
2018-08-02 08:42:01.567 [WARN ] [clipse.smarthome.model.script.Uponor] - setpoint_write_enable               :          0 :  9 :  0
2018-08-02 08:42:01.568 [WARN ] [clipse.smarthome.model.script.Uponor] - cooling_allowed                     :          1 :  9 :  0
2018-08-02 08:42:01.568 [WARN ] [clipse.smarthome.model.script.Uponor] - rh_setpoint                         :      100.0 :  9 :  0
2018-08-02 08:42:01.569 [WARN ] [clipse.smarthome.model.script.Uponor] - min_setpoint                        :        5.0 :  9 :  0
2018-08-02 08:42:01.570 [WARN ] [clipse.smarthome.model.script.Uponor] - max_setpoint                        :       35.0 :  9 :  0
2018-08-02 08:42:01.571 [WARN ] [clipse.smarthome.model.script.Uponor] - min_floor_temp                      :       20.0 :  9 :  0
2018-08-02 08:42:01.571 [WARN ] [clipse.smarthome.model.script.Uponor] - max_floor_temp                      :       26.0 :  9 :  0
2018-08-02 08:42:01.572 [WARN ] [clipse.smarthome.model.script.Uponor] - room_setpoint                       :       22.1 :  9 :  0
2018-08-02 08:42:01.573 [WARN ] [clipse.smarthome.model.script.Uponor] - eco_offset                          :        4.0 :  9 :  0
2018-08-02 08:42:01.573 [WARN ] [clipse.smarthome.model.script.Uponor] - eco_profile_active                  :          0 :  9 :  0
2018-08-02 08:42:01.573 [WARN ] [clipse.smarthome.model.script.Uponor] - home_away_mode_status               :          0 :  9 :  0
2018-08-02 08:42:01.574 [WARN ] [clipse.smarthome.model.script.Uponor] - room_in_demand                      :          0 :  9 :  0
2018-08-02 08:42:01.575 [WARN ] [clipse.smarthome.model.script.Uponor] - rh_limit_reached                    :          0 :  9 :  0
2018-08-02 08:42:01.575 [WARN ] [clipse.smarthome.model.script.Uponor] - floor_limit_status                  :          0 :  9 :  0
2018-08-02 08:42:01.577 [WARN ] [clipse.smarthome.model.script.Uponor] - rh_sensor                           :          1 :  9 :  0
2018-08-02 08:42:01.578 [WARN ] [clipse.smarthome.model.script.Uponor] - thermostat_type                     :        2.0 :  9 :  0
2018-08-02 08:42:01.578 [WARN ] [clipse.smarthome.model.script.Uponor] - regulation_mode                     :        0.0 :  9 :  0
2018-08-02 08:42:01.579 [WARN ] [clipse.smarthome.model.script.Uponor] - room_temperature                    :       25.3 :  9 :  0
2018-08-02 08:42:01.580 [WARN ] [clipse.smarthome.model.script.Uponor] - room_temperature_ext                :     1802.6 :  9 :  0
2018-08-02 08:42:01.581 [WARN ] [clipse.smarthome.model.script.Uponor] - rh_value                            :       51.0 :  9 :  0
2018-08-02 08:42:01.581 [WARN ] [clipse.smarthome.model.script.Uponor] - ch_linked_to_th                     :      512.0 :  9 :  0
2018-08-02 08:42:01.582 [WARN ] [clipse.smarthome.model.script.Uponor] - room_name                           : 10 Kids1 :  9 :  0
2018-08-02 08:42:01.583 [WARN ] [clipse.smarthome.model.script.Uponor] - utilization_factor_24h              :        0.0 :  9 :  0
2018-08-02 08:42:01.583 [WARN ] [clipse.smarthome.model.script.Uponor] - utilization_factor_7d               :        0.0 :  9 :  0
2018-08-02 08:42:01.584 [WARN ] [clipse.smarthome.model.script.Uponor] - reg_mode                            :          0 :  9 :  0
2018-08-02 08:42:01.585 [WARN ] [clipse.smarthome.model.script.Uponor] - channel_average                     :          1 :  9 :  0
2018-08-02 08:42:01.586 [WARN ] [clipse.smarthome.model.script.Uponor] - radiator_heating                    :        0.0 :  9 :  0
2018-08-02 08:42:01.591 [WARN ] [clipse.smarthome.model.script.Uponor] - 
2018-08-02 08:42:01.591 [WARN ] [clipse.smarthome.model.script.Uponor] - ****** Room: 10
2018-08-02 08:42:01.666 [WARN ] [clipse.smarthome.model.script.Uponor] - eco_profile_active_cf               :          0 : 10 :  0
2018-08-02 08:42:01.667 [WARN ] [clipse.smarthome.model.script.Uponor] - dehumidifier_control_activation     :          0 : 10 :  0
2018-08-02 08:42:01.668 [WARN ] [clipse.smarthome.model.script.Uponor] - rh_control_activation               :          0 : 10 :  0
2018-08-02 08:42:01.668 [WARN ] [clipse.smarthome.model.script.Uponor] - eco_profile_number                  :        0.0 : 10 :  0
2018-08-02 08:42:01.669 [WARN ] [clipse.smarthome.model.script.Uponor] - setpoint_write_enable               :          0 : 10 :  0
2018-08-02 08:42:01.670 [WARN ] [clipse.smarthome.model.script.Uponor] - cooling_allowed                     :          1 : 10 :  0
2018-08-02 08:42:01.671 [WARN ] [clipse.smarthome.model.script.Uponor] - rh_setpoint                         :      100.0 : 10 :  0
2018-08-02 08:42:01.671 [WARN ] [clipse.smarthome.model.script.Uponor] - min_setpoint                        :        5.0 : 10 :  0
2018-08-02 08:42:01.672 [WARN ] [clipse.smarthome.model.script.Uponor] - max_setpoint                        :       35.0 : 10 :  0
2018-08-02 08:42:01.673 [WARN ] [clipse.smarthome.model.script.Uponor] - min_floor_temp                      :       20.0 : 10 :  0
2018-08-02 08:42:01.674 [WARN ] [clipse.smarthome.model.script.Uponor] - max_floor_temp                      :       26.0 : 10 :  0
2018-08-02 08:42:01.674 [WARN ] [clipse.smarthome.model.script.Uponor] - room_setpoint                       :       18.6 : 10 :  0
2018-08-02 08:42:01.675 [WARN ] [clipse.smarthome.model.script.Uponor] - eco_offset                          :        4.0 : 10 :  0
2018-08-02 08:42:01.676 [WARN ] [clipse.smarthome.model.script.Uponor] - eco_profile_active                  :          0 : 10 :  0
2018-08-02 08:42:01.677 [WARN ] [clipse.smarthome.model.script.Uponor] - home_away_mode_status               :          0 : 10 :  0
2018-08-02 08:42:01.677 [WARN ] [clipse.smarthome.model.script.Uponor] - room_in_demand                      :          0 : 10 :  0
2018-08-02 08:42:01.678 [WARN ] [clipse.smarthome.model.script.Uponor] - rh_limit_reached                    :          0 : 10 :  0
2018-08-02 08:42:01.679 [WARN ] [clipse.smarthome.model.script.Uponor] - floor_limit_status                  :          0 : 10 :  0
2018-08-02 08:42:01.680 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :          1 : -- :  1
2018-08-02 08:42:01.681 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :        2.0 : -- :  1
2018-08-02 08:42:01.681 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :        0.0 : -- :  1
2018-08-02 08:42:01.682 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :       25.9 : -- :  1
2018-08-02 08:42:01.683 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :     1802.6 : -- :  1
2018-08-02 08:42:01.683 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :       50.0 : -- :  1
2018-08-02 08:42:01.684 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :     1024.0 : -- :  1
2018-08-02 08:42:01.685 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :  11 Kids2 : -- :  1
2018-08-02 08:42:01.685 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :        0.0 : -- :  1
2018-08-02 08:42:01.686 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :        0.0 : -- :  1
2018-08-02 08:42:01.687 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :          0 : -- :  1
2018-08-02 08:42:01.687 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :          1 : -- :  1
2018-08-02 08:42:01.688 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :        0.0 : -- :  1
2018-08-02 08:42:01.693 [WARN ] [clipse.smarthome.model.script.Uponor] - 
2018-08-02 08:42:01.694 [WARN ] [clipse.smarthome.model.script.Uponor] - ****** Room: 11
2018-08-02 08:42:01.755 [WARN ] [clipse.smarthome.model.script.Uponor] - module_id                           :          0 : -- :  1
2018-08-02 08:42:01.756 [WARN ] [clipse.smarthome.model.script.Uponor] - cooling_available                   :          0 : -- :  1
2018-08-02 08:42:01.757 [WARN ] [clipse.smarthome.model.script.Uponor] - holiday_mode                        :          0 : -- :  1
2018-08-02 08:42:01.757 [WARN ] [clipse.smarthome.model.script.Uponor] - forced_eco_mode                     :        0.0 : -- :  1
2018-08-02 08:42:01.758 [WARN ] [clipse.smarthome.model.script.Uponor] - hc_mode                             :          0 : -- :  1
2018-08-02 08:42:01.758 [WARN ] [clipse.smarthome.model.script.Uponor] - hc_masterslave                      :          1 : -- :  1
2018-08-02 08:42:01.759 [WARN ] [clipse.smarthome.model.script.Uponor] - ts_sv_version                       :      100.0 : -- :  1
2018-08-02 08:42:01.760 [WARN ] [clipse.smarthome.model.script.Uponor] - holiday_setpoint                    :        5.0 : -- :  1
2018-08-02 08:42:01.760 [WARN ] [clipse.smarthome.model.script.Uponor] - average_temp_low                    :       35.0 : -- :  1
2018-08-02 08:42:01.761 [WARN ] [clipse.smarthome.model.script.Uponor] - low_temp_alarm_limit                :       20.0 : -- :  1
2018-08-02 08:42:01.762 [WARN ] [clipse.smarthome.model.script.Uponor] - low_temp_alarm_hysteresis           :       26.0 : -- :  1
2018-08-02 08:42:01.762 [WARN ] [clipse.smarthome.model.script.Uponor] - remote_access_alarm                 :       20.1 : -- :  1
2018-08-02 08:42:01.763 [WARN ] [clipse.smarthome.model.script.Uponor] - device_lost_alarm                   :        4.0 : -- :  1
2018-08-02 08:42:01.764 [WARN ] [clipse.smarthome.model.script.Uponor] - no_comm_controller1                 :          0 : -- :  1
2018-08-02 08:42:01.764 [WARN ] [clipse.smarthome.model.script.Uponor] - no_comm_controller2                 :          0 : -- :  1
2018-08-02 08:42:01.765 [WARN ] [clipse.smarthome.model.script.Uponor] - no_comm_controller3                 :          0 : -- :  1
2018-08-02 08:42:01.766 [WARN ] [clipse.smarthome.model.script.Uponor] - no_comm_controller4                 :          0 : -- :  1
2018-08-02 08:42:01.766 [WARN ] [clipse.smarthome.model.script.Uponor] - average_room_temperature            :          0 : -- :  1
2018-08-02 08:42:01.767 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :          1 : -- :  1
2018-08-02 08:42:01.768 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :        2.0 : -- :  1
2018-08-02 08:42:01.769 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :        0.0 : -- :  1
2018-08-02 08:42:01.769 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :       20.7 : -- :  1
2018-08-02 08:42:01.770 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :     1802.6 : -- :  1
2018-08-02 08:42:01.771 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :       65.0 : -- :  1
2018-08-02 08:42:01.771 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :     2048.0 : -- :  1
2018-08-02 08:42:01.772 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :  12 Bath : -- :  1
2018-08-02 08:42:01.773 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :        0.0 : -- :  1
2018-08-02 08:42:01.773 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :        0.0 : -- :  1
2018-08-02 08:42:01.774 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :          0 : -- :  1
2018-08-02 08:42:01.774 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :          1 : -- :  1
2018-08-02 08:42:01.775 [WARN ] [clipse.smarthome.model.script.Uponor] - null                                :        0.0 : -- :  1

Any idea why? For the last room, I can see e.g. ‘device_lost_alarm’, but not for the other 11 rooms.

The reason is that when you have 11 or more rooms the room id will be higher than 500 and the id parsing breaks. I will see if I can fix it.

EDIT:
If only have one module you could try changing:

var tmp = id.intValue() % 500;

to:

var tmp = id.intValue()

It should work.

This should work:

import java.util.HashMap

val numRooms = 6
val numModules = 1

val Procedures$Procedure3<List, Integer, Integer> processRequest = [ itemQueryList, roomNumber, moduleNumber |
    val HashMap<String, String> idMap = newHashMap(
        "20" -> "module_id",
        "21" -> "cooling_available",
        "22" -> "holiday_mode",
        "23" -> "forced_eco_mode",
        "24" -> "hc_mode",
        "25" -> "hc_masterslave",
        "26" -> "ts_sv_version",
        "27" -> "holiday_setpoint",
        "28" -> "average_temp_low",
        "29" -> "low_temp_alarm_limit",
        "30" -> "low_temp_alarm_hysteresis",
        "31" -> "remote_access_alarm",
        "32" -> "device_lost_alarm",
        "33" -> "no_comm_controller1",
        "34" -> "no_comm_controller2",
        "35" -> "no_comm_controller3",
        "36" -> "no_comm_controller4",
        "37" -> "average_room_temperature",
        "38" -> "controller_presence",
        "39" -> "allow_hc_mode_change",
        "40" -> "hc_master_type",

        "60" -> "output_module",
        "61" -> "rh_deadzone",
        "62" -> "controller_sv_version",
        "63" -> "thermostat_presence",
        "64" -> "supply_high_alarm",
        "65" -> "supply_low_alarm",
        "66" -> "average_room_temperature_NO",
        "67" -> "measured_outdoor_temperature",
        "68" -> "supply_temp",
        "69" -> "dehumidifier_status",
        "70" -> "outdoor_sensor_presence",

        "80" -> "eco_profile_active_cf",
        "81" -> "dehumidifier_control_activation",
        "82" -> "rh_control_activation",
        "83" -> "eco_profile_number",
        "84" -> "setpoint_write_enable",
        "85" -> "cooling_allowed",
        "86" -> "rh_setpoint",
        "87" -> "min_setpoint",
        "88" -> "max_setpoint",
        "89" -> "min_floor_temp",
        "90" -> "max_floor_temp",
        "91" -> "room_setpoint",
        "92" -> "eco_offset",
        "93" -> "eco_profile_active",
        "94" -> "home_away_mode_status",
        "95" -> "room_in_demand",
        "96" -> "rh_limit_reached",
        "97" -> "floor_limit_status",
        "98" -> "technical_alarm",
        "99" -> "tamper_indication",
        "100" -> "rf_alarm",
        "101" -> "battery_alarm",
        "102" -> "rh_sensor",
        "103" -> "thermostat_type",
        "104" -> "regulation_mode",
        "105" -> "room_temperature",
        "106" -> "room_temperature_ext",
        "107" -> "rh_value",
        "108" -> "ch_linked_to_th",
        "109" -> "room_name",
        "110" -> "utilization_factor_24h",
        "111" -> "utilization_factor_7d",
        "112" -> "reg_mode",
        "113" -> "channel_average",
        "114" -> "radiator_heating")

    val url = "http://<ip>/api"
    val contenttype = "application/json"
    var POSTrequest = '{"jsonrpc":"2.0", "id":8, "method":"read", "params":{ "objects":[%s]}}'
    val request = String.format(POSTrequest, itemQueryList.join(','))
    val json = sendHttpPostRequest(url, contenttype, request);
    val count = Integer::parseInt(transform("JSONPATH", "$.result.objects.length()", json));
    for(var i = 0; i < count; i++) {
        if (transform("JSONPATH", "$.result.objects[" +i+ "]", json).contains("value")) {
            val Number id = Integer::parseInt(transform("JSONPATH", "$.result.objects[" +i+ "].id", json))
            val value = transform("JSONPATH", "$.result.objects[" +i+ "].properties.85.value", json)

            var Number realId = id - (moduleNumber * 500) - (roomNumber * 40)
            val printString = "%1$-35s : %2$10s : %3$2d : %4$2d"
            val name = idMap.get("" + realId)
            logWarn("Uponor", String.format(printString, name, ""+value, roomNumber.intValue(), moduleNumber.intValue()))
        }
    }
]

rule "Read Uponor values 2"
when
    Time cron "0 0/1 * * * ?"
then
    val itemQuery = '{"id":"%s","properties":{"85":{}}}'
    val itemQueryList = newArrayList()
    //Add global keys to query
    for (var i = 20; i < 41; i++) {
        itemQueryList.add(String.format(itemQuery, i))
    }
    logWarn("Uponor", "************ Global values *****************")
    processRequest.apply(itemQueryList, 0, 0)
    //Add module keys to query
    for (var j = 0; j < numModules; j++) {
        itemQueryList = newArrayList()
        for (var i = 60; i < 71; i++) {
            itemQueryList.add(String.format(itemQuery, i + j*500))
        }
        logWarn("Uponor", "************ Module " + j + " values *****************")
        processRequest.apply(itemQueryList, 0, j)
    }


    //Query room keys
    for (var j = 0; j < numModules; j++) {
        for (var k = 0; k < numRooms; k++) {
            itemQueryList = newArrayList()
            for (var i = 80; i < 115; i++) {
                itemQueryList.add(String.format(itemQuery, i + k*40 + j*500))
            }
            logWarn("Uponor", "************ Room " + k + " and Module " + j + " values *****************")
            processRequest.apply(itemQueryList, k, j)
        }
    }
end

Spot on :slight_smile:
Will do some further test, but really nice work!

Thanks.

I have made a rule for updating values. This example updates my set point values so it uses number values and works on any item in the group defined in the rule.

I added the item to the itemMap (with id 91 + (room number *40)) and created the corresponding items and group.
This rule assumes that the system is set to accept changes through the api. It is quite simple to add a switch for turning that on and off if needed.

Rule:

rule "Set Uponor target temperature"
when
    Member of tempSetting received command
then
    val url = "http://<ip>/api";
    val contenttype = "application/json";
    var POSTrequest = '{"jsonrpc":"2.0", "id":9, "method":"write", "params":{ "objects":[%s]}}'
    val itemQuery = '{"id":"%s","properties":{"85":{"value":%s:}}}'

    for(e:itemMap.entrySet) {
        if(e.value.equals(triggeringItem)) {
            POSTrequest = String.format(POSTrequest, String.format(itemQuery, e.key, triggeringItem.state));
            val json = sendHttpPostRequest(url, contenttype, POSTrequest);
        }
    }

end

Here is an example on how I modified the rule above to be able to toggle thermostat/app control of the set point for a room:

rule "Enable Uponor set temperature"
when
    Member of setWithApp received command
then
    val url = "http://<ip>/api";
    val contenttype = "application/json";
    var POSTrequest = '{"jsonrpc":"2.0", "id":9, "method":"write", "params":{ "objects":[%s]}}'
    val itemQuery = '{"id":"%s","properties":{"85":{"value":%s:}}}'

    for(e:itemMap.entrySet) {
        if(e.value.equals(triggeringItem)) {
            var state = 1;
            if(triggeringItem.state == OFF) {
                state = 0;
            }
            POSTrequest = String.format(POSTrequest, String.format(itemQuery, e.key, state));
            val json = sendHttpPostRequest(url, contenttype, POSTrequest);
        }
    }

end

The field id for that is 84 + (40*room number).

With this and the rule above I can now set the temperature from openhab and still be able to use the physical thermostat in the room if I want. I just have to remember to toggle the switch to thermostat once I have set the value with openhab.
EDIT: It turns out that the thermostat will send its value after a few minutes if it is toggled back so to control the temperature with openhab the switch have to be on all the time. That makes sense now when I think about it.

Reading out the alarms doesn’t seem to work for me. I have a couple of alarms in the system, but I don’t see anything in the log. Can it be the ID which is different?

If it is the “Read Uponor alarms” rule it only reads alarms that have triggered. I tested it by setting up the ‘low temp limit’ to 30 degrees C.