[openwebnet] adding support for central unit (#12062)

* - read 'standAlone' flag from thing
- send standAlone flag to own4j for setting the temperature on central unit
- own4j 0.7.1 required
* added localmode and central unit thing
* added localOffSet channel to readme.md
* added remoteControl, batteryStatus and modeCentralUnit for bus_thermo_cu
* added weekly and scenarios to modeCentralUnit
* - manual setting of a zone to T temperature (with persistence in central unit)
- manual setting of central unit to T temperature (all zones)
- set the central unit in OFF mode (all zones)
- set central unit in thermal protection (all zones)
- set central unit in antifreeze mode (all zones)
- weekly program activation command (all zones)
- scenario activation command (all zones)
* renamed cu's channels name
* removed unused channel 'modeCentralUnit" from readme
* fix #12298
* - add configuration section (where) for BusThermoCentralUnit
- strings ("OK", "KO", "ENABLED", "DISABLED" converted to constants
- fix typo

Signed-off-by: Conte Andrea <andrea@conte.com>

Co-authored-by: M Valla <12682715+mvalla@users.noreply.github.com>
This commit is contained in:
Conte Andrea
2022-02-27 19:11:45 +01:00
committed by GitHub
parent 339df2cb3a
commit b2765a3895
8 changed files with 414 additions and 81 deletions

View File

@@ -59,6 +59,8 @@ public class OpenWebNetBindingConstants {
public static final String THING_LABEL_BUS_THERMO_SENSOR = "Thermo Sensor";
public static final ThingTypeUID THING_TYPE_BUS_THERMO_ZONE = new ThingTypeUID(BINDING_ID, "bus_thermo_zone");
public static final String THING_LABEL_BUS_THERMO_ZONE = "Thermo Zone";
public static final ThingTypeUID THING_TYPE_BUS_THERMO_CU = new ThingTypeUID(BINDING_ID, "bus_thermo_cu");
public static final String THING_LABEL_BUS_THERMO_CU = "Thermo Central Unit";
public static final ThingTypeUID THING_TYPE_BUS_CEN_SCENARIO_CONTROL = new ThingTypeUID(BINDING_ID,
"bus_cen_scenario_control");
public static final String THING_LABEL_BUS_CEN_SCENARIO_CONTROL = "CEN Control";
@@ -91,7 +93,7 @@ public class OpenWebNetBindingConstants {
THING_TYPE_BUS_AUTOMATION);
// ## Thermoregulation
public static final Set<ThingTypeUID> THERMOREGULATION_SUPPORTED_THING_TYPES = Set.of(THING_TYPE_BUS_THERMO_ZONE,
THING_TYPE_BUS_THERMO_SENSOR);
THING_TYPE_BUS_THERMO_SENSOR, THING_TYPE_BUS_THERMO_CU);
// ## Energy Management
public static final Set<ThingTypeUID> ENERGY_MANAGEMENT_SUPPORTED_THING_TYPES = Set.of(THING_TYPE_BUS_ENERGY_METER);
// ## CEN/CEN+ Scenario
@@ -126,6 +128,12 @@ public class OpenWebNetBindingConstants {
public static final String CHANNEL_CONDITIONING_VALVES = "conditioningValves";
public static final String CHANNEL_HEATING_VALVES = "heatingValves";
public static final String CHANNEL_ACTUATORS = "actuators";
public static final String CHANNEL_LOCAL_OFFSET = "localOffset";
public static final String CHANNEL_CU_REMOTE_CONTROL = "remoteControl";
public static final String CHANNEL_CU_BATTERY_STATUS = "batteryStatus";
public static final String CHANNEL_CU_WEEKLY_PROGRAM_NUMBER = "weeklyProgram";
public static final String CHANNEL_CU_SCENARIO_PROGRAM_NUMBER = "scenarioProgram";
// energy management
public static final String CHANNEL_POWER = "power";
// scenario button channels
@@ -138,6 +146,8 @@ public class OpenWebNetBindingConstants {
public static final String CONFIG_PROPERTY_WHERE = "where";
public static final String CONFIG_PROPERTY_SHUTTER_RUN = "shutterRun";
public static final String CONFIG_PROPERTY_SCENARIO_BUTTONS = "buttons";
public static final String CONFIG_PROPERTY_STANDALONE = "standAlone";
// gw config properties
public static final String CONFIG_PROPERTY_HOST = "host";
public static final String CONFIG_PROPERTY_SERIAL_PORT = "serialPort";

View File

@@ -144,7 +144,9 @@ public class OpenWebNetDeviceDiscoveryService extends AbstractDiscoveryService
break;
}
case SCS_THERMO_CENTRAL_UNIT: {
logger.warn("newDiscoveryResult() deviceType={} is not supported yet (WHERE={})", deviceType, where);
thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_CU;
thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_THERMO_CU;
deviceWho = Who.THERMOREGULATION;
break;
}
case SCS_ENERGY_METER: {

View File

@@ -12,7 +12,19 @@
*/
package org.openhab.binding.openwebnet.internal.handler;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.*;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_ACTUATORS;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_CONDITIONING_VALVES;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_CU_BATTERY_STATUS;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_CU_REMOTE_CONTROL;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_CU_SCENARIO_PROGRAM_NUMBER;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_CU_WEEKLY_PROGRAM_NUMBER;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_FAN_SPEED;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_FUNCTION;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_HEATING_VALVES;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_LOCAL_OFFSET;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_MODE;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_TEMPERATURE;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_TEMP_SETPOINT;
import java.util.Set;
@@ -25,6 +37,7 @@ import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.types.Command;
@@ -34,6 +47,7 @@ import org.openwebnet4j.message.BaseOpenMessage;
import org.openwebnet4j.message.FrameException;
import org.openwebnet4j.message.MalformedFrameException;
import org.openwebnet4j.message.Thermoregulation;
import org.openwebnet4j.message.Thermoregulation.WhatThermo;
import org.openwebnet4j.message.Where;
import org.openwebnet4j.message.WhereThermo;
import org.openwebnet4j.message.Who;
@@ -55,16 +69,49 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.THERMOREGULATION_SUPPORTED_THING_TYPES;
private boolean isTempSensor = false; // is the thing a sensor ?
private double currentSetPointTemp = 11.5d; // 11.5 is the default setTemp used in MyHomeUP mobile app
private Thermoregulation.Function currentFunction = Thermoregulation.Function.GENERIC;
private boolean isStandAlone = false;
private boolean isCentralUnit = false;
private String programNumber = "";
private static final String CU_REMOTE_CONTROL_ENABLED = "ENABLED";
private static final String CU_REMOTE_CONTROL_DISABLED = "DISABLED";
private static final String CU_BATTERY_OK = "OK";
private static final String CU_BATTERY_KO = "KO";
public OpenWebNetThermoregulationHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
super.initialize();
ThingTypeUID thingType = thing.getThingTypeUID();
isCentralUnit = OpenWebNetBindingConstants.THING_TYPE_BUS_THERMO_CU.equals(thingType);
if (!isCentralUnit) {
Object standAloneConfig = getConfig().get(OpenWebNetBindingConstants.CONFIG_PROPERTY_STANDALONE);
if (standAloneConfig != null) {
// null in case of thermo_sensor
isStandAlone = Boolean.parseBoolean(standAloneConfig.toString());
}
} else {
// central unit must have WHERE=0
if (!deviceWhere.value().equals("0")) {
logger.warn("initialize() Invalid WHERE={} for Central Unit.", deviceWhere.value());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/offline.conf-error-where");
}
}
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
super.bridgeStatusChanged(bridgeStatusInfo);
@@ -89,6 +136,10 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
case CHANNEL_FAN_SPEED:
handleSetFanSpeed(command);
break;
case CHANNEL_CU_WEEKLY_PROGRAM_NUMBER:
case CHANNEL_CU_SCENARIO_PROGRAM_NUMBER:
handleSetProgramNumber(command);
break;
default: {
logger.warn("handleChannelCommand() Unsupported ChannelUID {}", channel.getId());
}
@@ -101,34 +152,9 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
refreshDevice(false);
}
@Override
protected void refreshDevice(boolean refreshAll) {
logger.debug("--- refreshDevice() : refreshing SINGLE... ({})", thing.getUID());
if (deviceWhere != null) {
String w = deviceWhere.value();
try {
send(Thermoregulation.requestTemperature(w));
if (!this.isTempSensor) {
// for bus_thermo_zone request also other single channels updates
send(Thermoregulation.requestSetPointTemperature(w));
send(Thermoregulation.requestFanCoilSpeed(w));
send(Thermoregulation.requestMode(w));
send(Thermoregulation.requestValvesStatus(w));
send(Thermoregulation.requestActuatorsStatus(w));
}
} catch (OWNException e) {
logger.warn("refreshDevice() where='{}' returned OWNException {}", w, e.getMessage());
}
}
}
@Override
protected Where buildBusWhere(String wStr) throws IllegalArgumentException {
WhereThermo wt = new WhereThermo(wStr);
if (wt.isProbe()) {
isTempSensor = true;
}
return wt;
return new WhereThermo(wStr);
}
@Override
@@ -156,6 +182,21 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
}
}
private void handleSetProgramNumber(Command command) {
if (command instanceof DecimalType) {
if (!isCentralUnit) {
logger.warn("handleSetProgramNumber() This command can be sent only for a Central Unit.");
return;
}
programNumber = command.toString();
logger.debug("handleSetProgramNumber() Program number set to {}", programNumber);
} else {
logger.warn("handleSetProgramNumber() Unsupported command {} for thing {}", command, getThing().getUID());
}
}
private void handleSetpoint(Command command) {
if (command instanceof QuantityType || command instanceof DecimalType) {
Where w = deviceWhere;
@@ -170,7 +211,8 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
newTemp = ((DecimalType) command).doubleValue();
}
try {
send(Thermoregulation.requestWriteSetpointTemperature(w.value(), newTemp, currentFunction));
send(Thermoregulation.requestWriteSetpointTemperature(getWhere(w.value()), newTemp,
currentFunction));
} catch (MalformedFrameException | OWNException e) {
logger.warn("handleSetpoint() {}", e.getMessage());
}
@@ -185,8 +227,15 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
Where w = deviceWhere;
if (w != null) {
try {
Thermoregulation.OperationMode mode = Thermoregulation.OperationMode.valueOf(command.toString());
send(Thermoregulation.requestWriteMode(w.value(), mode, currentFunction, currentSetPointTemp));
Thermoregulation.OperationMode new_mode = Thermoregulation.OperationMode.OFF;
if (isCentralUnit && WhatThermo.isComplex(command.toString()))
new_mode = Thermoregulation.OperationMode.valueOf(command.toString() + "_" + programNumber);
else
new_mode = Thermoregulation.OperationMode.valueOf(command.toString());
send(Thermoregulation.requestWriteMode(getWhere(w.value()), new_mode, currentFunction,
currentSetPointTemp));
} catch (OWNException e) {
logger.warn("handleMode() {}", e.getMessage());
} catch (IllegalArgumentException e) {
@@ -199,6 +248,14 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
}
}
private String getWhere(String where) {
if (isCentralUnit) {
return "#0";
} else {
return isStandAlone ? where : "#" + where;
}
}
private void handleFunction(Command command) {
if (command instanceof StringType) {
Where w = deviceWhere;
@@ -221,6 +278,23 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
@Override
protected void handleMessage(BaseOpenMessage msg) {
super.handleMessage(msg);
if (isCentralUnit) {
if (msg.isCommand()) {
updateModeAndFunction((Thermoregulation) msg);
}
if (msg.getWhat() == Thermoregulation.WhatThermo.REMOTE_CONTROL_DISABLED) {
updateCURemoteControlStatus(CU_REMOTE_CONTROL_DISABLED);
} else if (msg.getWhat() == Thermoregulation.WhatThermo.REMOTE_CONTROL_ENABLED) {
updateCURemoteControlStatus(CU_REMOTE_CONTROL_ENABLED);
} else if (msg.getWhat() == Thermoregulation.WhatThermo.BATTERY_KO) {
updateCUBatteryStatus(CU_BATTERY_KO);
}
return;
}
if (msg.isCommand()) {
updateModeAndFunction((Thermoregulation) msg);
} else {
@@ -239,6 +313,8 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
updateActuatorStatus((Thermoregulation) msg);
} else if (msg.getDim() == Thermoregulation.DimThermo.FAN_COIL_SPEED) {
updateFanCoilSpeed((Thermoregulation) msg);
} else if (msg.getDim() == Thermoregulation.DimThermo.OFFSET) {
updateLocalOffset((Thermoregulation) msg);
} else {
logger.debug("handleMessage() Ignoring unsupported DIM {} for thing {}. Frame={}", msg.getDim(),
getThing().getUID(), msg);
@@ -252,7 +328,6 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
tmsg.getFrameValue());
return;
}
Thermoregulation.WhatThermo w = Thermoregulation.WhatThermo.fromValue(tmsg.getWhat().value());
if (w.getMode() == null) {
@@ -267,14 +342,8 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
Thermoregulation.OperationMode mode = w.getMode();
Thermoregulation.Function function = w.getFunction();
if (w == Thermoregulation.WhatThermo.HEATING) {
function = Thermoregulation.Function.HEATING;
} else if (w == Thermoregulation.WhatThermo.CONDITIONING) {
function = Thermoregulation.Function.COOLING;
}
updateState(CHANNEL_MODE, new StringType(mode.toString()));
updateState(CHANNEL_FUNCTION, new StringType(function.toString()));
updateState(CHANNEL_MODE, new StringType(mode.toString()));
// store current function
currentFunction = function;
@@ -336,4 +405,82 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
updateState(CHANNEL_ACTUATORS, UnDefType.UNDEF);
}
}
private void updateLocalOffset(Thermoregulation tmsg) {
try {
Thermoregulation.LocalOffset offset = Thermoregulation.parseLocalOffset(tmsg);
updateState(CHANNEL_LOCAL_OFFSET, new StringType(offset.toString()));
logger.debug("updateLocalOffset() {}: {}", tmsg, offset.toString());
} catch (FrameException e) {
logger.warn("updateLocalOffset() FrameException on frame {}: {}", tmsg, e.getMessage());
updateState(CHANNEL_LOCAL_OFFSET, UnDefType.UNDEF);
}
}
private void updateCURemoteControlStatus(String status) {
updateState(CHANNEL_CU_REMOTE_CONTROL, new StringType(status));
logger.debug("updateCURemoteControlStatus(): {}", status);
}
private void updateCUBatteryStatus(String status) {
updateState(CHANNEL_CU_BATTERY_STATUS, new StringType(status));
logger.debug("updateCUBatteryStatus(): {}", status);
}
private Boolean channelExists(String channelID) {
return thing.getChannel("openwebnet:" + channelID) != null;
}
@Override
protected void refreshDevice(boolean refreshAll) {
logger.debug("--- refreshDevice() : refreshing SINGLE... ({})", thing.getUID());
if (isCentralUnit) {
// TODO: 4 zone central -> zone #0 CAN be also a zone with its temp.. with 99-zones central no!
// let's assume it's a 99 zone
try {
// there isn't a message used for setting OK for battery status so let's assume
// it's OK and then change to KO if according message is received
updateCUBatteryStatus(CU_BATTERY_OK);
send(Thermoregulation.requestStatus("#0"));
} catch (OWNException e) {
logger.warn("refreshDevice() central unit returned OWNException {}", e.getMessage());
}
return;
}
if (deviceWhere != null) {
String w = deviceWhere.value();
try {
send(Thermoregulation.requestTemperature(w));
if (!((WhereThermo) deviceWhere).isProbe()) {
// for bus_thermo_zone request also other single channels updates
send(Thermoregulation.requestSetPointTemperature(w));
send(Thermoregulation.requestMode(w));
// refresh ONLY subscribed channels
if (channelExists(CHANNEL_FAN_SPEED)) {
send(Thermoregulation.requestFanCoilSpeed(w));
}
if (channelExists(CHANNEL_CONDITIONING_VALVES) || channelExists(CHANNEL_HEATING_VALVES)) {
send(Thermoregulation.requestValvesStatus(w));
}
if (channelExists(CHANNEL_ACTUATORS)) {
send(Thermoregulation.requestActuatorsStatus(w));
}
if (channelExists(CHANNEL_LOCAL_OFFSET)) {
send(Thermoregulation.requestLocalOffset(w));
}
}
} catch (OWNException e) {
logger.warn("refreshDevice() where='{}' returned OWNException {}", w, e.getMessage());
}
}
}
}

View File

@@ -12,7 +12,9 @@
*/
package org.openhab.binding.openwebnet.internal.handler;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.*;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CONFIG_PROPERTY_WHERE;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.PROPERTY_OWNID;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.THING_STATE_REQ_TIMEOUT_SEC;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="openwebnet"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Thing for BUS Thermo Central Unit -->
<thing-type id="bus_thermo_cu">
<supported-bridge-type-refs>
<bridge-type-ref id="bus_gateway"/>
</supported-bridge-type-refs>
<label>Thermo Central Unit</label>
<description>A OpenWebNet BUS/SCS configured thermo Central Unit.</description>
<channels>
<!-- read only -->
<channel id="remoteControl" typeId="remoteControl"/>
<channel id="batteryStatus" typeId="batteryStatus"/>
<!-- read/write -->
<channel id="setpointTemperature" typeId="setpointTemperature"/>
<channel id="mode" typeId="modeCentralUnit"/>
<channel id="weeklyProgram" typeId="weeklyProgramCentralUnit"/>
<channel id="scenarioProgram" typeId="scenarioProgramCentralUnit"/>
</channels>
<properties>
<property name="vendor">BTicino/Legrand</property>
<property name="model">BTicino Central Unit 3550 (99 zones) or BTI-L/NT/HC/4695 (4 zones) </property>
<property name="ownDeviceType">430</property>
</properties>
<representation-property>ownId</representation-property>
<config-description>
<parameter name="where" type="text" readOnly="true">
<label>OpenWebNet Address (where)</label>
<description>The Central Unit can only assume where=0.</description>
<default>0</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -19,6 +19,7 @@
<channel id="conditioningValves" typeId="conditioningValves"/>
<channel id="heatingValves" typeId="heatingValves"/>
<channel id="actuators" typeId="actuators"/>
<channel id="localOffset" typeId="localOffset"/>
<!-- read/write -->
<channel id="setpointTemperature" typeId="setpointTemperature"/>
<channel id="function" typeId="function"/>

View File

@@ -171,6 +171,104 @@
</state>
</channel-type>
<channel-type id="localOffset" advanced="true">
<item-type>String</item-type>
<label>Local Offset</label>
<description>Local knob status (read only)</description>
<state readOnly="true">
<options>
<option value="OFF">OFF</option>
<option value="PROTECTION">PROTECTION</option>
<option value="PLUS_3">+3</option>
<option value="PLUS_2">+2</option>
<option value="PLUS_1">+1</option>
<option value="NORMAL">0</option>
<option value="MINUS_1">-1</option>
<option value="MINUS_2">-2</option>
<option value="MINUS_3">-3</option>
</options>
</state>
</channel-type>
<channel-type id="modeCentralUnit">
<item-type>String</item-type>
<label>Central Unit Mode</label>
<description>Set mode of the Central Unit (read/write)</description>
<state>
<options>
<option value="MANUAL">Manual</option>
<option value="PROTECTION">Protection</option>
<option value="OFF">Off</option>
<option value="WEEKLY">Weekly</option>
<option value="SCENARIO">Scenario</option>
</options>
</state>
</channel-type>
<channel-type id="weeklyProgramCentralUnit">
<item-type>Number</item-type>
<label>Weekly Program Number</label>
<description>Set weekly program number for the Central Unit, valid only with Central Unit mode = "WEEKLY" (read/write)</description>
<state>
<options>
<option value="1">Program 1</option>
<option value="2">Program 2</option>
<option value="3">Program 3</option>
</options>
</state>
</channel-type>
<channel-type id="scenarioProgramCentralUnit">
<item-type>Number</item-type>
<label>Scenario Program Number</label>
<description>Set scenario program number for the Central Unit, valid only with Central Unit mode = "SCENARIO"
(read/write)</description>
<state>
<options>
<option value="1">Program 1</option>
<option value="2">Program 2</option>
<option value="3">Program 3</option>
<option value="4">Program 4</option>
<option value="5">Program 5</option>
<option value="6">Program 6</option>
<option value="7">Program 7</option>
<option value="8">Program 8</option>
<option value="9">Program 9</option>
<option value="10">Program 10</option>
<option value="11">Program 11</option>
<option value="12">Program 12</option>
<option value="13">Program 13</option>
<option value="14">Program 14</option>
<option value="15">Program 15</option>
<option value="16">Program 16</option>
</options>
</state>
</channel-type>
<channel-type id="remoteControl" advanced="true">
<item-type>String</item-type>
<label>Remote Control</label>
<description>Central Unit Remote Control status (read only)</description>
<state readOnly="true">
<options>
<option value="DISABLED">DISABLED</option>
<option value="ENABLED">ENABLED</option>
</options>
</state>
</channel-type>
<channel-type id="batteryStatus" advanced="true">
<item-type>String</item-type>
<label>Battery Status</label>
<description>Central Unit Battery status (read only)</description>
<state readOnly="true">
<options>
<option value="OK">OK</option>
<option value="KO">KO</option>
</options>
</state>
</channel-type>
<!-- Energy channels -->
<channel-type id="power">
<item-type>Number:Power</item-type>