2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.loxone.internal.controls;
15 import static org.openhab.binding.loxone.internal.LxBindingConstants.*;
17 import java.io.IOException;
19 import org.openhab.binding.loxone.internal.types.LxUuid;
20 import org.openhab.core.library.types.DecimalType;
21 import org.openhab.core.library.types.OnOffType;
22 import org.openhab.core.thing.type.ChannelTypeUID;
23 import org.openhab.core.types.Command;
24 import org.openhab.core.types.State;
27 * Loxone Miniserver's Sauna
29 * @author Pawel Pieczul - initial contribution
32 class LxControlSauna extends LxControl {
34 static class Factory extends LxControlInstance {
36 LxControl create(LxUuid uuid) {
37 return new LxControlSauna(uuid);
46 private static final String STATE_ACTIVE = "active";
47 private static final String STATE_POWER_LEVEL = "power";
48 private static final String STATE_TEMP_ACTUAL = "tempactual";
49 private static final String STATE_TEMP_BENCH = "tempbench";
50 private static final String STATE_TEMP_TARGET = "temptarget";
51 private static final String STATE_FAN = "fan";
52 private static final String STATE_DRYING = "drying";
53 private static final String STATE_DOOR_CLOSED = "doorclosed";
54 private static final String STATE_ERROR = "error";
55 private static final String STATE_VAPOR_POWER_LEVEL = "vaporpower";
56 private static final String STATE_SAUNA_ERROR = "saunaerror";
57 private static final String STATE_TIMER = "timer";
58 private static final String STATE_TIMER_TOTAL = "timertotal";
59 private static final String STATE_OUT_OF_WATER = "lesswater";
60 private static final String STATE_HUMIDITY_ACTUAL = "humidityactual";
61 private static final String STATE_HUMIDITY_TARGET = "humiditytarget";
62 private static final String STATE_EVAPORATOR_MODE = "mode";
64 private static final String CMD_ON = "on";
65 private static final String CMD_OFF = "off";
66 private static final String CMD_FAN_ON = "fanon";
67 private static final String CMD_FAN_OFF = "fanoff";
68 private static final String CMD_SET_TEMP_TARGET = "temp/";
69 private static final String CMD_SET_HUMIDITY_TARGET = "humidity/";
70 private static final String CMD_SET_EVAPORATOR_MODE = "mode/";
71 private static final String CMD_NEXT_STATE = "pulse";
72 private static final String CMD_START_TIMER = "starttimer";
74 LxControlSauna(LxUuid uuid) {
79 public void initialize(LxControlConfig config) {
80 super.initialize(config);
81 addChannel("Switch", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_SWITCH),
82 defaultChannelLabel + " / Active", "Sauna Active", tags, this::handleSaunaActivateCommands,
83 () -> getStateOnOffValue(STATE_ACTIVE));
84 addChannel("Number", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_RO_NUMBER),
85 defaultChannelLabel + " / Power", "Sauna Power Level", tags, null,
86 () -> getStatePercentValue(STATE_POWER_LEVEL));
87 addChannel("Number", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_RO_NUMBER),
88 defaultChannelLabel + " / Temperature / Actual", "Actual Temperature", tags, null,
89 () -> getStateDecimalValue(STATE_TEMP_ACTUAL));
90 addChannel("Number", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_RO_NUMBER),
91 defaultChannelLabel + " / Temperature / Bench", "Bench Temperature", tags, null,
92 () -> getStateDecimalValue(STATE_TEMP_BENCH));
93 addChannel("Number", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_NUMBER),
94 defaultChannelLabel + " / Temperature / Target", "Target Temperature", tags,
95 (cmd) -> handleSetNumberCommands(cmd, CMD_SET_TEMP_TARGET),
96 () -> getStateDecimalValue(STATE_TEMP_TARGET));
97 addChannel("Switch", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_SWITCH),
98 defaultChannelLabel + " / Fan", "Fan", tags, this::handleFanCommands,
99 () -> getStateOnOffValue(STATE_FAN));
100 addChannel("Switch", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_RO_SWITCH),
101 defaultChannelLabel + " / Drying", "Drying", tags, null, () -> getStateOnOffValue(STATE_DRYING));
102 if (details != null && details.hasDoorSensor != null && details.hasDoorSensor) {
103 addChannel("Switch", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_RO_SWITCH),
104 defaultChannelLabel + " / Door Closed", "Door Closed", tags, null,
105 () -> getStateOnOffValue(STATE_DOOR_CLOSED));
107 addChannel("Number", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_RO_NUMBER),
108 defaultChannelLabel + " / Error Code", "Error Code", tags, null, () -> getStateErrorValue());
109 addChannel("Number", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_RO_NUMBER),
110 defaultChannelLabel + " / Timer / Current", "Current Timer Value", tags, null,
111 () -> getStateDecimalValue(STATE_TIMER));
112 addChannel("Switch", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_SWITCH),
113 defaultChannelLabel + " / Timer / Trigger", "Start Timer", tags,
114 (cmd) -> handleTriggerCommands(cmd, CMD_START_TIMER), () -> OnOffType.OFF);
115 addChannel("Number", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_RO_NUMBER),
116 defaultChannelLabel + " / Timer / Total", "Total Timer Value", tags, null,
117 () -> getStateDecimalValue(STATE_TIMER_TOTAL));
118 if (details != null && details.hasVaporizer != null && details.hasVaporizer) {
119 addChannel("Number", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_RO_NUMBER),
120 defaultChannelLabel + " / Evaporator / Power", "Evaporator Power Level", tags, null,
121 () -> getStatePercentValue(STATE_VAPOR_POWER_LEVEL));
122 addChannel("Switch", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_RO_SWITCH),
123 defaultChannelLabel + " / Evaporator / Out Of Water", "Evaporator Out Of Water", tags, null,
124 () -> getStateOnOffValue(STATE_OUT_OF_WATER));
125 addChannel("Number", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_RO_NUMBER),
126 defaultChannelLabel + " / Evaporator / Humidity / Actual", "Actual Humidity", tags, null,
127 () -> getStateDecimalValue(STATE_HUMIDITY_ACTUAL));
128 addChannel("Number", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_NUMBER),
129 defaultChannelLabel + " / Evaporator / Humidity / Target", "Target Humidity", tags,
130 (cmd) -> handleSetNumberCommands(cmd, CMD_SET_HUMIDITY_TARGET),
131 () -> getStateDecimalValue(STATE_HUMIDITY_TARGET));
132 addChannel("Number", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_NUMBER),
133 defaultChannelLabel + " / Evaporator / Mode", "Evaporator Mode", tags, this::handleModeCommands,
134 () -> getStateDecimalValue(STATE_EVAPORATOR_MODE));
136 addChannel("Switch", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_SWITCH),
137 defaultChannelLabel + " / Next State", "Trigger Next State", tags,
138 (cmd) -> handleTriggerCommands(cmd, CMD_NEXT_STATE), () -> OnOffType.OFF);
141 private void handleSaunaActivateCommands(Command command) throws IOException {
142 if (command instanceof OnOffType onOffCommand) {
143 if (onOffCommand == OnOffType.ON) {
151 private void handleSetNumberCommands(Command command, String prefix) throws IOException {
152 if (command instanceof DecimalType decimalCommand) {
153 Double value = decimalCommand.doubleValue();
154 sendAction(prefix + value.toString());
158 private void handleFanCommands(Command command) throws IOException {
159 if (command instanceof OnOffType onOffCommand) {
160 if (onOffCommand == OnOffType.ON) {
161 sendAction(CMD_FAN_ON);
163 sendAction(CMD_FAN_OFF);
168 private void handleTriggerCommands(Command command, String prefix) throws IOException {
169 if (command instanceof OnOffType onOffCommand && onOffCommand == OnOffType.ON) {
174 private void handleModeCommands(Command command) throws IOException {
175 if (command instanceof DecimalType decimalCommand) {
176 Double value = decimalCommand.doubleValue();
177 // per API there are 7 evaporator modes selected with number 0-6
178 if (value % 1 == 0 && value >= 0.0 && value <= 6.0) {
179 sendAction(CMD_SET_EVAPORATOR_MODE + value.toString());
184 private State getStateErrorValue() {
185 Double val = getStateDoubleValue(STATE_ERROR);
186 if (val != null && val != 0.0) {
187 return getStateDecimalValue(STATE_SAUNA_ERROR);
189 return DecimalType.ZERO;