Skip to content

Cruc1bl3/Roth-Touchline

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

60 Commits
 
 
 
 
 
 

Repository files navigation

Roth Touchline Heating controller API

Background

Roth make a series of "Touchline" controllers for under floor heating systems, the older versions (pre 2021), only support a wired ethernet control port, newer versions support wireless. These are coupled with wireless (not WiFI) thermostats for control, each controller can attach upto 36 thermostats. As each controller can support upto 8 circuits, the design allows the controllers to be cascaded to add extra circuits, using a single Master with multiple slaves units. By default each controller is a slave, to activate the Master you have to press the "Master" button on the controller.

The older versions have a web interface based on a java module, which unfortunately does not work on modern browsers as the Java web launch feature has been removed. For those with Android or IoS devices a Touchline application exists to allow you to set the thermostats remotely.

Touchline BL Touchline Network Module

Networking

To connect the wired-only Roth controller to my network I used a Vonets VAR11N_300 Wireless/Ethernet bridge. The ethernet side is connected to the ethernet port of the touchline and the wireless is configured to connect to the (IoT?) WiFi SSID of your network. Other connection options are shown on page 42 of the Manual. You may have to change the default IP address of the touchline controller. If there are multiple controllers you need to designate one as a master by pressing the "Master" button, the network connection is only needed on the designated master.

API Interface

Data from the controller can be accessed using the web interface call points readVal.cgi and writeVal.cgi. e.g.

Read Value: http://xxx.xxx.xxx.xxx/cgi-bin/readVal.cgi?variable
Write Value: http://xxx.xxx.xxx.xxx/cgi-bin/writeVal.cgi?variable=value

Device Parameters

CD = Global Variables
Rx = Regulator
Gx = Thermostat
HW = Network Interface

Variable Values Description
hw.IP xxx.xxx.xxx.xxx IP Address of Device
hw.NM 255.255.255.0 Netmask of IP
hw.Addr M1-M2-M3-M4-M5-M6 MAC address of Interface
hw.DNS1 dd1.dd1.dd1.dd1 IP address of DNS entry #1
hw.DNS2 dd2.dd2.dd2.dd2 IP address of DNS entry #2
hw.GW zzz.zzz.zzz.zzz Default route
hw.HostName ROTH-M4M5M6 Hostname (default ROTH-last_6_digits_of_MAC)
totalNumberOfDevices 0-35 Number of thermostats attached, 4 would indicate thermostats 0-3
numberOfSlaveControllers 0 Number of slave controllers attached
VPI.href http://myroth.ininet.ch/remote/t_R0.uniqueID/ URL of remote access point, see uniqueID below
VPI.state 99 Remote access point status
isMaster 1 Is this a master or slave (push master button for this to work)
Status Server: Roth/1.0 (powered by SpiderControl TM), CGI=0, ILR=0, V.1.0, ILR2=0, V.2.00, ILR3=1, V.1.00 Status of webserver components
CD.uname Username (only certain FW versions)
CD.upass 1234 User interface password (default 1234)
STELL-APP 1.42 Module version (RO)
STELL-BL 1.20 Module version (RO)
STM-BL 1.20 Module version (RO)
R0.DateTime EPOCH datetime Date/time since 1970 e.g. 1703956882 or " Sat Dec 30 15:33:54 CET 2023", can be updated
R0.ErrorCode 0 Current error
R0.OPModeRegler 0 ???
R0.Safety 0 ???
R0.SystemStatus 0 System status, 0=off, 1=running
R0.Taupunkt 0 Dew point; is the temperature to which the air must cool for it to become completely saturated with water
R0.WeekProgWarn 1 ???
R0.kurzID 69 Short ID, same as Gx.kurzID
R0.numberOfPairedDevices 4 Number of paired devices, same as 'totalNumberOfDevices'
R0.uniqueID 16 Digit UUID Unique identifier, used to construct VPI.href

Thermostat parameters

These parameters can be updated using the writeVal.cgi?variable=value
e.g.
http://xxx.xxx.xxx.xxx/cgi-bin/writeVal.cgi?variable=value

x indicates the thermostat index (0 to totalNumberofDevices-1) e.g. G0

Variable Values Description
Gx.name Name of thermostat, if set
Gx.RaumTemp 2094 Room temperature, 20.94
Gx.SollTemp 2000 Room set temperature, 20.00
Gx.SollTempMaxVal 2600 Max temperature allowed for SollTemp, 26.00
Gx.SollTempMinVal 1600 Min temperature allowed for SollTemp, 16.00
Gx.TempSIUnit 0 Temperature scale, 0=C, 1=F
Gx.OPMode 0-2 Operation Mode: 0=Normal, 1=Night, 2=Vacation
Gx.WeekProg 1-3 Weekly Program, 1=Pro 1, 2=Pro 2, 3=Pro 3
Gx.OPModeEna 0-1 Thermostat enabled (1) or disabled (0)
Gx.WeekProgEna 1 Weekly program mode enabled
Gx.kurzID 1 Short ID = Thermostat Index = x
Gx.ownerKurzID 69 Owner Short ID??? Same for all thermostats

Modes

Each thermostat has 3 OPModes (Normal, Night, Vacation) and 3 Weekly programs (Pro 1, Pro 2, Pro 3).

For the purposes of illustration the examples use environment variables. Before use set the following:

# Set these variable 
IP=192.168.x.x      # The IP of your controller
TH=0                # Thermostat number (0-35)
URL=http://${IP}/cgi-bin

# Read current values
printf "%-10s:\t" "OPMode";curl ${URL}/readVal.cgi?G${TH}.OPMode;printf "\n%-10s:\t" "WeekProg";curl ${URL}/readVal.cgi?G${TH}.WeekProg;printf "\n"
Mode Values Example
Day Gx.OPMode=0, Gx.WeekProg=0 curl ${URL}/writeVal.cgi?G${TH}.OPMode=0;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=0;
Night Gx.OPMode=1, Gx.WeekProg=0 curl ${URL}/writeVal.cgi?G${TH}.OPMode=1;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=0;
Holiday Gx.OPMode=2, Gx.WeekProg=0 curl ${URL}/writeVal.cgi?G${TH}.OPMode=2;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=0;
Pro 1 Day Gx.OPMode=0, Gx.WeekProg=1 curl ${URL}/writeVal.cgi?G${TH}.OPMode=0;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=1;
Pro 1 Night Gx.OPMode=1, Gx.WeekProg=1 curl ${URL}/writeVal.cgi?G${TH}.OPMode=1;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=1;
Pro 1 Holiday Gx.OPMode=2, Gx.WeekProg=1 curl ${URL}/writeVal.cgi?G${TH}.OPMode=2;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=1;
Pro 2 Day Gx.OPMode=0, Gx.WeekProg=2 curl ${URL}/writeVal.cgi?G${TH}.OPMode=0;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=2;
Pro 2 Night Gx.OPMode=1, Gx.WeekProg=2 curl ${URL}/writeVal.cgi?G${TH}.OPMode=1;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=2;
Pro 2 Holiday Gx.OPMode=2, Gx.WeekProg=2 curl ${URL}/writeVal.cgi?G${TH}.OPMode=2;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=2;
Pro 3 Day Gx.OPMode=0, Gx.WeekProg=3 curl ${URL}/writeVal.cgi?G${TH}.OPMode=0;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=3;
Pro 3 Night Gx.OPMode=1, Gx.WeekProg=3 curl ${URL}/writeVal.cgi?G${TH}.OPMode=1;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=3;
Pro 3 Holiday Gx.OPMode=2, Gx.WeekProg=3 curl ${URL}/writeVal.cgi?G${TH}.OPMode=2;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=3;

Examples

Purpose cmdline
Read current date/time curl ${URL}/readVal.cgi?R0.DateTime
Set Date/Time curl ${URL}/writeVal.cgi?R0.DateTime=$(date +%s)
Set name of thermostat 0 curl ${URL}/writeVal.cgi?G0.name=My_Thermostat
Set Temp of thermostat 0 to 20.54 C curl ${URL}/cgi-bin/writeVal.cgi?G0.SollTemp=2054
Read Temp of thermostat 0 curl ${URL}/readVal.cgi?G0.SollTemp
Set thermostat 0 mode to night curl ${URL}/writeVal.cgi?G0.OPMode=1
Program 1 Day mode curl ${URL}/writeVal.cgi?G${TH}.OPMode=0;curl ${URL}/writeVal.cgi?G${TH}.WeekProg=1;

Locating API Variables and call points

The easiest way to find the API variables for the older controllers, not the SL version, is to download the firmware, unpack it and examine the file "Roth.tcr".

alt text

Source: https://www.roth-uk.com/support/software-and-firmware-updates

The "Roth.tcr" file contains a list of the (potential) API calls that can be used with readVal.cgi and writeVal.cgi calls. Not all of these are implemented in the Touchline build and the unimplemented ones return a 404 error or zero length response.

CD.reset;CD.reset; ; ; ; ; ; ; ; ; ;
CD.save;CD.save; ; ; ; ; ; ; ; ; ;
CD.submit;CD.submit; ; ; ; ; ; ; ; ; ;
CD.submit.err;CD.submit.err; ; ; ; ; ; ; ; ; ;
CD.uname;CD.uname; ; ; ; ; ; ; ; ; ;
CD.upass;CD.upass; ; ; ; ; ; ; ; ; ;
CD.ureg;CD.ureg; ; ; ; ; ; ; ; ; ;
G#CO_myGx#.TempSIUnit;G#CO_myGx#.TempSIUnit; ; ; ; ; ; ; ; ; ;
G#CO_myGx#.WeekProg;G#CO_myGx#.WeekProg; ; ; ; ; ; ; ; ; ;
G0+#COFF_devicePageOffset#.TempSIUnit;G0+#COFF_devicePageOffset#.TempSIUnit; ; ; ; ; ; ; ; ; ;
G0+@COFF_configPageOffset@.kurzID;G0+@COFF_configPageOffset@.kurzID; ; ; ; ; ; ; ; ; ;
G0+@COFF_configPageOffset@.name;G0+@COFF_configPageOffset@.name; ; ; ; ; ; ; ; ; ;
.
.
R0.DateTime;R0.DateTime; ; ;Int; ; ; ; ; ; ;
R0.ErrorCode;R0.ErrorCode; ; ; ; ; ; ; ; ; ;
R0.OPModeRegler;R0.OPModeRegler; ; ; ; ; ; ; ; ; ;
R0.Safety;R0.Safety; ; ; ; ; ; ; ; ; ;
R0.SystemStatus;R0.SystemStatus; ; ; ; ; ; ; ; ; ;
R0.Taupunkt;R0.Taupunkt; ; ; ; ; ; ; ; ; ;
R0.WeekProgWarn;R0.WeekProgWarn; ; ; ; ; ; ; ; ; ;
R0.kurzID;R0.kurzID; ; ; ; ; ; ; ; ; ;
R0.numberOfPairedDevices;R0.numberOfPairedDevices; ; ; ; ; ; ; ; ; ;
.
.

Note: the '+#COFF_devicePageOffset#' translates into the index of the thermostat e.g. if there are 5 thermostats, the devicePageOffset is from 0-4

API Call points

Finding the possible API call points (/cgi-bin) requires analysis of the Firmware files, specifically the Java applet that is called when you access the web interface of the controller.

  • Download and Unzip the firmware file into a directory
  • find the main .jar file, which has the name IMasterx_y_z.jar e.g. IMaster6_21_00.jar (depends on the FW version)
  • Unzip the .jar e.g. unzip IMaster6_21_00.jar
  • Search the files for 'cgi-bin' e.g. strings *.class | grep cgi-bin | sort | uniq
&cgi-bin/alarm.cgi?list=0&action=config
&cgi-bin/alarm.exe?list=0&action=config
,cgi-bin/trend.cgi?trendsList=0&action=config
,cgi-bin/trend.exe?trendsList=0&action=config
/cgi-bin/GetSrvInfo.exe
/cgi-bin/ILRReadValues.cgi
/cgi-bin/ILRReadValues.exe
/cgi-bin/OrderValues.exe?
/cgi-bin/ReadFile.cgi?
/cgi-bin/ReadFile.exe?
/cgi-bin/readVal.cgi?
/cgi-bin/readVal.exe?
/cgi-bin/writeVal.cgi?
/cgi-bin/writeVal.exe?
4cgi-bin/trend.cgi?trendsList=0&action=reinitTrending
4cgi-bin/trend.exe?trendsList=0&action=reinitTrending
6cgi-bin/trend.cgi?trendsList=0&action=clearTrdLogFiles
6cgi-bin/trend.exe?trendsList=0&action=clearTrdLogFiles
cgi-bin/alarm.cgi?list=
cgi-bin/alarm.exe?list=
cgi-bin/trend.cgi?trendNr=
cgi-bin/trend.exe?trendNr=

Note: On the 6_21_0 firmware The list included references to 'trendingAlarming.dll', which is not present in any of the sources.

Not all of these call points are implemented in the Touchline build and the unimplemented ones return either a 404 error.

Call point Method Status Description
/cgi-bin/readVal.cgi GET OK Read Value
/cgi-bin/writeVal.cgi GET OK Write Value
/cgi-bin/GetSrvInfo.exe GET OK Embedded web server info
/cgi-bin/ILRReadValues.cgi GET Blank Headers but no content
/cgi-bin/ILRReadValues.cgi POST OK XML name/value pairs (see below)
/cgi-bin/alarm.cgi GET 404 Not found
/cgi-bin/alarm.exe GET 404 Not found
/cgi-bin/ILRReadValues.exe GET 404 Not found
/cgi-bin/OrderValues.exe GET 404 Not found
/cgi-bin/ReadFile.cgi GET 404 Not found
/cgi-bin/ReadFile.exe GET 404 Not found
/cgi-bin/readVal.exe GET 404 Not found
/cgi-bin/trend.cgi GET 404 Not found
/cgi-bin/trend.exe GET 404 Not found
/cgi-bin/writeVal.exe GET 404 Not found

ILRReadValues.cgi

The /cgi-bin/ILRReadValues.cgi end point differs from the others in that it uses POST instead of GET and the body of the POST must contain an XML formatted item_list of the variables to be queried. It returns an XML formatted list of variable names and there values. This permits the caller to query multiple variables in one call, which is faster than reading each variable individually. If the variable name(s) match it adds a value group associated with the variable name.

HTTP headers used on POST:

  • "Content-Type: text/xml" (mandatory)
  • "User-Agent: Roth-Touchline.../1.05" (optional but does not affect the return value)

e.g.

curl -s -X POST -H "Content-Type: text/xml" -H "User-Agent: Roth-Touchline.../1.05" -d "${REQ}" http://IP/cgi-bin/ILRReadValues.cgi

where "${REQ}" contains the XML encoded list of variables to be queried (see examples below)

HTTP POST Body/data format (pretty print XML, the one line version also works):

<item_list_size>
  # items
</item_list_size>
<item_list>
  <i><n> ---Variable name --- </n></i>
  <i><n> ---Variable name --- </n></i>  
<item_list>

(you can add other tags before and after this to make it easier to parse, they have no impact on the results, invalid entries are ignore)

e.g. POST to query the number of attached thermostats:

<body>
   <version>1.0</version>
   <item_list_size>
     1
   </item_list_size>
   <item_list>
      <i>
         <n>totalNumberOfDevices</n>
      </i>
   </item_list>
</body>

HTTP return format (XML), appends entry to each :

<item_list_size>
  # items
</item_list_size>
<item_list>
  <i><n> ---Variable name --- </n><v> --- Variable value ---</v></i>
  <i><n> ---Variable name --- </n><v> --- Variable value ---</v></i>
<item_list>

e.g. HTTP return for a system with 4 thermostats attached:

<body>
   <version>1.0</version>
   <item_list_size>
     1
   </item_list_size>
   <item_list>
      <i>
         <n>totalNumberOfDevices</n>
         <v>4</v>
      </i>
   </item_list>
</body>

Examples

In the examples below the <body><version>1.0</version> prefix and </body> suffix have been added to the POST body.

POST Body POST Return Description
<body><version>1.0</version><item_list_size>1</item_list_size><item_list><i><n>totalNumberOfDevices</n></item_list></body> <body><version>1.0</version><item_list_size>1</item_list_size><item_list><i><n>totalNumberOfDevices</n><v>4</v></i></item_list></body> Number of thermostats attached, 4 would indicate thermostats 0-3
<body><version>1.0</version><item_list_size>29</item_list_size><item_list><i><n>totalNumberOfDevices</n></i><i><n>CD.name</n></i><i><n>CD.upass</n></i><i><n>STELL-APP</n></i><i><n>STELL-BL</n></i><i><n>ST-APP</n></i><i><n>STM-BL</n></i><i><n>hw.IP</n></i><i><n>hw.Addr</n></i><i><n>hw.DNS1</n></i><i><n>hw.DNS2</n></i><i><n>hw.GW</n></i><i><n>hw.NM</n></i><i><n>hw.HostName</n></i><i><n>numberOfSlaveControllers</n></i><i><n>VPI.href</n></i><i><n>VPI.state</n></i><i><n>isMaster</n></i><i><n>Status</n></i><i><n>R0.DateTime</n></i><i><n>R0.ErrorCode</n></i><i><n>R0.OPModeRegler</n></i><i><n>R0.Safety</n></i><i><n>R0.SystemStatus</n></i><i><n>R0.Taupunkt</n></i><i><n>R0.WeekProgWarn</n></i><i><n>R0.kurzID</n></i><i><n>R0.numberOfPairedDevices</n></i><i><n>R0.uniqueID</n></i></item_list></body> <body><version>1.0</version><item_list_size>29</item_list_size><item_list><i><n>totalNumberOfDevices</n><v>4</v></i><i><n>CD.name</n><v></v></i><i><n>CD.upass</n><v>1234</v></i><i><n>STELL-APP</n><v>1.42</v></i><i><n>STELL-BL</n><v>1.20</v></i><i><n>ST-APP</n><v></v></i><i><n>STM-BL</n><v>1.20</v></i><i><n>hw.IP</n><v>192.168.x.x</v></i><i><n>hw.Addr</n><v>5C-XX-XX-XX-XX-XX</v></i><i><n>hw.DNS1</n><v>192.168.x.x</v></i><i><n>hw.DNS2</n><v>192.168.x.x/v></i><i><n>hw.GW</n><v>192.168.x.x</v></i><i><n>hw.NM</n><v>255.255.0.0</v></i><i><n>hw.HostName</n><v>ROTH-00CCC8</v></i><i><n>numberOfSlaveControllers</n><v>0</v></i><i><n>VPI.href</n><v>http://myroth.ininet.ch/remote/t_AAAAAAAAA/</v></i><i><n>VPI.state</n><v>99</v></i><i><n>isMaster</n><v>1</v></i><i><n>Status</n><v></v></i><i><n>R0.DateTime</n><v>1760123686</v></i><i><n>R0.ErrorCode</n><v>0</v></i><i><n>R0.OPModeRegler</n><v>0</v></i><i><n>R0.Safety</n><v>0</v></i><i><n>R0.SystemStatus</n><v>0</v></i><i><n>R0.Taupunkt</n><v>0</v></i><i><n>R0.WeekProgWarn</n><v>0</v></i><i><n>R0.kurzID</n><v>69</v></i><i><n>R0.numberOfPairedDevices</n><v>4</v></i><i><n>R0.uniqueID</n><v>XXXXXXXXXXXXXXX</v></i></item_list></body> Retrieve all controller parameters (no thermostats)
<body><version>1.0</version><item_list_size>81</item_list_size><item_list><i><n>totalNumberOfDevices</n></i><i><n>CD.name</n></i><i><n>CD.upass</n></i><i><n>STELL-APP</n></i><i><n>STELL-BL</n></i><i><n>ST-APP</n></i><i><n>STM-BL</n></i><i><n>hw.IP</n></i><i><n>hw.Addr</n></i><i><n>hw.DNS1</n></i><i><n>hw.DNS2</n></i><i><n>hw.GW</n></i><i><n>hw.NM</n></i><i><n>hw.HostName</n></i><i><n>numberOfSlaveControllers</n></i><i><n>VPI.href</n></i><i><n>VPI.state</n></i><i><n>isMaster</n></i><i><n>Status</n></i><i><n>R0.DateTime</n></i><i><n>R0.ErrorCode</n></i><i><n>R0.OPModeRegler</n></i><i><n>R0.Safety</n></i><i><n>R0.SystemStatus</n></i><i><n>R0.Taupunkt</n></i><i><n>R0.WeekProgWarn</n></i><i><n>R0.kurzID</n></i><i><n>R0.numberOfPairedDevices</n></i><i><n>R0.uniqueID</n></i><i><n>G0.name</n></i><i><n>G0.RaumTemp</n></i><i><n>G0.SollTemp</n></i><i><n>G0.SollTempMaxVal</n></i><i><n>G0.SollTempMinVal</n></i><i><n>G0.SollTempStepal</n></i><i><n>G0.TempSIUnit</n></i><i><n>G0.WeekProg</n></i><i><n>G0.WeekProgEna</n></i><i><n>G0.OPMode</n></i><i><n>G0.OPModeEna</n></i><i><n>G0.kurzID</n></i><i><n>G0.ownerKurzID</n></i><i><n>G1.name</n></i><i><n>G1.RaumTemp</n></i><i><n>G1.SollTemp</n></i><i><n>G1.SollTempMaxVal</n></i><i><n>G1.SollTempMinVal</n></i><i><n>G1.SollTempStepal</n></i><i><n>G1.TempSIUnit</n></i><i><n>G1.WeekProg</n></i><i><n>G1.WeekProgEna</n></i><i><n>G1.OPMode</n></i><i><n>G1.OPModeEna</n></i><i><n>G1.kurzID</n></i><i><n>G1.ownerKurzID</n></i><i><n>G2.name</n></i><i><n>G2.RaumTemp</n></i><i><n>G2.SollTemp</n></i><i><n>G2.SollTempMaxVal</n></i><i><n>G2.SollTempMinVal</n></i><i><n>G2.SollTempStepal</n></i><i><n>G2.TempSIUnit</n></i><i><n>G2.WeekProg</n></i><i><n>G2.WeekProgEna</n></i><i><n>G2.OPMode</n></i><i><n>G2.OPModeEna</n></i><i><n>G2.kurzID</n></i><i><n>G2.ownerKurzID</n></i><i><n>G3.name</n></i><i><n>G3.RaumTemp</n></i><i><n>G3.SollTemp</n></i><i><n>G3.SollTempMaxVal</n></i><i><n>G3.SollTempMinVal</n></i><i><n>G3.SollTempStepal</n></i><i><n>G3.TempSIUnit</n></i><i><n>G3.WeekProg</n></i><i><n>G3.WeekProgEna</n></i><i><n>G3.OPMode</n></i><i><n>G3.OPModeEna</n></i><i><n>G3.kurzID</n></i><i><n>G3.ownerKurzID</n></i></item_list></body> <body><version>1.0</version><item_list_size>81</item_list_size><item_list><i><n>totalNumberOfDevices</n><v>4</v></i><i><n>CD.name</n><v></v></i><i><n>CD.upass</n><v>1234</v></i><i><n>STELL-APP</n><v>1.42</v></i><i><n>STELL-BL</n><v>1.20</v></i><i><n>ST-APP</n><v></v></i><i><n>STM-BL</n><v>1.20</v></i><i><n>hw.IP</n><v>192.168.x.x</v></i><i><n>hw.Addr</n><v>5C-XX-XX-XX-XX-XX</v></i><i><n>hw.DNS1</n><v>192.168.x.x</v></i><i><n>hw.DNS2</n><v>192.168.x.x/v></i><i><n>hw.GW</n><v>192.168.x.x</v></i><i><n>hw.NM</n><v>255.255.0.0</v></i><i><n>hw.HostName</n><v>ROTH-00CCC8</v></i><i><n>numberOfSlaveControllers</n><v>0</v></i><i><n>VPI.href</n><v>http://myroth.ininet.ch/remote/t_AAAAAAAAA/</v></i><i><n>VPI.state</n><v>99</v></i><i><n>isMaster</n><v>1</v></i><i><n>Status</n><v></v></i><i><n>R0.DateTime</n><v>1760123686</v></i><i><n>R0.ErrorCode</n><v>0</v></i><i><n>R0.OPModeRegler</n><v>0</v></i><i><n>R0.Safety</n><v>0</v></i><i><n>R0.SystemStatus</n><v>0</v></i><i><n>R0.Taupunkt</n><v>0</v></i><i><n>R0.WeekProgWarn</n><v>0</v></i><i><n>R0.kurzID</n><v>69</v></i><i><n>R0.numberOfPairedDevices</n><v>4</v></i><i><n>R0.uniqueID</n><v>XXXXXXXXXXXXXXX</v></i><i><n>G0.name</n><v>Kitchen</v></i><i><n>G0.RaumTemp</n><v>1401</v></i><i><n>G0.SollTemp</n><v>2000</v></i><i><n>G0.SollTempMaxVal</n><v>2200</v></i><i><n>G0.SollTempMinVal</n><v>2000</v></i><i><n>G0.SollTempStepal</n><v></v></i><i><n>G0.TempSIUnit</n><v>0</v></i><i><n>G0.WeekProg</n><v>0</v></i><i><n>G0.WeekProgEna</n><v>1</v></i><i><n>G0.OPMode</n><v>1</v></i><i><n>G0.OPModeEna</n><v>1</v></i><i><n>G0.kurzID</n><v>1</v></i><i><n>G0.ownerKurzID</n><v>69</v></i><i><n>G1.name</n><v>Living Room</v></i><i><n>G1.RaumTemp</n><v>1390</v></i><i><n>G1.SollTemp</n><v>1600</v></i><i><n>G1.SollTempMaxVal</n><v>3000</v></i><i><n>G1.SollTempMinVal</n><v>500</v></i><i><n>G1.SollTempStepal</n><v></v></i><i><n>G1.TempSIUnit</n><v>0</v></i><i><n>G1.WeekProg</n><v>0</v></i><i><n>G1.WeekProgEna</n><v>1</v></i><i><n>G1.OPMode</n><v>1</v></i><i><n>G1.OPModeEna</n><v>1</v></i><i><n>G1.kurzID</n><v>2</v></i><i><n>G1.ownerKurzID</n><v>69</v></i><i><n>G2.name</n><v>Hall</v></i><i><n>G2.RaumTemp</n><v>1370</v></i><i><n>G2.SollTemp</n><v>1600</v></i><i><n>G2.SollTempMaxVal</n><v>3000</v></i><i><n>G2.SollTempMinVal</n><v>500</v></i><i><n>G2.SollTempStepal</n><v></v></i><i><n>G2.TempSIUnit</n><v>0</v></i><i><n>G2.WeekProg</n><v>0</v></i><i><n>G2.WeekProgEna</n><v>1</v></i><i><n>G2.OPMode</n><v>1</v></i><i><n>G2.OPModeEna</n><v>1</v></i><i><n>G2.kurzID</n><v>3</v></i><i><n>G2.ownerKurzID</n><v>69</v></i><i><n>G3.name</n><v>Downstairs Bathroom</v></i><i><n>G3.RaumTemp</n><v>1372</v></i><i><n>G3.SollTemp</n><v>1600</v></i><i><n>G3.SollTempMaxVal</n><v>3000</v></i><i><n>G3.SollTempMinVal</n><v>500</v></i><i><n>G3.SollTempStepal</n><v></v></i><i><n>G3.TempSIUnit</n><v>0</v></i><i><n>G3.WeekProg</n><v>0</v></i><i><n>G3.WeekProgEna</n><v>1</v></i><i><n>G3.OPMode</n><v>1</v></i><i><n>G3.OPModeEna</n><v>1</v></i><i><n>G3.kurzID</n><v>4</v></i><i><n>G3.ownerKurzID</n><v>69</v></i></item_list></body> Query all variables on a 4 thermostat system

XML post processing

There are various ways to post process the XML list into something more accessible. For the sake of example we will use shell script and cmd line utilities, similar results maybe obtained used python or other languages.

If we assumed that the POST REQuest was contained in a shell variable ${RES}, the result of the query might be captured as follows:

RES=$(curl -s -X POST -H "Content-Type: text/xml" -H "User-Agent: Roth-Touchline.../1.05" -d "${req}" http://IP/cgi-bin/ILRReadValues.cgi)
  • Bash conversion to key=value pairs:
printf "$RES" | sed -e 's/<v>/=/g' -e 's/>/>\n/g' -e 's/<\/n>\n//g' -e 's/<\/v>//g' | grep '='
  • XSLT conversion using the template my.xslt (see below):
printf "${RES}" | xsltproc --nodtdattr --nonet --novalid my.xslt

XSLT templates

  1. Key=value XSLT:
cat <<_EOF_ >my.xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text" omit-xml-declaration="yes"/>
        <xsl:template match="/">
                <xsl:for-each select="body/item_list/i">
                        <xsl:value-of select="n" />
                        <xsl:text>=</xsl:text>
                        <xsl:value-of select="v" />
                        <xsl:text>&#xa;</xsl:text> 
                </xsl:for-each>
        </xsl:template>
</xsl:stylesheet>
_EOF_
printf "${RES}" | xsltproc --nodtdattr --nonet --novalid my.xslt
  1. Create shell script arrays of the key and value pairs (run the XLST conversion then call the output in your script)
cat <<_EOF_ >my.xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text" omit-xml-declaration="yes"/>
        <xsl:template match="/">
                <xsl:for-each select="body/item_list/i">
                        <xsl:text>aFIELDNAM[\${iCNT}]=</xsl:text>
                        <xsl:value-of select="n" />
                        <xsl:text>;</xsl:text>
                        <xsl:text>aFIELDVAL[\${iCNT}]="</xsl:text>
                        <xsl:value-of select="v" />
                        <xsl:text>";</xsl:text>
                        <xsl:text>iCNT=\$((iCNT+1))</xsl:text>
                        <xsl:text>&#xa;</xsl:text>
                </xsl:for-each>
        </xsl:template>
</xsl:stylesheet>
_EOF_
printf "${RES}" | xsltproc --nodtdattr --nonet --novalid my.xslt

API Script

For convenience the API calls have been encapsulated in the bash script 'rothread.sh' that:

  • Allows entry of temperatures in decimal x.y format i.e. 18.54 instead of 1854
  • Implements a status print of all variables
  • Logs the output to files in /var/tmp
  • Builds an arrays of field names/values to allow this to be called from other scripts
cmd line Description
rothread.sh -h Show help
rothread.sh -s Show status of all variables
rothread.sh -w G0.OPMode=1 Set Thermostat #0 to Night mode
rothread.sh -w G1.SollTemp=19.54 Set required Temperature to 19.54 on Thermostat #2
rothread.sh -w R0.Datetime=$(date +%s) Set controller Date/Time to current on Linux

Roth Touchline SL API

The firmware file for the newer Touchline SL controllers has a different format to the older Touchline BL/PL controllers. The file appears to be encoded and does not reveal anything about the internal contents.

I have not tested this script against the newer Touchline SL; if you have one of these controllers please let me know your results.

alt text

How does the Roth Application find the Controller?

The Roth IoS/Android application does not request the IP address of the master controller, so how does it find it?

Step 1: The client app sends a UDP unicast broadcast (255.255.255.255) to port 5000 (upnp) contained the payload "SEARCH R*\r\n":

0000  ff ff ff ff ff ff 28 8f f6 65 d4 cd 08 00 45 00   ......(..e....E.  
0010  00 28 ca 53 00 00 40 11 ea 41 c0 a8 05 88 ff ff   .(.S..@..A......  
0020  ff ff cd 7c 13 88 00 14 2c 52 53 45 41 52 43 48   ...|....,RSEARCH  
0030  20 52 2a 0d 0a 00 00 00 00 00 00 00                R*.........

Step 2: The Roth controller responds with a UDP unicast broadcast from port 5000 to the client port identified in the previous step:

0000  ff ff ff ff ff ff 00 17 13 3b a3 09 08 00 45 00   .........;....E.
0010  00 bc 08 59 00 00 80 11 6c 1d c0 a8 05 13 ff ff   ...Y....l.......
0020  ff ff 13 88 d1 7f 00 a8 12 4d 52 31 30 30 00 a0   .........MR100..
0030  00 45 00 20 00 00 c0 a8 07 19 c0 a8 07 01 ff ff   .E. ............
0040  ff 00 c0 a8 07 01 c0 a8 05 2c 5c c2 13 00 d8 18   .........,\.....
0050  00 00 00 00 00 00 00 00 00 00 52 4f 54 48 2d 46   ..........ROTH-F
0060  46 44 38 31 38 00 00 00 00 00 00 00 00 00 68 74   FD818.........ht
0070  74 70 3a 2f 2f 31 39 32 2e 31 36 38 2e 35 2e 31   tp://192.168.7.1
0080  39 2f 00 00 00 00 00 00 00 00 00 00 00 00 00 00   9/..............
0090  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00a0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00b0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 53 ff   ..............S.
00c0  71 06 49 89 49 53 18 46 02 87                     q.I.IS.F..

Step 3: The payload part of this contains the name of the controller (ROTH-FFD918) and the IP (192.168.7.19 / C0 A8 07 13 at offset 0x36), it uses this to connect. The service URL is specified here as http://192.168.7.19 (this version of the FW does not use SSL).

0020                                 52 31 30 30 00 a0             R100..
0030   00 45 00 20 00 00 c0 a8 07 19 c0 a8 07 01 ff ff   .E. ............
0040   ff 00 c0 a8 07 01 c0 a8 05 2c 5c c2 13 00 d8 18   .........,\.....
0050   00 00 00 00 00 00 00 00 00 00 52 4f 54 48 2d 46   ..........ROTH-F
0060   46 44 38 31 38 00 00 00 00 00 00 00 00 00 68 74   FD818.........ht
0070   74 70 3a 2f 2f 31 39 32 2e 31 36 38 2e 35 2e 31   tp://192.168.7.1
0080   39 2f 00 00 00 00 00 00 00 00 00 00 00 00 00 00   9/..............
0090   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00a0   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00b0   00 00 00 00 00 00 00 00 00 00 00 00 00 00 53 ff   ..............S.
00c0   71 06 49 89 49 53 18 46 02 87                     q.I.IS.F..

Caveat: This method of discovery by the application only works when you are directly connected to the same broadcast domain. It does not work over a routed network or via a VPN connection, as these filter broadcast traffic.

Documentation

Releases

No releases published

Packages

 
 
 

Contributors

Languages