added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.globalcache-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>file:${basedirRoot}/bundles/org.openhab.transform.map/target/feature/feature.xml</repository>
<feature name="openhab-binding-globalcache" description="GlobalCache Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-transformation-map</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.globalcache/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,120 @@
/**
* 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.globalcache.internal;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link GlobalCacheBindingConstants} class defines common constants that are
* used by the globalcache binding.
*
* @author Mark Hilbush - Initial contribution
*/
@NonNullByDefault
public class GlobalCacheBindingConstants {
public static final String BINDING_ID = "globalcache";
/*
* GlobalCache thing definitions
*/
// GlobalCache Thing Type UIDs -- IR = Infrared, CC = Contact Closure, SL = Serial
public static final ThingTypeUID THING_TYPE_ITACH_IR = new ThingTypeUID(BINDING_ID, "itachIR");
public static final ThingTypeUID THING_TYPE_ITACH_CC = new ThingTypeUID(BINDING_ID, "itachCC");
public static final ThingTypeUID THING_TYPE_ITACH_SL = new ThingTypeUID(BINDING_ID, "itachSL");
public static final ThingTypeUID THING_TYPE_ITACH_FLEX = new ThingTypeUID(BINDING_ID, "itachFlex");
public static final ThingTypeUID THING_TYPE_GC_100_06 = new ThingTypeUID(BINDING_ID, "gc100_06");
public static final ThingTypeUID THING_TYPE_GC_100_12 = new ThingTypeUID(BINDING_ID, "gc100_12");
public static final ThingTypeUID THING_TYPE_ZMOTE = new ThingTypeUID(BINDING_ID, "zmote");
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(
Stream.of(THING_TYPE_ITACH_IR, THING_TYPE_ITACH_CC, THING_TYPE_ITACH_SL, THING_TYPE_ITACH_FLEX,
THING_TYPE_GC_100_06, THING_TYPE_GC_100_12, THING_TYPE_ZMOTE).collect(Collectors.toSet()));
// GlobalCache-specific thing properties
public static final String THING_PROPERTY_UID = "uid";
public static final String THING_PROPERTY_MAC = "macAddress";
/*
* GlobalCache thing configuration items
*/
// Network address of the device
public static final String THING_PROPERTY_IP = "ipAddress";
// MAP file containing mappings from command to IR and SL string
public static final String THING_CONFIG_MAP_FILENAME = "mapFilename";
// Flex "Current Active Cable"
public static final String THING_CONFIG_ACTIVECABLE = "activeCable";
public static final String ACTIVE_CABLE_INFRARED = "FLEX_INFRARED";
public static final String ACTIVE_CABLE_SERIAL = "FLEX_SERIAL";
public static final String ACTIVE_CABLE_RELAY = "FLEX_RELAY";
// Serial readers
public static final String CONFIG_ENABLE_TWO_WAY_PORT_1 = "enableTwoWay1";
public static final String CONFIG_END_OF_MESSAGE_DELIMITER_PORT_1 = "eomDelimiter1";
public static final String CONFIG_ENABLE_TWO_WAY_PORT_2 = "enableTwoWay2";
public static final String CONFIG_END_OF_MESSAGE_DELIMITER_PORT_2 = "eomDelimiter2";
// Indicates TCP connection over which the command will be sent
public enum CommandType {
COMMAND,
SERIAL1,
SERIAL2
}
/*
* Channel constants
*/
// GlobalCache Channel Types
public static final String CHANNEL_TYPE_IR = "channel-type-ir";
public static final String CHANNEL_TYPE_CC = "channel-type-cc";
public static final String CHANNEL_TYPE_SL = "channel-type-sl";
public static final String CHANNEL_TYPE_SL_DIRECT = "channel-type-sl-direct";
public static final String CHANNEL_TYPE_SL_FEEDBACK = "channel-type-sl-receive";
// Channels for handing feedback from serial devices
public static final String CHANNEL_SL_M1_RECEIVE = "sl-m1#c1-receive";
public static final String CHANNEL_SL_M2_RECEIVE = "sl-m2#c1-receive";
// Channel properties that are used to specify module number and connector number
public static final String CHANNEL_PROPERTY_MODULE = "module";
public static final String CHANNEL_PROPERTY_CONNECTOR = "connector";
// List of iTach model strings returned in the device discovery beacon
public static final String GC_MODEL_ITACH = "iTach";
public static final String GC_MODEL_ITACHIP2IR = "iTachIP2IR";
public static final String GC_MODEL_ITACHWF2IR = "iTachWF2IR";
public static final String GC_MODEL_ITACHIP2CC = "iTachIP2CC";
public static final String GC_MODEL_ITACHWF2CC = "iTachWF2CC";
public static final String GC_MODEL_ITACHIP2SL = "iTachIP2SL";
public static final String GC_MODEL_ITACHWF2SL = "iTachWF2SL";
public static final String GC_MODEL_ITACHFLEXETH = "iTachFlexEthernet";
public static final String GC_MODEL_ITACHFLEXETHPOE = "iTachFlexEthernetPoE";
public static final String GC_MODEL_ITACHFLEXWIFI = "iTachFlexWiFi";
// List of GC-100 model strings returned in the device discovery beacon
public static final String GC_MODEL_GC_100 = "GC-100";
public static final String GC_MODEL_GC_100_06 = "GC-100-06";
public static final String GC_MODEL_GC_100_12 = "GC-100-12";
// List of Zmote strings returned in the device discovery beacon
public static final String GC_MODEL_ZMOTE = "ZV-2";
}

View File

@@ -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.globalcache.internal;
import static org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.SUPPORTED_THING_TYPES_UIDS;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.globalcache.internal.handler.GlobalCacheHandler;
import org.openhab.core.net.NetworkAddressService;
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 GlobalCacheHandlerFactory} is responsible for creating thing handlers.
*
* @author Mark Hilbush - Initial contribution
*/
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.globalcache")
public class GlobalCacheHandlerFactory extends BaseThingHandlerFactory {
private final NetworkAddressService networkAddressService;
@Activate
public GlobalCacheHandlerFactory(@Reference NetworkAddressService networkAddressService) {
this.networkAddressService = networkAddressService;
}
@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 (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
return new GlobalCacheHandler(thing, networkAddressService.getPrimaryIpv4HostAddress());
}
return null;
}
}

View File

@@ -0,0 +1,517 @@
/**
* 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.globalcache.internal.command;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants;
import org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.CommandType;
import org.openhab.binding.globalcache.internal.handler.GlobalCacheHandler;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link AbstractCommand} class implements the basic functionality needed for all GlobalCache commands.
*
* @author Mark Hilbush - Initial contribution
*/
public abstract class AbstractCommand implements CommandInterface {
private final Logger logger = LoggerFactory.getLogger(AbstractCommand.class);
private LinkedBlockingQueue<RequestMessage> requestQueue;
private final int RESPONSE_QUEUE_MAX_DEPTH = 1;
private final int RESPONSE_QUEUE_TIMEOUT = 3000;
protected Thing thing;
protected String ipAddress;
// Actual command strings sent to/received from the device (without CR)
protected String deviceCommand;
protected String deviceReply;
// Short human-readable name of the command
protected String commandName;
// Determines which TCP port will be used for the command
private CommandType commandType;
protected String module;
protected String connector;
protected String errorModule;
protected String errorConnector;
protected String errorCode;
protected String errorMessage;
private boolean isQuiet;
/*
* The {@link AbstractCommand} abstract class is the basis for all GlobalCache device command classes.
*
* @author Mark Hilbush - Initial contribution
*/
public AbstractCommand(Thing t, LinkedBlockingQueue<RequestMessage> q, String n, CommandType c) {
thing = t;
requestQueue = q;
commandName = n;
commandType = c;
setQuiet(false);
module = null;
connector = null;
deviceCommand = null;
deviceReply = null;
errorCode = null;
errorMessage = null;
ipAddress = ((GlobalCacheHandler) thing.getHandler()).getIP();
}
public String getCommandName() {
return commandName;
}
@Override
public String getModule() {
return module;
}
public void setModule(String m) {
module = m;
}
@Override
public String getConnector() {
return connector;
}
public void setConnector(String c) {
connector = c;
}
public void setCommandType(CommandType commandType) {
this.commandType = commandType;
}
public boolean isGC100Model12() {
return thing.getThingTypeUID().equals(GlobalCacheBindingConstants.THING_TYPE_GC_100_12);
}
@Override
public abstract void parseSuccessfulReply();
public boolean isSuccessful() {
return errorCode == null ? true : false;
}
public String successAsString() {
return errorCode == null ? "succeeded" : "failed";
}
public String getErrorCode() {
return errorCode;
}
public String getErrorMessage() {
return errorMessage;
}
public String getErrorModule() {
return errorModule;
}
public String getErrorConnector() {
return errorConnector;
}
protected boolean isQuiet() {
return isQuiet;
}
private void setQuiet(boolean quiet) {
isQuiet = quiet;
}
/*
* Execute a GlobalCache device command
*/
public void executeQuiet() {
setQuiet(true);
execute();
}
public void execute() {
if (requestQueue == null) {
createGenericError("Execute method was called with a null requestQueue");
return;
}
if (deviceCommand == null) {
createGenericError("Execute method was called with a null deviceCommand");
return;
}
if (thing == null) {
createGenericError("Execute method was called with a null thing");
return;
}
// Send command & get response
if (sendCommand()) {
parseSuccessfulReply();
if (!isQuiet()) {
logSuccess();
}
} else {
if (!isQuiet()) {
logFailure();
}
}
return;
}
/*
* Place a request message onto the request queue, then wait on the response queue for the
* response message. The CommandHandler private class in GlobalCacheHandler.java
* is responsible for the actual device interaction.
*/
private boolean sendCommand() {
// Create a response queue. The command processor will use this queue to return the device's reply.
LinkedBlockingQueue<ResponseMessage> responseQueue = new LinkedBlockingQueue<>(RESPONSE_QUEUE_MAX_DEPTH);
// Create the request message
RequestMessage requestMsg = new RequestMessage(commandName, commandType, deviceCommand, responseQueue);
try {
// Put the request message on the request queue
requestQueue.put(requestMsg);
logger.trace("Put request on queue (depth={}), sent command '{}'", requestQueue.size(), deviceCommand);
// Wait on the response queue for the response message
ResponseMessage responseMsg = responseQueue.poll(RESPONSE_QUEUE_TIMEOUT, TimeUnit.MILLISECONDS);
if (responseMsg == null) {
createGenericError("Timed out waiting on response queue for message");
return false;
}
deviceReply = responseMsg.getDeviceReply();
logger.trace("Got response message off response queue, received reply '{}'", deviceReply);
if (isErrorReply(deviceReply)) {
return false;
}
} catch (InterruptedException e) {
createGenericError("Poll of response queue was interrupted");
return false;
}
return true;
}
/*
* Parse the reply and set error values if an error occurred.
*/
private boolean isErrorReply(String reply) {
logger.trace("Checking device reply for error condition: {}", reply);
Pattern pattern;
Matcher matcher;
// Generic (generated by binding) errors are of the form
// ERROR: message
if (reply.startsWith("ERROR:")) {
createGenericError(reply);
return true;
}
// iTach response for unknown command are of the form
// unknowncommand,eee, where eee is the error number
if (reply.startsWith("unknowncommand,") && reply.length() >= 16) {
String eCode = reply.substring(15);
createGenericError("Device does not understand command, error code is " + eCode);
errorCode = eCode;
return true;
}
// GC-100 response for unknown command are of the form
// unknowncommand ee, where ee is the error number
if (reply.startsWith("unknowncommand ") && reply.length() >= 16) {
errorModule = "";
errorConnector = "";
errorCode = reply.substring(15);
errorMessage = lookupErrorMessage(errorCode, GC100_ERROR_MESSAGES);
logger.debug("Device reply indicates GC-100 error condition");
return true;
}
// iTach error replies are of the form ERR_m:c,eee, where m is the module number,
// c is the connector number, and eee is the error number
pattern = Pattern.compile("ERR_[0-9]:[0-3],\\d\\d\\d");
matcher = pattern.matcher(reply);
if (matcher.find()) {
errorModule = reply.substring(4, 5);
errorConnector = reply.substring(6, 7);
errorCode = reply.substring(8, 11);
errorMessage = lookupErrorMessage(errorCode, ITACH_ERROR_MESSAGES);
logger.debug("Device reply indicates iTach error condition");
return true;
}
// Flex general error replies are of the form ERR eee, where eee is the error number
pattern = Pattern.compile("ERR \\d\\d\\d");
matcher = pattern.matcher(reply);
if (matcher.find()) {
errorModule = "";
errorConnector = "";
errorCode = reply.substring(4);
errorMessage = lookupErrorMessage(errorCode, FLEX_ERROR_MESSAGES);
logger.debug("Device reply indicates Flex general error condition");
return true;
}
// Flex infrared error replies are of the form ERR IReee, where eee is the error number
pattern = Pattern.compile("ERR IR\\d\\d\\d");
matcher = pattern.matcher(reply);
if (matcher.find()) {
errorModule = "";
errorConnector = "";
errorCode = reply.substring(6);
errorMessage = lookupErrorMessage(errorCode, FLEX_IR_ERROR_MESSAGES);
logger.debug("Device reply indicates Flex IR error condition");
return true;
}
// Flex serial error replies are of the form ERR SLeee, where eee is the error number
pattern = Pattern.compile("ERR SL\\d\\d\\d");
matcher = pattern.matcher(reply);
if (matcher.find()) {
errorModule = "";
errorConnector = "";
errorCode = reply.substring(6);
errorMessage = lookupErrorMessage(errorCode, FLEX_SL_ERROR_MESSAGES);
logger.debug("Device reply indicates Flex SL error condition");
return true;
}
errorCode = null;
return false;
}
private void createGenericError(String s) {
errorModule = "N/A";
errorConnector = "N/A";
errorCode = "N/A";
errorMessage = s;
}
private String lookupErrorMessage(String errorCode, String[] errorMessageArray) {
int eCode;
try {
eCode = Integer.parseInt(errorCode);
} catch (NumberFormatException e) {
eCode = 0;
logger.debug("Badly formatted error code '{}' received from device: {}", errorCode, e.getMessage());
}
if (eCode < 1 || eCode > errorMessageArray.length) {
eCode = 0;
}
return errorMessageArray[eCode];
}
/*
* Errors returned by GlobalCache iTach devices
*/
private static final String[] ITACH_ERROR_MESSAGES = {
// 0
"Unknown error",
// 1
"Invalid command. Command not found.",
// 2
"Invalid module address (does not exist).",
// 3
"Invalid connector address (does not exist).",
// 4
"Invalid ID value.",
// 5
"Invalid frequency value",
// 6
"Invalid repeat value.",
// 7
"Invalid offset value.",
// 8
"Invalid pulse count.",
// 9
"Invalid pulse data.",
// 10
"Uneven amount of <on|off> statements.",
// 11
"No carriage return found.",
// 12
"Repeat count exceeded.",
// 13
"IR command sent to input connector.",
// 14
"Blaster command sent to non-blaster connector.",
// 15
"No carriage return before buffer full.",
// 16
"No carriage return.",
// 17
"Bad command syntax.",
// 18
"Sensor command sent to non-input connector.",
// 19
"Repeated IR transmission failure.",
// 20
"Above designated IR <on|off> pair limit.",
// 21
"Symbol odd boundary.",
// 22
"Undefined symbol.",
// 23
"Unknown option.",
// 24
"Invalid baud rate setting.",
// 25
"Invalid flow control setting.",
// 26
"Invalid parity setting.",
// 27
"Settings are locked."
//
};
/*
* Errors returned by GlobalCache GC-100 devices
*/
private static final String[] GC100_ERROR_MESSAGES = {
// 0
"Unknown error.",
// 1
"Time out occurred because <CR> not received. Request not processed",
// 2
"Invalid module address (module does not exist) received with getversion.",
// 3
"Invalid module address (module does not exist).",
// 4
"Invalid connector address.",
// 5
"Connector address 1 is set up as “sensor in” when attempting IR command.",
// 6
"Connector address 2 is set up as “sensor in” when attempting IR command.",
// 7
"Connector address 3 is set up as “sensor in” when attempting IR command.",
// 8
"Offset is set to an even transition number, but should be odd.",
// 9
"Maximum number of transitions exceeded (256 total allowed).",
// 10
"Number of transitions in the IR command is not even.",
// 11
"Contact closure command sent to a module that is not a relay.",
// 12
"Missing carriage return. All commands must end with a carriage return.",
// 13
"State was requested of an invalid connector address.",
// 14
"Command sent to the unit is not supported by the GC-100.",
// 15
"Maximum number of IR transitions exceeded. (SM_IR_INPROCESS)",
// 16
"Invalid number of IR transitions (must be an even number).",
// 17
"Unknown error.",
// 18
"Unknown error.",
// 19
"Unknown error.",
// 20
"Unknown error.",
// 21
"Attempted to send an IR command to a non-IR module.",
// 22
"Unknown error.",
// 23
"Command sent is not supported by this type of module."
//
};
/*
* General errors returned by Flex devices
*/
private static final String[] FLEX_ERROR_MESSAGES = {
// 0
"Unknown error.",
// 1
"Invalid command. Command not found.",
// 2
"Bad command syntax used with a known command.",
// 3
"Invalid connector address (does not exist).",
// 4
"No carriage return found.",
// 5
"Command not supported by current Flex Link Port setting.",
// 6
"Settings are locked.",
//
};
/*
* Infrared errors returned by Flex devices
*/
private static final String[] FLEX_IR_ERROR_MESSAGES = {
// 0
"Unknown error.",
// 1
"Invalid ID value.",
// 2
"Invalid frequency.",
// 3
"Invalid repeat.",
// 4
"Invalid offset.",
// 5
"Invalid IR pulse value.",
// 6
"Odd amount of IR pulse values (must be even).",
// 7
"Maximum pulse pair limit exceeded.",
//
};
/*
* Serial errors returned by Flex devices
*/
private static final String[] FLEX_SL_ERROR_MESSAGES = {
// 0
"Unknown error.",
// 1
"Invalid baud rate.",
// 2
"Invalid flow control setting.",
// 3
"Invalid parity setting.",
//
};
}

View File

@@ -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.globalcache.internal.command;
import java.util.concurrent.LinkedBlockingQueue;
import org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.CommandType;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link CommandGetdevices} class implements the GlobalCache getdevices command.
*
* @author Mark Hilbush - Initial contribution
*/
public class CommandGetdevices extends AbstractCommand {
private final Logger logger = LoggerFactory.getLogger(CommandGetdevices.class);
public CommandGetdevices(Thing thing, LinkedBlockingQueue<RequestMessage> requestQueue) {
super(thing, requestQueue, "getdevices", CommandType.COMMAND);
deviceCommand = "getdevices";
}
@Override
public void parseSuccessfulReply() {
if (deviceReply == null) {
return;
}
// decode response
}
@Override
public void logSuccess() {
logger.debug("Execute '{}' succeeded on thing {} at {}", commandName, thing.getUID().getId(), ipAddress);
}
@Override
public void logFailure() {
logger.error("Execute '{}' failed for thing {} at {}, errorCode={}, errorMessage={}", commandName,
thing.getUID().getId(), ipAddress, errorCode, errorMessage);
}
}

View File

@@ -0,0 +1,91 @@
/**
* 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.globalcache.internal.command;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.CommandType;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link CommandGetserial} class implements the GlobalCache get_SERIAL command, which retrieves the serial
* port parameters (baud, flow control, and parity) from the device.
*
* @author Mark Hilbush - Initial contribution
*/
public class CommandGetserial extends AbstractCommand {
private final Logger logger = LoggerFactory.getLogger(CommandGetserial.class);
private String baud;
private String flow;
private String parity;
public CommandGetserial(Thing thing, LinkedBlockingQueue<RequestMessage> requestQueue, String mod, String con) {
super(thing, requestQueue, "get_SERIAL", CommandType.COMMAND);
deviceCommand = "get_SERIAL," + mod + ":" + con;
}
@Override
public void parseSuccessfulReply() {
if (deviceReply == null) {
return;
}
// decode response of form SERIAL,1:1,<baudrate>,<flowcontrol>,<parity
Pattern p = Pattern.compile("SERIAL,\\d:\\d,\\S+,\\S+,\\S+");
Matcher m = p.matcher(deviceReply);
if (!m.matches()) {
return;
}
String fields[] = deviceReply.split(",");
if (fields.length != 5) {
return;
}
setModule(fields[1].substring(0, 1));
setConnector(fields[1].substring(2));
baud = fields[2];
flow = fields[3];
parity = fields[4];
}
public String getBaud() {
return baud;
}
public String getFlowcontrol() {
return flow;
}
public String getParity() {
return parity;
}
@Override
public void logSuccess() {
logger.debug("Execute '{}' succeeded on thing {} at {}", commandName, thing.getUID().getId(), ipAddress);
}
@Override
public void logFailure() {
logger.error("Execute '{}' failed on thing {} at {}: errorCode={}, errorMessage={}", commandName,
thing.getUID().getId(), ipAddress, errorCode, errorMessage);
}
}

View File

@@ -0,0 +1,81 @@
/**
* 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.globalcache.internal.command;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.CommandType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link CommandGetstate} class implements the GlobalCache getstate command, which retrieves the
* current state of the contact closure on the device.
*
* @author Mark Hilbush - Initial contribution
*/
public class CommandGetstate extends AbstractCommand {
private final Logger logger = LoggerFactory.getLogger(CommandGetstate.class);
private OnOffType state;
public CommandGetstate(Thing thing, LinkedBlockingQueue<RequestMessage> requestQueue, String mod, String con) {
super(thing, requestQueue, "getstate", CommandType.COMMAND);
deviceCommand = "getstate," + mod + ":" + con;
}
@Override
public void parseSuccessfulReply() {
if (deviceReply == null) {
return;
}
// decode response of form state,1:3,0
Pattern p = Pattern.compile("state,\\d:\\d,[01]");
Matcher m = p.matcher(deviceReply);
if (!m.matches()) {
logger.warn("Successful reply from device can't be matched: {}", deviceReply);
state = OnOffType.OFF;
return;
}
setModule(deviceReply.substring(6, 7));
setConnector(deviceReply.substring(8, 9));
setState((deviceReply.charAt(10) == '0' ? OnOffType.OFF : OnOffType.ON));
}
private void setState(OnOffType s) {
state = s;
}
public OnOffType state() {
return state;
}
@Override
public void logSuccess() {
logger.debug("Execute '{}' succeeded on thing {} at {}, state={}", commandName, thing.getUID().getId(),
ipAddress, state);
}
@Override
public void logFailure() {
logger.error("Execute '{}' failed on thing {} at {}: errorCode={}, errorMessage={}", commandName,
thing.getUID().getId(), ipAddress, errorCode, errorMessage);
}
}

View File

@@ -0,0 +1,63 @@
/**
* 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.globalcache.internal.command;
import java.util.concurrent.LinkedBlockingQueue;
import org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.CommandType;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link CommandGetversion} class implements the GlobalCache getversion command, which retrieves software
* version of the device.
*
* @author Mark Hilbush - Initial contribution
*/
public class CommandGetversion extends AbstractCommand {
private final Logger logger = LoggerFactory.getLogger(CommandGetversion.class);
private String version;
public CommandGetversion(Thing thing, LinkedBlockingQueue<RequestMessage> requestQueue) {
super(thing, requestQueue, "getversion", CommandType.COMMAND);
deviceCommand = "getversion";
}
@Override
public void parseSuccessfulReply() {
if (deviceReply == null) {
return;
}
// decode response of form <textversionstring>
version = deviceReply;
}
public String getVersion() {
return version;
}
@Override
public void logSuccess() {
logger.debug("Execute '{}' succeeded on thing {} at {}, version={}", commandName, thing.getUID().getId(),
ipAddress, version);
}
@Override
public void logFailure() {
logger.error("Execute '{}' failed for thing {} at {}, errorCode={}, errorMessage={}", commandName,
thing.getUID().getId(), ipAddress, errorCode, errorMessage);
}
}

View File

@@ -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.globalcache.internal.command;
/**
* The {@link CommandInterface} interface class defines the methods that all command classes must implement.
*
* @author Mark Hilbush - Initial contribution
*/
public interface CommandInterface {
/**
* Get the module number to which the command will be sent
*
* @return module number as String
*/
public String getModule();
/**
* Get the connector number to which the command will be sent
*
* @return connector number as String
*/
public String getConnector();
/**
* Used by command implementations to parse the device's response
*/
abstract void parseSuccessfulReply();
/*
* Used by command implementations to report a successful command execution
*/
abstract void logSuccess();
/*
* Used by command implementations to report a failed command execution
*/
abstract void logFailure();
}

View File

@@ -0,0 +1,77 @@
/**
* 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.globalcache.internal.command;
import java.util.concurrent.LinkedBlockingQueue;
import org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.CommandType;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link CommandSendir} class implements the GlobalCache sendir command, which sends
* an infrared command to the device.
*
* @author Mark Hilbush - Initial contribution
*/
public class CommandSendir extends AbstractCommand {
private final Logger logger = LoggerFactory.getLogger(CommandSendir.class);
private String rcvCounter;
Command command;
public CommandSendir(Thing thing, Command command, LinkedBlockingQueue<RequestMessage> queue, String mod,
String con, String code, int sendCounter) {
super(thing, queue, "sendir", CommandType.COMMAND);
this.command = command;
deviceCommand = "sendir," + mod + ":" + con + "," + String.valueOf(sendCounter) + "," + code;
}
@Override
public void parseSuccessfulReply() {
if (deviceReply == null) {
return;
}
// decode response of form completeir,1:1,<ID>
if (deviceReply.startsWith("completeir")) {
setModule(deviceReply.substring(11, 12));
setConnector(deviceReply.substring(13, 14));
setRcvCounter(deviceReply.substring(15));
}
}
private void setRcvCounter(String c) {
rcvCounter = c;
}
public String getRcvCounter() {
return rcvCounter;
}
@Override
public void logSuccess() {
logger.debug("Execute '{}' succeeded for command {} on thing {} at {}", commandName, command.toString(),
thing.getUID().getId(), ipAddress);
}
@Override
public void logFailure() {
logger.error("Execute '{}' failed on thing {} at {}: errorCode={}, errorMessage={}", commandName,
thing.getUID().getId(), ipAddress, errorCode, errorMessage);
}
}

View File

@@ -0,0 +1,63 @@
/**
* 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.globalcache.internal.command;
import java.util.concurrent.LinkedBlockingQueue;
import org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.CommandType;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link CommandSendserial} class sends a serial command string to the device.
*
* @author Mark Hilbush - Initial contribution
*/
public class CommandSendserial extends AbstractCommand {
private final Logger logger = LoggerFactory.getLogger(CommandSendserial.class);
private Command command;
public CommandSendserial(Thing thing, Command command, LinkedBlockingQueue<RequestMessage> queue, String mod,
String con, String code) {
super(thing, queue, "sendserial", CommandType.SERIAL1);
// Check to see if this is for the second serial port on a GC-100-12
if (isGC100Model12() && mod.equals("2")) {
setCommandType(CommandType.SERIAL2);
}
this.command = command;
this.deviceCommand = code;
}
@Override
public void parseSuccessfulReply() {
if (deviceReply == null) {
return;
}
// decode response
}
@Override
public void logSuccess() {
logger.debug("Execute '{}' succeeded for command {} on thing {} at {}", commandName, command.toString(),
thing.getUID().getId(), ipAddress);
}
@Override
public void logFailure() {
logger.error("Execute '{}' failed on thing {} at {}: errorCode={}, errorMessage={}", commandName,
thing.getUID().getId(), ipAddress, errorCode, errorMessage);
}
}

View File

@@ -0,0 +1,92 @@
/**
* 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.globalcache.internal.command;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.CommandType;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link CommandSetserial} class implements the GlobalCache set_SERIAL command, which sets the serial
* port parameters (baud, flow control, and parity) on the device.
*
* @author Mark Hilbush - Initial contribution
*/
public class CommandSetserial extends AbstractCommand {
private final Logger logger = LoggerFactory.getLogger(CommandSetserial.class);
private String baud;
private String flow;
private String parity;
public CommandSetserial(Thing thing, LinkedBlockingQueue<RequestMessage> requestQueue, String mod, String con,
String baud, String flowcontrol, String parity) {
super(thing, requestQueue, "set_SERIAL", CommandType.COMMAND);
deviceCommand = "set_SERIAL," + mod + ":" + con + "," + baud + "," + flowcontrol + "," + parity;
}
@Override
public void parseSuccessfulReply() {
if (deviceReply == null) {
return;
}
// decode response of form SERIAL,1:1,<baudrate>,<flowcontrol>,<parity
Pattern p = Pattern.compile("SERIAL,\\d:\\d,\\S+,\\S+,\\S+");
Matcher m = p.matcher(deviceReply);
if (!m.matches()) {
return;
}
String fields[] = deviceReply.split(",");
if (fields.length != 5) {
return;
}
setModule(fields[1].substring(0, 1));
setConnector(fields[1].substring(2));
baud = fields[2];
flow = fields[3];
parity = fields[4];
}
public String getBaud() {
return baud;
}
public String getFlowcontrol() {
return flow;
}
public String getParity() {
return parity;
}
@Override
public void logSuccess() {
logger.debug("Execute '{}' succeeded on thing {} at {}", commandName, thing.getUID().getId(), ipAddress);
}
@Override
public void logFailure() {
logger.error("Execute '{}' failed on thing {} at: ipAdress={}, errorCode={}, errorMessage={}", commandName,
thing.getUID().getId(), ipAddress, errorCode, errorMessage);
}
}

View File

@@ -0,0 +1,98 @@
/**
* 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.globalcache.internal.command;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.CommandType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link CommandSetstate} class implements the GlobalCache setstate command for devices that support contact
* closure.
*
* @author Mark Hilbush - Initial contribution
*/
public class CommandSetstate extends AbstractCommand {
private final Logger logger = LoggerFactory.getLogger(CommandSetstate.class);
private Command command;
private OnOffType state;
public CommandSetstate(Thing thing, Command command, LinkedBlockingQueue<RequestMessage> queue, String mod,
String con) {
super(thing, queue, "setstate", CommandType.COMMAND);
this.command = command;
if (command instanceof OnOffType) {
deviceCommand = "setstate," + mod + ":" + con + "," + (command.equals(OnOffType.ON) ? "1" : "0");
}
}
@Override
public void parseSuccessfulReply() {
if (deviceReply == null) {
return;
}
// Match on response of form setstate,1:3,0 or state,1:3,0
if (!matchSetstate()) {
logger.warn("Successful reply from device can't be matched: {}", deviceReply);
setState(OnOffType.OFF);
return;
}
}
private boolean matchSetstate() {
// Matches both iTach and GC-100 responses
Pattern p = Pattern.compile("(setstate|state),(\\d):(\\d),([01])");
Matcher m = p.matcher(deviceReply);
if (m.matches()) {
logger.trace("Matched setstate response: g2={}, g3={}, g4={}", m.group(2), m.group(3), m.group(4));
if (m.groupCount() == 4) {
setModule(m.group(2));
setConnector(m.group(3));
setState(m.group(4).equals("0") ? OnOffType.OFF : OnOffType.ON);
return true;
}
}
return false;
}
private void setState(OnOffType s) {
state = s;
}
public OnOffType state() {
return state;
}
@Override
public void logSuccess() {
logger.debug("Execute '{}' succeeded for command {} on thing {} at {}", commandName, command,
thing.getUID().getId(), ipAddress);
}
@Override
public void logFailure() {
logger.error("Execute '{}' failed on thing {} at {}: errorCode={}, errorMessage={}", commandName,
thing.getUID().getId(), ipAddress, errorCode, errorMessage);
}
}

View File

@@ -0,0 +1,70 @@
/**
* 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.globalcache.internal.command;
import java.util.concurrent.LinkedBlockingQueue;
import org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.CommandType;
/**
* The {@link RequestMessage} class is responsible for storing the command to be sent to the GlobalCache
* device and for storing whether the command is serial or not.
*
* @author Mark Hilbush - Initial contribution
*/
public class RequestMessage {
private LinkedBlockingQueue<ResponseMessage> rcvQueue;
private String deviceCommand;
private CommandType commandType;
private String commandName;
public RequestMessage(String commandName, CommandType commandType, String deviceCommand,
LinkedBlockingQueue<ResponseMessage> rcvQueue) {
this.commandName = commandName;
this.commandType = commandType;
this.deviceCommand = deviceCommand;
this.rcvQueue = rcvQueue;
}
public String getDeviceCommand() {
return deviceCommand;
}
public String getCommandName() {
return commandName;
}
public CommandType getCommandType() {
return commandType;
}
public boolean isCommand() {
return commandType == CommandType.COMMAND;
}
public boolean isSerial() {
return commandType == CommandType.SERIAL1 || commandType == CommandType.SERIAL2;
}
public boolean isSerial1() {
return commandType == CommandType.SERIAL1;
}
public boolean isSerial2() {
return commandType == CommandType.SERIAL2;
}
public LinkedBlockingQueue<ResponseMessage> getReceiveQueue() {
return rcvQueue;
}
}

View File

@@ -0,0 +1,32 @@
/**
* 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.globalcache.internal.command;
/**
* The {@link ResponseMessage} class is responsible for storing the raw and parsed response from the
* GlobalCache device.
*
* @author Mark Hilbush - Initial contribution
*/
public class ResponseMessage {
private String deviceReply;
public ResponseMessage(String deviceReply) {
this.deviceReply = deviceReply;
}
public String getDeviceReply() {
return deviceReply;
}
}

View File

@@ -0,0 +1,182 @@
/**
* 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.globalcache.internal.discovery;
import static org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.*;
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.net.NetworkAddressService;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link GlobalCacheDiscoveryService} class implements a service
* for discovering the GlobalCache devices.
*
* @author Mark Hilbush - Initial contribution
*/
@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.globalcache")
public class GlobalCacheDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(GlobalCacheDiscoveryService.class);
private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
private ScheduledFuture<?> gcDiscoveryJob;
// Discovery parameters
public static final boolean BACKGROUND_DISCOVERY_ENABLED = true;
public static final int BACKGROUND_DISCOVERY_DELAY = 10;
private NetworkAddressService networkAddressService;
private boolean terminate;
public GlobalCacheDiscoveryService() {
super(SUPPORTED_THING_TYPES_UIDS, 0, BACKGROUND_DISCOVERY_ENABLED);
gcDiscoveryJob = null;
terminate = false;
}
@Override
public Set<ThingTypeUID> getSupportedThingTypes() {
return SUPPORTED_THING_TYPES_UIDS;
}
@Override
protected void activate(Map<String, Object> configProperties) {
logger.debug("Globalcache discovery service activated");
super.activate(configProperties);
}
@Override
protected void deactivate() {
logger.debug("Globalcache discovery service deactivated");
stopBackgroundDiscovery();
super.deactivate();
}
@Override
@Modified
protected void modified(Map<String, Object> configProperties) {
super.modified(configProperties);
}
@Override
protected void startBackgroundDiscovery() {
if (gcDiscoveryJob == null) {
terminate = false;
logger.debug("Starting background discovery job in {} seconds", BACKGROUND_DISCOVERY_DELAY);
gcDiscoveryJob = scheduledExecutorService.schedule(this::discover, BACKGROUND_DISCOVERY_DELAY,
TimeUnit.SECONDS);
}
}
@Override
protected void stopBackgroundDiscovery() {
if (gcDiscoveryJob != null) {
logger.debug("Canceling background discovery job");
terminate = true;
gcDiscoveryJob.cancel(false);
gcDiscoveryJob = null;
}
}
@Override
public void startScan() {
}
@Override
public void stopScan() {
}
private synchronized void discover() {
logger.debug("Discovery job is running");
MulticastListener gcMulticastListener;
try {
gcMulticastListener = new MulticastListener(networkAddressService.getPrimaryIpv4HostAddress());
} catch (SocketException se) {
logger.error("Discovery job got Socket exception creating multicast socket: {}", se.getMessage());
return;
} catch (IOException ioe) {
logger.error("Discovery job got IO exception creating multicast socket: {}", ioe.getMessage());
return;
}
while (!terminate) {
boolean beaconReceived;
try {
// Wait for a discovery beacon.
beaconReceived = gcMulticastListener.waitForBeacon();
} catch (IOException ioe) {
logger.debug("Discovery job got exception waiting for beacon: {}", ioe.getMessage());
beaconReceived = false;
}
if (beaconReceived) {
// We got a discovery beacon. Process it as a potential new thing
Map<String, Object> properties = new HashMap<>();
properties.put(THING_PROPERTY_IP, gcMulticastListener.getIPAddress());
properties.put(THING_PROPERTY_MAC, gcMulticastListener.getMACAddress());
properties.put(THING_PROPERTY_UID, gcMulticastListener.getUID());
properties.put(Thing.PROPERTY_VENDOR, gcMulticastListener.getVendor());
properties.put(Thing.PROPERTY_MODEL_ID, gcMulticastListener.getModel());
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, gcMulticastListener.getSoftwareRevision());
properties.put(Thing.PROPERTY_HARDWARE_VERSION, gcMulticastListener.getHardwareRevision());
properties.put(Thing.PROPERTY_SERIAL_NUMBER, gcMulticastListener.getSerialNumber());
logger.trace("Device of type {} discovered with MAC {} and IP {}", gcMulticastListener.getModel(),
gcMulticastListener.getMACAddress(), gcMulticastListener.getIPAddress());
ThingTypeUID typeUID = gcMulticastListener.getThingTypeUID();
if (typeUID != null) {
ThingUID uid = new ThingUID(typeUID, gcMulticastListener.getSerialNumber());
logger.trace("Creating discovery result for: {}, type={}, IP={}", uid,
gcMulticastListener.getModel(), gcMulticastListener.getIPAddress());
thingDiscovered(DiscoveryResultBuilder.create(uid).withProperties(properties)
.withLabel(gcMulticastListener.getVendor() + " " + gcMulticastListener.getModel()).build());
}
}
}
gcMulticastListener.shutdown();
logger.debug("Discovery job is exiting");
}
@Reference
protected void setNetworkAddressService(NetworkAddressService networkAddressService) {
this.networkAddressService = networkAddressService;
}
protected void unsetNetworkAddressService(NetworkAddressService networkAddressService) {
this.networkAddressService = null;
}
}

View File

@@ -0,0 +1,323 @@
/**
* 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.globalcache.internal.discovery;
import static org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.*;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Date;
import org.openhab.core.thing.ThingTypeUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link MulticastListener} class is responsible for listening for the GlobalCache device announcement
* beacons on the multicast address, and then extracting the data fields out of the received datagram.
*
* @author Mark Hilbush - Initial contribution
*/
public class MulticastListener {
private final Logger logger = LoggerFactory.getLogger(MulticastListener.class);
private MulticastSocket socket;
private String serialNumber = "";
private String vendor = "";
private String model = "";
private String softwareRevision = "";
private String hardwareRevision = "";
// GlobalCache-specific properties defined in this binding
private String uid = "";
private String ipAddress = "";
private String macAddress = "";
private Date lastUpdate;
// GC devices announce themselves on a multicast port
private static final String GC_MULTICAST_GROUP = "239.255.250.250";
private static final int GC_MULTICAST_PORT = 9131;
// How long to wait in milliseconds for a discovery beacon
public static final int DEFAULT_SOCKET_TIMEOUT = 3000;
/*
* Constructor joins the multicast group, throws IOException on failure.
*/
public MulticastListener(String ipv4Address) throws IOException, SocketException {
InetAddress ifAddress = InetAddress.getByName(ipv4Address);
logger.debug("Discovery job using address {} on network interface {}", ifAddress.getHostAddress(),
NetworkInterface.getByInetAddress(ifAddress).getName());
socket = new MulticastSocket(GC_MULTICAST_PORT);
socket.setInterface(ifAddress);
socket.setSoTimeout(DEFAULT_SOCKET_TIMEOUT);
InetAddress mcastAddress = InetAddress.getByName(GC_MULTICAST_GROUP);
socket.joinGroup(mcastAddress);
logger.debug("Multicast listener joined multicast group {}:{}", GC_MULTICAST_GROUP, GC_MULTICAST_PORT);
}
public void shutdown() {
logger.debug("Multicast listener closing down multicast socket");
socket.close();
}
/*
* Wait on the multicast socket for an announcement beacon. Return false on socket timeout or error.
* Otherwise, parse the beacon for information about the device.
*/
public boolean waitForBeacon() throws IOException {
byte[] bytes = new byte[600];
boolean beaconFound;
// Wait for a device to announce itself
logger.trace("Multicast listener waiting for datagram on multicast port");
DatagramPacket msgPacket = new DatagramPacket(bytes, bytes.length);
try {
socket.receive(msgPacket);
beaconFound = true;
logger.trace("Multicast listener got datagram of length {} from multicast port: {}", msgPacket.getLength(),
msgPacket.toString());
} catch (SocketTimeoutException e) {
beaconFound = false;
}
if (beaconFound) {
// Get the device properties from the announcement beacon
parseAnnouncementBeacon(msgPacket);
}
return beaconFound;
}
/*
* Parse the announcement beacon into the elements needed to create the thing.
*
* Example iTach beacon:
*
* AMXB<-UUID=GlobalCache_000C1E021777><-SDKClass=Utility><-Make=GlobalCache><-Model=iTachWF2IR>
* <-Revision=710-1001-05><-Pkg_Level=GCPK002><-Config-URL=http://192.168.1.90><-PCB_PN=025-0026-06>
* <-Status=Ready>CR
*
* Example GC-100 beacon:
*
* AMXB<-UUID=GC100_000C1E00F0E9_GlobalCache><-SDKClass=Utility><-Make=GlobalCache><-Model=GC-100-06>
* <-Revision=1.0.0><Config-Name=GC-100><Config-URL=http://192.168.1.70>CR
*
*/
private void parseAnnouncementBeacon(DatagramPacket packet) {
String beacon = (new String(packet.getData())).trim();
logger.trace("Multicast listener parsing announcement packet: {}", beacon);
clearProperties();
if (beacon.contains(GC_MODEL_ITACH)) {
parseItachAnnouncementBeacon(beacon);
} else if (beacon.contains(GC_MODEL_GC_100)) {
parseGC100AnnouncementBeacon(beacon);
} else if (beacon.contains(GC_MODEL_ZMOTE)) {
parseZmoteAnnouncementBeacon(beacon);
} else {
logger.debug("Multicast listener doesn't know how to parse beacon: {}", beacon);
}
}
private void parseItachAnnouncementBeacon(String beacon) {
String[] parameterList = beacon.split("<-");
for (String parameter : parameterList) {
String[] keyValue = parameter.split("=");
if (keyValue.length != 2) {
continue;
}
if (keyValue[0].contains("UUID")) {
uid = keyValue[1].substring(0, keyValue[1].length() - 1);
macAddress = uid.substring(uid.indexOf("_") + 1);
serialNumber = macAddress;
} else if (keyValue[0].contains("Make")) {
vendor = keyValue[1].substring(0, keyValue[1].length() - 1);
} else if (keyValue[0].contains("Model")) {
model = keyValue[1].substring(0, keyValue[1].length() - 1);
} else if (keyValue[0].contains("Revision")) {
softwareRevision = keyValue[1].substring(0, keyValue[1].length() - 1);
} else if (keyValue[0].contains("Config-URL")) {
ipAddress = keyValue[1].substring(keyValue[1].indexOf("://") + 3, keyValue[1].length() - 1);
} else if (keyValue[0].contains("PCB_PN")) {
hardwareRevision = keyValue[1].substring(0, keyValue[1].length() - 1);
}
}
lastUpdate = new Date();
}
/*
* AMXB<-UUID=GC100_000C1E00F0E9_GlobalCache><-SDKClass=Utility><-Make=GlobalCache><-Model=GC-100-06>
* <-Revision=1.0.0><Config-Name=GC-100><Config-URL=http://192.168.1.70>CR
*/
private void parseGC100AnnouncementBeacon(String beacon) {
String[] parameterList = beacon.split("<");
for (String parameter : parameterList) {
String[] keyValue = parameter.split("=");
if (keyValue.length != 2) {
continue;
}
if (keyValue[0].contains("UUID")) {
uid = keyValue[1].substring(0, keyValue[1].length() - 1);
macAddress = uid.subSequence(6, 18).toString();
serialNumber = macAddress;
} else if (keyValue[0].contains("Make")) {
vendor = keyValue[1].substring(0, keyValue[1].length() - 1);
} else if (keyValue[0].contains("Model")) {
model = keyValue[1].substring(0, keyValue[1].length() - 1);
} else if (keyValue[0].contains("Revision")) {
softwareRevision = keyValue[1].substring(0, keyValue[1].length() - 1);
} else if (keyValue[0].contains("Config-URL")) {
ipAddress = keyValue[1].substring(keyValue[1].indexOf("://") + 3, keyValue[1].length() - 1);
}
}
hardwareRevision = "N/A";
lastUpdate = new Date(System.currentTimeMillis());
}
/*
* AMXB<-UUID=CI00a1b2c3><-Type=ZMT2><-Make=zmote.io><-Model=ZV-2><-Revision=2.1.4><-Config-URL=http://192.168.1.12>
*/
private void parseZmoteAnnouncementBeacon(String beacon) {
String[] parameterList = beacon.split("<-");
for (String parameter : parameterList) {
String[] keyValue = parameter.split("=");
if (keyValue.length != 2) {
continue;
}
if (keyValue[0].contains("UUID")) {
uid = keyValue[1].substring(0, keyValue[1].length() - 1);
serialNumber = uid;
} else if (keyValue[0].contains("Make")) {
vendor = keyValue[1].substring(0, keyValue[1].length() - 1);
} else if (keyValue[0].contains("Model")) {
model = keyValue[1].substring(0, keyValue[1].length() - 1);
} else if (keyValue[0].contains("Revision")) {
softwareRevision = keyValue[1].substring(0, keyValue[1].length() - 1);
} else if (keyValue[0].contains("Config-URL")) {
ipAddress = keyValue[1].substring(keyValue[1].indexOf("://") + 3, keyValue[1].length() - 1);
}
}
hardwareRevision = "N/A";
lastUpdate = new Date(System.currentTimeMillis());
}
private void clearProperties() {
serialNumber = "";
vendor = "";
model = "";
softwareRevision = "";
hardwareRevision = "";
uid = "";
ipAddress = "";
macAddress = "";
}
public String getSerialNumber() {
return serialNumber;
}
public String getVendor() {
return vendor;
}
public String getModel() {
return model;
}
public String getSoftwareRevision() {
return softwareRevision;
}
public String getHardwareRevision() {
return hardwareRevision;
}
public String getUID() {
return uid;
}
public String getIPAddress() {
return ipAddress;
}
public String getMACAddress() {
return macAddress;
}
public Date getLastUpdate() {
return lastUpdate;
}
public boolean isITach() {
return model.contains(GC_MODEL_ITACH);
}
public boolean isGC100() {
return model.contains(GC_MODEL_GC_100);
}
public ThingTypeUID getThingTypeUID() {
logger.trace("Multicast listener looking up thing type for model {} at IP {}", model, ipAddress);
switch (model) {
case GC_MODEL_ITACHIP2IR:
case GC_MODEL_ITACHWF2IR:
return THING_TYPE_ITACH_IR;
case GC_MODEL_ITACHIP2CC:
case GC_MODEL_ITACHWF2CC:
return THING_TYPE_ITACH_CC;
case GC_MODEL_ITACHIP2SL:
case GC_MODEL_ITACHWF2SL:
return THING_TYPE_ITACH_SL;
case GC_MODEL_ITACHFLEXETH:
case GC_MODEL_ITACHFLEXETHPOE:
case GC_MODEL_ITACHFLEXWIFI:
return THING_TYPE_ITACH_FLEX;
case GC_MODEL_GC_100_06:
return THING_TYPE_GC_100_06;
case GC_MODEL_GC_100_12:
return THING_TYPE_GC_100_12;
case GC_MODEL_ZMOTE:
return THING_TYPE_ZMOTE;
default:
return null;
}
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="globalcache" 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>GlobalCache Binding</name>
<description>Binding for GlobalCache iTach and GC-100 devices supporting infrared, serial, and contact closure
interfaces.</description>
<author>Mark Hilbush</author>
</binding:binding>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="globalcache"
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">
<!-- GlobalCache Channel Types -->
<channel-type id="channel-type-ir">
<item-type>String</item-type>
<label>Infrared</label>
<description>Transmits infrared command on module:connector</description>
</channel-type>
<channel-type id="channel-type-cc">
<item-type>Switch</item-type>
<label>Contact Closure</label>
<description>Transmits contact closure command on module:connector</description>
</channel-type>
<channel-type id="channel-type-sl">
<item-type>String</item-type>
<label>Serial</label>
<description>Transmits serial command on module:connector</description>
</channel-type>
<channel-type id="channel-type-sl-direct" advanced="false">
<item-type>String</item-type>
<label>Serial</label>
<description>Transmits serial command on module:connector bypassing MAP transform</description>
</channel-type>
<channel-type id="channel-type-sl-receive" advanced="true">
<item-type>String</item-type>
<label>Serial Receive</label>
<description>Data received on the serial port from the device</description>
<state readOnly="true"></state>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,287 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="globalcache"
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">
<!-- GlobalCache Channel Groups -->
<channel-group-type id="sl-m1">
<label>Module 1</label>
<description>Serial Module</description>
<channels>
<channel id="c1" typeId="channel-type-sl">
<label>Connector 1 (mapped)</label>
<description>Mapped commands to serial port</description>
<properties>
<property name="module">1</property>
<property name="connector">1</property>
</properties>
</channel>
<channel id="c1-direct" typeId="channel-type-sl-direct">
<label>Connector 1 (direct)</label>
<description>Direct commands to serial port</description>
<properties>
<property name="module">1</property>
<property name="connector">1</property>
</properties>
</channel>
<channel id="c1-receive" typeId="channel-type-sl-receive">
<label>Connector 1 (receive)</label>
<description>Data received on serial port</description>
<properties>
<property name="module">1</property>
<property name="connector">1</property>
</properties>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="sl-m2">
<label>Module 2</label>
<description>Serial Module</description>
<channels>
<channel id="c1" typeId="channel-type-sl">
<label>Connector 1 (mapped)</label>
<description>Mapped commands to serial port</description>
<properties>
<property name="module">2</property>
<property name="connector">1</property>
</properties>
</channel>
<channel id="c1-direct" typeId="channel-type-sl-direct">
<label>Connector 1 (direct)</label>
<description>Direct commands to serial port</description>
<properties>
<property name="module">2</property>
<property name="connector">1</property>
</properties>
</channel>
<channel id="c1-receive" typeId="channel-type-sl-receive">
<label>Connector 1 (receive)</label>
<description>Data received on serial port</description>
<properties>
<property name="module">2</property>
<property name="connector">1</property>
</properties>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="ir-m1">
<label>Module 1</label>
<description>Infrared Module</description>
<channels>
<channel id="c1" typeId="channel-type-ir">
<label>Connector 1</label>
<description>Infrared emitter on connector 1. Connector 1 is the connector closest to the power plug.</description>
<properties>
<property name="module">1</property>
<property name="connector">1</property>
</properties>
</channel>
<channel id="c2" typeId="channel-type-ir">
<label>Connector 2</label>
<description>Infrared emitter on connector 2.</description>
<properties>
<property name="module">1</property>
<property name="connector">2</property>
</properties>
</channel>
<channel id="c3" typeId="channel-type-ir">
<label>Connector 3</label>
<description>Infrared emitter/blaster on connector 3.</description>
<properties>
<property name="module">1</property>
<property name="connector">3</property>
</properties>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="ir-m1-c1">
<label>Module 1</label>
<description>Infrared Module</description>
<channels>
<channel id="c1" typeId="channel-type-ir">
<label>Connector 1</label>
<description>ZMote infrared emitter.</description>
<properties>
<property name="module">1</property>
<property name="connector">1</property>
</properties>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="ir-m2">
<label>Module 2</label>
<description>Infrared Module</description>
<channels>
<channel id="c1" typeId="channel-type-ir">
<label>Connector 1</label>
<description>Infrared emitter on connector 1. Connector 1 is the connector closest to the power plug.</description>
<properties>
<property name="module">2</property>
<property name="connector">1</property>
</properties>
</channel>
<channel id="c2" typeId="channel-type-ir">
<label>Connector 2</label>
<description>Infrared emitter on connector 2.</description>
<properties>
<property name="module">2</property>
<property name="connector">2</property>
</properties>
</channel>
<channel id="c3" typeId="channel-type-ir">
<label>Connector 3</label>
<description>Infrared emitter/blaster on connector 3.</description>
<properties>
<property name="module">2</property>
<property name="connector">3</property>
</properties>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="ir-m4">
<label>Module 4</label>
<description>Infrared Module</description>
<channels>
<channel id="c1" typeId="channel-type-ir">
<label>Connector 1</label>
<description>Infrared emitter on connector 1. Connector 1 is the connector closest to the power plug.</description>
<properties>
<property name="module">4</property>
<property name="connector">1</property>
</properties>
</channel>
<channel id="c2" typeId="channel-type-ir">
<label>Connector 2</label>
<description>Infrared emitter on connector 2.</description>
<properties>
<property name="module">4</property>
<property name="connector">2</property>
</properties>
</channel>
<channel id="c3" typeId="channel-type-ir">
<label>Connector 3</label>
<description>Infrared emitter/blaster on connector 3.</description>
<properties>
<property name="module">4</property>
<property name="connector">3</property>
</properties>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="ir-m5">
<label>Module 5</label>
<description>Infrared Module</description>
<channels>
<channel id="c1" typeId="channel-type-ir">
<label>Connector 1</label>
<description>Infrared emitter on connector 1. Connector 1 is the connector closest to the power plug.</description>
<properties>
<property name="module">5</property>
<property name="connector">1</property>
</properties>
</channel>
<channel id="c2" typeId="channel-type-ir">
<label>Connector 2</label>
<description>Infrared emitter on connector 2.</description>
<properties>
<property name="module">5</property>
<property name="connector">2</property>
</properties>
</channel>
<channel id="c3" typeId="channel-type-ir">
<label>Connector 3</label>
<description>Infrared emitter/blaster on connector 3.</description>
<properties>
<property name="module">5</property>
<property name="connector">3</property>
</properties>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="cc-m1">
<label>Module 1</label>
<description>Contact Closure Module</description>
<channels>
<channel id="c1" typeId="channel-type-cc">
<label>Connector 1</label>
<description>Contact closure on connector 1.</description>
<properties>
<property name="module">1</property>
<property name="connector">1</property>
</properties>
</channel>
<channel id="c2" typeId="channel-type-cc">
<label>Connector 2</label>
<description>Contact closure on connector 2.</description>
<properties>
<property name="module">1</property>
<property name="connector">2</property>
</properties>
</channel>
<channel id="c3" typeId="channel-type-cc">
<label>Connector 3</label>
<description>Contact closure on connector 3.</description>
<properties>
<property name="module">1</property>
<property name="connector">3</property>
</properties>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="cc-m3">
<label>Module 3</label>
<description>Contact Closure Module</description>
<channels>
<channel id="c1" typeId="channel-type-cc">
<label>Connector 1</label>
<description>Contact closure on connector 1.</description>
<properties>
<property name="module">3</property>
<property name="connector">1</property>
</properties>
</channel>
<channel id="c2" typeId="channel-type-cc">
<label>Connector 2</label>
<description>Contact closure on connector 2.</description>
<properties>
<property name="module">3</property>
<property name="connector">2</property>
</properties>
</channel>
<channel id="c3" typeId="channel-type-cc">
<label>Connector 3</label>
<description>Contact closure on connector 3.</description>
<properties>
<property name="module">3</property>
<property name="connector">3</property>
</properties>
</channel>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="globalcache"
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">
<!-- GlobalCache GC-100-06 device contains one SL module, one IR module -->
<thing-type id="gc100_06">
<label>GlobalCache GC-100-06</label>
<description>GC-100-06 Infrared and Serial Device</description>
<channel-groups>
<channel-group id="sl-m1" typeId="sl-m1"/>
<channel-group id="ir-m2" typeId="ir-m2"/>
</channel-groups>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<label>Network Address</label>
<description>Enter the IP address of the iTach CC device</description>
<context>network-address</context>
</parameter>
<parameter name="mapFilename" type="text">
<label>Map File</label>
<description>Enter name of file containing mapping of commands to IR and Serial codes</description>
</parameter>
<parameter name="enableTwoWay1" type="boolean">
<label>Enable Two Way</label>
<description>Enable two-way serial communication</description>
<default>false</default>
</parameter>
<parameter name="eomDelimiter1" type="text">
<label>End-of-message Delimiter</label>
<description>URL encoded end-of-message delimiter string for receiving messages</description>
<default>%0A</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="globalcache"
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">
<!-- GlobalCache GC-100-12 device contains two IR modules, two SL modules, one CC module -->
<thing-type id="gc100_12">
<label>GlobalCache GC-100-12</label>
<description>GC-100-12 Infrared, Serial, and Contact Closure Device</description>
<channel-groups>
<channel-group id="sl-m1" typeId="sl-m1"/>
<channel-group id="sl-m2" typeId="sl-m2"/>
<channel-group id="cc-m3" typeId="cc-m3"/>
<channel-group id="ir-m4" typeId="ir-m4"/>
<channel-group id="ir-m5" typeId="ir-m5"/>
</channel-groups>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<label>Network Address</label>
<description>Enter the IP address of the iTach CC device</description>
<context>network-address</context>
</parameter>
<parameter name="mapFilename" type="text">
<label>Map File</label>
<description>Enter name of file containing mapping of commands to IR and Serial codes</description>
</parameter>
<parameter name="enableTwoWay1" type="boolean">
<label>Enable Two Way Port 1</label>
<description>Enable two-way serial communication on serial port 1</description>
<default>false</default>
</parameter>
<parameter name="eomDelimiter1" type="text">
<label>End-of-message Delimiter Port 1</label>
<description>URL encoded end-of-message delimiter string for receiving messages on serial port 1</description>
<default>%0A</default>
</parameter>
<parameter name="enableTwoWay2" type="boolean">
<label>Enable Two Way Port 2</label>
<description>Enable two-way serial communication on serial port 2</description>
<default>false</default>
</parameter>
<parameter name="eomDelimiter2" type="text">
<label>End-of-message Delimiter Port 2</label>
<description>URL encoded end-of-message delimiter string for receiving messages on serial port 2</description>
<default>%0A</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="globalcache"
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">
<!-- GlobalCache iTach CC (relay) device contains one CC module -->
<thing-type id="itachCC">
<label>GlobalCache iTach CC</label>
<description>iTach Contact Closure Device (WF2CC or IP2CC)</description>
<channel-groups>
<channel-group id="cc-m1" typeId="cc-m1"/>
</channel-groups>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<label>Network Address</label>
<description>Enter the IP address of the iTach CC device</description>
<context>network-address</context>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="globalcache"
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">
<!-- GlobalCache iTach Flex device -->
<thing-type id="itachFlex">
<label>GlobalCache iTach Flex</label>
<description>iTach Flex Device</description>
<channel-groups>
<channel-group id="sl-m1" typeId="sl-m1"/>
<channel-group id="ir-m1" typeId="ir-m1"/>
<channel-group id="cc-m1" typeId="cc-m1"/>
</channel-groups>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<label>Network Address</label>
<description>Enter the IP address of the iTach Flex device</description>
<context>network-address</context>
</parameter>
<parameter name="mapFilename" type="text">
<label>Map File</label>
<description>Enter name of file containing mapping of commands to IR and Serial codes</description>
</parameter>
<parameter name="activeCable" type="text" required="true">
<label>Active Cable</label>
<description>This setting should match the Current Active Cable in the Flex configuration</description>
<options>
<option value="FLEX_INFRARED">Infrared</option>
<option value="FLEX_SERIAL">Serial</option>
<option value="FLEX_RELAY">Relay/Sensor</option>
</options>
<default>FLEX_INFRARED</default>
</parameter>
<parameter name="enableTwoWay1" type="boolean">
<label>Enable Two Way</label>
<description>Enable two-way serial communication</description>
<default>false</default>
</parameter>
<parameter name="eomDelimiter1" type="text">
<label>End-of-message Delimiter</label>
<description>URL encoded end-of-message delimiter string for receiving messages</description>
<default>%0A</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="globalcache"
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">
<!-- GlobalCache iTach IR (infrared) device contains one IR module -->
<thing-type id="itachIR">
<label>GlobalCache iTach IR</label>
<description>iTach Infrared Device (WF2IR or IP2IR)</description>
<channel-groups>
<channel-group id="ir-m1" typeId="ir-m1"/>
</channel-groups>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<label>Network Address</label>
<description>Enter the IP address of the iTach IR device</description>
<context>network-address</context>
</parameter>
<parameter name="mapFilename" type="text">
<label>Map File</label>
<description>Enter name of file containing mapping of commands to IR and Serial codes</description>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="globalcache"
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">
<!-- GlobalCache iTach SL (serial) device contains one SL module -->
<thing-type id="itachSL">
<label>GlobalCache iTach SL</label>
<description>iTach Serial Device (WF2SL or IP2SL)</description>
<channel-groups>
<channel-group id="sl-m1" typeId="sl-m1"/>
</channel-groups>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<label>Network Address</label>
<description>Enter the IP address of the iTach SL device</description>
<context>network-address</context>
</parameter>
<parameter name="mapFilename" type="text">
<label>Map File</label>
<description>Enter namer of file containing mapping of commands to IR and Serial codes</description>
</parameter>
<parameter name="enableTwoWay1" type="boolean">
<label>Enable Two Way</label>
<description>Enable two-way serial communication</description>
<default>false</default>
</parameter>
<parameter name="eomDelimiter1" type="text">
<label>End-of-message Delimiter</label>
<description>URL encoded end-of-message delimiter string for receiving messages</description>
<default>%0A</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="globalcache"
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">
<!-- Zmote IR (infrared) device contains one IR module -->
<thing-type id="zmote">
<label>Zmote IR</label>
<description>Zmote Infrared Device</description>
<channel-groups>
<channel-group id="ir-m1-c1" typeId="ir-m1-c1"/>
</channel-groups>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<label>Network Address</label>
<description>Enter the IP address of the Zmote device</description>
<context>network-address</context>
</parameter>
<parameter name="mapFilename" type="text">
<label>Map File</label>
<description>Enter name of file containing mapping of commands to IR codes</description>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>