Heizungsschalter

für eine Oekofen Heizung mit Openhab

Motivation

Die meisten Leute schalten das Licht aus, wenn sie Haus oder Wohnung verlassen. Der größte Energieverbraucher ist aber die Heizung. Es macht also Sinn, einen Schalter im Flur vor dem Ausgang zu haben, mit dem man die Heizung ausschalten oder absenken kann.

Systemumgebung

Wir haben seit kurzem eine Pelletheizung von Oekofen und schon etwas länger eine Infrastruktur für Hausautomatisierung mit Openhab und Mosquitto.

Komponenten

Schalter

Als Schalter wird ein mit Tasmota geflashter Sonoff SwitchMan M5-1C-86 verwendet. Die geschalteten Ausgänge werden nicht genutzt, dieser Schalter zeigt aber den Schaltzustand über ein LED an. Der Schalter wird als MQTT Thing in Openhab eingerichtet.

Channel

MQTT State Topic

stat/schalter-heizung/POWER1

MQTT Command Topic

cmnd/schalter-heizung/POWER1



Heizung

Heizungen von Ökofen (Pelletronic 4.02b in meinem Fall) haben ein via http zugängliches JSON Interface. Dieses ist unter

http://heizung:4321/****/

zu erreichen. Unter dieser URL findet man eine kurze Dokumentation.


Die Heizung wird entsprechend als HTTP Thing konfiguriert.


UID: http:url:<id>
label: Heizung
thingTypeUID: http:url
configuration:
  authMode: BASIC_PREEMPTIVE
  ignoreSSLErrors: false
  baseURL: http://<ip>:4321/<json-pwd>
  delay: 3000
  stateMethod: GET
  refresh: 60
  commandMethod: GET
  encoding: iso8859-1
  timeout: 3000
  bufferSize: 2048
channels:
…
  - id: betriebsart-heizkreis-int
    channelTypeUID: http:number
    label: Betriebsart Heizkreis (int)
    description: ""
    configuration:
      mode: READWRITE
      commandTransformation:
        - ""
      stateExtension: all
      commandExtension: hk1.mode_auto=%2$s
      stateTransformation:
        - JSONPATH:$.hk1.mode_auto


Nur der für den Schalter relevante Channel wurde gelistet. Für diesen Schalter wird ein Item angelegt.


label: Betriebsart Heizkreis (int)
type: Number
category: ""
groupNames:
  - SchalterHeizungGruppe
tags:
- Point

Die Gruppe kommt im nächsten Abschnitt.

Gruppe HeizungSchalter

Die Synchronisation der Zustände von Schalter und Heizung ist erstaunlich komplex. Um auf alle Zustandsänderungen in einer Rule reagieren zu können wird eine Gruppe benötigt, die beide Items enthält.

Die Gruppe wird als Item vom Typ Gruppe angelegt. Sie hat den Schalter und das Betriebsart-Item als direkte Mitgleder.

Transformation

Der Heizkreis der Heizung hat 4 nummerierte Zustände, während der Schalter nur 2 hat. Deshalb wird folgendes Mapping verwendet:

$ cat /etc/openhab/transform/heizungsschalter.map 
ON = 1
OFF = 3
# Aus
0 = OFF
# Auto
1 = ON
# Heizen
2 = ON
# Absenken
3 = OFF

Rule

configuration: {}
triggers:
  - id: "1"
    configuration:
      groupName: SchalterHeizungGruppe
    type: core.GroupStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      considerConditions: true
      ruleUIDs:
        - 9809810faf
    type: core.RunRuleAction



Die Action verweist auf ein Script. Dieses ist eine angepasste Variante aus einem Forumsbeitrag von Udo Hartmann.

// global var has to be defined first (no rules ahead)
var Boolean lock = false

// check if rule already started
if(lock)
  // and break if true
  return;   

// lock rule
lock = true  

val toStateOnOff = [ Item s |
	var state = s.state.toString
    if (state != "ON" && state != "OFF") {
		state = transform("MAP", "heizungsschalter.map", state)
	}
	state
]


logInfo("test", "HeizungSchalterSync called for " + triggeringItem.name);
// get a list of Alarm Switch Items without the triggering one.
SchalterHeizungGruppe.members.filter[j|j.name != triggeringItem.name]
  // only ON/OFF changes should switch
  .filter[j|toStateOnOff.apply(j) != toStateOnOff.apply(triggeringItem)]
  .forEach[i| 
  // and send the command to switch state
  i.sendCommand(
        transform("MAP", "heizungsschalter.map", triggeringItem.state.toString))                        
]
// give some time to rest
Thread::sleep(500)                                                      
// Unlock rule
lock = false