Eurotronic Spirit - Unsupported mode type 31

These are my experiences with Spirit. My main point: Its a good device as is, it would be even better with manual mode enabled. I hope it gets to that.

I have 6 of them now. It is a great valve for the price. For now I am using the internal temperature sensor and internal valve logic. It’s far from perfect, but it is not useless. It is opening and closing frequently (not very battery friendly), but it does keep temperature quite stable as a result. I mean, it does fluctuate ±1°C, but this is expected with radiators, when you close the valve a hot radiator will keep heating, and when you open the valve it will take some time to start heating. Also it is often just partly opened which causes water flow to be loud (whining). This depends on the pump also. In my case its annoying sometimes. Depending on the position of the valve in the room you have to figure out what is required offset of read temperature. You can set this offset to the valve, or just set a degree or two higher/lower setting because of it.
I have 60°C in my radiators.

If you want the valve fully closed or fully opened, you have to set it way below or above the current temperature. I think it is possible to open it fully with a command, and close it fully with another command. This could be used in external valve logic, but it takes some motor action (battery drain) to preform 0->100% and back. If I had manual control of the valve, I would probably also use just open/close states, but I would figure it out when it is already fully open (so no whining). So 0% for close and 20% for open on my valves for instance.

Anyway, I still think this is a good product. Batteries are cheap (2xAA) and in my case they are good for one season/year. It is very responsive. I have it set to report changes for 0.2-0.5°C difference or 5% valve change or 60 minutes (had it 10 minutes for first season even). So this is rather aggressive reporting schedule, and is good enough to compute logic to start/stop pump depending on difference between set temperature and read temperature.
For sure, I see how I could improve the logic with manual mode. I hope we some time find a way to make this happen. But even in its default state this is usable product.

Here is todays graph of set vs current temp in one of my rooms:
External thermometer shows 21°C in the afternoon, within a degree. It is quite good result.
And this is its valve % for the same time period:
It seems smart enough.
It does depend on my logic of starting the pump for hot water, I have it set to require at least 2°C of heat (sum of absolutes of differences of set and current temperature must bi at least 2°C for pump to start). But other than that, I only have cron schedule for this room (green graph), and it can be easily overwritten on the valve itself.
Maybe I add also pump run time for the same period. Other rooms had very small effect on these three graphs. Yesterday at 21:00 some other room needed heat.

I hope I shared some insight that may be useful for somebody.
I also hope that manual mode will be enabled. This is a good device and it could be even better. And they have great price in EU (I got mine from over 2 years and the price is stable 35-40€).

BR, Andraz


21.4 °C room temp (the value the Spirit has).
20 set temp.
15% valve open (that already heats 100%).
I set the Set temp back to 19:
Valve opens to 100%.
2 times I set the mode to Off / Heat: switches between 0 and 100%.
Again I switch to Off, and back to Heat: This time the valve opens 15%.

Completely random, unpredictabel, very expensive heating costs, and a room that is too warm. Useless stuff without direct valve control.

Maybe you have something else? My device:
Vendor: 0148 Eurotronics
Type: 0003:0001
Firmware: 0.16

vendor Eurotronics
zwave_deviceid 1
zwave_devicetype 3
manufacturerId 0148
manufacturerRef 0003:0001,0003:0003
zwave_version 0.16

Seems the same. I had to finetune the mounting on my valves with a spacer piece to make sure calibration then had correct 0-100%. I focused on 0%, this should turn off the valve completely. I guess this is OK in your configuration. As I understand, setting the mode to OFF and Full are working correctly, and you manage to completely shutoff or open the valve?
I think that if 15% is completely open already, then this can be a problem for internal algorithm. I’m sure that if you would leave it run for few minutes it would close to 0%. But it would be too hot, for sure.
I also notice that the first reaction of Spirit to setting temperature seems random, but in few minutes it will adjust according to the set/actual temperature. Best way to check its reactions is to have graphs of set/read temp and valve percentages. You have to set the reaction differences to small enough to get good graphs. I have 2-5 for temperature (meaning 0.2-0.5 changes are reported) and 5% for the valve change.

If nothing above explains the difference, then my setup works because my pump is not smart and is not running all the time. I control the pump with the differences between set/read temperature over all Spirits. If the sum is > 2°C I turn on the pump. So even if the valve is still open, if the temperature need is below 2°C radiator will not heat. This could be the key difference…

Anyway. If nothing works, you can still make your logic with the OFF and Full Power settings. You will need a separate SET_TEMP variable (you can’t use Spirits). Do your own calculation of differences between read temp and this variable and send OFF or FULL commands to the Spirit. It’s a workaround that I will maybe use for bedroom to get rid f the whine at low % of the valve.

BR, Andraž

Yes, controlling the pump in parallel could be the difference - I can’t control the water flow in my flat.

In theory I could script a rule for OFF / 30°C, but that’s what I have with my FS20 regulators, and I’m still not sure if that would really do it, and I actually don’t want it that way, for reasons. :slight_smile:

Yesterday the valve even opened while the mode was set to OFF. Restarting OH seems to have cured it.

I also did the adaption process of the Spirit again - which always failed, until I removed the batteries.
I also excluded it, removed it from OH & factory reset, to start over clean…

Side note: Charts (generally) do not really work (one of the many oddities I have with OH / HABmin). Maybe because I run it on a Mac.

I tried to graph the room and SET temp, and the dimmer, but it graphs at best the dimmer, and this is an example what the valve does, although the set temp is 3°C below the room temp:

I also realized that I couldn’t rely on the state shown in OH - I hear the valve moving, but it’s not updated in OH, looks like the Spirit does not report when the valve does it’s “secret magic”. So I set the polling time for the device from 1 day to 30 seconds, now the valve’s state is updated in OH reliable within 30 seconds and I see the irregularities better.

Actually we are a bit offtopic, explaining WHY direct valve control is desired. The Spirit is quite buggy for sure, and I think version number “0.16” is well justified, ha ha. :frowning:

This thread should disuss HOW direct valve control is possible (avoiding error 31). The zwave binding has not implemented it, and at least I couldn’t follow @Hans_B description how to implement it to the binding yourself.

So I ask @chris : “A few days” have passed. :wink: Is the plan dropped to implement it into the binding?

@Hans_B instructions are not clear enough and his post has some missing lines - xml tags.
For modifying the jar you should read @5iver’s post – Modify a zwave binding jar to add/change a zwave device while waiting for a build
Here are the lines to add to spirit_0.0.xml:

	  <channel id="basic_mode" typeId="eurotronic_spirit_00_000_basic_mode">
        <label>Basic mode</label>
          <property name="binding:*:DecimalType">COMMAND_CLASS_BASIC</property>


  <channel-type id="eurotronic_spirit_00_000_basic_mode">
    <label>Basic Mode</label>
    <description>Sets the Basic mode</description>
    <state pattern="%s">
        <option value="15">Off</option>
        <option value="0">Economy Heat</option>
        <option value="255">Heat</option>
        <option value="240">Full Power</option>
        <option value="254">Manual</option>

I’m also attaching the full modified file: spirit_0_0.xml (12.3 KB)
After compiling the jar (jar -uf org.openhab.binding.zwave-2.5.0.M1.jar ./ESH-INF/thing/eurotronic/spirit_0_0.xml as per @5iver’s instructions), I uninstalled the zwave binding and put the new jar in /usr/share/openhab2/addons/, removed the thing and discovered it again.
The new basic mode channel was detected:

Here a re the items used – it’s still in the test group :smile: :

Group gSpirit1 (gTest)

Dimmer Spirit1_Dimmer "Spirit1_Dimmer [%d %%]" (gSpirit1) {channel="zwave:device:1628a3e05cc:node85:switch_dimmer"}
Number:Temperature Spirit1_CurrentTemperature (gSpirit1) {channel="zwave:device:1628a3e05cc:node85:sensor_temperature"}
Number Spirit1_ExternalTemperature (gSpirit1) {channel="zwave:device:1628a3e05cc:node85:sensor_report"}
Number Spirit1_ThermostatMode (gSpirit1) {channel="zwave:device:1628a3e05cc:node85:thermostat_mode"}
Number:Temperature Spirit1_SetpointHeat (gSpirit1) {channel="zwave:device:1628a3e05cc:node85:thermostat_setpoint_heating"}
Number:Temperature Spirit1_SetpointEnergyHeat (gSpirit1) {channel="zwave:device:1628a3e05cc:node85:thermostat_setpoint_heating_econ"}
Switch Spirit1_AlarmSystem (gSpirit1) {channel="zwave:device:1628a3e05cc:node85:alarm_system"}
Switch Spirit1_AlarmPower (gSpirit1) {channel="zwave:device:1628a3e05cc:node85:alarm_power"}
Number Spirit1_BatteryLevel (gSpirit1) {channel="zwave:device:1628a3e05cc:node85:battery-level"}
Number Spirit1_BasicMode (gSpirit1) {channel="zwave:device:1628a3e05cc:node85:basic_mode"}

in openHAB’s console send the new mode to the basic_mode channel:

openhab> smarthome:send Spirit1_BasicMode 254

and here is the result:

2019-10-31 16:28:35.004 [nt.ItemStatePredictedEvent] - Spirit1_BasicMode predicted to become 254
2019-10-31 16:28:35.006 [vent.ItemStateChangedEvent] - Spirit1_BasicMode changed from NULL to 254
2019-10-31 16:28:36.872 [vent.ItemStateChangedEvent] - Spirit1_Dimmer changed from 38 to 20

Then, I tried the direct control of the valve and set the dimmer to some value - in this case 67:

2019-10-31 16:28:58.676 [ome.event.ItemCommandEvent] - Item 'Spirit1_Dimmer' received command 67
2019-10-31 16:28:58.677 [nt.ItemStatePredictedEvent] - Spirit1_Dimmer predicted to become 67
2019-10-31 16:28:58.684 [vent.ItemStateChangedEvent] - Spirit1_Dimmer changed from 20 to 67
2019-10-31 16:29:00.887 [vent.ItemStateChangedEvent] - Spirit1_ThermostatMode changed from 1 to 31
2019-10-31 16:42:55.038 [vent.ItemStateChangedEvent] - Spirit1_CurrentTemperature changed from 24.17 °C to 24.62 °C

The display of the TRV is displaying the valve opening percent, not the setpoint temp:

EDIT: HERE is the modified 2.5 M1 jar I’m using now


Thanks so much for your detailed instructions @Mihai_Badea. I downloaded your M1 jar, removed the zwave binding via PaperUI, logged out of OH, put your jar into
and I also tried the “native” location:
I also have a folder “Additional add-on files” inside “addons”, which also didn’t work.

I was playing with this and that - in all cases OH does not recognize the binding - Things remain “uninitialisied”, and in the binding list the zwave binding status is “not installed”. If I click “Install” it always downloads the official binding, and I don’t get basic mode.

Ok, to answer my own question, I guess I didn’t follow Mihai’s instructions carefully enough (it was late at night). :sleeping:

Maybe helpful for other tired noobs like me, this is how it worked for me today:

  • In PaperUI, note the node id of the Spirit, and trash it’s Thing.
  • In PaperUI, deinstall the zwave binding.
  • Shutdown OH
  • As OH does not remove the Thing’s XML file upon trashing a Thing: Remove the Thing’s XML file manually from:
    /openhab/userdata/zwave/network_xxxx_node_(Spirit’s id).xml
  • Download Mihai’s jar file and put it into openhab/addons/
  • Start OH
  • In PaperUI, install the official zwave binding from OH’s binding list.
  • In PaperUI, add the Spirit again from the Inbox. Boom: Basic Mode is in it’s chanel list present.

As I’m not using Thing-definition files (yet) I’m in PaperUI only. To find out where to send the “special 254 command” I did this:

  • In OH’s console, type: “smarthome:items list”
  • In the result, search for “basic_mode”. For me it is this line:
    zwave_device_8e7313d3_node16_basic_mode (Type=NumberItem, State=NULL, Label=Basic mode, Category=Temperature)
  • (Side note: You could also look into the Thing’s Channel list - look for the Basic Mode identifier and replace the “:” by “_”.)
  • In OH’s console, type: “smarthome:send zwave_device_8e7313d3_node16_basic_mode 254”
  • Console reply: Command has been sent successfully.
  • In PaperUI, immediately the mode changes to “Manual”, and the Dimmer-slider goes to 20.

And now I can use the slider to directly control the valve. :blush:

@Mihai_Badea: Kisses, beer, roses, hard drugs, whatever you want! :wink: :smiley:
Your very helpful instructions (and your ready-to-use jar) came on the right second - my plan for today was to try Domoticz, as I read it has valve control for the Spirit implemented ( ).
Thank you very much!

@chris: I (and probably some other people) still hope valve control will be implemented in the official binding, so we don’t have to hack the binding every time when it updates. :pleading_face:

That would be really great!

I don’t really know what this refers to - can you point me at the issue please? At a guess, if this is specific to a device, it would not be implemented in the binding.

Refer to this:

Here is the updated database file:

Correct me if I’m wrong, but there is no need to update the binding to control the valve of the Eurotronic Spirit directly. Update of the database should be enough…

As far as I understand it (OH noob) that would be one step forward - it would give us the required Basic Mode channel. But switching to “Manual” in the popup would still not make valve control work, as long as the special command is not send to the Basic Mode channel, like this:

smarthome:send zwave_device_8e7313d3_node16_basic_mode 254

Only after this is sent, the dimmer-slider controls the valve directly.

And I guess this is what @chris wants to think about:

No, I’m wrong. I completely missed there IS a new dropdown specifically for the basic mode - I oversaw it in the UI… And it sends the right command when Manual is chosen (no console command necessary):

Look at @Mihai_Badea Reply : Eurotronic Spirit - Unsupported mode type 31

This is how it looks like with Mihai’s modification.

I think the first popup can go away. I can switch with the bottom popup between Manual and Heat, and the Spirit reacts correctly.

Hallo Andraz,
I plan to implement in my appartment the Spirit thermostats. For now i’m running just on as a test.
My heating schedule is based on this topic: Heating Boilerplate - A Universal Temperature Control Solution with Modes I have the feeling that the valve stays fully opened all the time but the target temperatures are corrrectly displayed. Your’re scheme is based also on rules? Could you be so kind and share the .rules and .items file? Thank you in advance. Codrin

My heating rules are based on the same topic.


Group   Heating_Thermostat_Mode
Group   Heating_PresetNormal_Group
Group   Heizung

Number  WZ_TempNormal            "Wohnzimmer Preset (Normal Mode) [%.1f °C]"         (Heating_PresetNormal_Group)
Number  KI_TempNormal            "Küche Preset (Normal Mode) [%.1f °C]"              (Heating_PresetNormal_Group)

String  Heating_Mode             "Global Heating Mode [%s]"
Switch  Heating_UpdateHeaters    "Send Target Temperatures to Heaters"

Number  WZ_Temperatur            "Temperatur: [%.1f °C]"         <temperature> (Heizung,Wohnzimmer,Temperaturen) { channel="zwave:device:512:node6:sensor_temperature" }
Number  WZ_Modus                 "Modus: [%d]"                   <radiator> (Heating_Thermostat_Mode)            { channel="zwave:device:512:node6:thermostat_mode" }
Number  WZ_Batterie              "Batterie: [%d %%]"             <batterylevel> (Heizung,Batterien)              { channel="zwave:device:512:node6:battery-level" }
Number  WZ_Komfort_Temperatur    "Komforttemperatur: [%.1f °C]"  <temperature> (Heizung,Heizung_Soll)            { channel="zwave:device:512:node6:thermostat_setpoint_heating" }
Number  WZ_Spar_Temperatur       "Spartemperatur: [%.1f °C]"     <temperature> (Heizung,Heizung_Soll)            { channel="zwave:device:512:node6:thermostat_setpoint_heating_econ" }
Dimmer  WZ_Ventil_Stellung       "Ventilstellung: [%d %%]"       <DimmableLight> (Heizung)                       { channel="zwave:device:512:node6:switch_dimmer" }
Number  WZ_ext_Temperatur        "ext. Temperatur: [%.2f °C]"    <temperature>   (Temperaturen,Heizung)          { channel="zwave:device:512:node6:sensor_report" }

Number  KI_Temperatur            "Temperatur: [%.1f °C]"         <temperature> (Heizung,Wohnzimmer,Temperaturen) { channel="zwave:device:512:node3:sensor_temperature" }
Number  KI_Modus                 "Modus: [%d]"                   <radiator> (Heating_Thermostat_Mode)            { channel="zwave:device:512:node3:thermostat_mode" }
Number  KI_Batterie              "Batterie: [%d %%]"             <batterylevel> (Heizung,Batterien)              { channel="zwave:device:512:node3:battery-level" }
Number  KI_Komfort_Temperatur    "Komforttemperatur: [%.1f °C]"  <temperature> (Heizung,Heizung_Soll)            { channel="zwave:device:512:node3:thermostat_setpoint_heating" }
Number  KI_Spar_Temperatur       "Spartemperatur: [%.1f °C]"     <temperature> (Heizung,Heizung_Soll)            { channel="zwave:device:512:node3:thermostat_setpoint_heating_econ" }
Dimmer  KI_Ventil_Stellung       "Ventilstellung: [%d %%]"       <DimmableLight> (Heizung)                       { channel="zwave:device:512:node3:switch_dimmer" }
Number  KI_ext_Temperatur        "ext. Temperatur: [%.2f °C]"    <temperature>   (Temperaturen,Heizung)          { channel="zwave:device:512:node3:sensor_report" }


val String filename = "heating_mode.rules"

rule "Initialize uninitialized virtual Items"
    System started
    createTimer(now.plusSeconds(180)) [ |
        logInfo(filename, "Executing 'System started' rule for Heating")
        if (Heating_Mode.state == NULL)
        Heating_PresetNormal_Group.members.filter[item | item.state == NULL].forEach[item | item.postUpdate(19.0)]

rule "React on heating mode switch, send target temperatures"
    Item Heating_Mode received update or
    Item Heating_UpdateHeaters received command ON
    logInfo(filename, "Heating Mode: " + Heating_Mode.state)
    switch Heating_Mode.state {
        case "NORMAL": {
            WZ_Komfort_Temperatur.sendCommand(WZ_TempNormal.state as Number)
            KI_Komfort_Temperatur.sendCommand(KI_TempNormal.state as Number)
        case "PARTY": {
        case "SICKDAY": {
        case "WEEKEND_TRIP": {
        case "AWAY": {
        case "OFF_SUMMER": {
        default : { logError(filename, "Heating Mode unknown: " + Heating_Mode.state) }

// ========================
// mode resets

rule "End PARTY and SICKDAY mode at 2:00 in the night"
    Time cron "0 0 2 ? * * *"
    if (Heating_Mode.state == "PARTY" || Heating_Mode.state == "SICKDAY") {

rule "End WEEKEND_TRIP mode at 13:00 on Sunday"
    Time cron "0 0 13 ? * SUN *"
    if (Heating_Mode.state == "WEEKEND_TRIP") {

// ========================
// NORMAL schedule

rule "MON-FRI, 13:00"
    Time cron "0 0 13 ? * MON-FRI *"

rule "SAT-SUN, 07:00"
    Time cron "0 0 07 ? * SAT-SUN *"

rule "SUN-THU, 22:00"
    Time cron "0 0 22 ? * SUN-THU *"

rule "FRI-SAT, 23:00"
    Time cron "0 0 23 ? * FRI,SAT *"

rule "MON-FRI, 02:00"
    Time cron "0 0 02 ? * MON-FRI *"

rule "MON-FRI, 06:00"
    Time cron "0 0 06 ? * MON-FRI *"

Thank you Franck!

@chris Just thought I’d add my ‘+1’ to this discussion - I’d like to see support for Manual mode implemented in OH if possible.

The manual mode is available isn’t it? It would be good if someone could summarise exactly what is still required in an issue on github. I think that what is needed is a channel linked to the BASIC command class? Or is there something more required?

I opened a ticket for your zwave database last week where the manual mode issue is summarized. An additional channel for the basic command class is required, because the manual mode of thermostat mode doesn’t work.

Here is the solution:

@chris Yes, the Manual mode is already available on the device as a Thermostat Mode. However it needs to be sent the value ‘0xFE’ (‘Manufacturer Specific’) via the Basic command class first before it will recognise it. Once that has been sent, the device will respond to the ‘0x1F’ (‘Manufacturer Specific’) command via the existing ‘thermostat_mode’ Channel. At that point, direct control of the valve position will be available via the existing ‘switch_dimmer’ Channel.

I suppose one way to achieve this would be in the device configuration. A ‘Manual mode’ option could send the two necessary commands. However, this would bake in the behaviour so wouldn’t allow it to be changed again (I presume) without editing the Thing’s configuration.

As you mentioned, maybe the simplest way would be to make the Basic mode available as a Channel in the binding, as has been discussed (and achieved by hacking) above. Then the commands could be sent ‘manually’. I imagine the sort of users who want to mess around with direct control of the valve would be fine with this.

Please open an issue on Github - that way it has some visibility. If it’s here, or in my email, then it will get lost. A nice, clear, concise description of what is needed is much easier (for me at least :wink: ) than having to search through the forum to work out what’s up :sunglasses:.