added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.digiplex-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-digiplex" description="Digiplex/EVO Alarm System Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<feature>openhab-transport-serial</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.digiplex/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal;
|
||||
|
||||
/**
|
||||
* The {@link DigiplexAreaConfiguration} class contains fields mapping area configuration parameters.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
public class DigiplexAreaConfiguration {
|
||||
|
||||
public int refreshPeriod;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link DigiplexBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DigiplexBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "digiplex";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "bridge");
|
||||
public static final ThingTypeUID THING_TYPE_ZONE = new ThingTypeUID(BINDING_ID, "zone");
|
||||
public static final ThingTypeUID THING_TYPE_AREA = new ThingTypeUID(BINDING_ID, "area");
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream
|
||||
.of(DigiplexBindingConstants.THING_TYPE_BRIDGE, DigiplexBindingConstants.THING_TYPE_ZONE,
|
||||
DigiplexBindingConstants.THING_TYPE_AREA)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
public static final String PROPERTY_ZONE_NO = "ZONE_ID";
|
||||
public static final String PROPERTY_AREA_NO = "AREA_ID";
|
||||
|
||||
// List of all Channel ids
|
||||
// Bridge
|
||||
public static final String BRIDGE_MESSAGES_SENT = "statistics#messages_sent";
|
||||
public static final String BRIDGE_RESPONSES_RECEIVED = "statistics#responses_received";
|
||||
public static final String BRIDGE_EVENTS_RECEIVED = "statistics#events_received";
|
||||
|
||||
public static final String BRIDGE_TLM_TROUBLE = "troubles#tlm_trouble";
|
||||
public static final String BRIDGE_AC_FAILURE = "troubles#ac_failure";
|
||||
public static final String BRIDGE_BATTERY_FAILURE = "troubles#battery_failure";
|
||||
public static final String BRIDGE_AUX_CURRENT_LIMIT = "troubles#aux_current_limit";
|
||||
public static final String BRIDGE_BELL_CURRENT_LIMIT = "troubles#bell_current_limit";
|
||||
public static final String BRIDGE_BELL_ABSENT = "troubles#bell_absent";
|
||||
public static final String BRIDGE_CLOCK_TROUBLE = "troubles#clock_trouble";
|
||||
public static final String BRIDGE_GLOBAL_FIRE_LOOP = "troubles#global_fire_loop";
|
||||
// Zone
|
||||
public static final String ZONE_STATUS = "status";
|
||||
public static final String ZONE_EXTENDED_STATUS = "extended_status";
|
||||
public static final String ZONE_ALARM = "alarm";
|
||||
public static final String ZONE_FIRE_ALARM = "fire_alarm";
|
||||
public static final String ZONE_SUPERVISION_LOST = "supervision_lost";
|
||||
public static final String ZONE_LOW_BATTERY = "low_battery";
|
||||
public static final String ZONE_LAST_TRIGGERED = "last_triggered";
|
||||
// Area
|
||||
public static final String AREA_STATUS = "status";
|
||||
public static final String AREA_ARMED = "armed";
|
||||
public static final String AREA_ZONE_IN_MEMORY = "zone_in_memory";
|
||||
public static final String AREA_TROUBLE = "trouble";
|
||||
public static final String AREA_READY = "ready";
|
||||
public static final String AREA_IN_PROGRAMMING = "in_programming";
|
||||
public static final String AREA_ALARM = "alarm";
|
||||
public static final String AREA_STROBE = "strobe";
|
||||
public static final String AREA_CONTROL = "control";
|
||||
|
||||
public static final List<String> ZONE_DEFAULT_NAMES = Arrays.asList("Zone %03d", "Zone %d");
|
||||
public static final String AREA_DEFAULT_NAME = "Area %d";
|
||||
|
||||
public static final StringType COMMAND_OK = new StringType("Ok");
|
||||
public static final StringType COMMAND_FAIL = new StringType("Fail");
|
||||
|
||||
public static final int GLOBAL_AREA_NO = 0;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal;
|
||||
|
||||
/**
|
||||
* The {@link DigiplexBridgeConfiguration} class contains fields mapping bridge configuration parameters.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
public class DigiplexBridgeConfiguration {
|
||||
|
||||
public String port;
|
||||
public int baudrate;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal;
|
||||
|
||||
import static org.openhab.binding.digiplex.internal.DigiplexBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.digiplex.internal.handler.DigiplexAreaHandler;
|
||||
import org.openhab.binding.digiplex.internal.handler.DigiplexBridgeHandler;
|
||||
import org.openhab.binding.digiplex.internal.handler.DigiplexZoneHandler;
|
||||
import org.openhab.core.io.transport.serial.SerialPortManager;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link DigiplexHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.digiplex")
|
||||
@NonNullByDefault
|
||||
public class DigiplexHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private final SerialPortManager serialPortManager;
|
||||
|
||||
@Activate
|
||||
public DigiplexHandlerFactory(final @Reference SerialPortManager serialPortManager) {
|
||||
this.serialPortManager = serialPortManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (thingTypeUID.equals(THING_TYPE_ZONE)) {
|
||||
return new DigiplexZoneHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_AREA)) {
|
||||
return new DigiplexAreaHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_BRIDGE)) {
|
||||
return new DigiplexBridgeHandler((Bridge) thing, serialPortManager);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Base class for all responses retrieved from PRT3 module.
|
||||
*
|
||||
* Handles success/failure.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractResponse implements DigiplexResponse {
|
||||
|
||||
public final boolean success;
|
||||
|
||||
public AbstractResponse() {
|
||||
this.success = true;
|
||||
}
|
||||
|
||||
public AbstractResponse(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Response for arm, quick arm and disarm requests
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AreaArmDisarmResponse extends AbstractResponse {
|
||||
|
||||
public final int areaNo;
|
||||
public final ArmDisarmType type;
|
||||
|
||||
private AreaArmDisarmResponse(int areaNo, ArmDisarmType type, boolean success) {
|
||||
super(success);
|
||||
this.areaNo = areaNo;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a response for a given areaNo and type. Indicates that request failed.
|
||||
*/
|
||||
public static AreaArmDisarmResponse failure(int areaNo, ArmDisarmType type) {
|
||||
return new AreaArmDisarmResponse(areaNo, type, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a response for a given areaNo and type. Indicates that request was successful.
|
||||
*/
|
||||
public static AreaArmDisarmResponse success(int areaNo, ArmDisarmType type) {
|
||||
return new AreaArmDisarmResponse(areaNo, type, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleArmDisarmAreaResponse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Command for arming area
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AreaArmRequest implements DigiplexRequest {
|
||||
|
||||
private int areaNo;
|
||||
private ArmType armType;
|
||||
private String pin;
|
||||
|
||||
public AreaArmRequest(int areaNo, ArmType armType, String pin) {
|
||||
this.areaNo = areaNo;
|
||||
this.armType = armType;
|
||||
this.pin = pin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSerialMessage() {
|
||||
return String.format("AA%03d%c%s\r", areaNo, armType.getIndicator(), pin);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Command for disarming area
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AreaDisarmRequest implements DigiplexRequest {
|
||||
|
||||
private int areaNo;
|
||||
private String pin;
|
||||
|
||||
public AreaDisarmRequest(int areaNo, String pin) {
|
||||
this.areaNo = areaNo;
|
||||
this.pin = pin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSerialMessage() {
|
||||
return String.format("AD%03d%s\r", areaNo, pin);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Command for requesting area label information from PRT3 device
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AreaLabelRequest implements DigiplexRequest {
|
||||
|
||||
private int areaNo;
|
||||
|
||||
public AreaLabelRequest(int areaNo) {
|
||||
this.areaNo = areaNo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSerialMessage() {
|
||||
return String.format("AL%03d\r", areaNo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Response for {@link AreaLabelRequest}
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AreaLabelResponse extends AbstractResponse {
|
||||
|
||||
public final int areaNo;
|
||||
public final @Nullable String areaName;
|
||||
|
||||
private AreaLabelResponse(int areaNo, String areaName) {
|
||||
super(true);
|
||||
this.areaNo = areaNo;
|
||||
this.areaName = areaName;
|
||||
}
|
||||
|
||||
private AreaLabelResponse(int areaNo) {
|
||||
super(false);
|
||||
this.areaNo = areaNo;
|
||||
this.areaName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a response for a given areaNo. Indicates that request failed.
|
||||
*/
|
||||
|
||||
public static AreaLabelResponse failure(int areaNo) {
|
||||
return new AreaLabelResponse(areaNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a response for a given areaNo and areaName. Indicates that request was successful.
|
||||
*/
|
||||
public static AreaLabelResponse success(int areaNo, String areaName) {
|
||||
return new AreaLabelResponse(areaNo, areaName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleAreaLabelResponse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Command for quick arming area
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AreaQuickArmRequest implements DigiplexRequest {
|
||||
|
||||
private int areaNo;
|
||||
private ArmType armType;
|
||||
|
||||
public AreaQuickArmRequest(int areaNo, ArmType armType) {
|
||||
this.areaNo = areaNo;
|
||||
this.armType = armType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSerialMessage() {
|
||||
return String.format("AQ%03d%c\r", areaNo, armType.getIndicator());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
|
||||
/**
|
||||
* Area status, as received for the Area Status requests
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum AreaStatus {
|
||||
DISARMED('D'),
|
||||
ARMED('A'),
|
||||
ARMED_FORCE('F'),
|
||||
ARMED_STAY('S'),
|
||||
ARMED_INSTANT('I'),
|
||||
UNKNOWN('u');
|
||||
|
||||
private char indicator;
|
||||
|
||||
AreaStatus(char indicator) {
|
||||
this.indicator = indicator;
|
||||
}
|
||||
|
||||
public OpenClosedType toOpenClosedType() {
|
||||
return this == DISARMED ? OpenClosedType.CLOSED : OpenClosedType.OPEN;
|
||||
}
|
||||
|
||||
public static AreaStatus fromMessage(char indicator) {
|
||||
return Arrays.stream(AreaStatus.values()).filter(type -> type.indicator == indicator).findFirst()
|
||||
.orElse(UNKNOWN);
|
||||
}
|
||||
|
||||
public StringType toStringType() {
|
||||
return new StringType(this.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Command for requesting zone status information from PRT3 device
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AreaStatusRequest implements DigiplexRequest {
|
||||
|
||||
private int areaNo;
|
||||
|
||||
public AreaStatusRequest(int areaNo) {
|
||||
this.areaNo = areaNo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSerialMessage() {
|
||||
return String.format("RA%03d\r", areaNo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Response for {@link AreaStatusRequest}
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AreaStatusResponse extends AbstractResponse {
|
||||
|
||||
public final int areaNo;
|
||||
public final @Nullable AreaStatus status;
|
||||
public final boolean zoneInMemory;
|
||||
public final boolean trouble;
|
||||
public final boolean ready;
|
||||
public final boolean inProgramming;
|
||||
public final boolean alarm;
|
||||
public final boolean strobe;
|
||||
|
||||
private AreaStatusResponse(int areaNo, AreaStatus status, boolean zoneInMemory, boolean trouble, boolean ready,
|
||||
boolean inProgramming, boolean alarm, boolean strobe) {
|
||||
this.areaNo = areaNo;
|
||||
this.status = status;
|
||||
this.zoneInMemory = zoneInMemory;
|
||||
this.trouble = trouble;
|
||||
this.ready = ready;
|
||||
this.inProgramming = inProgramming;
|
||||
this.alarm = alarm;
|
||||
this.strobe = strobe;
|
||||
}
|
||||
|
||||
private AreaStatusResponse(int areaNo) {
|
||||
super(false);
|
||||
this.areaNo = areaNo;
|
||||
this.status = null;
|
||||
this.zoneInMemory = false;
|
||||
this.trouble = false;
|
||||
this.ready = false;
|
||||
this.inProgramming = false;
|
||||
this.alarm = false;
|
||||
this.strobe = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a response for a given areaNo. Indicates that request failed.
|
||||
*/
|
||||
public static AreaStatusResponse failure(int areaNo) {
|
||||
return new AreaStatusResponse(areaNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a response for a given parameters. Indicates that request was successful.
|
||||
*/
|
||||
public static AreaStatusResponse success(int areaNo, AreaStatus status, boolean zoneInMemory, boolean trouble,
|
||||
boolean ready, boolean inProgramming, boolean alarm, boolean strobe) {
|
||||
return new AreaStatusResponse(areaNo, status, zoneInMemory, trouble, ready, inProgramming, alarm, strobe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleAreaStatusResponse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
*
|
||||
* Indicates type of arm/disarm message returned for PRT3 module
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum ArmDisarmType {
|
||||
ARM("AA"),
|
||||
QUICK_ARM("AQ"),
|
||||
DISARM("AD"),
|
||||
UNKNOWN("");
|
||||
|
||||
private String indicator;
|
||||
|
||||
ArmDisarmType(String indicator) {
|
||||
this.indicator = indicator;
|
||||
}
|
||||
|
||||
public static ArmDisarmType fromMessage(String indicator) {
|
||||
return Arrays.stream(ArmDisarmType.values()).filter(type -> type.indicator.equals(indicator)).findFirst()
|
||||
.orElse(UNKNOWN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Indicates arm type
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum ArmType {
|
||||
REGULAR_ARM('A'),
|
||||
FORCE_ARM('F'),
|
||||
STAY_ARM('S'),
|
||||
INSTANT_ARM('I'),
|
||||
UNKNOWN('u');
|
||||
|
||||
private char indicator;
|
||||
|
||||
ArmType(char indicator) {
|
||||
this.indicator = indicator;
|
||||
}
|
||||
|
||||
public char getIndicator() {
|
||||
return indicator;
|
||||
}
|
||||
|
||||
public static ArmType fromMessage(char indicator) {
|
||||
return Arrays.stream(values()).filter(type -> type.indicator == indicator).findFirst().orElse(UNKNOWN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Message indicating communication status between PRT3 device and Digiplex controller.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CommunicationStatus extends AbstractResponse {
|
||||
|
||||
public static final CommunicationStatus OK = new CommunicationStatus(true);
|
||||
public static final CommunicationStatus FAILURE = new CommunicationStatus(false);
|
||||
|
||||
private CommunicationStatus(boolean success) {
|
||||
super(success);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleCommunicationStatus(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link DigiplexMessage} is a common ancestor for all commands send to/received from the PRT3 device
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface DigiplexMessage {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.AreaEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.GenericEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.SpecialAlarmEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.TroubleEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.ZoneEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.ZoneStatusEvent;
|
||||
|
||||
/**
|
||||
* Interface for message handlers.
|
||||
*
|
||||
* Visitor pattern is used to dispatch message processing to proper methods.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface DigiplexMessageHandler {
|
||||
|
||||
default void handleCommunicationStatus(CommunicationStatus response) {
|
||||
}
|
||||
|
||||
default void handleZoneLabelResponse(ZoneLabelResponse response) {
|
||||
}
|
||||
|
||||
default void handleZoneStatusResponse(ZoneStatusResponse response) {
|
||||
}
|
||||
|
||||
default void handleAreaLabelResponse(AreaLabelResponse response) {
|
||||
}
|
||||
|
||||
default void handleAreaStatusResponse(AreaStatusResponse response) {
|
||||
}
|
||||
|
||||
default void handleArmDisarmAreaResponse(AreaArmDisarmResponse response) {
|
||||
}
|
||||
|
||||
default void handleUnknownResponse(UnknownResponse response) {
|
||||
}
|
||||
|
||||
// Events
|
||||
default void handleZoneEvent(ZoneEvent event) {
|
||||
}
|
||||
|
||||
default void handleZoneStatusEvent(ZoneStatusEvent event) {
|
||||
}
|
||||
|
||||
default void handleSpecialAlarmEvent(SpecialAlarmEvent event) {
|
||||
}
|
||||
|
||||
default void handleAreaEvent(AreaEvent event) {
|
||||
}
|
||||
|
||||
default void handleGenericEvent(GenericEvent event) {
|
||||
}
|
||||
|
||||
default void handleTroubleEvent(TroubleEvent troubleEvent) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Common ancestor for all requests
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface DigiplexRequest extends DigiplexMessage {
|
||||
|
||||
String getSerialMessage();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Common ancestor for all responses
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface DigiplexResponse extends DigiplexMessage {
|
||||
|
||||
void accept(DigiplexMessageHandler visitor);
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.AreaEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.AreaEventType;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.GenericEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.SpecialAlarmEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.SpecialAlarmType;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.TroubleEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.TroubleStatus;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.TroubleType;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.ZoneEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.ZoneEventType;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.ZoneStatusEvent;
|
||||
|
||||
/**
|
||||
* Resolves serial messages to appropriate classes
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DigiplexResponseResolver {
|
||||
|
||||
private static final String OK = "&ok";
|
||||
// TODO: handle failures
|
||||
private static final String FAIL = "&fail";
|
||||
|
||||
public static DigiplexResponse resolveResponse(String message) {
|
||||
if (message.length() < 4) { // sanity check: try to filter out malformed responses
|
||||
return new UnknownResponse(message);
|
||||
}
|
||||
|
||||
int zoneNo, areaNo;
|
||||
String commandType = message.substring(0, 2);
|
||||
switch (commandType) {
|
||||
case "CO": // communication status
|
||||
if (message.contains(FAIL)) {
|
||||
return CommunicationStatus.FAILURE;
|
||||
} else {
|
||||
return CommunicationStatus.OK;
|
||||
}
|
||||
case "ZL": // zone label
|
||||
zoneNo = Integer.valueOf(message.substring(2, 5));
|
||||
if (message.contains(FAIL)) {
|
||||
return ZoneLabelResponse.failure(zoneNo);
|
||||
} else {
|
||||
return ZoneLabelResponse.success(zoneNo, message.substring(5).trim());
|
||||
}
|
||||
case "AL": // area label
|
||||
areaNo = Integer.valueOf(message.substring(2, 5));
|
||||
if (message.contains(FAIL)) {
|
||||
return AreaLabelResponse.failure(areaNo);
|
||||
} else {
|
||||
return AreaLabelResponse.success(areaNo, message.substring(5).trim());
|
||||
}
|
||||
case "RZ": // zone status
|
||||
zoneNo = Integer.valueOf(message.substring(2, 5));
|
||||
if (message.contains(FAIL)) {
|
||||
return ZoneStatusResponse.failure(zoneNo);
|
||||
} else {
|
||||
return ZoneStatusResponse.success(zoneNo, // zone number
|
||||
ZoneStatus.fromMessage(message.charAt(5)), // status
|
||||
toBoolean(message.charAt(6)), // alarm
|
||||
toBoolean(message.charAt(7)), // fire alarm
|
||||
toBoolean(message.charAt(8)), // supervision lost
|
||||
toBoolean(message.charAt(9))); // battery low
|
||||
}
|
||||
case "RA": // area status
|
||||
areaNo = Integer.valueOf(message.substring(2, 5));
|
||||
if (message.contains(FAIL)) {
|
||||
return AreaStatusResponse.failure(areaNo);
|
||||
} else {
|
||||
return AreaStatusResponse.success(areaNo, // zone number
|
||||
AreaStatus.fromMessage(message.charAt(5)), // status
|
||||
toBoolean(message.charAt(6)), // zone in memory
|
||||
toBoolean(message.charAt(7)), // trouble
|
||||
!toBoolean(message.charAt(8)), // ready (note ! in front)
|
||||
toBoolean(message.charAt(9)), // in programming
|
||||
toBoolean(message.charAt(10)), // in alarm
|
||||
toBoolean(message.charAt(11))); // strobe
|
||||
}
|
||||
case "AA": // area arm
|
||||
case "AQ": // area quick arm
|
||||
case "AD": // area disarm
|
||||
areaNo = Integer.valueOf(message.substring(2, 5));
|
||||
if (message.contains(FAIL)) {
|
||||
return AreaArmDisarmResponse.failure(areaNo, ArmDisarmType.fromMessage(commandType));
|
||||
} else {
|
||||
return AreaArmDisarmResponse.success(areaNo, ArmDisarmType.fromMessage(commandType));
|
||||
}
|
||||
case "UL": // user label
|
||||
case "PG": // PGM events
|
||||
default:
|
||||
if (message.startsWith("G")) {
|
||||
return resolveSystemEvent(message);
|
||||
} else {
|
||||
return new UnknownResponse(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean toBoolean(char value) {
|
||||
if (value == 'O') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static DigiplexResponse resolveSystemEvent(String message) {
|
||||
int eventGroup = Integer.parseInt(message.substring(1, 4));
|
||||
int eventNumber = Integer.parseInt(message.substring(5, 8));
|
||||
int areaNumber = Integer.parseInt(message.substring(9, 12));
|
||||
switch (eventGroup) {
|
||||
case 0:
|
||||
return new ZoneStatusEvent(eventNumber, ZoneStatus.CLOSED, areaNumber);
|
||||
case 1:
|
||||
return new ZoneStatusEvent(eventNumber, ZoneStatus.OPEN, areaNumber);
|
||||
case 2:
|
||||
return new ZoneStatusEvent(eventNumber, ZoneStatus.TAMPERED, areaNumber);
|
||||
case 3:
|
||||
return new ZoneStatusEvent(eventNumber, ZoneStatus.FIRE_LOOP_TROUBLE, areaNumber);
|
||||
case 8:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.TX_DELAY_ZONE_ALARM, areaNumber);
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
return new AreaEvent(AreaEventType.DISARMED, areaNumber);
|
||||
case 23:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.BYPASSED, areaNumber);
|
||||
case 24:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.ALARM, areaNumber);
|
||||
case 25:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.FIRE_ALARM, areaNumber);
|
||||
case 26:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.ALARM_RESTORE, areaNumber);
|
||||
case 27:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.FIRE_ALARM_RESTORE, areaNumber);
|
||||
case 30:
|
||||
return new SpecialAlarmEvent(areaNumber, SpecialAlarmType.fromMessage(eventNumber));
|
||||
case 32:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.SHUTDOWN, areaNumber);
|
||||
case 33:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.TAMPER, areaNumber);
|
||||
case 34:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.TAMPER_RESTORE, areaNumber);
|
||||
case 36:
|
||||
return new TroubleEvent(TroubleType.fromEventNumber(eventNumber), TroubleStatus.TROUBLE_STARTED,
|
||||
areaNumber);
|
||||
case 37:
|
||||
return new TroubleEvent(TroubleType.fromEventNumber(eventNumber), TroubleStatus.TROUBLE_RESTORED,
|
||||
areaNumber);
|
||||
case 41:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.LOW_BATTERY, areaNumber);
|
||||
case 42:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.SUPERVISION_TROUBLE, areaNumber);
|
||||
case 43:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.LOW_BATTERY_RESTORE, areaNumber);
|
||||
case 44:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.SUPERVISION_TROUBLE_RESTORE, areaNumber);
|
||||
case 55:
|
||||
return new ZoneEvent(eventNumber, ZoneEventType.INTELLIZONE_TRIGGERED, areaNumber);
|
||||
case 64:
|
||||
switch (eventNumber) {
|
||||
case 0:
|
||||
return new AreaEvent(AreaEventType.ARMED, areaNumber);
|
||||
case 1:
|
||||
return new AreaEvent(AreaEventType.ARMED_FORCE, areaNumber);
|
||||
case 2:
|
||||
return new AreaEvent(AreaEventType.ARMED_STAY, areaNumber);
|
||||
case 3:
|
||||
return new AreaEvent(AreaEventType.ARMED_INSTANT, areaNumber);
|
||||
case 4:
|
||||
return new AreaEvent(AreaEventType.ALARM_STROBE, areaNumber);
|
||||
case 5:
|
||||
return new AreaEvent(AreaEventType.ALARM_SILENT, areaNumber);
|
||||
case 6:
|
||||
return new AreaEvent(AreaEventType.ALARM_AUDIBLE, areaNumber);
|
||||
case 7:
|
||||
return new AreaEvent(AreaEventType.ALARM_FIRE, areaNumber);
|
||||
}
|
||||
break;
|
||||
case 65:
|
||||
switch (eventNumber) {
|
||||
case 0:
|
||||
return new AreaEvent(AreaEventType.READY, areaNumber);
|
||||
case 1:
|
||||
return new AreaEvent(AreaEventType.EXIT_DELAY, areaNumber);
|
||||
case 2:
|
||||
return new AreaEvent(AreaEventType.ENTRY_DELAY, areaNumber);
|
||||
case 3:
|
||||
return new AreaEvent(AreaEventType.SYSTEM_IN_TROUBLE, areaNumber);
|
||||
case 4:
|
||||
return new AreaEvent(AreaEventType.ALARM_IN_MEMORY, areaNumber);
|
||||
case 5:
|
||||
return new AreaEvent(AreaEventType.ZONES_BYPASSED, areaNumber);
|
||||
}
|
||||
}
|
||||
return new GenericEvent(eventGroup, eventNumber, areaNumber);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Unknown message from PRT3
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class UnknownResponse implements DigiplexResponse {
|
||||
|
||||
public final String message;
|
||||
|
||||
public UnknownResponse(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleUnknownResponse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Command for requesting zone label information from PRT3 device
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ZoneLabelRequest implements DigiplexRequest {
|
||||
|
||||
private int zoneNo;
|
||||
|
||||
public ZoneLabelRequest(int zoneNo) {
|
||||
this.zoneNo = zoneNo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSerialMessage() {
|
||||
return String.format("ZL%03d\r", zoneNo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Response for {@link ZoneLabelRequest}
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ZoneLabelResponse extends AbstractResponse {
|
||||
|
||||
public final int zoneNo;
|
||||
public final @Nullable String zoneName;
|
||||
|
||||
private ZoneLabelResponse(int zoneNo, String zoneName) {
|
||||
super(true);
|
||||
this.zoneNo = zoneNo;
|
||||
this.zoneName = zoneName;
|
||||
}
|
||||
|
||||
private ZoneLabelResponse(int zoneNo) {
|
||||
super(false);
|
||||
this.zoneNo = zoneNo;
|
||||
this.zoneName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a response for a given zoneNo. Indicates that request failed.
|
||||
*/
|
||||
public static ZoneLabelResponse failure(int zoneNo) {
|
||||
return new ZoneLabelResponse(zoneNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a response for a given zoneNo. Indicates that request was successful.
|
||||
*/
|
||||
public static ZoneLabelResponse success(int zoneNo, String zoneName) {
|
||||
return new ZoneLabelResponse(zoneNo, zoneName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleZoneLabelResponse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
|
||||
/**
|
||||
* Zone status, as received from the alarm system
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum ZoneStatus {
|
||||
CLOSED('C'),
|
||||
OPEN('O'),
|
||||
TAMPERED('T'),
|
||||
FIRE_LOOP_TROUBLE('F'),
|
||||
UNKNOWN('u');
|
||||
|
||||
private char indicator;
|
||||
|
||||
ZoneStatus(char indicator) {
|
||||
this.indicator = indicator;
|
||||
}
|
||||
|
||||
public OpenClosedType toOpenClosedType() {
|
||||
return this == CLOSED ? OpenClosedType.CLOSED : OpenClosedType.OPEN;
|
||||
}
|
||||
|
||||
public static ZoneStatus fromMessage(char indicator) {
|
||||
return Arrays.stream(ZoneStatus.values()).filter(type -> type.indicator == indicator).findFirst()
|
||||
.orElse(UNKNOWN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Command for requesting zone status information from PRT3 device
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ZoneStatusRequest implements DigiplexRequest {
|
||||
|
||||
private int zoneNo;
|
||||
|
||||
public ZoneStatusRequest(int zoneNo) {
|
||||
this.zoneNo = zoneNo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSerialMessage() {
|
||||
return String.format("RZ%03d\r", zoneNo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Response for {@link ZoneStatusRequest}
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ZoneStatusResponse extends AbstractResponse {
|
||||
|
||||
public final int zoneNo;
|
||||
@Nullable
|
||||
public final ZoneStatus status;
|
||||
public final boolean alarm;
|
||||
public final boolean fireAlarm;
|
||||
public final boolean supervisionLost;
|
||||
public final boolean lowBattery;
|
||||
|
||||
private ZoneStatusResponse(int zoneNo, ZoneStatus status, boolean alarm, boolean fireAlarm, boolean supervisionLost,
|
||||
boolean lowBattery) {
|
||||
super(true);
|
||||
this.zoneNo = zoneNo;
|
||||
this.status = status;
|
||||
this.alarm = alarm;
|
||||
this.fireAlarm = fireAlarm;
|
||||
this.supervisionLost = supervisionLost;
|
||||
this.lowBattery = lowBattery;
|
||||
}
|
||||
|
||||
private ZoneStatusResponse(int zoneNo) {
|
||||
super(false);
|
||||
this.zoneNo = zoneNo;
|
||||
this.status = null;
|
||||
this.alarm = false;
|
||||
this.fireAlarm = false;
|
||||
this.supervisionLost = false;
|
||||
this.lowBattery = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a response for a given zoneNo. Indicates that request failed.
|
||||
*/
|
||||
public static ZoneStatusResponse failure(int zoneNo) {
|
||||
return new ZoneStatusResponse(zoneNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a response for a given zoneNo. Indicates that request was successful.
|
||||
*/
|
||||
public static ZoneStatusResponse success(int zoneNo, ZoneStatus status, boolean alarm, boolean fireAlarm,
|
||||
boolean supervisionLost, boolean lowBattery) {
|
||||
return new ZoneStatusResponse(zoneNo, status, alarm, fireAlarm, supervisionLost, lowBattery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleZoneStatusResponse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexResponse;
|
||||
|
||||
/**
|
||||
* Common ancestor for all events received from Digiplex system
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractEvent implements DigiplexResponse {
|
||||
|
||||
private int areaNo;
|
||||
|
||||
public AbstractEvent(int areaNo) {
|
||||
this.areaNo = areaNo;
|
||||
}
|
||||
|
||||
public int getAreaNo() {
|
||||
return areaNo;
|
||||
}
|
||||
|
||||
public boolean isForArea(int areaNo) {
|
||||
if (this.areaNo == 0 || this.areaNo == areaNo) {
|
||||
return true;
|
||||
}
|
||||
// TODO: According to documentation: areaNo = 255 - Occurs in at least one area enabled in the system.
|
||||
// I did never encounter 255 on my system though (EVO192).
|
||||
// 15 is returned instead, which (I believe) has the same meaning.
|
||||
if (this.areaNo == 15 || this.areaNo == 255) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexMessageHandler;
|
||||
|
||||
/**
|
||||
* Message providing miscellaneous area informations
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AreaEvent extends AbstractEvent {
|
||||
|
||||
private AreaEventType type;
|
||||
|
||||
public AreaEvent(AreaEventType type, int areaNo) {
|
||||
super(areaNo);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public AreaEventType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleAreaEvent(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Area event type.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum AreaEventType {
|
||||
ARMED,
|
||||
ARMED_FORCE,
|
||||
ARMED_STAY,
|
||||
ARMED_INSTANT,
|
||||
|
||||
DISARMED,
|
||||
|
||||
ALARM_STROBE,
|
||||
ALARM_SILENT,
|
||||
ALARM_AUDIBLE,
|
||||
ALARM_FIRE,
|
||||
|
||||
READY,
|
||||
EXIT_DELAY,
|
||||
ENTRY_DELAY,
|
||||
SYSTEM_IN_TROUBLE,
|
||||
ALARM_IN_MEMORY,
|
||||
ZONES_BYPASSED,
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexMessageHandler;
|
||||
|
||||
/**
|
||||
* Represents generic event received from PRT3 module.
|
||||
*
|
||||
* It is created when no specific handler is found for the received event.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GenericEvent extends AbstractEvent {
|
||||
|
||||
private int eventGroup;
|
||||
private int eventNumber;
|
||||
|
||||
public GenericEvent(int eventGroup, int eventNumber, int areaNumber) {
|
||||
super(areaNumber);
|
||||
this.eventGroup = eventGroup;
|
||||
this.eventNumber = eventNumber;
|
||||
}
|
||||
|
||||
public int getEventGroup() {
|
||||
return eventGroup;
|
||||
}
|
||||
|
||||
public int getEventNumber() {
|
||||
return eventNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleGenericEvent(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexMessageHandler;
|
||||
|
||||
/**
|
||||
* Message providing information about special alarm events
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SpecialAlarmEvent extends AbstractEvent {
|
||||
|
||||
private SpecialAlarmType type;
|
||||
|
||||
public SpecialAlarmEvent(int areaNo, SpecialAlarmType type) {
|
||||
super(areaNo);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public SpecialAlarmType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleSpecialAlarmEvent(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication.events;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Type of special alarm.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum SpecialAlarmType {
|
||||
EMERGENCY_PANIC(0),
|
||||
MEDICAL_PANIC(1),
|
||||
FIRE_PANIC(2),
|
||||
RECENT_CLOSING(3),
|
||||
POLICE_CODE(4),
|
||||
GLOBAL_SHUTDOWN(5),
|
||||
UNKNOWN(-1);
|
||||
|
||||
private int indicator;
|
||||
|
||||
SpecialAlarmType(int indicator) {
|
||||
this.indicator = indicator;
|
||||
}
|
||||
|
||||
public static SpecialAlarmType fromMessage(int indicator) {
|
||||
return Arrays.stream(values()).filter(type -> type.indicator == indicator).findFirst().orElse(UNKNOWN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexMessageHandler;
|
||||
|
||||
/**
|
||||
* Message providing global trouble status
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TroubleEvent extends AbstractEvent {
|
||||
|
||||
private TroubleStatus status;
|
||||
private TroubleType type;
|
||||
|
||||
public TroubleEvent(TroubleType type, TroubleStatus status, int areaNo) {
|
||||
super(areaNo);
|
||||
this.type = type;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public TroubleStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public TroubleType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleTroubleEvent(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Trouble status.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum TroubleStatus {
|
||||
TROUBLE_STARTED,
|
||||
TROUBLE_RESTORED;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication.events;
|
||||
|
||||
import static org.openhab.binding.digiplex.internal.DigiplexBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Trouble event type.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum TroubleType {
|
||||
TLM_TROUBLE(BRIDGE_TLM_TROUBLE),
|
||||
AC_FAILURE(BRIDGE_AC_FAILURE),
|
||||
BATTERY_FAILURE(BRIDGE_BATTERY_FAILURE),
|
||||
AUXILIARY_CURRENT_LIMIT(BRIDGE_AUX_CURRENT_LIMIT),
|
||||
BELL_CURRENT_LIMIT(BRIDGE_BELL_CURRENT_LIMIT),
|
||||
BELL_ABSENT(BRIDGE_BELL_ABSENT),
|
||||
CLOCK_TROUBLE(BRIDGE_CLOCK_TROUBLE),
|
||||
GLOBAL_FIRE_LOOP(BRIDGE_GLOBAL_FIRE_LOOP);
|
||||
|
||||
private String bridgeChannel;
|
||||
|
||||
private TroubleType(String bridgeChannel) {
|
||||
this.bridgeChannel = bridgeChannel;
|
||||
}
|
||||
|
||||
public String getBridgeChannel() {
|
||||
return bridgeChannel;
|
||||
}
|
||||
|
||||
public static TroubleType fromEventNumber(int eventNumber) {
|
||||
return TroubleType.values()[eventNumber];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexMessageHandler;
|
||||
|
||||
/**
|
||||
* Message providing miscellaneous zone informations
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ZoneEvent extends AbstractEvent {
|
||||
|
||||
private int zoneNo;
|
||||
private ZoneEventType type;
|
||||
|
||||
public ZoneEvent(int zoneNo, ZoneEventType type, int areaNo) {
|
||||
super(areaNo);
|
||||
this.zoneNo = zoneNo;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getZoneNo() {
|
||||
return zoneNo;
|
||||
}
|
||||
|
||||
public ZoneEventType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleZoneEvent(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Type of zone-related event
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum ZoneEventType {
|
||||
TX_DELAY_ZONE_ALARM,
|
||||
BYPASSED,
|
||||
ALARM,
|
||||
FIRE_ALARM,
|
||||
ALARM_RESTORE,
|
||||
FIRE_ALARM_RESTORE,
|
||||
SHUTDOWN,
|
||||
TAMPER,
|
||||
TAMPER_RESTORE,
|
||||
LOW_BATTERY,
|
||||
LOW_BATTERY_RESTORE,
|
||||
SUPERVISION_TROUBLE,
|
||||
SUPERVISION_TROUBLE_RESTORE,
|
||||
INTELLIZONE_TRIGGERED
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.communication.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexMessageHandler;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexResponse;
|
||||
import org.openhab.binding.digiplex.internal.communication.ZoneStatus;
|
||||
|
||||
/**
|
||||
* Message indicating zone status.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ZoneStatusEvent extends AbstractEvent implements DigiplexResponse {
|
||||
|
||||
private int zoneNo;
|
||||
private ZoneStatus state;
|
||||
|
||||
public ZoneStatusEvent(int zoneNo, ZoneStatus state, int areaNo) {
|
||||
super(areaNo);
|
||||
this.zoneNo = zoneNo;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public int getZoneNo() {
|
||||
return zoneNo;
|
||||
}
|
||||
|
||||
public ZoneStatus getStatus() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DigiplexMessageHandler visitor) {
|
||||
visitor.handleZoneStatusEvent(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.digiplex.internal.DigiplexBindingConstants.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.digiplex.internal.communication.AreaLabelRequest;
|
||||
import org.openhab.binding.digiplex.internal.communication.AreaLabelResponse;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexMessageHandler;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexRequest;
|
||||
import org.openhab.binding.digiplex.internal.communication.ZoneLabelRequest;
|
||||
import org.openhab.binding.digiplex.internal.communication.ZoneLabelResponse;
|
||||
import org.openhab.binding.digiplex.internal.handler.DigiplexBridgeHandler;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
|
||||
/**
|
||||
* Service for discovering things on Digiplex alarm systems
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DigiplexDiscoveryService extends AbstractDiscoveryService
|
||||
implements DiscoveryService, ThingHandlerService, DigiplexMessageHandler {
|
||||
|
||||
private static final int MAX_ZONE = 96;
|
||||
private static final int MAX_AREA = 8;
|
||||
|
||||
private static final int DISCOVERY_TIMEOUT = 30;
|
||||
|
||||
private @Nullable DigiplexBridgeHandler bridgeHandler;
|
||||
|
||||
public DigiplexDiscoveryService() {
|
||||
super(Collections.singleton(THING_TYPE_ZONE), DISCOVERY_TIMEOUT, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("null")
|
||||
protected void startScan() {
|
||||
bridgeHandler.registerMessageHandler(this);
|
||||
// find zones
|
||||
for (int i = 1; i <= MAX_ZONE; i++) {
|
||||
DigiplexRequest command = new ZoneLabelRequest(i);
|
||||
bridgeHandler.sendRequest(command);
|
||||
}
|
||||
// find areas
|
||||
for (int i = 1; i <= MAX_AREA; i++) {
|
||||
DigiplexRequest command = new AreaLabelRequest(i);
|
||||
bridgeHandler.sendRequest(command);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("null")
|
||||
protected synchronized void stopScan() {
|
||||
bridgeHandler.unregisterMessageHandler(this);
|
||||
super.stopScan();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("null")
|
||||
public void handleZoneLabelResponse(ZoneLabelResponse response) {
|
||||
// we have no other option to check whether zone is actually enabled than to compare its name with the default
|
||||
if (isDefaultName(response)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ThingUID bridgeUID = bridgeHandler.getThing().getUID();
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_ZONE, bridgeUID, String.format("zone%d", response.zoneNo));
|
||||
|
||||
Map<String, Object> properties = new HashMap<>(1);
|
||||
properties.put(PROPERTY_ZONE_NO, Integer.toString(response.zoneNo));
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withBridge(bridgeUID)
|
||||
.withProperties(properties).withLabel(response.zoneName).build();
|
||||
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
|
||||
private boolean isDefaultName(ZoneLabelResponse response) {
|
||||
return ZONE_DEFAULT_NAMES.stream().anyMatch(format -> {
|
||||
if (String.format(format, response.zoneNo).equals(response.zoneName)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("null")
|
||||
public void handleAreaLabelResponse(AreaLabelResponse response) {
|
||||
// we have no other option to check whether area is actually enabled than to compare its name with the default
|
||||
if (response.success && response.areaName.equals(String.format(AREA_DEFAULT_NAME, response.areaNo))) {
|
||||
return;
|
||||
}
|
||||
|
||||
ThingUID bridgeUID = bridgeHandler.getThing().getUID();
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_AREA, bridgeUID, String.format("area%d", response.areaNo));
|
||||
|
||||
Map<String, Object> properties = new HashMap<>(1);
|
||||
properties.put(PROPERTY_AREA_NO, Integer.toString(response.areaNo));
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withBridge(bridgeUID)
|
||||
.withProperties(properties).withLabel(response.areaName).build();
|
||||
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
if (handler instanceof DigiplexBridgeHandler) {
|
||||
bridgeHandler = (DigiplexBridgeHandler) handler;
|
||||
bridgeHandler.registerMessageHandler(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return bridgeHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
super.activate(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
super.deactivate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.handler;
|
||||
|
||||
import static org.openhab.binding.digiplex.internal.DigiplexBindingConstants.*;
|
||||
import static org.openhab.binding.digiplex.internal.handler.TypeUtils.openClosedFromBoolean;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.digiplex.internal.DigiplexAreaConfiguration;
|
||||
import org.openhab.binding.digiplex.internal.DigiplexBindingConstants;
|
||||
import org.openhab.binding.digiplex.internal.communication.AreaArmDisarmResponse;
|
||||
import org.openhab.binding.digiplex.internal.communication.AreaArmRequest;
|
||||
import org.openhab.binding.digiplex.internal.communication.AreaDisarmRequest;
|
||||
import org.openhab.binding.digiplex.internal.communication.AreaQuickArmRequest;
|
||||
import org.openhab.binding.digiplex.internal.communication.AreaStatus;
|
||||
import org.openhab.binding.digiplex.internal.communication.AreaStatusRequest;
|
||||
import org.openhab.binding.digiplex.internal.communication.AreaStatusResponse;
|
||||
import org.openhab.binding.digiplex.internal.communication.ArmType;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexMessageHandler;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexRequest;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.AreaEvent;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
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.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
|
||||
/**
|
||||
* The {@link DigiplexAreaHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DigiplexAreaHandler extends BaseThingHandler {
|
||||
|
||||
private @Nullable DigiplexAreaConfiguration config;
|
||||
private @Nullable DigiplexBridgeHandler bridgeHandler;
|
||||
private DigiplexAreaMessageHandler visitor = new DigiplexAreaMessageHandler();
|
||||
private int areaNo;
|
||||
private OpenClosedType armed = OpenClosedType.CLOSED;
|
||||
private StringType status = AreaStatus.DISARMED.toStringType();
|
||||
private OpenClosedType zoneInMemory = OpenClosedType.CLOSED;
|
||||
private OpenClosedType trouble = OpenClosedType.CLOSED;
|
||||
private OpenClosedType ready = OpenClosedType.CLOSED;
|
||||
private OpenClosedType inProgramming = OpenClosedType.CLOSED;
|
||||
private OpenClosedType alarm = OpenClosedType.CLOSED;
|
||||
private OpenClosedType strobe = OpenClosedType.CLOSED;
|
||||
private StringType lastCommandResult = new StringType();
|
||||
|
||||
private @Nullable ScheduledFuture<?> refreshTask;
|
||||
|
||||
public DigiplexAreaHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
switch (channelUID.getId()) {
|
||||
case AREA_STATUS:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(AREA_STATUS, status);
|
||||
}
|
||||
break;
|
||||
case AREA_ARMED:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(AREA_ARMED, armed);
|
||||
}
|
||||
break;
|
||||
case AREA_ZONE_IN_MEMORY:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(AREA_ZONE_IN_MEMORY, zoneInMemory);
|
||||
}
|
||||
break;
|
||||
case AREA_TROUBLE:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(AREA_TROUBLE, trouble);
|
||||
}
|
||||
break;
|
||||
case AREA_READY:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(AREA_READY, ready);
|
||||
}
|
||||
break;
|
||||
case AREA_IN_PROGRAMMING:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(AREA_IN_PROGRAMMING, inProgramming);
|
||||
}
|
||||
break;
|
||||
case AREA_ALARM:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(AREA_ALARM, alarm);
|
||||
}
|
||||
break;
|
||||
case AREA_STROBE:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(AREA_STROBE, strobe);
|
||||
}
|
||||
break;
|
||||
case AREA_CONTROL:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(AREA_CONTROL, lastCommandResult);
|
||||
} else if (command instanceof StringType) {
|
||||
processControlCommand(((StringType) command).toString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
private void processControlCommand(String command) {
|
||||
if (command.length() < 2) {
|
||||
updateControlChannel(COMMAND_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
char commandType = command.charAt(0);
|
||||
char commandSubType = command.charAt(1);
|
||||
switch (commandType) {
|
||||
case 'A':
|
||||
bridgeHandler.sendRequest(
|
||||
new AreaArmRequest(areaNo, ArmType.fromMessage(commandSubType), command.substring(2)));
|
||||
break;
|
||||
case 'Q':
|
||||
bridgeHandler.sendRequest(new AreaQuickArmRequest(areaNo, ArmType.fromMessage(commandSubType)));
|
||||
break;
|
||||
case 'D':
|
||||
bridgeHandler.sendRequest(new AreaDisarmRequest(areaNo, command.substring(1)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Override
|
||||
public void initialize() {
|
||||
config = getConfigAs(DigiplexAreaConfiguration.class);
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||
return;
|
||||
}
|
||||
bridgeHandler = (DigiplexBridgeHandler) bridge.getHandler();
|
||||
|
||||
String areaParm = getThing().getProperties().get(DigiplexBindingConstants.PROPERTY_AREA_NO);
|
||||
areaNo = Integer.parseInt(areaParm);
|
||||
bridgeHandler.registerMessageHandler(visitor);
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
||||
refreshTask = scheduler.scheduleWithFixedDelay(() -> {
|
||||
sendStatusUpdateRequest();
|
||||
}, 0, config.refreshPeriod, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void updateChannelsAfterStatusResponse() {
|
||||
updateState(AREA_STATUS, status);
|
||||
updateState(AREA_ARMED, armed);
|
||||
updateState(AREA_ZONE_IN_MEMORY, zoneInMemory);
|
||||
updateState(AREA_TROUBLE, trouble);
|
||||
updateState(AREA_READY, ready);
|
||||
updateState(AREA_IN_PROGRAMMING, inProgramming);
|
||||
updateState(AREA_ALARM, alarm);
|
||||
updateState(AREA_STROBE, strobe);
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Override
|
||||
public void handleRemoval() {
|
||||
if (visitor != null) {
|
||||
bridgeHandler.unregisterMessageHandler(visitor);
|
||||
}
|
||||
if (refreshTask != null) {
|
||||
refreshTask.cancel(true);
|
||||
}
|
||||
super.handleRemoval();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bridgeStatusChanged(ThingStatusInfo thingStatusInfo) {
|
||||
if (thingStatusInfo.getStatus() == ThingStatus.OFFLINE) {
|
||||
updateStatus(ThingStatus.OFFLINE, thingStatusInfo.getStatusDetail());
|
||||
} else if (thingStatusInfo.getStatus() == ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
sendStatusUpdateRequest();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void updateControlChannel(StringType response) {
|
||||
lastCommandResult = response;
|
||||
updateState(AREA_CONTROL, lastCommandResult);
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
private void sendStatusUpdateRequest() {
|
||||
DigiplexRequest request = new AreaStatusRequest(areaNo);
|
||||
bridgeHandler.sendRequest(request);
|
||||
}
|
||||
|
||||
private class DigiplexAreaMessageHandler implements DigiplexMessageHandler {
|
||||
|
||||
@Override
|
||||
public void handleAreaStatusResponse(AreaStatusResponse response) {
|
||||
if (response.success && response.areaNo == DigiplexAreaHandler.this.areaNo) {
|
||||
status = new StringType(response.status.toString());
|
||||
armed = response.status.toOpenClosedType();
|
||||
zoneInMemory = openClosedFromBoolean(response.zoneInMemory);
|
||||
trouble = openClosedFromBoolean(response.trouble);
|
||||
ready = openClosedFromBoolean(response.ready);
|
||||
inProgramming = openClosedFromBoolean(response.inProgramming);
|
||||
alarm = openClosedFromBoolean(response.alarm);
|
||||
strobe = openClosedFromBoolean(response.strobe);
|
||||
updateChannelsAfterStatusResponse();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleArmDisarmAreaResponse(AreaArmDisarmResponse response) {
|
||||
if (response.areaNo == DigiplexAreaHandler.this.areaNo) {
|
||||
if (response.success) {
|
||||
updateControlChannel(COMMAND_OK);
|
||||
} else {
|
||||
updateControlChannel(COMMAND_FAIL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleAreaEvent(AreaEvent event) {
|
||||
if (event.isForArea(DigiplexAreaHandler.this.areaNo)) {
|
||||
switch (event.getType()) {
|
||||
case READY: // TODO: not sure what it means. Let's send status update request
|
||||
case DISARMED: // in case of disarm we want to ensure that all other channels are updated as well
|
||||
sendStatusUpdateRequest();
|
||||
break;
|
||||
case ALARM_STROBE:
|
||||
strobe = OpenClosedType.OPEN;
|
||||
updateState(AREA_STROBE, strobe);
|
||||
// no break intentionally
|
||||
case ALARM_FIRE:
|
||||
case ALARM_AUDIBLE:
|
||||
case ALARM_IN_MEMORY:
|
||||
case ALARM_SILENT:
|
||||
alarm = OpenClosedType.OPEN;
|
||||
updateState(AREA_ALARM, alarm);
|
||||
break;
|
||||
case ARMED:
|
||||
case ARMED_FORCE:
|
||||
case ARMED_INSTANT:
|
||||
case ARMED_STAY:
|
||||
armed = OpenClosedType.OPEN;
|
||||
updateState(AREA_ARMED, armed);
|
||||
break;
|
||||
case SYSTEM_IN_TROUBLE:
|
||||
trouble = OpenClosedType.OPEN;
|
||||
updateState(AREA_TROUBLE, trouble);
|
||||
break;
|
||||
case ZONES_BYPASSED:
|
||||
case ENTRY_DELAY:
|
||||
case EXIT_DELAY:
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
// update status separately, for more concise logic
|
||||
Optional<AreaStatus> tempStatus = Optional.empty();
|
||||
switch (event.getType()) {
|
||||
case ARMED:
|
||||
tempStatus = Optional.of(AreaStatus.ARMED);
|
||||
break;
|
||||
case ARMED_FORCE:
|
||||
tempStatus = Optional.of(AreaStatus.ARMED_FORCE);
|
||||
break;
|
||||
case ARMED_INSTANT:
|
||||
tempStatus = Optional.of(AreaStatus.ARMED_INSTANT);
|
||||
break;
|
||||
case ARMED_STAY:
|
||||
tempStatus = Optional.of(AreaStatus.ARMED_STAY);
|
||||
break;
|
||||
case DISARMED:
|
||||
tempStatus = Optional.of(AreaStatus.DISARMED);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
tempStatus.ifPresent(s -> updateState(AREA_STATUS, s.toStringType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,382 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.handler;
|
||||
|
||||
import static org.openhab.binding.digiplex.internal.DigiplexBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TooManyListenersException;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.digiplex.internal.DigiplexBridgeConfiguration;
|
||||
import org.openhab.binding.digiplex.internal.communication.CommunicationStatus;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexMessageHandler;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexRequest;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexResponse;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexResponseResolver;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.AbstractEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.TroubleEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.TroubleStatus;
|
||||
import org.openhab.binding.digiplex.internal.discovery.DigiplexDiscoveryService;
|
||||
import org.openhab.core.io.transport.serial.PortInUseException;
|
||||
import org.openhab.core.io.transport.serial.SerialPort;
|
||||
import org.openhab.core.io.transport.serial.SerialPortEvent;
|
||||
import org.openhab.core.io.transport.serial.SerialPortEventListener;
|
||||
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
|
||||
import org.openhab.core.io.transport.serial.SerialPortManager;
|
||||
import org.openhab.core.io.transport.serial.UnsupportedCommOperationException;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link DigiplexBridgeHandler} is responsible for handling communication with PRT3 module
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DigiplexBridgeHandler extends BaseBridgeHandler implements SerialPortEventListener {
|
||||
|
||||
private static final int REINITIALIZE_DELAY = 1; // in minutes
|
||||
private static final int STALLED_MESSAGES_THRESHOLD = 5;
|
||||
private static final int END_OF_MESSAGE = '\r';
|
||||
private static final int END_OF_STREAM = -1;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(DigiplexBridgeHandler.class);
|
||||
|
||||
private @Nullable DigiplexBridgeConfiguration config;
|
||||
private @Nullable SerialPort serialPort;
|
||||
private @Nullable DigiplexReceiverThread receiverThread;
|
||||
private @Nullable DigiplexSenderThread senderThread;
|
||||
private final BlockingQueue<DigiplexRequest> sendQueue = new LinkedBlockingQueue<>();
|
||||
private final SerialPortManager serialPortManager;
|
||||
private final Set<DigiplexMessageHandler> handlers = ConcurrentHashMap.newKeySet();
|
||||
|
||||
@Nullable
|
||||
private ScheduledFuture<?> reinitializeTask;
|
||||
|
||||
private AtomicLong messagesSent = new AtomicLong(0);
|
||||
private AtomicLong responsesReceived = new AtomicLong(0);
|
||||
private AtomicLong eventsReceived = new AtomicLong(0);
|
||||
|
||||
public DigiplexBridgeHandler(Bridge bridge, SerialPortManager serialPortManager) {
|
||||
super(bridge);
|
||||
this.serialPortManager = serialPortManager;
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Override
|
||||
public void initialize() {
|
||||
config = getConfigAs(DigiplexBridgeConfiguration.class);
|
||||
if (config.port == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, "Port must be set!");
|
||||
return;
|
||||
}
|
||||
|
||||
SerialPortIdentifier portId = serialPortManager.getIdentifier(config.port);
|
||||
if (portId == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
|
||||
"No such port: " + config.port);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
serialPort = initializeSerialPort(portId);
|
||||
|
||||
InputStream inputStream = serialPort.getInputStream();
|
||||
OutputStream outputStream = serialPort.getOutputStream();
|
||||
|
||||
if (inputStream == null || outputStream == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Input/Output stream null");
|
||||
return;
|
||||
}
|
||||
|
||||
receiverThread = new DigiplexReceiverThread(inputStream);
|
||||
senderThread = new DigiplexSenderThread(outputStream);
|
||||
|
||||
registerMessageHandler(new BridgeMessageHandler());
|
||||
|
||||
messagesSent.set(0);
|
||||
responsesReceived.set(0);
|
||||
eventsReceived.set(0);
|
||||
|
||||
receiverThread.start();
|
||||
senderThread.start();
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} catch (PortInUseException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Port in use: " + config.port);
|
||||
} catch (Exception e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Communication error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
private @Nullable SerialPort initializeSerialPort(SerialPortIdentifier portId)
|
||||
throws PortInUseException, TooManyListenersException, UnsupportedCommOperationException {
|
||||
SerialPort serialPort = portId.open(getThing().getUID().toString(), 2000);
|
||||
serialPort.setSerialPortParams(config.baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
|
||||
SerialPort.PARITY_NONE);
|
||||
serialPort.enableReceiveThreshold(0);
|
||||
serialPort.enableReceiveTimeout(1000);
|
||||
|
||||
// RXTX serial port library causes high CPU load
|
||||
// Start event listener, which will just sleep and slow down event loop
|
||||
serialPort.addEventListener(this);
|
||||
serialPort.notifyOnDataAvailable(true);
|
||||
|
||||
return serialPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command == RefreshType.REFRESH && isLinked(channelUID.getId())) {
|
||||
switch (channelUID.getId()) {
|
||||
case BRIDGE_MESSAGES_SENT:
|
||||
updateState(BRIDGE_MESSAGES_SENT, new DecimalType(messagesSent.get()));
|
||||
break;
|
||||
case BRIDGE_RESPONSES_RECEIVED:
|
||||
updateState(BRIDGE_RESPONSES_RECEIVED, new DecimalType(responsesReceived.get()));
|
||||
break;
|
||||
case BRIDGE_EVENTS_RECEIVED:
|
||||
updateState(BRIDGE_EVENTS_RECEIVED, new DecimalType(eventsReceived.get()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendRequest(DigiplexRequest request) {
|
||||
sendQueue.add(request);
|
||||
}
|
||||
|
||||
public void handleResponse(String message) {
|
||||
DigiplexResponse response = DigiplexResponseResolver.resolveResponse(message);
|
||||
handlers.forEach(visitor -> response.accept(visitor));
|
||||
if (response instanceof AbstractEvent) {
|
||||
updateState(BRIDGE_EVENTS_RECEIVED, new DecimalType(eventsReceived.incrementAndGet()));
|
||||
} else {
|
||||
updateState(BRIDGE_RESPONSES_RECEIVED, new DecimalType(responsesReceived.incrementAndGet()));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerMessageHandler(DigiplexMessageHandler handler) {
|
||||
handlers.add(handler);
|
||||
}
|
||||
|
||||
public void unregisterMessageHandler(DigiplexMessageHandler handler) {
|
||||
handlers.remove(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the connection to the PRT3 module.
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
@Override
|
||||
public void dispose() {
|
||||
stopThread(senderThread);
|
||||
stopThread(receiverThread);
|
||||
senderThread = null;
|
||||
receiverThread = null;
|
||||
if (serialPort != null) {
|
||||
try {
|
||||
InputStream inputStream = serialPort.getInputStream();
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.debug("Error closing input stream", e);
|
||||
}
|
||||
|
||||
try {
|
||||
OutputStream outputStream = serialPort.getOutputStream();
|
||||
if (outputStream != null) {
|
||||
outputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.debug("Error closing output stream", e);
|
||||
}
|
||||
|
||||
serialPort.close();
|
||||
serialPort = null;
|
||||
}
|
||||
logger.info("Stopped Digiplex serial handler");
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void stopThread(@Nullable Thread thread) {
|
||||
if (thread != null) {
|
||||
thread.interrupt();
|
||||
try {
|
||||
thread.join(1000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleCommunicationError() {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
if (reinitializeTask == null) {
|
||||
reinitializeTask = scheduler.schedule(() -> {
|
||||
logger.info("Reconnecting to PRT3 device...");
|
||||
thingUpdated(getThing());
|
||||
reinitializeTask = null;
|
||||
}, REINITIALIZE_DELAY, TimeUnit.MINUTES);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialEvent(@Nullable SerialPortEvent arg0) {
|
||||
try {
|
||||
logger.trace("RXTX library CPU load workaround, sleep forever");
|
||||
Thread.sleep(Long.MAX_VALUE);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Collections.singletonList(DigiplexDiscoveryService.class);
|
||||
}
|
||||
|
||||
private class BridgeMessageHandler implements DigiplexMessageHandler {
|
||||
|
||||
@Override
|
||||
public void handleCommunicationStatus(CommunicationStatus response) {
|
||||
if (response.success) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTroubleEvent(TroubleEvent troubleEvent) {
|
||||
if (troubleEvent.getAreaNo() == GLOBAL_AREA_NO) {
|
||||
String channel = troubleEvent.getType().getBridgeChannel();
|
||||
State state = OnOffType.from(troubleEvent.getStatus() == TroubleStatus.TROUBLE_STARTED);
|
||||
updateState(channel, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DigiplexReceiverThread extends Thread {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(DigiplexReceiverThread.class);
|
||||
|
||||
private final InputStream stream;
|
||||
|
||||
DigiplexReceiverThread(InputStream stream) {
|
||||
super("DigiplexReceiveThread");
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
logger.debug("Receiver thread started");
|
||||
while (!interrupted()) {
|
||||
try {
|
||||
Optional<String> message = readLineBlocking();
|
||||
message.ifPresent(m -> {
|
||||
logger.debug("message received: '{}'", m);
|
||||
handleResponse(m);
|
||||
});
|
||||
if (messagesSent.get() - responsesReceived.get() > STALLED_MESSAGES_THRESHOLD) {
|
||||
throw new IOException("PRT3 module is not responding!");
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
handleCommunicationError();
|
||||
break;
|
||||
}
|
||||
}
|
||||
logger.debug("Receiver thread finished");
|
||||
}
|
||||
|
||||
private Optional<String> readLineBlocking() throws IOException {
|
||||
StringBuilder s = new StringBuilder();
|
||||
while (true) {
|
||||
int c = stream.read();
|
||||
if (c == END_OF_STREAM) {
|
||||
return Optional.empty();
|
||||
}
|
||||
if (c == END_OF_MESSAGE) {
|
||||
break;
|
||||
}
|
||||
s.append((char) c);
|
||||
}
|
||||
return Optional.of(s.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private class DigiplexSenderThread extends Thread {
|
||||
|
||||
private static final int SLEEP_TIME = 150;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(DigiplexSenderThread.class);
|
||||
|
||||
private OutputStream stream;
|
||||
|
||||
public DigiplexSenderThread(OutputStream stream) {
|
||||
super("DigiplexSenderThread");
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
logger.debug("Sender thread started");
|
||||
while (!interrupted()) {
|
||||
try {
|
||||
DigiplexRequest request = sendQueue.take();
|
||||
stream.write(request.getSerialMessage().getBytes());
|
||||
stream.flush();
|
||||
updateState(BRIDGE_MESSAGES_SENT, new DecimalType(messagesSent.incrementAndGet()));
|
||||
logger.debug("message sent: '{}'", request.getSerialMessage().replaceAll("\r", ""));
|
||||
Thread.sleep(SLEEP_TIME); // do not flood PRT3 with messages as it creates unpredictable responses
|
||||
} catch (IOException e) {
|
||||
handleCommunicationError();
|
||||
break;
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
logger.debug("Sender thread finished");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.handler;
|
||||
|
||||
import static org.openhab.binding.digiplex.internal.DigiplexBindingConstants.*;
|
||||
import static org.openhab.binding.digiplex.internal.handler.TypeUtils.openClosedFromBoolean;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.digiplex.internal.DigiplexBindingConstants;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexMessageHandler;
|
||||
import org.openhab.binding.digiplex.internal.communication.DigiplexRequest;
|
||||
import org.openhab.binding.digiplex.internal.communication.ZoneStatusRequest;
|
||||
import org.openhab.binding.digiplex.internal.communication.ZoneStatusResponse;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.ZoneEvent;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.ZoneEventType;
|
||||
import org.openhab.binding.digiplex.internal.communication.events.ZoneStatusEvent;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
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.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* The {@link DigiplexZoneHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DigiplexZoneHandler extends BaseThingHandler {
|
||||
|
||||
private @Nullable DigiplexBridgeHandler bridgeHandler;
|
||||
private DigiplexZoneMessageHandler messageHandler = new DigiplexZoneMessageHandler();
|
||||
private int zoneNo;
|
||||
private int areaNo = 0; // not known at the beginning (protocol limitation)
|
||||
private OpenClosedType status = OpenClosedType.CLOSED;
|
||||
private StringType extendedStatus = new StringType("CLOSED");
|
||||
private OpenClosedType alarm = OpenClosedType.CLOSED;
|
||||
private OpenClosedType fireAlarm = OpenClosedType.CLOSED;
|
||||
private OpenClosedType supervisionLost = OpenClosedType.CLOSED;
|
||||
private OpenClosedType lowBattery = OpenClosedType.CLOSED;
|
||||
private State lastTriggered = UnDefType.NULL;
|
||||
|
||||
public DigiplexZoneHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
switch (channelUID.getId()) {
|
||||
case ZONE_STATUS:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(ZONE_STATUS, status);
|
||||
}
|
||||
break;
|
||||
case ZONE_EXTENDED_STATUS:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(ZONE_EXTENDED_STATUS, extendedStatus);
|
||||
}
|
||||
break;
|
||||
case ZONE_ALARM:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(ZONE_ALARM, alarm);
|
||||
}
|
||||
break;
|
||||
case ZONE_FIRE_ALARM:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(ZONE_FIRE_ALARM, fireAlarm);
|
||||
}
|
||||
break;
|
||||
case ZONE_SUPERVISION_LOST:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(ZONE_SUPERVISION_LOST, supervisionLost);
|
||||
}
|
||||
break;
|
||||
case ZONE_LOW_BATTERY:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateState(ZONE_LOW_BATTERY, lowBattery);
|
||||
}
|
||||
break;
|
||||
case ZONE_LAST_TRIGGERED:
|
||||
if (command == RefreshType.REFRESH) {
|
||||
if (lastTriggered != UnDefType.NULL) {
|
||||
updateState(ZONE_LAST_TRIGGERED, lastTriggered);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Override
|
||||
public void initialize() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||
return;
|
||||
}
|
||||
this.bridgeHandler = (DigiplexBridgeHandler) bridge.getHandler();
|
||||
|
||||
String nodeParm = getThing().getProperties().get(DigiplexBindingConstants.PROPERTY_ZONE_NO);
|
||||
zoneNo = Integer.parseInt(nodeParm);
|
||||
String areaParm = getThing().getProperties().get(DigiplexBindingConstants.PROPERTY_AREA_NO);
|
||||
if (areaParm != null) {
|
||||
areaNo = Integer.parseInt(areaParm);
|
||||
}
|
||||
|
||||
bridgeHandler.registerMessageHandler(messageHandler);
|
||||
|
||||
DigiplexRequest request = new ZoneStatusRequest(zoneNo);
|
||||
bridgeHandler.sendRequest(request);
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
private void updateChannels(boolean allChannels) {
|
||||
updateState(ZONE_STATUS, status);
|
||||
updateState(ZONE_EXTENDED_STATUS, extendedStatus);
|
||||
if (lastTriggered != UnDefType.NULL) {
|
||||
updateState(ZONE_LAST_TRIGGERED, lastTriggered);
|
||||
}
|
||||
if (allChannels) {
|
||||
updateState(ZONE_ALARM, alarm);
|
||||
updateState(ZONE_FIRE_ALARM, fireAlarm);
|
||||
updateState(ZONE_SUPERVISION_LOST, supervisionLost);
|
||||
updateState(ZONE_LOW_BATTERY, lowBattery);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Override
|
||||
public void handleRemoval() {
|
||||
if (messageHandler != null) {
|
||||
bridgeHandler.unregisterMessageHandler(messageHandler);
|
||||
}
|
||||
super.handleRemoval();
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Override
|
||||
public void bridgeStatusChanged(ThingStatusInfo thingStatusInfo) {
|
||||
if (thingStatusInfo.getStatus() == ThingStatus.OFFLINE) {
|
||||
updateStatus(ThingStatus.OFFLINE, thingStatusInfo.getStatusDetail());
|
||||
} else if (thingStatusInfo.getStatus() == ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
DigiplexRequest request = new ZoneStatusRequest(zoneNo);
|
||||
bridgeHandler.sendRequest(request);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAreaNo(int areaNo) {
|
||||
if (this.areaNo == 0) {
|
||||
this.areaNo = areaNo;
|
||||
getThing().setProperty(DigiplexBindingConstants.PROPERTY_AREA_NO, Integer.toString(areaNo));
|
||||
}
|
||||
}
|
||||
|
||||
private class DigiplexZoneMessageHandler implements DigiplexMessageHandler {
|
||||
|
||||
@Override
|
||||
public void handleZoneStatusResponse(ZoneStatusResponse response) {
|
||||
if (response.zoneNo == DigiplexZoneHandler.this.zoneNo) {
|
||||
status = response.status.toOpenClosedType();
|
||||
extendedStatus = new StringType(response.status.toString());
|
||||
alarm = openClosedFromBoolean(response.alarm);
|
||||
fireAlarm = openClosedFromBoolean(response.fireAlarm);
|
||||
supervisionLost = openClosedFromBoolean(response.supervisionLost);
|
||||
lowBattery = openClosedFromBoolean(response.lowBattery);
|
||||
updateChannels(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleZoneStatusEvent(ZoneStatusEvent event) {
|
||||
if (event.getZoneNo() == DigiplexZoneHandler.this.zoneNo) {
|
||||
status = event.getStatus().toOpenClosedType();
|
||||
extendedStatus = new StringType(event.getStatus().toString());
|
||||
lastTriggered = new DateTimeType(ZonedDateTime.now());
|
||||
updateChannels(false);
|
||||
updateAreaNo(event.getAreaNo());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleZoneEvent(ZoneEvent event) {
|
||||
if (event.getZoneNo() == DigiplexZoneHandler.this.zoneNo) {
|
||||
switch (event.getType()) {
|
||||
case ALARM:
|
||||
case ALARM_RESTORE:
|
||||
alarm = openClosedFromBoolean(event.getType() == ZoneEventType.ALARM);
|
||||
updateState(ZONE_ALARM, alarm);
|
||||
break;
|
||||
case FIRE_ALARM:
|
||||
case FIRE_ALARM_RESTORE:
|
||||
fireAlarm = openClosedFromBoolean(event.getType() == ZoneEventType.FIRE_ALARM);
|
||||
updateState(ZONE_FIRE_ALARM, fireAlarm);
|
||||
break;
|
||||
case LOW_BATTERY:
|
||||
case LOW_BATTERY_RESTORE:
|
||||
lowBattery = openClosedFromBoolean(event.getType() == ZoneEventType.LOW_BATTERY);
|
||||
updateState(ZONE_LOW_BATTERY, lowBattery);
|
||||
break;
|
||||
case SUPERVISION_TROUBLE:
|
||||
case SUPERVISION_TROUBLE_RESTORE:
|
||||
supervisionLost = openClosedFromBoolean(event.getType() == ZoneEventType.SUPERVISION_TROUBLE);
|
||||
updateState(ZONE_SUPERVISION_LOST, supervisionLost);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
updateAreaNo(event.getAreaNo());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.digiplex.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
|
||||
/**
|
||||
* Utility classes for type conversions
|
||||
*
|
||||
* @author Robert Michalak - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TypeUtils {
|
||||
|
||||
public static OpenClosedType openClosedFromBoolean(boolean value) {
|
||||
return value ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="digiplex" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>Digiplex/EVO Binding</name>
|
||||
<description>Binding for Digiplex/EVO alarm systems (utilizing PRT3 module)</description>
|
||||
<author>Robert Michalak</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="digiplex"
|
||||
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-type id="area" listed="false">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Area</label>
|
||||
<description>Area</description>
|
||||
<channels>
|
||||
<channel typeId="area_status" id="status"/>
|
||||
<channel typeId="area_armed" id="armed"/>
|
||||
<channel typeId="zone_in_memory" id="zone_in_memory"/>
|
||||
<channel typeId="trouble" id="trouble"/>
|
||||
<channel typeId="ready" id="ready"/>
|
||||
<channel typeId="in_programming" id="in_programming"/>
|
||||
<channel typeId="alarm" id="alarm"/>
|
||||
<channel typeId="strobe" id="strobe"/>
|
||||
<channel typeId="control" id="control"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="refreshPeriod" type="integer" unit="s">
|
||||
<label>Refresh Time of Area Status</label>
|
||||
<description>Controls how often area status will be refreshed from the PRT3 module</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
|
||||
<channel-type id="area_status">
|
||||
<item-type>String</item-type>
|
||||
<label>Area Status</label>
|
||||
<description>Area Status as received from 'Area Status Request'</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="DISARMED">Disarmed</option>
|
||||
<option value="ARMED">Armed</option>
|
||||
<option value="ARMED_FORCE">Force armed</option>
|
||||
<option value="ARMED_STAY">Stay armed</option>
|
||||
<option value="ARMED_INSTANT">Instant armed</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="area_armed">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Area Armed</label>
|
||||
<description>Indicates if area is armed</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">Ok</option>
|
||||
<option value="OPEN">Armed</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="zone_in_memory">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Zone in Memory</label>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">Ok</option>
|
||||
<option value="OPEN">Zone in memory</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="trouble">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Trouble</label>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">Ok</option>
|
||||
<option value="OPEN">Trouble</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ready">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Area Ready</label>
|
||||
<description>Indicates if area is ready (no open zones)</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">Not ready</option>
|
||||
<option value="OPEN">Ready</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="in_programming">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Area in Programming Mode</label>
|
||||
<description>Indicates if area is in the programming mode</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">Ok</option>
|
||||
<option value="OPEN">In programming mode</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="alarm">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Area in Alarm</label>
|
||||
<description>Indicates if area is in alarm</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">Ok</option>
|
||||
<option value="OPEN">Alarm</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="strobe">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Strobe</label>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">Ok</option>
|
||||
<option value="OPEN">Strobe</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="control">
|
||||
<item-type>String</item-type>
|
||||
<label>Control Alarm System</label>
|
||||
<description>Used to control area status. By reading its state one can check result of the last command sent to the
|
||||
alarm system.</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="OK">Ok</option>
|
||||
<option value="FAIL">Fail</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,192 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="digiplex"
|
||||
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">
|
||||
|
||||
<bridge-type id="bridge">
|
||||
<label>Digiplex PRT3 Module</label>
|
||||
<description>Digiplex PRT3 module with Serial Interface</description>
|
||||
<channel-groups>
|
||||
<channel-group typeId="statistics" id="statistics"/>
|
||||
<channel-group typeId="troubles" id="troubles"/>
|
||||
</channel-groups>
|
||||
|
||||
<config-description>
|
||||
|
||||
<parameter-group name="port">
|
||||
<context>communication</context>
|
||||
<label>Port Configuration</label>
|
||||
<description></description>
|
||||
</parameter-group>
|
||||
|
||||
<parameter name="port" type="text" required="true" groupName="port">
|
||||
<label>Serial Port</label>
|
||||
<context>serial-port</context>
|
||||
<limitToOptions>false</limitToOptions>
|
||||
<description>Set the serial port used to access PRT3 device</description>
|
||||
<default></default>
|
||||
</parameter>
|
||||
|
||||
<parameter name="baudrate" type="integer" required="true" groupName="port">
|
||||
<label>Baud Rate</label>
|
||||
<context>serial-port</context>
|
||||
<description>Set the serial port baud rate</description>
|
||||
<default>2400</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
<options>
|
||||
<option value="2400">2400</option>
|
||||
<option value="9600">9600</option>
|
||||
<option value="19200">19200</option>
|
||||
<option value="57600">57600</option>
|
||||
</options>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
|
||||
<channel-group-type id="statistics">
|
||||
<label>Statistics</label>
|
||||
<description>Statistics of PRT3 communication</description>
|
||||
<channels>
|
||||
<channel typeId="messages_sent" id="messages_sent"/>
|
||||
<channel typeId="responses_received" id="responses_received"/>
|
||||
<channel typeId="events_received" id="events_received"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="troubles">
|
||||
<label>Troubles</label>
|
||||
<description>Problems reported by the alarm system</description>
|
||||
<channels>
|
||||
<channel typeId="tlm_trouble" id="tlm_trouble"/>
|
||||
<channel typeId="ac_failure" id="ac_failure"/>
|
||||
<channel typeId="battery_failure" id="battery_failure"/>
|
||||
<channel typeId="aux_current_limit" id="aux_current_limit"/>
|
||||
<channel typeId="bell_current_limit" id="bell_current_limit"/>
|
||||
<channel typeId="bell_absent" id="bell_absent"/>
|
||||
<channel typeId="clock_trouble" id="clock_trouble"/>
|
||||
<channel typeId="global_fire_loop" id="global_fire_loop"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-type id="messages_sent">
|
||||
<item-type>Number</item-type>
|
||||
<label>Messages Sent</label>
|
||||
<description>Counts messages sent to the alarm system</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="responses_received">
|
||||
<item-type>Number</item-type>
|
||||
<label>Responses Received</label>
|
||||
<description>Counts responses received from the alarm system</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="events_received">
|
||||
<item-type>Number</item-type>
|
||||
<label>Events Received</label>
|
||||
<description>Counts events received from the alarm system</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tlm_trouble">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Telephone Line</label>
|
||||
<description>Reports telephone line failure</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="ON">Failure</option>
|
||||
<option value="OFF">OK</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ac_failure">
|
||||
<item-type>Switch</item-type>
|
||||
<label>AC Line</label>
|
||||
<description>Reports power line failure</description>
|
||||
<category>Energy</category>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="ON">Failure</option>
|
||||
<option value="OFF">OK</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="battery_failure">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Battery</label>
|
||||
<description>Reports battery failure</description>
|
||||
<category>LowBattery</category>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="ON">Failure</option>
|
||||
<option value="OFF">OK</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="aux_current_limit">
|
||||
<item-type>Switch</item-type>
|
||||
<label>AUX Current Limit</label>
|
||||
<description>Auxiliary Outputs have exceeded their current limits</description>
|
||||
<category>Energy</category>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="ON">Exceeded</option>
|
||||
<option value="OFF">OK</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="bell_current_limit">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Bell Current Limit</label>
|
||||
<description>Bell Output has exceeded its current limit</description>
|
||||
<category>Energy</category>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="ON">Exceeded</option>
|
||||
<option value="OFF">OK</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="bell_absent">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Bell Status</label>
|
||||
<description>Reports if bell is absent</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="ON">Absent</option>
|
||||
<option value="OFF">OK</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="clock_trouble">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Clock</label>
|
||||
<description>Reports if clock is not malfunctioning</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="ON">Failure</option>
|
||||
<option value="OFF">OK</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="global_fire_loop">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Global Fire Loop</label>
|
||||
<description>Reports if fire loop has been triggered</description>
|
||||
<category>Smoke</category>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="ON">Fire!</option>
|
||||
<option value="OFF">OK</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="digiplex"
|
||||
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-type id="zone" listed="false">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Zone</label>
|
||||
<description>Zone</description>
|
||||
<channels>
|
||||
<channel typeId="status" id="status"/>
|
||||
<channel typeId="extended_status" id="extended_status"/>
|
||||
<channel typeId="alarm" id="alarm"/>
|
||||
<channel typeId="fire_alarm" id="fire_alarm"/>
|
||||
<channel typeId="supervision_lost" id="supervision_lost"/>
|
||||
<channel typeId="low_battery" id="low_battery"/>
|
||||
<channel typeId="last_triggered" id="last_triggered"/>
|
||||
</channels>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="status">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Zone Status</label>
|
||||
<description>Zone Status (Open/Closed)</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">Closed</option>
|
||||
<option value="OPEN">Open</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="extended_status">
|
||||
<item-type>String</item-type>
|
||||
<label>Extended Zone Status</label>
|
||||
<description>Indicates actual zone state as a string</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">Closed</option>
|
||||
<option value="OPEN">Open</option>
|
||||
<option value="TAMPERED">Tampered</option>
|
||||
<option value="FIRE_LOOP_TROUBLE">Fire Loop Trouble</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="alarm">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Alarm Triggered</label>
|
||||
<description>Indicates if zone is in alarm</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">No</option>
|
||||
<option value="OPEN">Yes</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fire_alarm">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Fire Alarm Triggered</label>
|
||||
<description>Indicates if zone is in fire alarm</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">No</option>
|
||||
<option value="OPEN">Yes</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="supervision_lost">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Supervision Lost</label>
|
||||
<description>Indicates if zone has lost a supervision</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">No</option>
|
||||
<option value="OPEN">Yes</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="low_battery">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Low Battery Warning</label>
|
||||
<description>Indicates if zone is low on battery</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="CLOSED">No</option>
|
||||
<option value="OPEN">Yes</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="last_triggered">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Last Triggered Time</label>
|
||||
<description>Indicates when the zone has been triggered for the last time</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user