[openwebnet] Add support for Dry Contact and IR interfaces for WHO=25 (#11747)

* [openwebnet] updated where parameter labels

Signed-off-by: Massimo Valla <mvcode00@gmail.com>

* [openwebnet] added support for DryContact/IR interfaces

Signed-off-by: Massimo Valla <mvcode00@gmail.com>

* [openwebnet] updated README

Signed-off-by: Massimo Valla <mvcode00@gmail.com>

* [openwebnet] checkstyle

Signed-off-by: Massimo Valla <mvcode00@gmail.com>
This commit is contained in:
M Valla
2021-12-12 13:58:27 +01:00
committed by GitHub
parent 67f7de1403
commit aba67bcfd8
10 changed files with 162 additions and 29 deletions

View File

@@ -25,8 +25,8 @@ import org.openhab.core.thing.ThingTypeUID;
* The {@link OpenWebNetBindingConstants} class defines common constants, which are used across the whole binding.
*
* @author Massimo Valla - Initial contribution
* @author Andrea Conte - Energy management, Thermoregulation
* @author Gilberto Cocchi - Thermoregulation
* @author Andrea Conte - Energy management, Thermoregulation
*/
@NonNullByDefault
@@ -62,6 +62,8 @@ public class OpenWebNetBindingConstants {
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";
public static final ThingTypeUID THING_TYPE_BUS_DRY_CONTACT_IR = new ThingTypeUID(BINDING_ID, "bus_dry_contact_ir");
public static final String THING_LABEL_BUS_DRY_CONTACT_IR = "Dry Contact/IR";
public static final ThingTypeUID THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL = new ThingTypeUID(BINDING_ID,
"bus_cenplus_scenario_control");
public static final String THING_LABEL_BUS_CENPLUS_SCENARIO_CONTROL = "CEN+ Control";
@@ -94,7 +96,7 @@ public class OpenWebNetBindingConstants {
public static final Set<ThingTypeUID> ENERGY_MANAGEMENT_SUPPORTED_THING_TYPES = Set.of(THING_TYPE_BUS_ENERGY_METER);
// ## CEN/CEN+ Scenario
public static final Set<ThingTypeUID> SCENARIO_SUPPORTED_THING_TYPES = Set.of(THING_TYPE_BUS_CEN_SCENARIO_CONTROL,
THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL);
THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL, THING_TYPE_BUS_DRY_CONTACT_IR);
// ## Groups
public static final Set<ThingTypeUID> DEVICE_SUPPORTED_THING_TYPES = Stream
.of(LIGHTING_SUPPORTED_THING_TYPES, AUTOMATION_SUPPORTED_THING_TYPES,
@@ -130,6 +132,7 @@ public class OpenWebNetBindingConstants {
public static final String CHANNEL_SCENARIO_BUTTON = "button#";
public static final String CHANNEL_TYPE_CEN_BUTTON_EVENT = "cenButtonEvent";
public static final String CHANNEL_TYPE_CEN_PLUS_BUTTON_EVENT = "cenPlusButtonEvent";
public static final String CHANNEL_DRY_CONTACT_IR = "sensor";
// devices config properties
public static final String CONFIG_PROPERTY_WHERE = "where";

View File

@@ -159,6 +159,12 @@ public class OpenWebNetDeviceDiscoveryService extends AbstractDiscoveryService
deviceWho = Who.CEN_SCENARIO_SCHEDULER;
break;
}
case SCS_DRY_CONTACT_IR: {
thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_DRY_CONTACT_IR;
thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_DRY_CONTACT_IR;
deviceWho = Who.CEN_PLUS_SCENARIO_SCHEDULER;
break;
}
case MULTIFUNCTION_SCENARIO_CONTROL: {
thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL;
thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_CENPLUS_SCENARIO_CONTROL;

View File

@@ -26,6 +26,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants;
import org.openhab.binding.openwebnet.internal.actions.OpenWebNetCENActions;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
@@ -36,6 +37,7 @@ import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.thing.type.ChannelKind;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.Command;
import org.openwebnet4j.communication.OWNException;
import org.openwebnet4j.message.BaseOpenMessage;
import org.openwebnet4j.message.CEN;
import org.openwebnet4j.message.CEN.Pressure;
@@ -51,8 +53,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link OpenWebNetScenarioHandler} is responsible for handling commands/messages for CEN/CEN+ Scenarios. It
* extends the abstract {@link OpenWebNetThingHandler}.
* The {@link OpenWebNetScenarioHandler} is responsible for handling CEN/CEN+ Scenarios messages and Dry Contact / IR
* Interfaces messages.
* It extends the abstract {@link OpenWebNetThingHandler}.
*
* @author Massimo Valla - Initial contribution
*/
@@ -112,13 +115,21 @@ public class OpenWebNetScenarioHandler extends OpenWebNetThingHandler {
}
}
private boolean isDryContactIR = false;
private boolean isCENPlus = false;
private static long lastAllDevicesRefreshTS = -1; // timestamp when the last request for all device refresh was sent
// for this handler
protected static final int ALL_DEVICES_REFRESH_INTERVAL_MSEC = 10000; // interval in msec before sending another all
// devices refresh request
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.SCENARIO_SUPPORTED_THING_TYPES;
public OpenWebNetScenarioHandler(Thing thing) {
super(thing);
if (OpenWebNetBindingConstants.THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL.equals(thing.getThingTypeUID())) {
if (OpenWebNetBindingConstants.THING_TYPE_BUS_DRY_CONTACT_IR.equals(thing.getThingTypeUID())) {
isDryContactIR = true;
logger.debug("created DryContact/IR device for thing: {}", getThing().getUID());
} else if (OpenWebNetBindingConstants.THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL.equals(thing.getThingTypeUID())) {
isCENPlus = true;
logger.debug("created CEN+ device for thing: {}", getThing().getUID());
} else {
@@ -156,7 +167,7 @@ public class OpenWebNetScenarioHandler extends OpenWebNetThingHandler {
@Override
protected String ownIdPrefix() {
if (isCENPlus) {
if (isCENPlus || isDryContactIR) {
return Who.CEN_PLUS_SCENARIO_SCHEDULER.value().toString();
} else {
return Who.CEN_SCENARIO_SCHEDULER.value().toString();
@@ -167,13 +178,33 @@ public class OpenWebNetScenarioHandler extends OpenWebNetThingHandler {
protected void handleMessage(BaseOpenMessage msg) {
super.handleMessage(msg);
if (msg.isCommand()) {
triggerChannel((CEN) msg);
if (isDryContactIR) {
updateDryContactIRState((CENPlusScenario) msg);
} else {
triggerButtonChannel((CEN) msg);
}
} else {
logger.debug("handleMessage() Ignoring unsupported DIM for thing {}. Frame={}", getThing().getUID(), msg);
}
}
private void triggerChannel(CEN cenMsg) {
private void updateDryContactIRState(CENPlusScenario msg) {
logger.debug("updateDryContactIRState() for thing: {}", thing.getUID());
try {
if (msg.isOn()) {
updateState(CHANNEL_DRY_CONTACT_IR, OnOffType.ON);
} else if (msg.isOff()) {
updateState(CHANNEL_DRY_CONTACT_IR, OnOffType.OFF);
} else {
logger.debug("updateDryContactIRState() Ignoring unsupported WHAT for thing {}. Frame={}",
getThing().getUID(), msg);
}
} catch (FrameException fe) {
logger.warn("updateDryContactIRState() Ignoring invalid frame {}", msg);
}
}
private void triggerButtonChannel(CEN cenMsg) {
Integer buttonNumber;
try {
buttonNumber = cenMsg.getButtonNumber();
@@ -244,7 +275,6 @@ public class OpenWebNetScenarioHandler extends OpenWebNetThingHandler {
return;
}
}
triggerChannel(channel.getUID(), pressEv.toString());
}
@@ -326,21 +356,59 @@ public class OpenWebNetScenarioHandler extends OpenWebNetThingHandler {
@Override
protected void handleChannelCommand(ChannelUID channel, Command command) {
logger.warn("CEN/CEN+ channels are trigger channels and do not handle commands");
logger.warn("CEN/CEN+ and DryContact/IR have read-only channels. Ignoring command {} for channel {}", command,
channel);
}
@Override
protected void refreshDevice(boolean refreshAll) {
logger.debug("CEN/CEN+ channels are trigger channels and do not have state");
if (isDryContactIR) {
if (refreshAll) {
long now = System.currentTimeMillis();
if (now - lastAllDevicesRefreshTS > ALL_DEVICES_REFRESH_INTERVAL_MSEC) {
try {
send(CENPlusScenario.requestStatus("30"));
lastAllDevicesRefreshTS = now;
} catch (OWNException e) {
logger.warn("Excpetion while requesting all DryContact/IR devices refresh: {}", e.getMessage());
}
} else {
logger.debug("Refresh all devices just sent...");
}
} else {
requestState();
}
} else {
logger.debug("CEN/CEN+ channels are trigger channels and do not have state");
}
}
@Override
protected void requestChannelState(ChannelUID channel) {
if (isDryContactIR) {
requestState();
} else {
logger.debug("CEN/CEN+ channels are trigger channels and do not have state");
}
}
/* helper method to request DryContact/IR device state */
private void requestState() {
Where w = deviceWhere;
if (w != null) {
try {
send(CENPlusScenario.requestStatus(w.value()));
} catch (OWNException e) {
logger.warn("requestState() Exception while requesting device state: {} for thing {}", e.getMessage(),
thing.getUID());
}
} else {
logger.warn("Could not requestState(): deviceWhere is null");
}
}
@Override
protected Where buildBusWhere(String wStr) throws IllegalArgumentException {
return new WhereCEN(wStr);
}
@Override
protected void requestChannelState(ChannelUID channel) {
logger.debug("CEN/CEN+ channels are trigger channels and do not have state");
}
}

View File

@@ -31,7 +31,7 @@
</parameter>
<parameter name="where" type="text" required="true">
<label>OpenWebNet Address (where)</label>
<description>Use 2+N[0-2047]. Example: scenario control 5 --> WHERE=25</description>
<description>Use 2+N[0-2047]. Example: scenario control 5 --> where=25</description>
</parameter>
</config-description>

View File

@@ -31,7 +31,7 @@
</parameter>
<parameter name="where" type="text" required="true">
<label>OpenWebNet Address (where)</label>
<description>Example: A/PL address: A=1 PL=3 --> WHERE=13. On local bus: WHERE=13#4#01</description>
<description>Example: A/PL address: A=1 PL=3 --> where=13. On local bus: where=13#4#01</description>
</parameter>
</config-description>

View File

@@ -0,0 +1,38 @@
<?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 Dry Contact Interfaces and IR Interfaces -->
<thing-type id="bus_dry_contact_ir">
<supported-bridge-type-refs>
<bridge-type-ref id="bus_gateway"/>
</supported-bridge-type-refs>
<label>Dry Contact/IR Interface</label>
<description>A OpenWebNet BUS/SCS Dry Contact Interface or IR Interface. BTicino models: 3477/F428, IR 4610-4611-4640
etc.</description>
<channels>
<channel id="sensor" typeId="dryContactIR"/>
</channels>
<properties>
<property name="vendor">BTicino/Legrand</property>
<property name="model">BTI-3477/F428/IR 4610-4611-4640 etc.</property>
<property name="ownDeviceType">2510</property>
</properties>
<representation-property>ownId</representation-property>
<config-description>
<parameter name="where" type="text" required="true">
<label>OpenWebNet Address (where)</label>
<description>Automation Dry Contacts (N=1-201): example N=60 --> where=360. Alarm Dry Contacts and IR sensors
(Zone=1-9, N=1-9): example Zone=4, N=5 --> where=345</description>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -24,7 +24,7 @@
<config-description>
<parameter name="where" type="text" required="true">
<label>OpenWebNet Device Address (where)</label>
<label>OpenWebNet Address (where)</label>
<description>It identifies one OpenWebNet device</description>
</parameter>
</config-description>

View File

@@ -205,4 +205,12 @@
</options>
</event>
</channel-type>
<channel-type id="dryContactIR">
<item-type>Switch</item-type>
<label>Sensor</label>
<description>Dry Contact Interface or IR Interface sensor movement (read only)</description>
<state readOnly="true"></state>
</channel-type>
</thing:thing-descriptions>

View File

@@ -22,6 +22,7 @@ import org.openhab.core.thing.Bridge;
import org.openwebnet4j.message.BaseOpenMessage;
import org.openwebnet4j.message.FrameException;
import org.openwebnet4j.message.Where;
import org.openwebnet4j.message.WhereCEN;
import org.openwebnet4j.message.WhereEnergyManagement;
import org.openwebnet4j.message.WhereLightAutom;
import org.openwebnet4j.message.WhereThermo;
@@ -60,9 +61,9 @@ public class OwnIdTest {
* BUS Thermo actuator 1#2 1 4.1 1
* BUS TempSensor 500 500 4.500 500
* BUS Energy 51 51 18.51 51
* -INACTIVE- BUS CEN 51 51 15.51 51
* -INACTIVE- BUS CEN+ 212 212 25.212 212
* -INACTIVE- BUS DryContact 399 399 25.399 399
* BUS CEN 51 51 15.51 51
* BUS CEN+ 212 212 25.212 212
* BUS DryContact 399 399 25.399 399
*
*/
// @formatter:on
@@ -79,7 +80,10 @@ public class OwnIdTest {
bus_thermo(new WhereThermo("1"), Who.fromValue(4),"*#4*1*0*0020##" , "1", "4.1", "1"),
bus_thermo_act(new WhereThermo("1#2"), Who.fromValue(4),"*#4*1#2*20*0##" ,"1", "4.1", "1"),
bus_tempSensor(new WhereThermo("500"), Who.fromValue(4), "*#4*500*15*1*0020*0001##", "500", "4.500", "500"),
bus_energy(new WhereEnergyManagement("51"), Who.fromValue(18), "*#18*51*113##", "51", "18.51", "51");
bus_energy(new WhereEnergyManagement("51"), Who.fromValue(18), "*#18*51*113##", "51", "18.51", "51"),
bus_cen(new WhereCEN("51"), Who.fromValue(15), "*15*31*51##", "51", "15.51", "51"),
bus_cen_plus(new WhereCEN("212"), Who.fromValue(25), "*25*21#31*212##", "212", "25.212", "212"),
bus_drycontact(new WhereCEN("399"), Who.fromValue(25), "*25*32#1*399##", "399", "25.399", "399");
// @formatter:on