I thought i’d document my implementation of my MAX! system in openHAB. I hope it’s useful to someone.
Questions and comments are welcome.
Installation
The installation of the Max! addon is quite straight ahead:
In Paper UI, go to the “Addons” section, and select to install the MAX! Binding (make sure you don’t use the MAX! CUL Binding).
After that, you should find a new thing in your Inbox:
Go to the “Inbox” section, and select to Add the MAX! Cube LAN Gateway:
After doing so, you’ll find all MAX! devices in your Inbox. Add them all.
Configuration
After openHAB “knows” your devices, you can start to configure them as items.
Groups
I use groups in “two dimensions”: First, all devices in one room make up a group. Second, all attributes (like temperyture, valve etc) make up othe groups.
Using this, you can easily use rules looping though all groups to set all thermostats to manual mode or do other things.
//=====================================================================================================================
// Gruppe für alles
Group gMax "Max! Heizungssystem" <temperature>
// Gruppen für die einzelnen Räume
Group gMaxWohnzimmer "Thermostat Wohnzimmer" <temperature> (gMax) ["Thermostat"]
Group gMaxKueche "Thermostat Küche" <temperature> (gMax) ["Thermostat"]
Group gMaxKinderzimmer "Thermostat Kinderzimmer" <temperature> (gMax) ["Thermostat"]
Group gMaxArbeitszimmer "Thermostat Arbeitszimmer" <temperature> (gMax) ["Thermostat"]
Group gMaxSchlafzimmer "Thermostat Schlafzimmer " <temperature> (gMax) ["Thermostat"]
Group gMaxBad "Thermostat Bad" <temperature> (gMax) ["Thermostat"]
// Gruppen für die einzelnen Aspekte
Group gMaxMode "Modus" <temperature>
Group gMaxSetTemp "Wunschtemperatur" <temperature>
Group gMaxActualTemp "Raumemperatur" <temperature>
Group:Switch:OR(ON,OFF) gMaxBatLow "Batteriestatus [MAP(max.map):%s]" <battery>
Group gMaxValve "Ventilstellungen" <max_valve>
Group:Contact:OR(OPEN,CLOSED) gMaxWindow "Fenster [MAP(max.map):%s]" <window>
Group:Contact:OR(CLOSED,OPEN) gMaxLock "Bediensperre [MAP(max.map):%s]" <lock>
// Gruppen für die Automatik bei Anwesenheit ("alle" außer Schlafzimmer)
Group gMaxAutoTemp
Group gMaxAutoMode
Explanation
gMax is the “Master” group that includes all other items.
Second, there are groups for my rooms. Each has a label, uses the “temperature” item, belongs to the master group “gMax”, and is tagged “Themostat” so it can be controlled using Alexa.
Third, there are groups for mode, setpoint, actual temperature etc.
And lastt, there are some groups I use in rules
Using logic to sum up individual states
Three of these groups sum up the individual states.
gMaxBatLow should be “on” (= battery low) when any of the individual states is “on”.
gMaxWindow should be “open” when any of the windows is “open”.
gMaxLock works just the other way 'round, it should be “closed” when any of the themostats is locked.
Using transformations for labels
These groups are using a transformation for displaying a label. To use this, you have to activate the “Map Transformation” in Paper UI, and create a .map file containing the mappings:
ON=niedrig
OFF=ausreichend
OPEN=geöffnet
CLOSED=geschlossen
The first thermostat
//=====================================================================================================================
// Kueche
String maxModeKueche "Modus" <max_mode> (gMaxKueche, gMaxMode, gMaxAutoMode) {channel="max:thermostat:JEQ0438859:KEQ0335349:mode"}
Number maxSetTempKueche "Wunschtemperatur [%.1f °C]" <max_temp> (gMaxKueche, gMaxSetTemp, gMaxAutoTemp) ["TargetTemperature"] {channel="max:thermostat:JEQ0438859:KEQ0335349:set_temp"}
Number maxActualTempKueche "Raumtemperatur [%.1f °C]" <max_temp> (gMaxKueche, gMaxActualTemp) ["CurrentTemperature"] {channel="max:thermostat:JEQ0438859:KEQ0335349:actual_temp"}
Switch maxBatLowKueche "Batteriestatus Küche [MAP(max.map):%s]" <battery> (gMaxKueche, gMaxBatLow) {channel="max:thermostat:JEQ0438859:KEQ0335349:battery_low"}
Number maxValveKueche "Ventilstellung [%d %%]" <max_valve> (gMaxKueche, gMaxValve) {channel="max:thermostat:JEQ0438859:KEQ0335349:valve"}
Contact maxLockedKueche "Bediensperre [MAP(max.map):%s]" <lock> (gMaxKueche, gMaxLock) {channel="max:thermostat:JEQ0438859:KEQ0335349:locked"}
You see here all aspects of a MAX! thermostat: mode, set temperature, current temperature, battery low state, valve setting and lock state. I use labels with a reasonable formatting of values (temperature as °C with one decimal, valve as integer percent). I created some SVG graphics (max_mode, max_temp, max_valve) to visualize the states. In the next column, the items are added to the respective groups.
maxSetTempKueche and maxActualTempKueche are tagged for the Alexa skill.
The last column are the channels. You find the channel name (and the type) in Paper UI:
A room with window sensor
This is an example of a room with a window sensor:
//=====================================================================================================================
// Arbeitszimmer
String maxModeArbeitszimmer "Modus" <max_mode> (gMaxArbeitszimmer, gMaxMode, gMaxAutoMode) {channel="max:thermostat:JEQ0438859:JHA0008545:mode"}
Number maxSetTempArbeitszimmer "Wunschtemperatur [%.1f °C]" <max_temp> (gMaxArbeitszimmer, gMaxSetTemp, gMaxAutoTemp) ["TargetTemperature"] {channel="max:thermostat:JEQ0438859:JHA0008545:set_temp"}
Number maxActualTempArbeitszimmer "Raumtemperatur [%.1f °C]" <max_temp> (gMaxArbeitszimmer, gMaxActualTemp) ["CurrentTemperature"] {channel="max:thermostat:JEQ0438859:JHA0008545:actual_temp"}
Switch maxBatLowArbeitszimmer "Batteriestatus Arbeitszimmer [MAP(max.map):%s]" <battery> (gMaxArbeitszimmer, gMaxBatLow) {channel="max:thermostat:JEQ0438859:JHA0008545:battery_low"}
Number maxValveArbeitszimmer "Ventilstellung [%d %%]" <max_valve> (gMaxArbeitszimmer, gMaxValve) {channel="max:thermostat:JEQ0438859:JHA0008545:valve"}
Contact maxLockedArbeitszimmer "Bediensperre [MAP(max.map):%s]" <lock> (gMaxArbeitszimmer, gMaxLock) {channel="max:thermostat:JEQ0438859:JHA0008545:locked"}
Contact maxFensterArbeitszimmer "Fenster Arbeitszimmer [MAP(max.map):%s]" <window> (gMaxArbeitszimmer, gMaxWindow) {channel="max:shuttercontact:JEQ0438859:OEQ0417571:contact_state"}
Switch maxBatLowFensterArbeitszimmer "Batteriestatus Fenster Arbeitszimmer [MAP(max.map):%s]" <battery> (gMaxArbeitszimmer, gMaxBatLow) {channel="max:shuttercontact:JEQ0438859:OEQ0417571:battery_low"}
A room with a wall thermostat
Im my living room, there are two heatings and a wall mounted thermostat:
//=====================================================================================================================
// Wohnzimmer
String maxModeWohnzimmer "Modus" <max_mode> (gMaxWohnzimmer, gMaxMode, gMaxAutoMode) {channel="max:wallthermostat:JEQ0438859:MEQ0854379:mode"}
Number maxSetTempWohnzimmer "Wunschtemperatur [%.1f °C]" <max_temp> (gMaxWohnzimmer, gMaxSetTemp, gMaxAutoTemp) ["TargetTemperature"] {channel="max:wallthermostat:JEQ0438859:MEQ0854379:set_temp"}
Number maxActualTempWohnzimmer "Raumtemperatur [%.1f °C]" <max_temp> (gMaxWohnzimmer, gMaxActualTemp) ["CurrentTemperature"] {channel="max:wallthermostat:JEQ0438859:MEQ0854379:actual_temp"}
Switch maxBatLowWohnzimmer "Batteriestatus Wandthermostat [MAP(max.map):%s]" <battery> (gMaxWohnzimmer, gMaxBatLow) {channel="max:wallthermostat:JEQ0438859:MEQ0854379:battery_low"}
Contact maxLockedWohnzimmer "Bediensperre [MAP(max.map):%s]" <lock> (gMaxWohnzimmer, gMaxLock) {channel="max:wallthermostat:JEQ0438859:MEQ0854379:locked"}
String maxModeWohnzimmerl "Modus" <max_mode> (gMaxWohnzimmer) {channel="max:thermostat:JEQ0438859:JEQ0616861:mode"}
Number maxSetTempWohnzimmerl "Wunschtemperatur [%.1f °C]" <max_temp> (gMaxWohnzimmer) ["TargetTemperature"] {channel="max:thermostat:JEQ0438859:JEQ0616861:set_temp"}
Switch maxBatLowWohnzimmerl "Batteriestatus Wohnzimmer links [MAP(max.map):%s]" <battery> (gMaxWohnzimmer, gMaxBatLow) {channel="max:thermostat:JEQ0438859:JEQ0616861:battery_low"}
Number maxValveWohnzimmerl "Ventilstellung links [%d %%]" <max_valve> (gMaxWohnzimmer, gMaxValve) {channel="max:thermostat:JEQ0438859:JEQ0616861:valve"}
Contact maxLockedWohnzimmerl "Bediensperre links [MAP(max.map):%s]" <lock> (gMaxWohnzimmer, gMaxLock) {channel="max:thermostat:JEQ0438859:JEQ0616861:locked"}
String maxModeWohnzimmerr "Modus" <max_mode> (gMaxWohnzimmer) {channel="max:thermostat:JEQ0438859:JEQ0617410:mode"}
Number maxSetTempWohnzimmerr "Wunschtemperatur [%.1f °C]" <max_temp> (gMaxWohnzimmer) ["TargetTemperature"] {channel="max:thermostat:JEQ0438859:JEQ0617410:set_temp"}
Switch maxBatLowWohnzimmerr "Batteriestatus Wohnzimmer rechts [MAP(max.map):%s]" <battery> (gMaxWohnzimmer, gMaxBatLow) {channel="max:thermostat:JEQ0438859:JEQ0617410:battery_low"}
Number maxValveWohnzimmerr "Ventilstellung rechts [%d %%]" <max_valve> (gMaxWohnzimmer, gMaxValve) {channel="max:thermostat:JEQ0438859:JEQ0616861:valve"}
Contact maxLockedWohnzimmerr "Bediensperre rechts [MAP(max.map):%s]" <lock> (gMaxWohnzimmer, gMaxLock) {channel="max:thermostat:JEQ0438859:JEQ0616861:locked"}
Sitemap
To test the configuration, you can use an simple sitemap:
sitemap max label="Heizungssteuerung" {
Group item=gMax
}
This will show you all your rooms, and all devices in this room:
However, you can’t set the desired temperature, and all in all it’s not very user friendly. So here is my complete sitemap:
sitemap max label="Heizungssteuerung" {
Frame label="Wichtige Informationen" visibility=[gMaxBatLow==ON] {
Group item=gMaxBatLow visibility=[gMaxBatLow==ON] {
Text item=maxBatLowWohnzimmer visibility=[maxBatLowWohnzimmer==ON]
Text item=maxBatLowWohnzimmerl visibility=[maxBatLowWohnzimmerl==ON]
Text item=maxBatLowWohnzimmerr visibility=[maxBatLowWohnzimmerr==ON]
Text item=maxBatLowKueche visibility=[maxBatLowKueche==ON]
Text item=maxBatLowKinderzimmer visibility=[maxBatLowKinderzimmer==ON]
Text item=maxBatLowArbeitszimmer visibility=[maxBatLowArbeitszimmer==ON]
Text item=maxBatLowSchlafzimmer visibility=[maxBatLowSchlafzimmer==ON]
Text item=maxBatLowBad visibility=[maxBatLowBad==ON]
Text item=maxBatLowTaster visibility=[maxBatLowTaster==ON]
Text item=maxBatLowFensterKinderzimmer visibility=[maxBatLowFensterKinderzimmer==ON]
Text item=maxBatLowFensterArbeitszimmer visibility=[maxBatLowFensterArbeitszimmer==ON]
}
}
Frame label="Bediensperre" visibility=[gMaxLock==CLOSED] {
Group item=gMaxLock visibility=[gMaxLock==CLOSED] {
Text item=maxLockedWohnzimmer visibility=[maxLockedWohnzimmer==CLOSED]
Text item=maxLockedWohnzimmerl visibility=[maxLockedWohnzimmerl==CLOSED]
Text item=maxLockedWohnzimmerr visibility=[maxLockedWohnzimmerr==CLOSED]
Text item=maxLockedKueche visibility=[maxLockedKueche==CLOSED]
Text item=maxLockedKinderzimmer visibility=[maxLockedKinderzimmer==CLOSED]
Text item=maxLockedArbeitszimmer visibility=[maxLockedArbeitszimmer==CLOSED]
Text item=maxLockedSchlafzimmer visibility=[maxLockedSchlafzimmer==CLOSED]
Text item=maxLockedBad visibility=[maxLockedBad==CLOSED]
}
}
Frame label="Fenster" visibility=[gMaxWindow==OPEN] {
Group item=gMaxWindow visibility=[gMaxWindow==OPEN] {
Text item=maxFensterKinderzimmer visibility=[maxFensterKinderzimmer==OPEN]
Text item=maxFensterArbeitszimmer visibility=[maxFensterArbeitszimmer==OPEN]
}
}
Frame label="Wohnzimmer" {
Text item=maxActualTempWohnzimmer
Setpoint item=maxSetTempWohnzimmer minValue=4.5 maxValue=25 step=0.5
Selection item=maxModeWohnzimmer mappings=[AUTOMATIC=Auto, MANUAL=Manu, BOOST=Boost]
}
Frame label="Küche" {
Text item=maxActualTempKueche
Setpoint item=maxSetTempKueche minValue=4.5 maxValue=25 step=0.5
Selection item=maxModeKueche mappings=[AUTOMATIC=Auto, MANUAL=Manu, BOOST=Boost]
}
Frame label="Arbeitszimmer" {
Text item=maxActualTempArbeitszimmer
Setpoint item=maxSetTempArbeitszimmer minValue=4.5 maxValue=25 step=0.5
Selection item=maxModeArbeitszimmer mappings=[AUTOMATIC=Auto, MANUAL=Manu, BOOST=Boost]
Text item=maxFensterArbeitszimmer
}
The first three frames only show up when there is a battery low, a thermostat locked or a window open. That is the reason why the respective groups are defined using the logic.
In these groups, only the probematic items are shown. Here is an example what happens if there are two batteries low:
Usage in rules
As said above, you can use the groups in rules.
To set all thermostats to a specifix temperature, use
// Temperatur absenken
gMaxAutoTemp.members.forEach[item | item.sendCommand(11)]
gMaxAutoMode.members.forEach[item | item.sendCommand("MANUAL")]
To return to automatic mode, use
gMaxAutoMode.members.forEach[item | item.sendCommand("AUTOMATIC")]