Whee I finally got the time to look at this again!
Looking at @rlkoshak’s vTimeOfDays rule got me on the track, and I finally figured out what he meant about “unbound items”
So it is just that: an item with nothing attached, just to store the state (nothing special you just create an item). And then it is updated using some rules.
So to hopefully help others on their way, here is my items and rules files.
Configured for 12 thermostats because thats what I have. Names are read from the controller and injected into the labels, combined with the current temperature.
Items:
Number RaumTempG0 "[%.1f °C]" <Temperature>
Number RaumTempG1 "[%.1f °C]" <Temperature>
Number RaumTempG2 "[%.1f °C]" <Temperature>
Number RaumTempG3 "[%.1f °C]" <Temperature>
Number RaumTempG4 "[%.1f °C]" <Temperature>
Number RaumTempG5 "[%.1f °C]" <Temperature>
Number RaumTempG6 "[%.1f °C]" <Temperature>
Number RaumTempG7 "[%.1f °C]" <Temperature>
Number RaumTempG8 "[%.1f °C]" <Temperature>
Number RaumTempG9 "[%.1f °C]" <Temperature>
Number RaumTempG10 "[%.1f °C]" <Temperature>
Number RaumTempG11 "[%.1f °C]" <Temperature>
Number SollTempG0 "[%.1f °C]" <Temperature>
Number SollTempG1 "[%.1f °C]" <Temperature>
Number SollTempG2 "[%.1f °C]" <Temperature>
Number SollTempG3 "[%.1f °C]" <Temperature>
Number SollTempG4 "[%.1f °C]" <Temperature>
Number SollTempG5 "[%.1f °C]" <Temperature>
Number SollTempG6 "[%.1f °C]" <Temperature>
Number SollTempG7 "[%.1f °C]" <Temperature>
Number SollTempG8 "[%.1f °C]" <Temperature>
Number SollTempG9 "[%.1f °C]" <Temperature>
Number SollTempG10 "[%.1f °C]" <Temperature>
Number SollTempG11 "[%.1f °C]" <Temperature>
And rules that match:
val logName = "rothreadset"
val String roth_read = "http://192.168.0.70/cgi-bin/ILRReadValues.cgi"
val String roth_set = "http://192.168.0.70/cgi-bin/writeVal.cgi"
val String roth_post = "<body><item_list>
<i><n>G0.name</n></i><i><n>G0.RaumTemp</n></i><i><n>G0.SollTemp</n></i>
<i><n>G1.name</n></i><i><n>G1.RaumTemp</n></i><i><n>G1.SollTemp</n></i>
<i><n>G2.name</n></i><i><n>G2.RaumTemp</n></i><i><n>G2.SollTemp</n></i>
<i><n>G3.name</n></i><i><n>G3.RaumTemp</n></i><i><n>G3.SollTemp</n></i>
<i><n>G4.name</n></i><i><n>G4.RaumTemp</n></i><i><n>G4.SollTemp</n></i>
<i><n>G5.name</n></i><i><n>G5.RaumTemp</n></i><i><n>G5.SollTemp</n></i>
<i><n>G6.name</n></i><i><n>G6.RaumTemp</n></i><i><n>G6.SollTemp</n></i>
<i><n>G7.name</n></i><i><n>G7.RaumTemp</n></i><i><n>G7.SollTemp</n></i>
<i><n>G8.name</n></i><i><n>G8.RaumTemp</n></i><i><n>G8.SollTemp</n></i>
<i><n>G9.name</n></i><i><n>G9.RaumTemp</n></i><i><n>G9.SollTemp</n></i>
<i><n>G10.name</n></i><i><n>G10.RaumTemp</n></i><i><n>G10.SollTemp</n></i>
<i><n>G11.name</n></i><i><n>G11.RaumTemp</n></i><i><n>G11.SollTemp</n></i>
</item_list></body>"
rule "Update Roth Touchline+ temperatures"
when
System started or
//Time cron "*/10 * * * * ? *" or
Time cron "23 */10 * * * ? *"
then
var String SetPoint_read = sendHttpPostRequest(roth_read, "text/xml", roth_post)
RaumTempG0.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G0.RaumTemp')]/v", SetPoint_read)))
RaumTempG1.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G1.RaumTemp')]/v", SetPoint_read)))
RaumTempG2.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G2.RaumTemp')]/v", SetPoint_read)))
RaumTempG3.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G3.RaumTemp')]/v", SetPoint_read)))
RaumTempG4.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G4.RaumTemp')]/v", SetPoint_read)))
RaumTempG5.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G5.RaumTemp')]/v", SetPoint_read)))
RaumTempG6.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G6.RaumTemp')]/v", SetPoint_read)))
RaumTempG7.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G7.RaumTemp')]/v", SetPoint_read)))
RaumTempG8.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G8.RaumTemp')]/v", SetPoint_read)))
RaumTempG9.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G9.RaumTemp')]/v", SetPoint_read)))
RaumTempG10.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G10.RaumTemp')]/v", SetPoint_read)))
RaumTempG11.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G11.RaumTemp')]/v", SetPoint_read)))
SollTempG0.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G0.SollTemp')]/v", SetPoint_read)))
SollTempG1.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G1.SollTemp')]/v", SetPoint_read)))
SollTempG2.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G2.SollTemp')]/v", SetPoint_read)))
SollTempG3.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G3.SollTemp')]/v", SetPoint_read)))
SollTempG4.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G4.SollTemp')]/v", SetPoint_read)))
SollTempG5.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G5.SollTemp')]/v", SetPoint_read)))
SollTempG6.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G6.SollTemp')]/v", SetPoint_read)))
SollTempG7.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G7.SollTemp')]/v", SetPoint_read)))
SollTempG8.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G8.SollTemp')]/v", SetPoint_read)))
SollTempG9.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G9.SollTemp')]/v", SetPoint_read)))
SollTempG10.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G10.SollTemp')]/v", SetPoint_read)))
SollTempG11.sendCommand(transform("REGEX", "s/(.?.)(..)/$1.$2/g", transform("XPATH", "/body/item_list/i[contains(n,'G11.SollTemp')]/v", SetPoint_read)))
SollTempG0.label = transform("XPATH", "/body/item_list/i[contains(n,'G0.name')]/v", SetPoint_read).toString + " " + RaumTempG0.state as Number + "°C"
SollTempG1.label = transform("XPATH", "/body/item_list/i[contains(n,'G1.name')]/v", SetPoint_read).toString + " " + RaumTempG1.state as Number + "°C"
SollTempG2.label = transform("XPATH", "/body/item_list/i[contains(n,'G2.name')]/v", SetPoint_read).toString + " " + RaumTempG2.state as Number + "°C"
SollTempG3.label = transform("XPATH", "/body/item_list/i[contains(n,'G3.name')]/v", SetPoint_read).toString + " " + RaumTempG3.state as Number + "°C"
SollTempG4.label = transform("XPATH", "/body/item_list/i[contains(n,'G4.name')]/v", SetPoint_read).toString + " " + RaumTempG4.state as Number + "°C"
SollTempG5.label = transform("XPATH", "/body/item_list/i[contains(n,'G5.name')]/v", SetPoint_read).toString + " " + RaumTempG5.state as Number + "°C"
SollTempG6.label = transform("XPATH", "/body/item_list/i[contains(n,'G6.name')]/v", SetPoint_read).toString + " " + RaumTempG6.state as Number + "°C"
SollTempG7.label = transform("XPATH", "/body/item_list/i[contains(n,'G7.name')]/v", SetPoint_read).toString + " " + RaumTempG7.state as Number + "°C"
SollTempG8.label = transform("XPATH", "/body/item_list/i[contains(n,'G8.name')]/v", SetPoint_read).toString + " " + RaumTempG8.state as Number + "°C"
SollTempG9.label = transform("XPATH", "/body/item_list/i[contains(n,'G9.name')]/v", SetPoint_read).toString + " " + RaumTempG9.state as Number + "°C"
SollTempG10.label = transform("XPATH", "/body/item_list/i[contains(n,'G10.name')]/v", SetPoint_read).toString + " " + RaumTempG10.state as Number + "°C"
SollTempG11.label = transform("XPATH", "/body/item_list/i[contains(n,'G11.name')]/v", SetPoint_read).toString + " " + RaumTempG11.state as Number + "°C"
//logInfo(logName, "return from post" + SetPoint_read)
end
rule "Set Roth Touchline+ temperatures room 0"
when
Item SollTempG0 changed
then
sendHttpGetRequest(roth_set + "?G0.SollTemp=" + (SollTempG0.state as Number * 100).intValue())
end
rule "Set Roth Touchline+ temperatures room 1"
when
Item SollTempG1 changed
then
sendHttpGetRequest(roth_set + "?G1.SollTemp=" + (SollTempG1.state as Number * 100).intValue())
end
rule "Set Roth Touchline+ temperatures room 2"
when
Item SollTempG2 changed
then
sendHttpGetRequest(roth_set + "?G2.SollTemp=" + (SollTempG2.state as Number * 100).intValue())
end
rule "Set Roth Touchline+ temperatures room 3"
when
Item SollTempG3 changed
then
sendHttpGetRequest(roth_set + "?G3.SollTemp=" + (SollTempG3.state as Number * 100).intValue())
end
rule "Set Roth Touchline+ temperatures room 4"
when
Item SollTempG4 changed
then
sendHttpGetRequest(roth_set + "?G4.SollTemp=" + (SollTempG4.state as Number * 100).intValue())
end
rule "Set Roth Touchline+ temperatures room 5"
when
Item SollTempG5 changed
then
sendHttpGetRequest(roth_set + "?G5.SollTemp=" + (SollTempG5.state as Number * 100).intValue())
end
rule "Set Roth Touchline+ temperatures room 6"
when
Item SollTempG6 changed
then
sendHttpGetRequest(roth_set + "?G6.SollTemp=" + (SollTempG6.state as Number * 100).intValue())
end
rule "Set Roth Touchline+ temperatures room 7"
when
Item SollTempG7 changed
then
sendHttpGetRequest(roth_set + "?G7.SollTemp=" + (SollTempG7.state as Number * 100).intValue())
end
rule "Set Roth Touchline+ temperatures room 8"
when
Item SollTempG8 changed
then
sendHttpGetRequest(roth_set + "?G8.SollTemp=" + (SollTempG8.state as Number * 100).intValue())
end
rule "Set Roth Touchline+ temperatures room 9"
when
Item SollTempG9 changed
then
sendHttpGetRequest(roth_set + "?G9.SollTemp=" + (SollTempG9.state as Number * 100).intValue())
end
rule "Set Roth Touchline+ temperatures room 10"
when
Item SollTempG10 changed
then
sendHttpGetRequest(roth_set + "?G10.SollTemp=" + (SollTempG10.state as Number * 100).intValue())
end
rule "Set Roth Touchline+ temperatures room 11"
when
Item SollTempG11 changed
then
sendHttpGetRequest(roth_set + "?G11.SollTemp=" + (SollTempG11.state as Number * 100).intValue())
end
//logInfo(logName, "GET request" + roth_set + "?G0.SollTemp=" + (SollTempG0.state as Number * 100).intValue())
Finally what I have in my sites file:
Text label="Gulvvarme" icon="temperature" {
//Setpoint item=SollTempG0 valuecolor=[>22="red",>21="green",>20="orange",<=20="blue"]
Setpoint item=SollTempG0 minValue=5 maxValue=30 step=0.5
Setpoint item=SollTempG1 minValue=5 maxValue=30 step=0.5
Setpoint item=SollTempG2 minValue=5 maxValue=30 step=0.5
Setpoint item=SollTempG3 minValue=5 maxValue=30 step=0.5
Setpoint item=SollTempG4 minValue=5 maxValue=30 step=0.5
Setpoint item=SollTempG5 minValue=5 maxValue=30 step=0.5
Setpoint item=SollTempG6 minValue=5 maxValue=30 step=0.5
Setpoint item=SollTempG7 minValue=5 maxValue=30 step=0.5
Setpoint item=SollTempG8 minValue=5 maxValue=30 step=0.5
Setpoint item=SollTempG9 minValue=5 maxValue=30 step=0.5
Setpoint item=SollTempG10 minValue=5 maxValue=30 step=0.5
Setpoint item=SollTempG11 minValue=5 maxValue=30 step=0.5
}
It’s neither perfect nor finished, but it works for now.
The current temperature is part of the label to put it all on one line, that also means the current temperature jumps back and forth depending on the label length:
If someone has a suggestion how to adjust that (possibly justify it on the right side), please let me know.
Also I will see if I can find time to implement vacation mode and error reporting.
Let me know if this is of any use for you, or if you have any troubles.