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,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.onewire-${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-onewire" description="OneWire Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.onewire/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,230 @@
/**
* 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.onewire.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
/**
* The {@link DS2438Configuration} is a helper class for the multisensor thing configuration
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2438Configuration {
private OwSensorType sensorSubType = OwSensorType.DS2438;
private String vendor = "Dallas/Maxim";
private String hwRevision = "0";
private String prodDate = "unknown";
private final Map<SensorId, OwSensorType> associatedSensors = new HashMap<>();
public DS2438Configuration(OwserverBridgeHandler bridgeHandler, SensorId sensorId) throws OwException {
OwSensorType sensorType = bridgeHandler.getType(sensorId);
if (sensorType != OwSensorType.DS2438) {
throw new OwException("sensor " + sensorId.getId() + " is not a DS2438!");
}
OwPageBuffer pageBuffer = bridgeHandler.readPages(sensorId);
String sensorTypeId = pageBuffer.getPageString(3).substring(0, 2);
switch (sensorTypeId) {
case "19":
vendor = "iButtonLink";
sensorSubType = OwSensorType.MS_TH;
break;
case "1A":
vendor = "iButtonLink";
sensorSubType = OwSensorType.MS_TV;
break;
case "1B":
vendor = "iButtonLink";
sensorSubType = OwSensorType.MS_TL;
break;
case "1C":
vendor = "iButtonLink";
sensorSubType = OwSensorType.MS_TC;
break;
case "F1":
case "F3":
vendor = "Elaborated Networks";
sensorSubType = OwSensorType.MS_TH;
break;
case "F2":
vendor = "Elaborated Networks";
sensorSubType = OwSensorType.MS_TH_S;
break;
case "F4":
vendor = "Elaborated Networks";
sensorSubType = OwSensorType.MS_TV;
break;
default:
}
if (sensorSubType == OwSensorType.MS_TH || sensorSubType == OwSensorType.MS_TH_S
|| sensorSubType == OwSensorType.MS_TV) {
for (int i = 4; i < 7; i++) {
String str = new StringBuilder(pageBuffer.getPageString(i)).insert(2, ".").delete(15, 17).toString();
Matcher matcher = SensorId.SENSOR_ID_PATTERN.matcher(str);
if (matcher.matches()) {
SensorId associatedSensorId = new SensorId(sensorId.getPath() + matcher.group(2));
switch (matcher.group(2).substring(0, 2)) {
case "26":
DS2438Configuration associatedDs2438Config = new DS2438Configuration(bridgeHandler,
associatedSensorId);
associatedSensors.put(associatedSensorId, associatedDs2438Config.getSensorSubType());
associatedSensors.putAll(associatedDs2438Config.getAssociatedSensors());
break;
case "28":
associatedSensors.put(associatedSensorId, OwSensorType.DS18B20);
break;
case "3A":
associatedSensors.put(associatedSensorId, OwSensorType.DS2413);
break;
default:
}
}
}
prodDate = String.format("%d/%d", pageBuffer.getByte(5, 0),
256 * pageBuffer.getByte(5, 1) + pageBuffer.getByte(5, 2));
hwRevision = String.valueOf(pageBuffer.getByte(5, 3));
}
}
public Map<SensorId, OwSensorType> getAssociatedSensors() {
return associatedSensors;
}
/**
* get a list of sensor ids associated with this sensor
*
* @return a list of the sensor ids (if found), empty list otherwise
*/
public List<SensorId> getAssociatedSensorIds() {
return new ArrayList<>(associatedSensors.keySet());
}
/**
* get all secondary sensor ids of a given type
*
* @param sensorType filter for sensors
* @return a list of OwDiscoveryItems
*/
public List<SensorId> getAssociatedSensorIds(OwSensorType sensorType) {
return associatedSensors.entrySet().stream().filter(s -> s.getValue() == sensorType).map(s -> s.getKey())
.collect(Collectors.toList());
}
/**
* get a list of sensor types associated with this sensor
*
* @return a list of the sensor typess (if found), empty list otherwise
*/
public List<OwSensorType> getAssociatedSensorTypes() {
return new ArrayList<>(associatedSensors.values());
}
/**
* get the number of associated sensors
*
* @return the number
*/
public int getAssociatedSensorCount() {
return associatedSensors.size();
}
/**
* get hardware revision (available on some multisensors)
*
* @return hardware revision
*/
public String getHardwareRevision() {
return hwRevision;
}
/**
* get production date (available on some multisensors)
*
* @return production date in ww/yy
*/
public String getProductionDate() {
return prodDate;
}
/**
* get sensor type (without associated sensors)
*
* @return basic sensor type
*/
public OwSensorType getSensorSubType() {
return sensorSubType;
}
/**
* get vendor name (if available)
*
* @return the vendor name
*/
public String getVendor() {
return vendor;
}
/**
* determine multisensor type
*
* @param mainsensorType the type of the main sensor
* @param associatedSensorTypes a list of OwSensorTypes of all associated sensors
* @return the multisensor type (if known)
*/
public static OwSensorType getMultisensorType(OwSensorType mainsensorType,
List<OwSensorType> associatedSensorTypes) {
OwSensorType multisensorType = OwSensorType.UNKNOWN;
switch (associatedSensorTypes.size()) {
case 0:
multisensorType = mainsensorType;
break;
case 1:
if (mainsensorType == OwSensorType.MS_TH_S && associatedSensorTypes.contains(OwSensorType.DS18B20)) {
multisensorType = OwSensorType.BMS_S;
} else if (mainsensorType == OwSensorType.MS_TH
&& associatedSensorTypes.contains(OwSensorType.DS18B20)) {
multisensorType = OwSensorType.BMS;
}
break;
case 3:
if (mainsensorType == OwSensorType.MS_TH_S && associatedSensorTypes.contains(OwSensorType.MS_TV)
&& associatedSensorTypes.contains(OwSensorType.DS18B20)
&& associatedSensorTypes.contains(OwSensorType.DS2413)) {
// two DS2438 (first THS, second TV), DS18B20, DS2413
multisensorType = OwSensorType.AMS_S;
} else if (mainsensorType == OwSensorType.MS_TH && associatedSensorTypes.contains(OwSensorType.MS_TV)
&& associatedSensorTypes.contains(OwSensorType.DS18B20)
&& associatedSensorTypes.contains(OwSensorType.DS2413)) {
// two DS2438 (first TH, second TV), DS18B20, DS2413
multisensorType = OwSensorType.AMS;
}
break;
default:
}
return multisensorType;
}
}

View File

@@ -0,0 +1,105 @@
/**
* 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.onewire.internal;
import static org.openhab.binding.onewire.internal.OwBindingConstants.CHANNEL_DIGITAL;
import java.util.Arrays;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.State;
/**
* The {@link DigitalIoConfig} class provides the configuration of a digital IO channel
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DigitalIoConfig {
private final String channelID;
private final ChannelUID channelUID;
private final OwserverDeviceParameter inParam;
private final OwserverDeviceParameter outParam;
private DigitalIoMode ioMode = DigitalIoMode.INPUT;
private DigitalIoLogic ioLogic = DigitalIoLogic.NORMAL;
public DigitalIoConfig(Thing thing, Integer channelIndex, OwserverDeviceParameter inParam,
OwserverDeviceParameter outParam) {
this.channelUID = new ChannelUID(thing.getUID(), String.format("%s%d", CHANNEL_DIGITAL, channelIndex));
this.channelID = String.format("%s%d", CHANNEL_DIGITAL, channelIndex);
this.inParam = inParam;
this.outParam = outParam;
}
public void setIoMode(String ioMode) {
this.ioMode = DigitalIoMode.valueOf(ioMode.toUpperCase());
}
public void setIoLogic(String ioLogic) {
this.ioLogic = DigitalIoLogic.valueOf(ioLogic.toUpperCase());
}
public Boolean isInverted() {
return (ioLogic == DigitalIoLogic.INVERTED);
}
public ChannelUID getChannelUID() {
return channelUID;
}
public String getChannelId() {
return channelID;
}
public OwserverDeviceParameter getParameter() {
return (ioMode == DigitalIoMode.INPUT) ? inParam : outParam;
}
public Boolean isInput() {
return (ioMode == DigitalIoMode.INPUT);
}
public Boolean isOutput() {
return (ioMode == DigitalIoMode.OUTPUT);
}
public DigitalIoMode getIoDirection() {
return ioMode;
}
public State convertState(Boolean rawValue) {
if (ioLogic == DigitalIoLogic.NORMAL) {
return rawValue ? OnOffType.ON : OnOffType.OFF;
} else {
return rawValue ? OnOffType.OFF : OnOffType.ON;
}
}
public DecimalType convertState(OnOffType command) {
if (ioLogic == DigitalIoLogic.NORMAL) {
return command.equals(OnOffType.ON) ? new DecimalType(1) : DecimalType.ZERO;
} else {
return command.equals(OnOffType.ON) ? DecimalType.ZERO : new DecimalType(1);
}
}
@Override
public String toString() {
return String.format("path=%s, mode=%s, logic=%s", Arrays.asList(getParameter()), ioMode, ioLogic);
}
}

View File

@@ -0,0 +1,26 @@
/**
* 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.onewire.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link DigitalIoLogic} provides the logic level of a digital IO channel
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public enum DigitalIoLogic {
NORMAL,
INVERTED
}

View File

@@ -0,0 +1,26 @@
/**
* 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.onewire.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link DigitalIoMode} provides the direction of a digital IO channel
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public enum DigitalIoMode {
INPUT,
OUTPUT
}

View File

@@ -0,0 +1,162 @@
/**
* 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.onewire.internal;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.device.OwChannelConfig;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.type.ChannelTypeUID;
/**
* The {@link OneWireBinding} class defines common constants, which are
* used across the whole binding.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwBindingConstants {
public static final String BINDING_ID = "onewire";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_OWSERVER = new ThingTypeUID(BINDING_ID, "owserver");
public static final ThingTypeUID THING_TYPE_MS_TX = new ThingTypeUID(BINDING_ID, "ms-tx");
public static final ThingTypeUID THING_TYPE_BMS = new ThingTypeUID(BINDING_ID, "bms");
public static final ThingTypeUID THING_TYPE_AMS = new ThingTypeUID(BINDING_ID, "ams");
public static final ThingTypeUID THING_TYPE_BASIC = new ThingTypeUID(BINDING_ID, "basic");
public static final ThingTypeUID THING_TYPE_EDS_ENV = new ThingTypeUID(BINDING_ID, "edsenv");
public static final ThingTypeUID THING_TYPE_BAE091X = new ThingTypeUID(BINDING_ID, "bae091x");
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections
.unmodifiableSet(Stream.of(THING_TYPE_OWSERVER, THING_TYPE_AMS, THING_TYPE_BMS, THING_TYPE_MS_TX,
THING_TYPE_EDS_ENV, THING_TYPE_BASIC, THING_TYPE_BAE091X).collect(Collectors.toSet()));
// List of all config options
public static final String CONFIG_ADDRESS = "network-address";
public static final String CONFIG_PORT = "port";
public static final String CONFIG_ID = "id";
public static final String CONFIG_RESOLUTION = "resolution";
public static final String CONFIG_IGNORE_POR = "ignorepor";
public static final String CONFIG_REFRESH = "refresh";
public static final String CONFIG_DIGITALREFRESH = "digitalrefresh";
public static final String CONFIG_OFFSET = "offset";
public static final String CONFIG_HUMIDITY = "humiditytype";
public static final String CONFIG_DIGITAL_MODE = "mode";
public static final String CONFIG_DIGITAL_LOGIC = "logic";
public static final String CONFIG_TEMPERATURESENSOR = "temperaturesensor";
public static final String CONFIG_LIGHTSENSOR = "lightsensor";
public static final String CONFIG_BAE_PIN_DISABLED = "disabled";
public static final String CONFIG_BAE_PIN_PIO = "pio";
public static final String CONFIG_BAE_PIN_COUNTER = "counter";
public static final String CONFIG_BAE_PIN_PWM = "pwm";
public static final String CONFIG_BAE_PIN_ANALOG = "analog";
public static final String CONFIG_BAE_PIN_IN = "input";
public static final String CONFIG_BAE_PIN_OUT = "output";
// list of all properties
public static final String PROPERTY_MODELID = "modelId";
public static final String PROPERTY_VENDOR = "vendor";
public static final String PROPERTY_SENSORCOUNT = "sensorCount";
public static final String PROPERTY_PROD_DATE = "prodDate";
public static final String PROPERTY_HW_REVISION = "hwRevision";
// List of all channel ids
public static final String CHANNEL_HUMIDITY = "humidity";
public static final String CHANNEL_ABSOLUTE_HUMIDITY = "absolutehumidity";
public static final String CHANNEL_DEWPOINT = "dewpoint";
public static final String CHANNEL_PRESENT = "present";
public static final String CHANNEL_TEMPERATURE = "temperature";
public static final String CHANNEL_LIGHT = "light";
public static final String CHANNEL_SUPPLYVOLTAGE = "supplyvoltage";
public static final String CHANNEL_VOLTAGE = "voltage";
public static final String CHANNEL_CURRENT = "current";
public static final String CHANNEL_PRESSURE = "pressure";
public static final String CHANNEL_DIGITAL = "digital";
public static final String CHANNEL_DIGITAL0 = "digital0";
public static final String CHANNEL_DIGITAL1 = "digital1";
public static final String CHANNEL_DIGITAL2 = "digital2";
public static final String CHANNEL_DIGITAL3 = "digital3";
public static final String CHANNEL_DIGITAL4 = "digital4";
public static final String CHANNEL_DIGITAL5 = "digital5";
public static final String CHANNEL_DIGITAL6 = "digital6";
public static final String CHANNEL_DIGITAL7 = "digital7";
public static final String CHANNEL_DIGITAL8 = "digital8";
public static final String CHANNEL_COUNTER = "counter";
public static final String CHANNEL_COUNTER0 = "counter0";
public static final String CHANNEL_COUNTER1 = "counter1";
public static final String CHANNEL_PWM_DUTY1 = "pwmduty1";
public static final String CHANNEL_PWM_DUTY2 = "pwmduty2";
public static final String CHANNEL_PWM_DUTY3 = "pwmduty3";
public static final String CHANNEL_PWM_DUTY4 = "pwmduty4";
public static final String CHANNEL_PWM_FREQ1 = "pwmfreq1";
public static final String CHANNEL_PWM_FREQ2 = "pwmfreq2";
public static final ChannelTypeUID CHANNEL_TYPE_UID_ABSHUMIDITY = new ChannelTypeUID(BINDING_ID, "abshumidity");
public static final ChannelTypeUID CHANNEL_TYPE_UID_COUNTER = new ChannelTypeUID(BINDING_ID, "counter");
public static final ChannelTypeUID CHANNEL_TYPE_UID_CURRENT = new ChannelTypeUID(BINDING_ID, "current");
public static final ChannelTypeUID CHANNEL_TYPE_UID_DEWPOINT = new ChannelTypeUID(BINDING_ID, "dewpoint");
public static final ChannelTypeUID CHANNEL_TYPE_UID_DIO = new ChannelTypeUID(BINDING_ID, "dio");
public static final ChannelTypeUID CHANNEL_TYPE_UID_HUMIDITY = new ChannelTypeUID(BINDING_ID, "humidity");
public static final ChannelTypeUID CHANNEL_TYPE_UID_HUMIDITYCONF = new ChannelTypeUID(BINDING_ID, "humidityconf");
public static final ChannelTypeUID CHANNEL_TYPE_UID_LIGHT = new ChannelTypeUID(BINDING_ID, "light");
public static final ChannelTypeUID CHANNEL_TYPE_UID_PRESENT = new ChannelTypeUID(BINDING_ID, "present");
public static final ChannelTypeUID CHANNEL_TYPE_UID_PRESSURE = new ChannelTypeUID(BINDING_ID, "pressure");
public static final ChannelTypeUID CHANNEL_TYPE_UID_TEMPERATURE = new ChannelTypeUID(BINDING_ID, "temperature");
public static final ChannelTypeUID CHANNEL_TYPE_UID_TEMPERATURE_POR = new ChannelTypeUID(BINDING_ID,
"temperature-por");
public static final ChannelTypeUID CHANNEL_TYPE_UID_TEMPERATURE_POR_RES = new ChannelTypeUID(BINDING_ID,
"temperature-por-res");
public static final ChannelTypeUID CHANNEL_TYPE_UID_VOLTAGE = new ChannelTypeUID(BINDING_ID, "voltage");
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_ANALOG = new ChannelTypeUID(BINDING_ID, "bae-analog");
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_COUNTER = new ChannelTypeUID(BINDING_ID, "bae-counter");
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_DIGITAL_OUT = new ChannelTypeUID(BINDING_ID, "bae-do");
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_DIN = new ChannelTypeUID(BINDING_ID, "bae-in");
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_DOUT = new ChannelTypeUID(BINDING_ID, "bae-out");
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_PIO = new ChannelTypeUID(BINDING_ID, "bae-pio");
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_PWM_DUTY = new ChannelTypeUID(BINDING_ID, "bae-pwm-duty");
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_PWM_FREQUENCY = new ChannelTypeUID(BINDING_ID,
"bae-pwm-frequency");
public static final ChannelTypeUID CHANNEL_TYPE_UID_OWFS_NUMBER = new ChannelTypeUID(BINDING_ID, "owfs-number");
public static final ChannelTypeUID CHANNEL_TYPE_UID_OWFS_STRING = new ChannelTypeUID(BINDING_ID, "owfs-string");
// Maps for Discovery
public static final Map<OwSensorType, ThingTypeUID> THING_TYPE_MAP;
public static final Map<OwSensorType, String> THING_LABEL_MAP;
public static final Map<OwSensorType, Set<OwChannelConfig>> SENSOR_TYPE_CHANNEL_MAP;
public static final Map<String, String> ACCEPTED_ITEM_TYPES_MAP = Util
.readPropertiesFile("accepted_itemtypes.properties");
static {
Map<String, String> properties = Util.readPropertiesFile("sensor.properties");
THING_TYPE_MAP = properties.entrySet().stream().filter(e -> e.getKey().endsWith(".thingtype"))
.collect(Collectors.toConcurrentMap(e -> OwSensorType.valueOf(e.getKey().split("\\.")[0]),
e -> new ThingTypeUID(BINDING_ID, e.getValue())));
SENSOR_TYPE_CHANNEL_MAP = properties.entrySet().stream().filter(e -> e.getKey().endsWith(".channels"))
.collect(Collectors.toConcurrentMap(e -> OwSensorType.valueOf(e.getKey().split("\\.")[0]),
e -> !e.getValue().isEmpty() ? Stream.of(e.getValue().split(","))
.map(c -> OwChannelConfig.fromString(c)).collect(Collectors.toSet())
: new HashSet<>()));
THING_LABEL_MAP = properties.entrySet().stream().filter(e -> e.getKey().endsWith(".label")).collect(
Collectors.toConcurrentMap(e -> OwSensorType.valueOf(e.getKey().split("\\.")[0]), e -> e.getValue()));
}
}

View File

@@ -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.onewire.internal;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
import org.openhab.core.types.StateDescription;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Dynamic channel state description provider.
* Overrides the state description for the controls, which receive its configuration in the runtime.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
@Component(service = { DynamicStateDescriptionProvider.class,
OwDynamicStateDescriptionProvider.class }, immediate = true)
public class OwDynamicStateDescriptionProvider implements DynamicStateDescriptionProvider {
private final Map<ChannelUID, StateDescription> descriptions = new ConcurrentHashMap<>();
private final Logger logger = LoggerFactory.getLogger(OwDynamicStateDescriptionProvider.class);
/**
* Set a state description for a channel. This description will be used when preparing the channel state by
* the framework for presentation. A previous description, if existed, will be replaced.
*
* @param channelUID
* channel UID
* @param description
* state description for the channel
*/
public void setDescription(ChannelUID channelUID, StateDescription description) {
logger.trace("adding state description for channel {}", channelUID);
descriptions.put(channelUID, description);
}
/**
* remove all descriptions for a given thing
*
* @param thingUID the thing's UID
*/
public void removeDescriptionsForThing(ThingUID thingUID) {
logger.trace("removing state description for thing {}", thingUID);
descriptions.entrySet().removeIf(entry -> entry.getKey().getThingUID().equals(thingUID));
}
@Override
public @Nullable StateDescription getStateDescription(Channel channel,
@Nullable StateDescription originalStateDescription, @Nullable Locale locale) {
if (descriptions.containsKey(channel.getUID())) {
logger.trace("returning new stateDescription for {}", channel.getUID());
return descriptions.get(channel.getUID());
} else {
return null;
}
}
}

View File

@@ -0,0 +1,29 @@
/**
* 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.onewire.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link OwException} class defines an exception for handling OneWireExceptions
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwException extends Exception {
private static final long serialVersionUID = 71120587360960199L;
public OwException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,123 @@
/**
* 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.onewire.internal;
import static org.openhab.binding.onewire.internal.OwBindingConstants.SUPPORTED_THING_TYPES;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.onewire.internal.discovery.OwDiscoveryService;
import org.openhab.binding.onewire.internal.handler.AdvancedMultisensorThingHandler;
import org.openhab.binding.onewire.internal.handler.BAE091xSensorThingHandler;
import org.openhab.binding.onewire.internal.handler.BasicMultisensorThingHandler;
import org.openhab.binding.onewire.internal.handler.BasicThingHandler;
import org.openhab.binding.onewire.internal.handler.EDSSensorThingHandler;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link OwHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.onewire")
public class OwHandlerFactory extends BaseThingHandlerFactory {
Logger logger = LoggerFactory.getLogger(OwHandlerFactory.class);
private final Map<ThingUID, @Nullable ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
@NonNullByDefault({})
private OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider;
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (OwserverBridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
OwserverBridgeHandler owserverBridgeHandler = new OwserverBridgeHandler((Bridge) thing);
registerDiscoveryService(owserverBridgeHandler);
return owserverBridgeHandler;
} else if (BasicMultisensorThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
return new BasicMultisensorThingHandler(thing, dynamicStateDescriptionProvider);
} else if (AdvancedMultisensorThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
return new AdvancedMultisensorThingHandler(thing, dynamicStateDescriptionProvider);
} else if (BasicThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
return new BasicThingHandler(thing, dynamicStateDescriptionProvider);
} else if (EDSSensorThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
return new EDSSensorThingHandler(thing, dynamicStateDescriptionProvider);
} else if (BAE091xSensorThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
return new BAE091xSensorThingHandler(thing, dynamicStateDescriptionProvider);
}
return null;
}
@Override
public void unregisterHandler(Thing thing) {
super.unregisterHandler(thing);
logger.error("factory {} deleting thing {}", this, thing);
}
private synchronized void registerDiscoveryService(OwserverBridgeHandler owserverBridgeHandler) {
OwDiscoveryService owDiscoveryService = new OwDiscoveryService(owserverBridgeHandler);
this.discoveryServiceRegs.put(owserverBridgeHandler.getThing().getUID(),
bundleContext.registerService(DiscoveryService.class.getName(), owDiscoveryService, new Hashtable<>()));
}
@Override
protected synchronized void removeHandler(ThingHandler thingHandler) {
if (thingHandler instanceof OwserverBridgeHandler) {
// remove discovery service, if bridge handler is removed
ServiceRegistration<?> serviceReg = this.discoveryServiceRegs.remove(thingHandler.getThing().getUID());
if (serviceReg != null) {
OwDiscoveryService service = (OwDiscoveryService) bundleContext.getService(serviceReg.getReference());
serviceReg.unregister();
if (service != null) {
service.deactivate();
}
}
}
}
@Reference
protected void setDynamicStateDescriptionProvider(OwDynamicStateDescriptionProvider provider) {
this.dynamicStateDescriptionProvider = provider;
}
protected void unsetDynamicStateDescriptionProvider(OwDynamicStateDescriptionProvider provider) {
this.dynamicStateDescriptionProvider = null;
}
}

View File

@@ -0,0 +1,147 @@
/**
* 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.onewire.internal;
import java.nio.ByteBuffer;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link OwPageBuffer} provides encapsulates a buffer for OwPacket payloads
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwPageBuffer {
private final Logger logger = LoggerFactory.getLogger(OwPageBuffer.class);
public static final int PAGE_SIZE = 8;
private ByteBuffer byteBuffer;
/**
* constructor for empty buffer
*
*/
public OwPageBuffer() {
byteBuffer = ByteBuffer.allocate(0);
}
/**
* constructor for new buffer of given length
*
* @param pageNum number of pages
*/
public OwPageBuffer(int pageNum) {
byteBuffer = ByteBuffer.allocate(pageNum * PAGE_SIZE);
}
/**
* constructor for given byte array
*
* @param bytes byte array containing the data
*/
public OwPageBuffer(byte[] bytes) {
if (bytes.length % PAGE_SIZE != 0) {
byteBuffer = ByteBuffer.allocate((bytes.length / PAGE_SIZE + 1) * PAGE_SIZE);
logger.warn("initializing buffer which is not aligned to pages (requested size is {})!", bytes.length);
} else {
byteBuffer = ByteBuffer.allocate(bytes.length);
}
byteBuffer.put(bytes);
}
/**
* get number of pages in this buffer
*
* @return number of pages
*/
public int length() {
return byteBuffer.limit() / PAGE_SIZE;
}
/**
* get a single page as byte array
*
* @param pageNum page number, starting with 0
* @return byte array containing the page's data
*/
public byte[] getPage(int pageNum) {
byte[] page = new byte[PAGE_SIZE];
byteBuffer.position(pageNum * PAGE_SIZE);
byteBuffer.get(page);
return page;
}
/**
* get a single page
*
* @param pageNum page number, starting with 0
* @return string representation of the page's data
*/
public String getPageString(int pageNum) {
return HexUtils.bytesToHex(getPage(pageNum));
}
/**
* get a single byte in a page
*
* @param pageNum page number, starting with 0
* @param byteNum byte number, starting from 0 (beginning of page)
* @return integer of the requested byte
*/
public int getByte(int pageNum, int byteNum) {
int index = pageNum * PAGE_SIZE + byteNum;
if (index < byteBuffer.limit()) {
return byteBuffer.get(index) & 0xFF;
} else {
return 0;
}
}
public void setByte(int pageNum, int byteNum, byte value) {
int index = pageNum * PAGE_SIZE + byteNum;
if (index < byteBuffer.limit()) {
byteBuffer.put(index, value);
} else {
throw new IllegalArgumentException("index out of range");
}
}
/**
* get this page buffer as byte array
*
* @return this page buffer as byte array
*/
public byte[] getBytes() {
return byteBuffer.array();
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append(new String("["));
for (int i = 0; i < length(); i++) {
if (i > 0) {
s.append(new String(", "));
}
s.append(getPageString(i));
}
s.append(new String("]"));
return s.toString();
}
}

View File

@@ -0,0 +1,115 @@
/**
* 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.onewire.internal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link SensorId} provides a sensorID for the Onewire bus.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class SensorId {
public static final Pattern SENSOR_ID_PATTERN = Pattern
.compile("^\\/?((?:(?:1F\\.[0-9A-Fa-f]{12})\\/(?:main|aux)\\/)+)?([0-9A-Fa-f]{2}\\.[0-9A-Fa-f]{12})$");
private final String sensorId;
private final String path;
private final String fullPath;
/**
* construct a new SensorId object
*
* allowed formats:
* - "28.0123456789ab"
* - "1F.1234566890ab/main/28.0123456789ab"
* - "1F.1234566890ab/aux/28.0123456789ab"
* - leading "/" characters are allowed but not required
* - characters are case-insensitive
* - hubs ("1F.xxxxxxxxxxxx/aux/") may be repeated
*/
public SensorId(String fullPath) {
Matcher matcher = SENSOR_ID_PATTERN.matcher(fullPath);
if (matcher.matches() && matcher.groupCount() == 2) {
path = matcher.group(1) == null ? "" : matcher.group(1);
sensorId = matcher.group(2);
this.fullPath = "/" + path + sensorId;
} else {
throw new IllegalArgumentException();
}
}
/**
* get the full path to the sensor
*
* @return full path (including hub parts, separated by "/" characters)
*/
public String getFullPath() {
return fullPath;
}
/**
* get the sensor id
*
* @return sensor id without leading "/" character
*/
public String getId() {
return sensorId;
}
/**
* get the path of this sensorId
*
* @return path without sensor id (including hub parts, separated by "/" characters)
*/
public String getPath() {
return path;
}
/**
* get family id (first to characters of sensor id)
*
* @return the family id
*/
public String getFamilyId() {
return sensorId.substring(0, 2);
}
@Override
public String toString() {
return fullPath;
}
@Override
public int hashCode() {
return this.fullPath.hashCode();
}
@Override
public boolean equals(@Nullable Object o) {
if (o == this) {
return true;
}
if (!(o instanceof SensorId)) {
return false;
}
return ((SensorId) o).fullPath.equals(fullPath);
}
}

View File

@@ -0,0 +1,102 @@
/**
* 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.onewire.internal;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link Util} is a set of helper functions
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class Util {
private static final Logger LOGGER = LoggerFactory.getLogger(Util.class);
/**
* calculate absolute humidity in g/m³ from measured values
*
* @param temperature the measured temperature
* @param relativeHumidity the measured relative humidity
* @return the corresponding absolute humidity
*/
public static State calculateAbsoluteHumidity(QuantityType<Temperature> temperature,
QuantityType<Dimensionless> relativeHumidity) {
QuantityType<Temperature> temperatureDegC = temperature.toUnit(SIUnits.CELSIUS);
if (temperatureDegC == null) {
throw new IllegalArgumentException("could not change unit");
}
Double theta = temperatureDegC.doubleValue();
// saturation vapor pressure in kg/(m s^2)
Double saturationVaporPressure = 611.2 * Math.exp(17.62 * theta / (243.12 + theta));
// absolute humidity in kg/m^3
Double aH = relativeHumidity.doubleValue() / 100 * saturationVaporPressure / (461.52 * (273.15 + theta));
State absoluteHumidity = new QuantityType<>(aH, SmartHomeUnits.KILOGRAM_PER_CUBICMETRE).toUnit("g/m³");
if (absoluteHumidity != null) {
return absoluteHumidity;
} else {
throw new IllegalArgumentException("could not change unit");
}
}
/**
* calculates the dewpoint in °C from measured values
*
* @param temperature the measured temperature
* @param relativeHumidity the measured relative humidity
* @return the corresponding dewpoint
*/
public static State calculateDewpoint(QuantityType<Temperature> temperature,
QuantityType<Dimensionless> relativeHumidity) {
QuantityType<Temperature> temperatureDegC = temperature.toUnit(SIUnits.CELSIUS);
if (temperatureDegC == null) {
throw new IllegalArgumentException("could not change unit");
}
Double theta = temperatureDegC.doubleValue();
Double rH = relativeHumidity.doubleValue() / 100;
// dewpoint in °C
Double dP = 243.12 * (((17.62 * theta) / (243.12 + theta) + Math.log(rH))
/ (((17.62 * 243.12) / (243.12 + theta) - Math.log(rH))));
State dewPoint = new QuantityType<>(dP, SIUnits.CELSIUS);
return dewPoint;
}
public static Map<String, String> readPropertiesFile(String filename) {
URL resource = Thread.currentThread().getContextClassLoader().getResource(filename);
Properties properties = new Properties();
try {
properties.load(resource.openStream());
return properties.entrySet().stream()
.collect(Collectors.toMap(e -> (String) e.getKey(), e -> (String) e.getValue()));
} catch (IOException e) {
LOGGER.warn("Could not read resource file {}, binding will probably fail: {}", filename, e.getMessage());
return new HashMap<>();
}
}
}

View File

@@ -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.onewire.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link AMSHandlerConfiguration} is a helper class for the mstx thing handler configuration
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class AMSHandlerConfiguration extends BaseHandlerConfiguration {
public int digitalRefresh = 10;
}

View File

@@ -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.onewire.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link BAE091xAnalogConfiguration} is a helper class for the BAE091x ADC Pin configuration
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class BAE091xAnalogConfiguration {
public Boolean hires = false;
}

View File

@@ -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.onewire.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwBindingConstants;
/**
* The {@link BAE091xHandlerConfiguration} is a helper class for the BAE091x thing handler configuration
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class BAE091xHandlerConfiguration extends BaseHandlerConfiguration {
public String pin1 = OwBindingConstants.CONFIG_BAE_PIN_DISABLED;
public String pin2 = OwBindingConstants.CONFIG_BAE_PIN_DISABLED;
public String pin6 = OwBindingConstants.CONFIG_BAE_PIN_DISABLED;
public String pin7 = OwBindingConstants.CONFIG_BAE_PIN_DISABLED;
public String pin8 = OwBindingConstants.CONFIG_BAE_PIN_DISABLED;
}

View File

@@ -0,0 +1,26 @@
/**
* 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.onewire.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link BAE091xPIOConfiguration} is a helper class for the BAE091x PIO Pin configuration
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class BAE091xPIOConfiguration {
public String mode = "input";
public String pulldevice = "disabled";
}

View File

@@ -0,0 +1,26 @@
/**
* 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.onewire.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link BAE091xPWMConfiguration} is a helper class for the BAE091x PWM Frequency configuration
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class BAE091xPWMConfiguration {
public int prescaler = 0;
public boolean reversePolarity = false;
}

View File

@@ -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.onewire.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link BaseHandlerConfiguration} is a helper class for the base thing handler configuration
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class BaseHandlerConfiguration {
public @Nullable String id;
public int refresh = 300;
}

View File

@@ -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.onewire.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.onewire.internal.device.OwSensorType;
/**
* The {@link MstxHandlerConfiguration} is a helper class for the mstx thing handler configuration
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class MstxHandlerConfiguration extends BaseHandlerConfiguration {
public @Nullable OwSensorType manualsensor;
}

View File

@@ -0,0 +1,158 @@
/**
* 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.onewire.internal.device;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.DigitalIoConfig;
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.StateDescriptionFragmentBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link AbstractDigitalOwDevice} class defines an abstract digital I/O device
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public abstract class AbstractDigitalOwDevice extends AbstractOwDevice {
private final Logger logger = LoggerFactory.getLogger(AbstractDigitalOwDevice.class);
protected @NonNullByDefault({}) OwserverDeviceParameter fullInParam;
protected @NonNullByDefault({}) OwserverDeviceParameter fullOutParam;
protected final List<DigitalIoConfig> ioConfig = new ArrayList<>();
public AbstractDigitalOwDevice(SensorId sensorId, OwBaseThingHandler callback) {
super(sensorId, callback);
}
@Override
public void configureChannels() throws OwException {
Thing thing = callback.getThing();
OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider = callback
.getDynamicStateDescriptionProvider();
for (Integer i = 0; i < ioConfig.size(); i++) {
String channelId = ioConfig.get(i).getChannelId();
Channel channel = thing.getChannel(channelId);
if (channel != null) {
Configuration channelConfig = channel.getConfiguration();
try {
if (channelConfig.get(CONFIG_DIGITAL_MODE) != null) {
ioConfig.get(i).setIoMode((String) channelConfig.get(CONFIG_DIGITAL_MODE));
}
if (channelConfig.get(CONFIG_DIGITAL_LOGIC) != null) {
ioConfig.get(i).setIoLogic((String) channelConfig.get(CONFIG_DIGITAL_LOGIC));
}
} catch (IllegalArgumentException e) {
throw new OwException(channelId + " has invalid configuration");
}
if (dynamicStateDescriptionProvider != null) {
StateDescription stateDescription = StateDescriptionFragmentBuilder.create()
.withReadOnly(ioConfig.get(i).isInput()).build().toStateDescription();
if (stateDescription != null) {
dynamicStateDescriptionProvider.setDescription(ioConfig.get(i).getChannelUID(),
stateDescription);
} else {
logger.warn("Failed to create state description in thing {}", thing.getUID());
}
} else {
logger.debug(
"state description may be inaccurate, state description provider not available in thing {}",
thing.getUID());
}
logger.debug("configured {} channel {}: {}", thing.getUID(), i, ioConfig.get(i));
} else {
throw new OwException(channelId + " not found");
}
}
isConfigured = true;
}
/**
* refreshes this sensor - note that the update interval check is not performed as its and i/o device
*/
@Override
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
logger.trace("refresh of sensor {} started", sensorId);
if (isConfigured) {
State state;
BitSet statesSensed = bridgeHandler.readBitSet(sensorId, fullInParam);
BitSet statesPIO = bridgeHandler.readBitSet(sensorId, fullOutParam);
for (int i = 0; i < ioConfig.size(); i++) {
if (ioConfig.get(i).isInput()) {
state = ioConfig.get(i).convertState(statesSensed.get(i));
logger.trace("{} IN{}: raw {}, final {}", sensorId, i, statesSensed, state);
} else {
state = ioConfig.get(i).convertState(statesPIO.get(i));
logger.trace("{} OUT{}: raw {}, final {}", sensorId, i, statesPIO, state);
}
callback.postUpdate(ioConfig.get(i).getChannelId(), state);
}
}
}
/**
* get the number of channels
*
* @return number of channels
*/
public int getChannelCount() {
return ioConfig.size();
}
public boolean writeChannel(OwserverBridgeHandler bridgeHandler, Integer ioChannel, Command command) {
if (ioChannel < getChannelCount()) {
try {
if (ioConfig.get(ioChannel).isOutput()) {
bridgeHandler.writeDecimalType(sensorId, ioConfig.get(ioChannel).getParameter(),
ioConfig.get(ioChannel).convertState((OnOffType) command));
return true;
} else {
return false;
}
} catch (OwException e) {
logger.info("could not write {} to {}: {}", command, ioChannel, e.getMessage());
return false;
}
} else {
throw new IllegalArgumentException("channel number out of range");
}
}
}

View File

@@ -0,0 +1,140 @@
/**
* 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.onewire.internal.device;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link AbstractOwClass} class defines an abstract onewire device
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public abstract class AbstractOwDevice {
private final Logger logger = LoggerFactory.getLogger(AbstractOwDevice.class);
protected SensorId sensorId;
protected OwSensorType sensorType;
protected OwBaseThingHandler callback;
protected Boolean isConfigured = false;
protected Set<String> enabledChannels = new HashSet<>();
/**
* constructor for the onewire device
*
* @param sensorId onewire ID of the sensor
* @param callback ThingHandler callback for posting updates
*/
public AbstractOwDevice(SensorId sensorId, OwBaseThingHandler callback) {
this.sensorId = sensorId;
this.callback = callback;
this.sensorType = OwSensorType.UNKNOWN;
}
public AbstractOwDevice(SensorId sensorId, OwSensorType sensorType, OwBaseThingHandler callback) {
this.sensorId = sensorId;
this.callback = callback;
this.sensorType = sensorType;
}
/**
* configures the onewire devices channels
*
*/
public abstract void configureChannels() throws OwException;
/**
* refresh this sensor
*
* @param bridgeHandler for sending requests
* @param forcedRefresh post update even if state did not change
* @throws OwException in case of communication error
*/
public abstract void refresh(OwserverBridgeHandler owBridgeHandler, Boolean forcedRefresh) throws OwException;
/**
* enables a channel on this device
*
* @param channelID the channels channelID
*/
public void enableChannel(String channelID) {
if (!enabledChannels.contains(channelID)) {
enabledChannels.add(channelID);
}
}
/**
* disables a channel on this device
*
* @param channelID the channels channelID
*/
public void disableChannel(String channelID) {
if (enabledChannels.contains(channelID)) {
enabledChannels.remove(channelID);
}
}
/**
* get onewire ID of this sensor
*
* @return sensor ID
*/
public SensorId getSensorId() {
return sensorId;
}
/**
* check sensor presence and update thing state
*
* @param owServerConnection
* @return sensors presence state
*/
public Boolean checkPresence(OwserverBridgeHandler bridgeHandler) {
try {
State present = bridgeHandler.checkPresence(sensorId);
callback.updatePresenceStatus(present);
return OnOffType.ON.equals(present);
} catch (OwException e) {
logger.debug("error refreshing presence {} on bridge {}: {}", this.sensorId,
bridgeHandler.getThing().getUID(), e.getMessage());
return false;
}
}
/**
* get this sensors type
*
* @param bridgeHandler bridge handler to request from if type formerly unknown
* @return this sensors type
* @throws OwException
*/
public OwSensorType getSensorType(OwserverBridgeHandler bridgeHandler) throws OwException {
if (sensorType == OwSensorType.UNKNOWN) {
sensorType = bridgeHandler.getType(sensorId);
}
return sensorType;
}
}

View File

@@ -0,0 +1,408 @@
/**
* 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.onewire.internal.device;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.BitSet;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.Frequency;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.config.BAE091xAnalogConfiguration;
import org.openhab.binding.onewire.internal.config.BAE091xPIOConfiguration;
import org.openhab.binding.onewire.internal.config.BAE091xPWMConfiguration;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link BAE0910} class defines an BAE0910 device
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class BAE0910 extends AbstractOwDevice {
private static final int OUTC_OUTEN = 4;
private static final int OUTC_DS = 3;
private static final int PIOC_PIOEN = 4;
private static final int PIOC_DS = 3;
private static final int PIOC_PD = 2;
private static final int PIOC_PE = 1;
private static final int PIOC_DD = 0;
private static final int ADCC_ADCEN = 4;
private static final int ADCC_10BIT = 3;
@SuppressWarnings("unused") // for future use
private static final int ADCC_OFS = 2;
@SuppressWarnings("unused")
private static final int ADCC_GRP = 1;
@SuppressWarnings("unused")
private static final int ADCC_STP = 0;
private static final int TPMC_POL = 7;
private static final int TPMC_INENA = 5;
private static final int TPMC_PWMDIS = 4;
private static final int TPMC_PS2 = 2;
private static final int TPMC_PS1 = 1;
private static final int TPMC_PS0 = 0;
private final Logger logger = LoggerFactory.getLogger(BAE0910.class);
private final OwserverDeviceParameter pin1CounterParameter = new OwserverDeviceParameter("/counter");
private final OwserverDeviceParameter pin2OutParameter = new OwserverDeviceParameter("/out");
private final OwserverDeviceParameter pin6PIOParameter = new OwserverDeviceParameter("/pio");
private final OwserverDeviceParameter pin7AnalogParameter = new OwserverDeviceParameter("/adc");
private final OwserverDeviceParameter outcParameter = new OwserverDeviceParameter("/outc");
private final OwserverDeviceParameter piocParameter = new OwserverDeviceParameter("/pioc");
private final OwserverDeviceParameter adccParameter = new OwserverDeviceParameter("/adcc");
private final OwserverDeviceParameter tpm1cParameter = new OwserverDeviceParameter("/tpm1c");
private final OwserverDeviceParameter tpm2cParameter = new OwserverDeviceParameter("/tpm2c");
private final OwserverDeviceParameter period1Parameter = new OwserverDeviceParameter("/period1");
private final OwserverDeviceParameter period2Parameter = new OwserverDeviceParameter("/period2");
private final OwserverDeviceParameter duty1Parameter = new OwserverDeviceParameter("/duty1");
private final OwserverDeviceParameter duty2Parameter = new OwserverDeviceParameter("/duty2");
private final OwserverDeviceParameter duty3Parameter = new OwserverDeviceParameter("/duty3");
private final OwserverDeviceParameter duty4Parameter = new OwserverDeviceParameter("/duty4");
private BitSet outcRegister = new BitSet(8);
private BitSet piocRegister = new BitSet(8);
private BitSet adccRegister = new BitSet(8);
private BitSet tpm1cRegister = new BitSet(8);
private BitSet tpm2cRegister = new BitSet(8);
private double resolution1 = 8; // in µs
private double resolution2 = 8; // in µs
public BAE0910(SensorId sensorId, OwBaseThingHandler callback) {
super(sensorId, callback);
}
@Override
public void configureChannels() {
}
public void configureChannels(OwserverBridgeHandler bridgeHandler) throws OwException {
outcRegister.clear();
piocRegister.clear();
adccRegister.clear();
tpm1cRegister.clear();
tpm2cRegister.clear();
if (enabledChannels.contains(CHANNEL_PWM_FREQ1)) {
Channel channel = callback.getThing().getChannel(CHANNEL_PWM_FREQ1);
if (channel != null) {
BAE091xPWMConfiguration channelConfig = channel.getConfiguration().as(BAE091xPWMConfiguration.class);
tpm1cRegister.set(TPMC_POL, channelConfig.reversePolarity);
tpm1cRegister.set(TPMC_PS2, (channelConfig.prescaler & 4) == 4);
tpm1cRegister.set(TPMC_PS1, (channelConfig.prescaler & 2) == 2);
tpm1cRegister.set(TPMC_PS0, (channelConfig.prescaler & 1) == 1);
resolution1 = 0.0625 * (1 << channelConfig.prescaler);
} else {
throw new OwException("trying to configure pwm but frequency channel is missing");
}
}
if (enabledChannels.contains(CHANNEL_PWM_FREQ2)) {
Channel channel = callback.getThing().getChannel(CHANNEL_PWM_FREQ2);
if (channel != null) {
BAE091xPWMConfiguration channelConfig = channel.getConfiguration().as(BAE091xPWMConfiguration.class);
tpm2cRegister.set(TPMC_POL, channelConfig.reversePolarity);
tpm2cRegister.set(TPMC_PS2, (channelConfig.prescaler & 4) == 4);
tpm2cRegister.set(TPMC_PS1, (channelConfig.prescaler & 2) == 2);
tpm2cRegister.set(TPMC_PS0, (channelConfig.prescaler & 1) == 1);
resolution2 = 0.0625 * (1 << channelConfig.prescaler);
} else {
throw new OwException("trying to configure pwm but frequency channel is missing");
}
}
// Pin 2
if (enabledChannels.contains(CHANNEL_DIGITAL2)) {
outcRegister.set(OUTC_DS);
outcRegister.set(OUTC_OUTEN);
}
// Pin 6
if (enabledChannels.contains(CHANNEL_DIGITAL6)) {
piocRegister.set(PIOC_PIOEN);
piocRegister.set(PIOC_DS);
Channel channel = callback.getThing().getChannel(CHANNEL_DIGITAL6);
if (channel != null) {
BAE091xPIOConfiguration channelConfig = channel.getConfiguration().as(BAE091xPIOConfiguration.class);
piocRegister.set(PIOC_DD, channelConfig.mode.equals("output"));
switch (channelConfig.pulldevice) {
case "pullup":
piocRegister.set(PIOC_PE);
piocRegister.clear(PIOC_PD);
break;
case "pulldown":
piocRegister.set(PIOC_PE);
piocRegister.set(PIOC_PD);
break;
default:
}
} else {
throw new OwException("trying to configure pin 6 but channel is missing");
}
}
// Pin 7
if (enabledChannels.contains(CHANNEL_VOLTAGE)) {
adccRegister.set(ADCC_ADCEN);
Channel channel = callback.getThing().getChannel(CHANNEL_VOLTAGE);
if (channel != null) {
BAE091xAnalogConfiguration channelConfig = channel.getConfiguration()
.as(BAE091xAnalogConfiguration.class);
adccRegister.set(ADCC_10BIT, channelConfig.hires);
} else {
throw new OwException("trying to configure pin 7 but channel is missing");
}
}
if (enabledChannels.contains(CHANNEL_DIGITAL7)) {
tpm2cRegister.set(TPMC_PWMDIS);
}
// Pin 8
if (enabledChannels.contains(CHANNEL_DIGITAL8)) {
tpm1cRegister.set(TPMC_PWMDIS);
Channel channel = callback.getThing().getChannel(CHANNEL_DIGITAL8);
if (channel != null) {
if ((new ChannelTypeUID(BINDING_ID, "bae-in")).equals(channel.getChannelTypeUID())) {
tpm1cRegister.set(TPMC_INENA);
}
} else {
throw new OwException("trying to configure pin 8 but channel is missing");
}
}
// write configuration
bridgeHandler.writeBitSet(sensorId, outcParameter, outcRegister);
bridgeHandler.writeBitSet(sensorId, piocParameter, piocRegister);
bridgeHandler.writeBitSet(sensorId, adccParameter, adccRegister);
bridgeHandler.writeBitSet(sensorId, tpm1cParameter, tpm1cRegister);
bridgeHandler.writeBitSet(sensorId, tpm2cParameter, tpm2cRegister);
isConfigured = true;
}
@Override
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
if (isConfigured) {
logger.trace("refresh of sensor {} started", sensorId);
// Counter
if (enabledChannels.contains(CHANNEL_COUNTER)) {
State counterValue = bridgeHandler.readDecimalType(sensorId, pin1CounterParameter);
callback.postUpdate(CHANNEL_COUNTER, counterValue);
}
// Digital Pins
if (enabledChannels.contains(CHANNEL_DIGITAL2)) {
BitSet value = bridgeHandler.readBitSet(sensorId, pin2OutParameter);
callback.postUpdate(CHANNEL_DIGITAL2, OnOffType.from(value.get(0)));
}
if (enabledChannels.contains(CHANNEL_DIGITAL6)) {
BitSet value = bridgeHandler.readBitSet(sensorId, pin6PIOParameter);
callback.postUpdate(CHANNEL_DIGITAL6, OnOffType.from(value.get(0)));
}
if (enabledChannels.contains(CHANNEL_DIGITAL7)) {
BitSet value = bridgeHandler.readBitSet(sensorId, tpm2cParameter);
callback.postUpdate(CHANNEL_DIGITAL7, OnOffType.from(value.get(TPMC_POL)));
}
if (enabledChannels.contains(CHANNEL_DIGITAL8)) {
BitSet value = bridgeHandler.readBitSet(sensorId, tpm1cParameter);
callback.postUpdate(CHANNEL_DIGITAL8, OnOffType.from(value.get(TPMC_POL)));
}
// Analog
if (enabledChannels.contains(CHANNEL_VOLTAGE)) {
State analogValue = bridgeHandler.readDecimalType(sensorId, pin7AnalogParameter);
callback.postUpdate(CHANNEL_VOLTAGE,
new QuantityType<>((DecimalType) analogValue, SmartHomeUnits.VOLT));
}
// PWM
int period1 = 0;
int period2 = 0;
if (enabledChannels.contains(CHANNEL_PWM_FREQ1)) {
period1 = ((DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)).intValue();
double frequency = (period1 > 0) ? 1 / (period1 * resolution1 * 1e-6) : 0;
callback.postUpdate(CHANNEL_PWM_FREQ1, new QuantityType<>(frequency, SmartHomeUnits.HERTZ));
}
if (enabledChannels.contains(CHANNEL_PWM_FREQ2)) {
period2 = ((DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)).intValue();
double frequency = (period2 > 0) ? 1 / (period2 * resolution2 * 1e-6) : 0;
callback.postUpdate(CHANNEL_PWM_FREQ2, new QuantityType<>(frequency, SmartHomeUnits.HERTZ));
}
if (enabledChannels.contains(CHANNEL_PWM_DUTY1)) {
int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty1Parameter)).intValue();
double duty = (period1 > 0 && dutyValue <= period1) ? 100 * dutyValue / period1 : 100;
callback.postUpdate(CHANNEL_PWM_DUTY1, new QuantityType<>(duty, SmartHomeUnits.PERCENT));
}
if (enabledChannels.contains(CHANNEL_PWM_DUTY2)) {
int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty2Parameter)).intValue();
double duty = (period2 > 0 && dutyValue <= period2) ? 100 * dutyValue / period2 : 100;
callback.postUpdate(CHANNEL_PWM_DUTY2, new QuantityType<>(duty, SmartHomeUnits.PERCENT));
}
if (enabledChannels.contains(CHANNEL_PWM_DUTY3)) {
int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty3Parameter)).intValue();
double duty = (period1 > 0 && dutyValue <= period1) ? 100 * dutyValue / period1 : 100;
callback.postUpdate(CHANNEL_PWM_DUTY3, new QuantityType<>(duty, SmartHomeUnits.PERCENT));
}
if (enabledChannels.contains(CHANNEL_PWM_DUTY4)) {
int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty4Parameter)).intValue();
double duty = (period2 > 0 && dutyValue <= period2) ? 100 * dutyValue / period2 : 100;
callback.postUpdate(CHANNEL_PWM_DUTY4, new QuantityType<>(duty, SmartHomeUnits.PERCENT));
}
}
}
public boolean writeChannel(OwserverBridgeHandler bridgeHandler, String channelId, Command command) {
try {
BitSet value = new BitSet(8);
switch (channelId) {
case CHANNEL_DIGITAL2:
// output
if (!outcRegister.get(OUTC_OUTEN)) {
return false;
}
value.set(0, ((OnOffType) command).equals(OnOffType.ON));
bridgeHandler.writeBitSet(sensorId, pin2OutParameter, value);
break;
case CHANNEL_DIGITAL6:
// not input, pio
if (!piocRegister.get(PIOC_DD) || !piocRegister.get(PIOC_PIOEN)) {
return false;
}
value.set(0, ((OnOffType) command).equals(OnOffType.ON));
bridgeHandler.writeBitSet(sensorId, pin6PIOParameter, value);
break;
case CHANNEL_DIGITAL7:
// not pwm, not analog
if (!tpm2cRegister.get(TPMC_PWMDIS) || adccRegister.get(ADCC_ADCEN)) {
return false;
}
tpm2cRegister.set(TPMC_POL, ((OnOffType) command).equals(OnOffType.ON));
bridgeHandler.writeBitSet(sensorId, tpm2cParameter, tpm2cRegister);
break;
case CHANNEL_DIGITAL8:
// not input, not pwm
if (tpm1cRegister.get(TPMC_INENA) || !tpm1cRegister.get(TPMC_PWMDIS)) {
return false;
}
tpm1cRegister.set(TPMC_POL, ((OnOffType) command).equals(OnOffType.ON));
bridgeHandler.writeBitSet(sensorId, tpm1cParameter, tpm1cRegister);
break;
case CHANNEL_PWM_FREQ1:
if (command instanceof QuantityType<?>) {
bridgeHandler.writeDecimalType(sensorId, period1Parameter,
convertFrequencyToPeriod(command, resolution1));
}
break;
case CHANNEL_PWM_FREQ2:
if (command instanceof QuantityType<?>) {
bridgeHandler.writeDecimalType(sensorId, period2Parameter,
convertFrequencyToPeriod(command, resolution2));
}
break;
case CHANNEL_PWM_DUTY1:
if (command instanceof QuantityType<?>) {
bridgeHandler.writeDecimalType(sensorId, duty1Parameter, calculateDutyCycle(command,
(DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)));
}
break;
case CHANNEL_PWM_DUTY2:
if (command instanceof QuantityType<?>) {
bridgeHandler.writeDecimalType(sensorId, duty2Parameter, calculateDutyCycle(command,
(DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)));
}
break;
case CHANNEL_PWM_DUTY3:
if (command instanceof QuantityType<?>) {
bridgeHandler.writeDecimalType(sensorId, duty3Parameter, calculateDutyCycle(command,
(DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)));
}
break;
case CHANNEL_PWM_DUTY4:
if (command instanceof QuantityType<?>) {
bridgeHandler.writeDecimalType(sensorId, duty4Parameter, calculateDutyCycle(command,
(DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)));
}
break;
default:
throw new OwException("unknown or invalid channel");
}
return true;
} catch (
OwException e) {
logger.info("could not write {} to {}: {}", command, channelId, e.getMessage());
return false;
}
}
public static OwSensorType getDeviceSubType(OwserverBridgeHandler bridgeHandler, SensorId sensorId)
throws OwException {
OwserverDeviceParameter deviceTypeParameter = new OwserverDeviceParameter("/device_type");
String subDeviceType = bridgeHandler.readString(sensorId, deviceTypeParameter);
switch (subDeviceType) {
case "2":
return OwSensorType.BAE0910;
case "3":
return OwSensorType.BAE0911;
default:
return OwSensorType.UNKNOWN;
}
}
private DecimalType convertFrequencyToPeriod(Command command, double resolution) throws OwException {
@SuppressWarnings("unchecked")
QuantityType<Frequency> fHz = ((QuantityType<Frequency>) command).toUnit(SmartHomeUnits.HERTZ);
if (fHz == null) {
throw new OwException("could not convert command to frequency");
}
double f = fHz.doubleValue();
int period = 0;
if (f > 0) {
period = (int) Math.min(Math.round(1 / (f * resolution * 1e-6)), 65535);
}
return new DecimalType(period);
}
private DecimalType calculateDutyCycle(Command command, DecimalType period) throws OwException {
@SuppressWarnings("unchecked")
double dutyCycle = ((QuantityType<Dimensionless>) command).doubleValue();
int dutyValue = 0;
if (dutyCycle > 0 && dutyCycle <= 100) {
dutyValue = (int) Math.round(dutyCycle / 100.0 * period.intValue());
} else if (dutyCycle > 100) {
dutyValue = 65535;
}
return new DecimalType(dutyValue);
}
}

View File

@@ -0,0 +1,90 @@
/**
* 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.onewire.internal.device;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DS18x20} class defines an DS18x20 or DS1822 device
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS18x20 extends AbstractOwDevice {
private final Logger logger = LoggerFactory.getLogger(DS18x20.class);
private OwserverDeviceParameter temperatureParameter = new OwserverDeviceParameter("/temperature");
private boolean ignorePOR = false;
public DS18x20(SensorId sensorId, OwBaseThingHandler callback) {
super(sensorId, callback);
}
@Override
public void configureChannels() throws OwException {
Thing thing = callback.getThing();
Channel temperatureChannel = thing.getChannel(CHANNEL_TEMPERATURE);
if (temperatureChannel != null) {
Configuration channelConfiguration = temperatureChannel.getConfiguration();
if (channelConfiguration.containsKey(CONFIG_RESOLUTION)) {
temperatureParameter = new OwserverDeviceParameter(
"/temperature" + (String) channelConfiguration.get(CONFIG_RESOLUTION));
} else {
temperatureParameter = new OwserverDeviceParameter("/temperature");
}
if (channelConfiguration.containsKey(CONFIG_IGNORE_POR)) {
ignorePOR = (Boolean) channelConfiguration.get(CONFIG_IGNORE_POR);
} else {
ignorePOR = false;
}
} else {
throw new OwException(CHANNEL_TEMPERATURE + " not found");
}
isConfigured = true;
}
@Override
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
if (isConfigured && enabledChannels.contains(CHANNEL_TEMPERATURE)) {
logger.trace("refresh of sensor {} started", sensorId);
QuantityType<Temperature> temperature = new QuantityType<>(
(DecimalType) bridgeHandler.readDecimalType(sensorId, temperatureParameter), SIUnits.CELSIUS);
logger.trace("read temperature {} from {}", temperature, sensorId);
if (ignorePOR && (Double.compare(temperature.doubleValue(), 85.0) == 0)) {
logger.trace("ignored POR value from sensor {}", sensorId);
} else {
callback.postUpdate(CHANNEL_TEMPERATURE, temperature);
}
}
}
}

View File

@@ -0,0 +1,88 @@
/**
* 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.onewire.internal.device;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.Util;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DS1923} class defines an DS1923 device
*
* @author Jan N. Klug - Initial contribution
* @author Michał Wójcik - Adapted to DS1923
*/
@NonNullByDefault
public class DS1923 extends AbstractOwDevice {
private final Logger logger = LoggerFactory.getLogger(DS1923.class);
private final OwserverDeviceParameter temperatureParameter = new OwserverDeviceParameter("/temperature");
private final OwserverDeviceParameter humidityParameter = new OwserverDeviceParameter("/humidity");
public DS1923(SensorId sensorId, OwBaseThingHandler callback) {
super(sensorId, callback);
}
@Override
public void configureChannels() throws OwException {
isConfigured = true;
}
@Override
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
if (isConfigured) {
logger.trace("refresh of sensor {} started", sensorId);
if (enabledChannels.contains(CHANNEL_TEMPERATURE) || enabledChannels.contains(CHANNEL_HUMIDITY)
|| enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)
|| enabledChannels.contains(CHANNEL_DEWPOINT)) {
QuantityType<Temperature> temperature = new QuantityType<>(
(DecimalType) bridgeHandler.readDecimalType(sensorId, temperatureParameter), SIUnits.CELSIUS);
callback.postUpdate(CHANNEL_TEMPERATURE, temperature);
if (enabledChannels.contains(CHANNEL_HUMIDITY) || enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)
|| enabledChannels.contains(CHANNEL_DEWPOINT)) {
QuantityType<Dimensionless> humidity = new QuantityType<>(
(DecimalType) bridgeHandler.readDecimalType(sensorId, humidityParameter),
SmartHomeUnits.PERCENT);
if (enabledChannels.contains(CHANNEL_HUMIDITY)) {
callback.postUpdate(CHANNEL_HUMIDITY, humidity);
}
if (enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)) {
callback.postUpdate(CHANNEL_ABSOLUTE_HUMIDITY,
Util.calculateAbsoluteHumidity(temperature, humidity));
}
if (enabledChannels.contains(CHANNEL_DEWPOINT)) {
callback.postUpdate(CHANNEL_DEWPOINT, Util.calculateDewpoint(temperature, humidity));
}
}
}
}
}
}

View File

@@ -0,0 +1,40 @@
/**
* 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.onewire.internal.device;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
/**
* The {@link DS2401} class defines an DS2401 (iButton) device
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2401 extends AbstractOwDevice {
public DS2401(SensorId sensorId, OwBaseThingHandler callback) {
super(sensorId, callback);
isConfigured = true;
}
@Override
public void configureChannels() throws OwException {
}
@Override
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
}
}

View File

@@ -0,0 +1,45 @@
/**
* 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.onewire.internal.device;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.DigitalIoConfig;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
/**
* The {@link DS2405} class defines an DS2405 device
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2405 extends AbstractDigitalOwDevice {
public DS2405(SensorId sensorId, OwBaseThingHandler callback) {
super(sensorId, callback);
}
@Override
public void configureChannels() throws OwException {
OwserverDeviceParameter inParam = new OwserverDeviceParameter("uncached/", "/sensed");
OwserverDeviceParameter outParam = new OwserverDeviceParameter("/PIO");
ioConfig.add(new DigitalIoConfig(callback.getThing(), 0, inParam, outParam));
fullInParam = inParam;
fullOutParam = outParam;
super.configureChannels();
}
}

View File

@@ -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.onewire.internal.device;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.DigitalIoConfig;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
/**
* The {@link DS2406_DS2413} class defines an DS2406 or DS2413 device
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2406_DS2413 extends AbstractDigitalOwDevice {
public DS2406_DS2413(SensorId sensorId, OwBaseThingHandler callback) {
super(sensorId, callback);
}
@Override
public void configureChannels() throws OwException {
ioConfig.clear();
ioConfig.add(new DigitalIoConfig(callback.getThing(), 0, new OwserverDeviceParameter("uncached/", "/sensed.A"),
new OwserverDeviceParameter("/PIO.A")));
ioConfig.add(new DigitalIoConfig(callback.getThing(), 1, new OwserverDeviceParameter("uncached/", "/sensed.B"),
new OwserverDeviceParameter("/PIO.B")));
fullInParam = new OwserverDeviceParameter("uncached/", "/sensed.BYTE");
fullOutParam = new OwserverDeviceParameter("/PIO.BYTE");
super.configureChannels();
}
}

View File

@@ -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.onewire.internal.device;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.DigitalIoConfig;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
/**
* The {@link DS2408} class defines an DS2408 device
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2408 extends AbstractDigitalOwDevice {
public DS2408(SensorId sensorId, OwBaseThingHandler callback) {
super(sensorId, callback);
}
@Override
public void configureChannels() throws OwException {
ioConfig.clear();
for (int i = 0; i < 8; i++) {
ioConfig.add(new DigitalIoConfig(callback.getThing(), i,
new OwserverDeviceParameter("uncached/", String.format("/sensed.%d", i)),
new OwserverDeviceParameter(String.format("/PIO.%d", i))));
}
fullInParam = new OwserverDeviceParameter("uncached/", "/sensed.BYTE");
fullOutParam = new OwserverDeviceParameter("/PIO.BYTE");
super.configureChannels();
}
}

View File

@@ -0,0 +1,62 @@
/**
* 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.onewire.internal.device;
import static org.openhab.binding.onewire.internal.OwBindingConstants.CHANNEL_COUNTER;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DS2423} class defines an DS2423 device
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2423 extends AbstractOwDevice {
private final Logger logger = LoggerFactory.getLogger(DS2423.class);
private final OwserverDeviceParameter counterParameter = new OwserverDeviceParameter("/counters.ALL");
public DS2423(SensorId sensorId, OwBaseThingHandler callback) {
super(sensorId, callback);
}
@Override
public void configureChannels() throws OwException {
isConfigured = true;
}
@Override
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
if (isConfigured) {
logger.trace("refresh of sensor {} started", sensorId);
List<State> states = bridgeHandler.readDecimalTypeArray(sensorId, counterParameter);
if (states.size() != 2) {
throw new OwException("Expected exactly two values, got " + String.valueOf(states.size()));
} else {
callback.postUpdate(CHANNEL_COUNTER + "0", states.get(0));
callback.postUpdate(CHANNEL_COUNTER + "1", states.get(1));
}
}
}
}

View File

@@ -0,0 +1,222 @@
/**
* 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.onewire.internal.device;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import static org.openhab.core.library.unit.MetricPrefix.MILLI;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.Util;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DS2438} class defines an DS2438 device
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2438 extends AbstractOwDevice {
private final Logger logger = LoggerFactory.getLogger(DS2438.class);
public enum LightSensorType {
ELABNET_V1,
ELABNET_V2,
IBUTTONLINK
}
public enum CurrentSensorType {
INTERNAL,
IBUTTONLINK
}
private LightSensorType lightSensorType = LightSensorType.ELABNET_V1;
private CurrentSensorType currentSensorType = CurrentSensorType.INTERNAL;
private final OwserverDeviceParameter temperatureParameter = new OwserverDeviceParameter("/temperature");
private OwserverDeviceParameter humidityParameter = new OwserverDeviceParameter("/humidity");
private final OwserverDeviceParameter voltageParameter = new OwserverDeviceParameter("/VAD");
private final OwserverDeviceParameter currentParamater = new OwserverDeviceParameter("/vis");
private final OwserverDeviceParameter supplyVoltageParameter = new OwserverDeviceParameter("/VDD");
public DS2438(SensorId sensorId, OwBaseThingHandler callback) {
super(sensorId, callback);
}
@Override
public void configureChannels() {
Thing thing = callback.getThing();
Channel humidityChannel = thing.getChannel(CHANNEL_HUMIDITY);
if (humidityChannel != null) {
Configuration channelConfiguration = humidityChannel.getConfiguration();
if (channelConfiguration.get(CONFIG_HUMIDITY) != null) {
humidityParameter = new OwserverDeviceParameter((String) channelConfiguration.get(CONFIG_HUMIDITY));
} else {
humidityParameter = new OwserverDeviceParameter("/humidity");
}
}
isConfigured = true;
}
@Override
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
if (isConfigured) {
logger.trace("refresh of sensor {} started", sensorId);
double Vcc = 5.0;
if (enabledChannels.contains(CHANNEL_TEMPERATURE) || enabledChannels.contains(CHANNEL_HUMIDITY)
|| enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)
|| enabledChannels.contains(CHANNEL_DEWPOINT)) {
QuantityType<Temperature> temperature = new QuantityType<>(
(DecimalType) bridgeHandler.readDecimalType(sensorId, temperatureParameter), SIUnits.CELSIUS);
logger.trace("read temperature {} from {}", temperature, sensorId);
if (enabledChannels.contains(CHANNEL_TEMPERATURE)) {
callback.postUpdate(CHANNEL_TEMPERATURE, temperature);
}
if (enabledChannels.contains(CHANNEL_HUMIDITY) || enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)
|| enabledChannels.contains(CHANNEL_DEWPOINT)) {
QuantityType<Dimensionless> humidity = new QuantityType<>(
(DecimalType) bridgeHandler.readDecimalType(sensorId, humidityParameter),
SmartHomeUnits.PERCENT);
logger.trace("read humidity {} from {}", humidity, sensorId);
if (enabledChannels.contains(CHANNEL_HUMIDITY)) {
callback.postUpdate(CHANNEL_HUMIDITY, humidity);
}
if (enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)) {
callback.postUpdate(CHANNEL_ABSOLUTE_HUMIDITY,
Util.calculateAbsoluteHumidity(temperature, humidity));
}
if (enabledChannels.contains(CHANNEL_DEWPOINT)) {
callback.postUpdate(CHANNEL_DEWPOINT, Util.calculateDewpoint(temperature, humidity));
}
}
}
if (enabledChannels.contains(CHANNEL_VOLTAGE)) {
double measured = ((DecimalType) bridgeHandler.readDecimalType(sensorId, voltageParameter))
.doubleValue();
if (measured < 0 || measured > 10.0) {
// workaround bug in DS2438
measured = 0.0;
}
State voltage = new QuantityType<>(measured, SmartHomeUnits.VOLT);
logger.trace("read voltage {} from {}", voltage, sensorId);
callback.postUpdate(CHANNEL_VOLTAGE, voltage);
}
if (enabledChannels.contains(CHANNEL_CURRENT)) {
if (currentSensorType == CurrentSensorType.IBUTTONLINK) {
State current = bridgeHandler.readDecimalType(sensorId, voltageParameter);
if (current instanceof DecimalType) {
double currentDouble = ((DecimalType) current).doubleValue();
if (currentDouble >= 0.1 || currentDouble <= 3.78) {
current = new QuantityType<>(currentDouble * 5.163 + 0.483, SmartHomeUnits.AMPERE);
}
callback.postUpdate(CHANNEL_CURRENT, current);
} else {
callback.postUpdate(CHANNEL_CURRENT, UnDefType.UNDEF);
}
} else {
State current = new QuantityType<>(
(DecimalType) bridgeHandler.readDecimalType(sensorId, currentParamater),
MILLI(SmartHomeUnits.AMPERE));
callback.postUpdate(CHANNEL_CURRENT, current);
}
}
if (enabledChannels.contains(CHANNEL_SUPPLYVOLTAGE)) {
Vcc = ((DecimalType) bridgeHandler.readDecimalType(sensorId, supplyVoltageParameter)).doubleValue();
State supplyVoltage = new QuantityType<>(Vcc, SmartHomeUnits.VOLT);
callback.postUpdate(CHANNEL_SUPPLYVOLTAGE, supplyVoltage);
}
if (enabledChannels.contains(CHANNEL_LIGHT)) {
switch (lightSensorType) {
case ELABNET_V2:
State light = bridgeHandler.readDecimalType(sensorId, currentParamater);
if (light instanceof DecimalType) {
light = new QuantityType<>(
Math.round(Math.pow(10, ((DecimalType) light).doubleValue() / 47 * 1000)),
SmartHomeUnits.LUX);
callback.postUpdate(CHANNEL_LIGHT, light);
}
break;
case ELABNET_V1:
light = bridgeHandler.readDecimalType(sensorId, currentParamater);
if (light instanceof DecimalType) {
light = new QuantityType<>(Math.round(Math
.exp(1.059 * Math.log(1000000 * ((DecimalType) light).doubleValue() / (4096 * 390))
+ 4.518)
* 20000), SmartHomeUnits.LUX);
callback.postUpdate(CHANNEL_LIGHT, light);
}
break;
case IBUTTONLINK:
double measured = ((DecimalType) bridgeHandler.readDecimalType(sensorId, voltageParameter))
.doubleValue();
if (measured <= 0 || measured > 10.0) {
// workaround bug in DS2438
light = new QuantityType<>(0, SmartHomeUnits.LUX);
} else {
light = new QuantityType<>(Math.pow(10, (65 / 7.5) - (47 / 7.5) * (Vcc / measured)),
SmartHomeUnits.LUX);
}
callback.postUpdate(CHANNEL_LIGHT, light);
}
}
}
}
/**
* set the type of the attached light sensor
*
* @param lightSensorType
*/
public void setLightSensorType(LightSensorType lightSensorType) {
this.lightSensorType = lightSensorType;
}
/**
* set the type of the attached current sensor
*
* @param currentSensorType
*/
public void setCurrentSensorType(CurrentSensorType currentSensorType) {
this.currentSensorType = currentSensorType;
}
}

View File

@@ -0,0 +1,114 @@
/**
* 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.onewire.internal.device;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.Illuminance;
import javax.measure.quantity.Pressure;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.Util;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.MetricPrefix;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link EDS006x} class defines an EDS006x device
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class EDS006x extends AbstractOwDevice {
private final Logger logger = LoggerFactory.getLogger(EDS006x.class);
private OwserverDeviceParameter temperatureParameter = new OwserverDeviceParameter("/temperature");
private OwserverDeviceParameter humidityParameter = new OwserverDeviceParameter("/humidity");
private OwserverDeviceParameter pressureParameter = new OwserverDeviceParameter("/pressure");
private OwserverDeviceParameter lightParameter = new OwserverDeviceParameter("/light");
public EDS006x(SensorId sensorId, OwSensorType sensorType, OwBaseThingHandler callback) {
super(sensorId, callback);
String sensorTypeName = sensorType.name();
temperatureParameter = new OwserverDeviceParameter("/" + sensorTypeName + "/temperature");
humidityParameter = new OwserverDeviceParameter("/" + sensorTypeName + "/humidity");
pressureParameter = new OwserverDeviceParameter("/" + sensorTypeName + "/pressure");
lightParameter = new OwserverDeviceParameter("/" + sensorTypeName + "/light");
}
@Override
public void configureChannels() {
isConfigured = true;
}
@Override
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
if (isConfigured) {
logger.trace("refresh of sensor {} started", sensorId);
if (enabledChannels.contains(CHANNEL_TEMPERATURE) || enabledChannels.contains(CHANNEL_HUMIDITY)
|| enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)
|| enabledChannels.contains(CHANNEL_DEWPOINT)) {
QuantityType<Temperature> temperature = new QuantityType<>(
(DecimalType) bridgeHandler.readDecimalType(sensorId, temperatureParameter), SIUnits.CELSIUS);
if (enabledChannels.contains(CHANNEL_TEMPERATURE)) {
callback.postUpdate(CHANNEL_TEMPERATURE, temperature);
}
if (enabledChannels.contains(CHANNEL_HUMIDITY) || enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)
|| enabledChannels.contains(CHANNEL_DEWPOINT)) {
QuantityType<Dimensionless> humidity = new QuantityType<>(
(DecimalType) bridgeHandler.readDecimalType(sensorId, humidityParameter),
SmartHomeUnits.PERCENT);
if (enabledChannels.contains(CHANNEL_HUMIDITY)) {
callback.postUpdate(CHANNEL_HUMIDITY, humidity);
}
if (enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)) {
callback.postUpdate(CHANNEL_ABSOLUTE_HUMIDITY,
Util.calculateAbsoluteHumidity(temperature, humidity));
}
if (enabledChannels.contains(CHANNEL_DEWPOINT)) {
callback.postUpdate(CHANNEL_DEWPOINT, Util.calculateDewpoint(temperature, humidity));
}
}
}
if (enabledChannels.contains(CHANNEL_LIGHT)) {
QuantityType<Illuminance> light = new QuantityType<>(
(DecimalType) bridgeHandler.readDecimalType(sensorId, lightParameter), SmartHomeUnits.LUX);
callback.postUpdate(CHANNEL_LIGHT, light);
}
if (enabledChannels.contains(CHANNEL_PRESSURE)) {
QuantityType<Pressure> pressure = new QuantityType<>(
(DecimalType) bridgeHandler.readDecimalType(sensorId, pressureParameter),
MetricPrefix.HECTO(SIUnits.PASCAL));
callback.postUpdate(CHANNEL_PRESSURE, pressure);
}
}
}
}

View File

@@ -0,0 +1,66 @@
/**
* 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.onewire.internal.device;
import static org.openhab.binding.onewire.internal.OwBindingConstants.BINDING_ID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.type.ChannelTypeUID;
/**
* The {@link OwChannelConfig} class defines a map entry
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwChannelConfig {
private static final Pattern CONFIG_PATTERN = Pattern.compile("^(.+):(.+):(.*)$");
public String channelId;
public ChannelTypeUID channelTypeUID;
public @Nullable String label;
public OwChannelConfig(String channelId, ChannelTypeUID channelTypeUID, @Nullable String label) {
this.channelId = channelId;
this.channelTypeUID = channelTypeUID;
this.label = label;
}
public OwChannelConfig(String channelId, ChannelTypeUID channelTypeUID) {
this(channelId, channelTypeUID, null);
}
public static OwChannelConfig fromString(String configString) {
Matcher matcher = CONFIG_PATTERN.matcher(configString);
if (matcher.matches()) {
if (matcher.group(3).trim().isEmpty()) {
return new OwChannelConfig(matcher.group(1).trim(),
new ChannelTypeUID(BINDING_ID, matcher.group(2).trim()));
} else {
return new OwChannelConfig(matcher.group(1).trim(),
new ChannelTypeUID(BINDING_ID, matcher.group(2).trim()), matcher.group(3).trim());
}
} else {
throw new IllegalArgumentException();
}
}
@Override
public String toString() {
return channelId + "/" + channelTypeUID.getAsString() + "/" + label;
}
}

View File

@@ -0,0 +1,55 @@
/**
* 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.onewire.internal.device;
/**
* The {@link OwSensorType} defines all known sensor types
*
* @author Jan N. Klug - Initial contribution
*/
public enum OwSensorType {
DS1420,
DS18S20,
DS18B20,
DS1822,
DS1923,
DS2401,
DS2405,
DS2406,
DS2408,
DS2409,
DS2413,
DS2423,
DS2431,
DS2438,
MS_TC,
MS_TH,
MS_TL,
MS_TH_S,
MS_TV,
AMS,
AMS_S,
BAE,
BAE0910,
BAE0911,
BMS,
BMS_S,
EDS,
EDS0064,
EDS0065,
EDS0066,
EDS0067,
EDS0068,
UNKNOWN
}

View File

@@ -0,0 +1,167 @@
/**
* 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.onewire.internal.discovery;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.DS2438Configuration;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.OwPageBuffer;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.core.thing.ThingTypeUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link OwDiscoveryItem} class defines a discovery item for OneWire devices
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwDiscoveryItem {
private final Logger logger = LoggerFactory.getLogger(OwDiscoveryItem.class);
private final SensorId sensorId;
private OwSensorType sensorType = OwSensorType.UNKNOWN;
private String vendor = "Dallas/Maxim";
private OwPageBuffer pages = new OwPageBuffer();
private ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, "");
private final Map<SensorId, OwSensorType> associatedSensors = new HashMap<>();
public OwDiscoveryItem(OwserverBridgeHandler bridgeHandler, SensorId sensorId) throws OwException {
this.sensorId = sensorId;
sensorType = bridgeHandler.getType(sensorId);
switch (sensorType) {
case DS2438:
pages = bridgeHandler.readPages(sensorId);
DS2438Configuration config = new DS2438Configuration(bridgeHandler, sensorId);
associatedSensors.putAll(config.getAssociatedSensors());
logger.trace("found associated sensors: {}", associatedSensors);
vendor = config.getVendor();
sensorType = config.getSensorSubType();
break;
case EDS:
vendor = "Embedded Data Systems";
pages = bridgeHandler.readPages(sensorId);
try { // determine subsensorType
sensorType = OwSensorType.valueOf(new String(pages.getPage(0), 0, 7, StandardCharsets.US_ASCII));
} catch (IllegalArgumentException e) {
sensorType = OwSensorType.UNKNOWN;
}
break;
default:
}
}
/**
* get sensor type
*
* @return sensor type
*/
public OwSensorType getSensorType() {
return sensorType;
}
/**
* get this sensor id
*
* @return sensor id
*/
public SensorId getSensorId() {
return sensorId;
}
/**
* normalized sensor id (for naming the discovery result)
*
* @return sensor id in format familyId_xxxxxxxxxx
*/
public String getNormalizedSensorId() {
return sensorId.getId().replace(".", "_");
}
/**
* get vendor name (if available)
*
* @return vendor name
*/
public String getVendor() {
return vendor;
}
/**
* get this sensors ThingTypeUID
*
* @return ThingTypeUID if mapping successful
*/
public ThingTypeUID getThingTypeUID() throws OwException {
if (THING_TYPE_MAP.containsKey(sensorType)) {
thingTypeUID = THING_TYPE_MAP.get(sensorType);
return thingTypeUID;
} else {
throw new OwException(sensorType + " cannot be mapped to thing type");
}
}
/**
* get a list of all sensors associated to this sensor
*
* @return list of strings
*/
public List<SensorId> getAssociatedSensorIds() {
return new ArrayList<>(associatedSensors.keySet());
}
/**
* determine this sensors type
*/
public void checkSensorType() {
logger.debug("checkSensorType: {} with {}", this, associatedSensors);
switch (sensorType) {
case MS_TH:
case MS_TH_S:
sensorType = DS2438Configuration.getMultisensorType(sensorType,
new ArrayList<>(associatedSensors.values()));
break;
default:
}
}
/**
* get Label "<thingtype> (<id>)"
*
* @return the thing label
*/
public String getLabel() {
return THING_LABEL_MAP.get(sensorType) + " (" + this.sensorId.getId() + ")";
}
@Override
public String toString() {
return String.format("%s/%s (associated: %d)", sensorId, sensorType, associatedSensors.size());
}
}

View File

@@ -0,0 +1,137 @@
/**
* 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.onewire.internal.discovery;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
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.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link OwDiscoveryService} implements the discovery service for the OneWire binding.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(OwDiscoveryService.class);
private final OwserverBridgeHandler owBridgeHandler;
private final ThingUID bridgeUID;
Map<SensorId, OwDiscoveryItem> owDiscoveryItems = new HashMap<>();
Set<SensorId> associatedSensors = new HashSet<>();
public OwDiscoveryService(OwserverBridgeHandler owBridgeHandler) {
super(SUPPORTED_THING_TYPES, 60, false);
this.owBridgeHandler = owBridgeHandler;
this.bridgeUID = owBridgeHandler.getThing().getUID();
logger.debug("registering discovery service for {}", owBridgeHandler);
}
private void scanDirectory(String baseDirectory) {
List<SensorId> directoryList;
logger.trace("scanning {} on bridge {}", baseDirectory, bridgeUID);
try {
directoryList = owBridgeHandler.getDirectory(baseDirectory);
} catch (OwException e) {
logger.info("empty directory '{}' for {}", baseDirectory, bridgeUID);
return;
}
// find all valid sensors
for (SensorId directoryEntry : directoryList) {
try {
OwDiscoveryItem owDiscoveryItem = new OwDiscoveryItem(owBridgeHandler, directoryEntry);
if (owDiscoveryItem.getSensorType() == OwSensorType.DS2409) {
// scan hub sub-directories
logger.trace("found hub {}, scanning sub-directories", directoryEntry);
scanDirectory(owDiscoveryItem.getSensorId().getFullPath() + "/main/");
scanDirectory(owDiscoveryItem.getSensorId().getFullPath() + "/aux/");
} else {
// add found sensor to list
logger.trace("found sensor {} (type: {})", directoryEntry, owDiscoveryItem.getSensorType());
owDiscoveryItems.put(owDiscoveryItem.getSensorId(), owDiscoveryItem);
associatedSensors.addAll(owDiscoveryItem.getAssociatedSensorIds());
}
} catch (OwException e) {
logger.debug("error while scanning for sensors in directory {} on bridge {}: {}", baseDirectory,
bridgeUID, e.getMessage());
}
}
}
@Override
public void startScan() {
scanDirectory("/");
// remove duplicates
owDiscoveryItems.entrySet().removeIf(s -> associatedSensors.contains(s.getKey()));
// make discovery results
for (OwDiscoveryItem owDiscoveryItem : owDiscoveryItems.values()) {
owDiscoveryItem.checkSensorType();
try {
ThingTypeUID thingTypeUID = owDiscoveryItem.getThingTypeUID();
String normalizedId = owDiscoveryItem.getNormalizedSensorId();
ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, normalizedId);
logger.debug("created thing UID {} for sensor {}, type {}", thingUID, owDiscoveryItem.getSensorId(),
owDiscoveryItem.getSensorType());
Map<String, Object> properties = new HashMap<>();
properties.put(PROPERTY_MODELID, owDiscoveryItem.getSensorType().toString());
properties.put(PROPERTY_VENDOR, owDiscoveryItem.getVendor());
properties.put(CONFIG_ID, owDiscoveryItem.getSensorId().getFullPath());
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID)
.withProperties(properties).withBridge(bridgeUID).withLabel(owDiscoveryItem.getLabel()).build();
thingDiscovered(discoveryResult);
} catch (OwException e) {
logger.info("sensor-id {}: {}", owDiscoveryItem.getSensorId(), e.getMessage());
}
}
}
@Override
protected synchronized void stopScan() {
removeOlderResults(getTimestampOfLastScan());
super.stopScan();
}
@Override
public void deactivate() {
removeOlderResults(new Date().getTime());
}
}

View File

@@ -0,0 +1,265 @@
/**
* 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.onewire.internal.handler;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.DS2438Configuration;
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.config.AMSHandlerConfiguration;
import org.openhab.binding.onewire.internal.device.AbstractOwDevice;
import org.openhab.binding.onewire.internal.device.DS18x20;
import org.openhab.binding.onewire.internal.device.DS2406_DS2413;
import org.openhab.binding.onewire.internal.device.DS2438;
import org.openhab.binding.onewire.internal.device.DS2438.LightSensorType;
import org.openhab.binding.onewire.internal.device.OwChannelConfig;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link AdvancedMultisensorThingHandler} is responsible for handling DS2438 based multisensors (modules)
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class AdvancedMultisensorThingHandler extends OwBaseThingHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(
Arrays.asList(THING_TYPE_AMS, THING_TYPE_BMS));
public static final Set<OwSensorType> SUPPORTED_SENSOR_TYPES = Collections
.unmodifiableSet(Stream.of(OwSensorType.AMS, OwSensorType.AMS_S, OwSensorType.BMS, OwSensorType.BMS_S)
.collect(Collectors.toSet()));
private static final String PROPERTY_DS18B20 = "ds18b20";
private static final String PROPERTY_DS2413 = "ds2413";
private static final String PROPERTY_DS2438 = "ds2438";
private static final Set<String> REQUIRED_PROPERTIES_AMS = Collections.unmodifiableSet(
Stream.of(PROPERTY_HW_REVISION, PROPERTY_PROD_DATE, PROPERTY_DS18B20, PROPERTY_DS2438, PROPERTY_DS2413)
.collect(Collectors.toSet()));
private static final Set<String> REQUIRED_PROPERTIES_BMS = Collections.unmodifiableSet(
Stream.of(PROPERTY_HW_REVISION, PROPERTY_PROD_DATE, PROPERTY_DS18B20).collect(Collectors.toSet()));
private final Logger logger = LoggerFactory.getLogger(AdvancedMultisensorThingHandler.class);
private final ThingTypeUID thingType = this.thing.getThingTypeUID();
private int hwRevision = 0;
private int digitalRefreshInterval = 10 * 1000;
private long digitalLastRefresh = 0;
public AdvancedMultisensorThingHandler(Thing thing,
OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
super(thing, dynamicStateDescriptionProvider, SUPPORTED_SENSOR_TYPES,
getRequiredProperties(thing.getThingTypeUID()));
}
@Override
public void initialize() {
AMSHandlerConfiguration configuration = getConfig().as(AMSHandlerConfiguration.class);
Map<String, String> properties = editProperties();
if (!super.configureThingHandler()) {
return;
}
hwRevision = Integer.valueOf(properties.get(PROPERTY_HW_REVISION));
sensors.add(new DS2438(sensorId, this));
sensors.add(new DS18x20(new SensorId(properties.get(PROPERTY_DS18B20)), this));
if (THING_TYPE_AMS.equals(thingType)) {
sensors.add(new DS2438(new SensorId(properties.get(PROPERTY_DS2438)), this));
sensors.add(new DS2406_DS2413(new SensorId(properties.get(PROPERTY_DS2413)), this));
digitalRefreshInterval = configuration.digitalRefresh * 1000;
digitalLastRefresh = 0;
}
scheduler.execute(() -> {
configureThingChannels();
});
}
@Override
public void refresh(OwserverBridgeHandler bridgeHandler, long now) {
try {
if ((now >= (digitalLastRefresh + digitalRefreshInterval)) && (thingType.equals(THING_TYPE_AMS))) {
logger.trace("refreshing digital {}", this.thing.getUID());
Boolean forcedRefresh = digitalLastRefresh == 0;
digitalLastRefresh = now;
if (!sensors.get(3).checkPresence(bridgeHandler)) {
return;
}
sensors.get(3).refresh(bridgeHandler, forcedRefresh);
}
if (now >= (lastRefresh + refreshInterval)) {
if (!sensors.get(0).checkPresence(bridgeHandler)) {
return;
}
logger.trace("refreshing analog {}", this.thing.getUID());
Boolean forcedRefresh = lastRefresh == 0;
lastRefresh = now;
if (thingType.equals(THING_TYPE_AMS)) {
for (int i = 0; i < sensors.size() - 1; i++) {
sensors.get(i).refresh(bridgeHandler, forcedRefresh);
}
} else {
for (int i = 0; i < sensors.size(); i++) {
sensors.get(i).refresh(bridgeHandler, forcedRefresh);
}
}
}
} catch (OwException e) {
logger.debug("{}: refresh exception '{}'", this.thing.getUID(), e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "refresh exception");
}
}
@Override
protected void configureThingChannels() {
Configuration configuration = getConfig();
ThingBuilder thingBuilder = editThing();
// delete unwanted channels
Set<String> existingChannelIds = thing.getChannels().stream().map(channel -> channel.getUID().getId())
.collect(Collectors.toSet());
Set<String> wantedChannelIds = SENSOR_TYPE_CHANNEL_MAP.get(sensorType).stream()
.map(channelConfig -> channelConfig.channelId).collect(Collectors.toSet());
wantedChannelIds.add(CHANNEL_TEMPERATURE);
wantedChannelIds.add(CHANNEL_HUMIDITY);
existingChannelIds.stream().filter(channelId -> !wantedChannelIds.contains(channelId))
.forEach(channelId -> removeChannelIfExisting(thingBuilder, channelId));
// add or update wanted channels
SENSOR_TYPE_CHANNEL_MAP.get(sensorType).stream().forEach(channelConfig -> {
addChannelIfMissingAndEnable(thingBuilder, channelConfig);
});
// temperature channel
if (configuration.containsKey(CONFIG_TEMPERATURESENSOR)
&& configuration.get(CONFIG_TEMPERATURESENSOR).equals("DS18B20")) {
addChannelIfMissingAndEnable(thingBuilder,
new OwChannelConfig(CHANNEL_TEMPERATURE, CHANNEL_TYPE_UID_TEMPERATURE_POR_RES), 1);
} else {
addChannelIfMissingAndEnable(thingBuilder,
new OwChannelConfig(CHANNEL_TEMPERATURE, CHANNEL_TYPE_UID_TEMPERATURE));
}
// humidity channel
addChannelIfMissingAndEnable(thingBuilder, new OwChannelConfig(CHANNEL_HUMIDITY, CHANNEL_TYPE_UID_HUMIDITY),
new Configuration(new HashMap<String, Object>() {
private static final long serialVersionUID = 1L;
{
put(CONFIG_HUMIDITY, "/HIH4000/humidity");
}
}));
// configure light channel
if (sensorType == OwSensorType.AMS_S || sensorType == OwSensorType.BMS_S) {
if (hwRevision <= 13) {
((DS2438) sensors.get(0)).setLightSensorType(LightSensorType.ELABNET_V1);
} else {
((DS2438) sensors.get(0)).setLightSensorType(LightSensorType.ELABNET_V2);
}
}
updateThing(thingBuilder.build());
try {
for (AbstractOwDevice sensor : sensors) {
sensor.configureChannels();
}
} catch (OwException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
return;
}
validConfig = true;
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE);
}
@Override
public void updateSensorProperties(OwserverBridgeHandler bridgeHandler) throws OwException {
Map<String, String> properties = editProperties();
DS2438Configuration ds2438configuration = new DS2438Configuration(bridgeHandler, sensorId);
sensorType = DS2438Configuration.getMultisensorType(ds2438configuration.getSensorSubType(),
ds2438configuration.getAssociatedSensorTypes());
properties.put(PROPERTY_MODELID, sensorType.toString());
properties.put(PROPERTY_VENDOR, ds2438configuration.getVendor());
properties.put(PROPERTY_PROD_DATE, ds2438configuration.getProductionDate());
properties.put(PROPERTY_HW_REVISION, ds2438configuration.getHardwareRevision());
switch (sensorType) {
case BMS:
case BMS_S:
properties.put(PROPERTY_DS18B20,
ds2438configuration.getAssociatedSensorIds(OwSensorType.DS18B20).get(0).getFullPath());
break;
case AMS:
case AMS_S:
properties.put(PROPERTY_DS18B20,
ds2438configuration.getAssociatedSensorIds(OwSensorType.DS18B20).get(0).getFullPath());
properties.put(PROPERTY_DS2413,
ds2438configuration.getAssociatedSensorIds(OwSensorType.DS2413).get(0).getFullPath());
properties.put(PROPERTY_DS2438,
ds2438configuration.getAssociatedSensorIds(OwSensorType.MS_TV).get(0).getFullPath());
break;
default:
throw new OwException("sensorType " + sensorType.toString() + " not supported by this thing handler");
}
updateProperties(properties);
}
/**
* used to determine the correct set of required properties
*
* @param thingType
* @return
*/
private static Set<String> getRequiredProperties(ThingTypeUID thingType) {
if (THING_TYPE_AMS.equals(thingType)) {
return REQUIRED_PROPERTIES_AMS;
} else {
return REQUIRED_PROPERTIES_BMS;
}
}
}

View File

@@ -0,0 +1,247 @@
/**
* 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.onewire.internal.handler;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.config.BAE091xHandlerConfiguration;
import org.openhab.binding.onewire.internal.device.BAE0910;
import org.openhab.binding.onewire.internal.device.OwChannelConfig;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.core.library.types.OnOffType;
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.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link BAE091xSensorThingHandler} is responsible for handling BAE0910 based multisensors
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class BAE091xSensorThingHandler extends OwBaseThingHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_BAE091X);
private final Logger logger = LoggerFactory.getLogger(BAE091xSensorThingHandler.class);
public static final Set<OwSensorType> SUPPORTED_SENSOR_TYPES = Collections.singleton(OwSensorType.BAE0910);
public BAE091xSensorThingHandler(Thing thing, OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
super(thing, dynamicStateDescriptionProvider, SUPPORTED_SENSOR_TYPES);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof OnOffType) {
if (channelUID.getId().startsWith(CHANNEL_DIGITAL)) {
Bridge bridge = getBridge();
if (bridge != null) {
OwserverBridgeHandler bridgeHandler = (OwserverBridgeHandler) bridge.getHandler();
if (bridgeHandler != null) {
if (!((BAE0910) sensors.get(0)).writeChannel(bridgeHandler, channelUID.getId(), command)) {
logger.debug("writing to channel {} in thing {} not permitted (input channel)", channelUID,
this.thing.getUID());
}
} else {
logger.warn("bridge handler not found");
}
} else {
logger.warn("bridge not found");
}
}
}
// TODO: PWM channels
super.handleCommand(channelUID, command);
}
@Override
public void initialize() {
if (!super.configureThingHandler()) {
return;
}
sensors.add(new BAE0910(sensorId, this));
scheduler.execute(() -> {
configureThingChannels();
});
}
@Override
protected void configureThingChannels() {
ThingUID thingUID = getThing().getUID();
logger.debug("configuring sensors for {}", thingUID);
BAE091xHandlerConfiguration configuration = getConfig().as(BAE091xHandlerConfiguration.class);
Set<OwChannelConfig> wantedChannel = new HashSet<>();
wantedChannel.addAll(SENSOR_TYPE_CHANNEL_MAP.get(sensorType));
// Pin1:
switch (configuration.pin1) {
case CONFIG_BAE_PIN_DISABLED:
break;
case CONFIG_BAE_PIN_COUNTER:
wantedChannel.add(new OwChannelConfig(CHANNEL_COUNTER, CHANNEL_TYPE_UID_BAE_COUNTER));
break;
default:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"unknown configuration option for pin 1");
return;
}
// Pin2:
switch (configuration.pin2) {
case CONFIG_BAE_PIN_DISABLED:
break;
case CONFIG_BAE_PIN_OUT:
wantedChannel.add(
new OwChannelConfig(CHANNEL_DIGITAL2, CHANNEL_TYPE_UID_BAE_DIGITAL_OUT, "Digital Out Pin 2"));
break;
case CONFIG_BAE_PIN_PWM:
wantedChannel
.add(new OwChannelConfig(CHANNEL_PWM_DUTY3, CHANNEL_TYPE_UID_BAE_PWM_DUTY, "Duty Cycle PWM 3"));
wantedChannel.add(new OwChannelConfig(CHANNEL_PWM_FREQ1, CHANNEL_TYPE_UID_BAE_PWM_FREQUENCY,
"Frequency PWM 1/3"));
break;
default:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"unknown configuration option for pin 2");
return;
}
// Pin6:
switch (configuration.pin6) {
case CONFIG_BAE_PIN_DISABLED:
break;
case CONFIG_BAE_PIN_PIO:
wantedChannel.add(new OwChannelConfig(CHANNEL_DIGITAL6, CHANNEL_TYPE_UID_BAE_PIO, "PIO Pin 6"));
break;
case CONFIG_BAE_PIN_PWM:
wantedChannel
.add(new OwChannelConfig(CHANNEL_PWM_DUTY4, CHANNEL_TYPE_UID_BAE_PWM_DUTY, "Duty Cycle PWM 4"));
wantedChannel.add(new OwChannelConfig(CHANNEL_PWM_FREQ2, CHANNEL_TYPE_UID_BAE_PWM_FREQUENCY,
"Frequency PWM 2/4"));
break;
default:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"unknown configuration option for pin 6");
return;
}
// Pin7:
switch (configuration.pin7) {
case CONFIG_BAE_PIN_DISABLED:
break;
case CONFIG_BAE_PIN_ANALOG:
wantedChannel.add(new OwChannelConfig(CHANNEL_VOLTAGE, CHANNEL_TYPE_UID_BAE_ANALOG, "Analog Input"));
break;
case CONFIG_BAE_PIN_OUT:
wantedChannel.add(
new OwChannelConfig(CHANNEL_DIGITAL7, CHANNEL_TYPE_UID_BAE_DIGITAL_OUT, "Digital Out Pin 7"));
break;
case CONFIG_BAE_PIN_PWM:
wantedChannel
.add(new OwChannelConfig(CHANNEL_PWM_DUTY2, CHANNEL_TYPE_UID_BAE_PWM_DUTY, "Duty Cycle PWM 2"));
wantedChannel.add(new OwChannelConfig(CHANNEL_PWM_FREQ2, CHANNEL_TYPE_UID_BAE_PWM_FREQUENCY,
"Frequency PWM 2/4"));
break;
default:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"unknown configuration option for pin 7");
return;
}
// Pin8:
switch (configuration.pin8) {
case CONFIG_BAE_PIN_DISABLED:
break;
case CONFIG_BAE_PIN_IN:
wantedChannel.add(new OwChannelConfig(CHANNEL_DIGITAL8, CHANNEL_TYPE_UID_BAE_DIN, "Digital In Pin 8"));
break;
case CONFIG_BAE_PIN_OUT:
wantedChannel
.add(new OwChannelConfig(CHANNEL_DIGITAL8, CHANNEL_TYPE_UID_BAE_DOUT, "Digital Out Pin 8"));
break;
case CONFIG_BAE_PIN_PWM:
wantedChannel
.add(new OwChannelConfig(CHANNEL_PWM_DUTY1, CHANNEL_TYPE_UID_BAE_PWM_DUTY, "Duty Cycle PWM 1"));
wantedChannel.add(new OwChannelConfig(CHANNEL_PWM_FREQ1, CHANNEL_TYPE_UID_BAE_PWM_FREQUENCY,
"Frequency PWM 1/3"));
break;
default:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"unknown configuration option for pin 8");
return;
}
ThingBuilder thingBuilder = editThing();
// remove unwanted channels
Set<String> existingChannelIds = thing.getChannels().stream().map(channel -> channel.getUID().getId())
.collect(Collectors.toSet());
Set<String> wantedChannelIds = wantedChannel.stream().map(channelConfig -> channelConfig.channelId)
.collect(Collectors.toSet());
existingChannelIds.stream().filter(channelId -> !wantedChannelIds.contains(channelId))
.forEach(channelId -> removeChannelIfExisting(thingBuilder, channelId));
// add or update wanted channels
wantedChannel.stream().forEach(channelConfig -> {
addChannelIfMissingAndEnable(thingBuilder, channelConfig);
});
updateThing(thingBuilder.build());
try {
sensors.get(0).configureChannels();
} catch (OwException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
return;
}
validConfig = true;
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE);
}
@Override
public void updateSensorProperties(OwserverBridgeHandler bridgeHandler) throws OwException {
Map<String, String> properties = editProperties();
sensorType = BAE0910.getDeviceSubType(bridgeHandler, sensorId);
properties.put(PROPERTY_MODELID, sensorType.toString());
properties.put(PROPERTY_VENDOR, "Brain4home");
updateProperties(properties);
logger.trace("updated modelid/vendor to {} / {}", sensorType.name(), "Brain4home");
}
}

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.onewire.internal.handler;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.DS2438Configuration;
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.config.MstxHandlerConfiguration;
import org.openhab.binding.onewire.internal.device.DS1923;
import org.openhab.binding.onewire.internal.device.DS2438;
import org.openhab.binding.onewire.internal.device.DS2438.CurrentSensorType;
import org.openhab.binding.onewire.internal.device.DS2438.LightSensorType;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link BasicMultisensorThingHandler} is responsible for handling DS2438/DS1923 based multisensors (single
* sensors)
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class BasicMultisensorThingHandler extends OwBaseThingHandler {
public Logger logger = LoggerFactory.getLogger(BasicMultisensorThingHandler.class);
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_MS_TX);
public static final Set<OwSensorType> SUPPORTED_SENSOR_TYPES = Collections
.unmodifiableSet(Stream.of(OwSensorType.MS_TH, OwSensorType.MS_TC, OwSensorType.MS_TL, OwSensorType.MS_TV,
OwSensorType.DS1923, OwSensorType.DS2438).collect(Collectors.toSet()));
public BasicMultisensorThingHandler(Thing thing,
OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
super(thing, dynamicStateDescriptionProvider, SUPPORTED_SENSOR_TYPES);
}
@Override
public void initialize() {
if (!super.configureThingHandler()) {
return;
}
MstxHandlerConfiguration configuration = getConfig().as(MstxHandlerConfiguration.class);
if (configuration.manualsensor != null && sensorType != configuration.manualsensor) {
logger.debug("sensorType override for thing {}: old={}, new={}", thing.getUID(), sensorType,
configuration.manualsensor);
sensorType = configuration.manualsensor;
}
// add sensors
if (sensorType == OwSensorType.DS1923) {
sensors.add(new DS1923(sensorId, this));
} else {
sensors.add(new DS2438(sensorId, this));
}
scheduler.execute(() -> {
configureThingChannels();
});
}
@Override
protected void configureThingChannels() {
switch (sensorType) {
case DS2438:
((DS2438) sensors.get(0)).setCurrentSensorType(CurrentSensorType.INTERNAL);
break;
case MS_TC:
((DS2438) sensors.get(0)).setCurrentSensorType(CurrentSensorType.IBUTTONLINK);
break;
case MS_TL:
((DS2438) sensors.get(0)).setLightSensorType(LightSensorType.IBUTTONLINK);
break;
default:
}
super.configureThingChannels();
}
@Override
public void updateSensorProperties(OwserverBridgeHandler bridgeHandler) throws OwException {
Map<String, String> properties = editProperties();
sensorType = bridgeHandler.getType(sensorId);
if (sensorType == OwSensorType.DS1923) {
properties.put(PROPERTY_MODELID, sensorType.toString());
properties.put(PROPERTY_VENDOR, "Dallas/Maxim");
} else {
DS2438Configuration ds2438configuration = new DS2438Configuration(bridgeHandler, sensorId);
sensorType = ds2438configuration.getSensorSubType();
properties.put(PROPERTY_MODELID, sensorType.toString());
String vendor = ds2438configuration.getVendor();
properties.put(PROPERTY_VENDOR, vendor);
}
updateProperties(properties);
}
}

View File

@@ -0,0 +1,118 @@
/**
* 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.onewire.internal.handler;
import static org.openhab.binding.onewire.internal.OwBindingConstants.CHANNEL_DIGITAL;
import static org.openhab.binding.onewire.internal.OwBindingConstants.THING_TYPE_BASIC;
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.binding.onewire.internal.OwDynamicStateDescriptionProvider;
import org.openhab.binding.onewire.internal.device.*;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link BasicThingHandler} is responsible for handling simple sensors
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class BasicThingHandler extends OwBaseThingHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_BASIC);
public static final Set<OwSensorType> SUPPORTED_SENSOR_TYPES = Collections
.unmodifiableSet(Stream.of(OwSensorType.DS1420, OwSensorType.DS18B20, OwSensorType.DS18S20,
OwSensorType.DS1822, OwSensorType.DS2401, OwSensorType.DS2405, OwSensorType.DS2406,
OwSensorType.DS2408, OwSensorType.DS2413, OwSensorType.DS2423).collect(Collectors.toSet()));
private final Logger logger = LoggerFactory.getLogger(BasicThingHandler.class);
public BasicThingHandler(Thing thing, OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
super(thing, dynamicStateDescriptionProvider, SUPPORTED_SENSOR_TYPES);
}
@Override
public void initialize() {
if (!super.configureThingHandler()) {
return;
}
// add sensor
switch (sensorType) {
case DS18B20:
case DS18S20:
case DS1822:
sensors.add(new DS18x20(sensorId, this));
break;
case DS1420:
case DS2401:
sensors.add(new DS2401(sensorId, this));
break;
case DS2405:
sensors.add(new DS2405(sensorId, this));
break;
case DS2406:
case DS2413:
sensors.add(new DS2406_DS2413(sensorId, this));
break;
case DS2408:
sensors.add(new DS2408(sensorId, this));
break;
case DS2423:
sensors.add(new DS2423(sensorId, this));
break;
default:
throw new IllegalArgumentException(
"unsupported sensorType " + sensorType.name() + ", this should have been checked before!");
}
scheduler.execute(() -> {
configureThingChannels();
});
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof OnOffType) {
if (channelUID.getId().startsWith(CHANNEL_DIGITAL) && thing.getChannel(channelUID.getId()) != null) {
Integer ioChannel = Integer.valueOf(channelUID.getId().substring(channelUID.getId().length() - 1));
Bridge bridge = getBridge();
if (bridge != null) {
OwserverBridgeHandler bridgeHandler = (OwserverBridgeHandler) bridge.getHandler();
if (bridgeHandler != null) {
if (!((AbstractDigitalOwDevice) sensors.get(0)).writeChannel(bridgeHandler, ioChannel,
command)) {
logger.debug("writing to channel {} in thing {} not permitted (input channel)", channelUID,
this.thing.getUID());
}
} else {
logger.warn("bridge handler not found");
}
} else {
logger.warn("bridge not found");
}
}
}
super.handleCommand(channelUID, command);
}
}

View File

@@ -0,0 +1,90 @@
/**
* 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.onewire.internal.handler;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.OwPageBuffer;
import org.openhab.binding.onewire.internal.device.EDS006x;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link EDSSensorThingHandler} is responsible for handling EDS multisensors
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class EDSSensorThingHandler extends OwBaseThingHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_EDS_ENV);
public static final Set<OwSensorType> SUPPORTED_SENSOR_TYPES = Collections
.unmodifiableSet(Stream.of(OwSensorType.EDS0064, OwSensorType.EDS0065, OwSensorType.EDS0066,
OwSensorType.EDS0067, OwSensorType.EDS0068).collect(Collectors.toSet()));
private static final Set<String> REQUIRED_PROPERTIES = Collections.singleton(PROPERTY_HW_REVISION);
public EDSSensorThingHandler(Thing thing, OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
super(thing, dynamicStateDescriptionProvider, SUPPORTED_SENSOR_TYPES, REQUIRED_PROPERTIES);
}
@Override
public void initialize() {
if (!super.configureThingHandler()) {
return;
}
// add sensors
sensors.add(new EDS006x(sensorId, sensorType, this));
scheduler.execute(() -> {
configureThingChannels();
});
}
@Override
public void updateSensorProperties(OwserverBridgeHandler bridgeHandler) throws OwException {
Map<String, String> properties = editProperties();
OwPageBuffer pages = bridgeHandler.readPages(sensorId);
OwSensorType sensorType = OwSensorType.UNKNOWN;
try {
sensorType = OwSensorType.valueOf(new String(pages.getPage(0), 0, 7, StandardCharsets.US_ASCII));
} catch (IllegalArgumentException e) {
}
if (!SUPPORTED_SENSOR_TYPES.contains(sensorType)) {
throw new OwException("sensorType not supported for EDSSensorThing");
}
int fwRevisionLow = pages.getByte(3, 3);
int fwRevisionHigh = pages.getByte(3, 4);
String fwRevision = String.format("%d.%d", fwRevisionHigh, fwRevisionLow);
properties.put(PROPERTY_MODELID, sensorType.name());
properties.put(PROPERTY_VENDOR, "Embedded Data Systems");
properties.put(PROPERTY_HW_REVISION, String.valueOf(fwRevision));
updateProperties(properties);
}
}

View File

@@ -0,0 +1,445 @@
/**
* 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.onewire.internal.handler;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.config.BaseHandlerConfiguration;
import org.openhab.binding.onewire.internal.device.AbstractOwDevice;
import org.openhab.binding.onewire.internal.device.OwChannelConfig;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
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.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link OwBaseThingHandler} class defines a handler for simple OneWire devices
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public abstract class OwBaseThingHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(OwBaseThingHandler.class);
protected static final int PROPERTY_UPDATE_INTERVAL = 5000; // in ms
protected static final int PROPERTY_UPDATE_MAX_RETRY = 5;
private static final Set<String> REQUIRED_PROPERTIES = Collections
.unmodifiableSet(Stream.of(PROPERTY_MODELID, PROPERTY_VENDOR).collect(Collectors.toSet()));
protected List<String> requiredProperties = new ArrayList<>(REQUIRED_PROPERTIES);
protected Set<OwSensorType> supportedSensorTypes;
protected final List<AbstractOwDevice> sensors = new ArrayList<>();
protected @NonNullByDefault({}) SensorId sensorId;
protected @NonNullByDefault({}) OwSensorType sensorType;
protected long lastRefresh = 0;
protected long refreshInterval = 300 * 1000;
protected boolean validConfig = false;
protected boolean showPresence = false;
protected OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider;
protected @Nullable ScheduledFuture<?> updateTask;
public OwBaseThingHandler(Thing thing, OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider,
Set<OwSensorType> supportedSensorTypes) {
super(thing);
this.dynamicStateDescriptionProvider = dynamicStateDescriptionProvider;
this.supportedSensorTypes = supportedSensorTypes;
}
public OwBaseThingHandler(Thing thing, OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider,
Set<OwSensorType> supportedSensorTypes, Set<String> requiredProperties) {
super(thing);
this.dynamicStateDescriptionProvider = dynamicStateDescriptionProvider;
this.supportedSensorTypes = supportedSensorTypes;
this.requiredProperties.addAll(requiredProperties);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
lastRefresh = 0;
logger.trace("scheduled {} for refresh", this.thing.getUID());
}
}
@Override
public void initialize() {
configureThingHandler();
}
protected boolean configureThingHandler() {
BaseHandlerConfiguration configuration = getConfig().as(BaseHandlerConfiguration.class);
Map<String, String> properties = thing.getProperties();
if (getBridge() == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "bridge missing");
return false;
}
sensors.clear();
final String id = configuration.id;
if (id != null) {
try {
this.sensorId = new SensorId(id);
} catch (IllegalArgumentException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "sensor id format mismatch");
return false;
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "sensor id missing");
return false;
}
refreshInterval = configuration.refresh * 1000;
// check if all required properties are present. update if not
for (String property : requiredProperties) {
if (!properties.containsKey(property)) {
updateSensorProperties();
return false;
}
}
sensorType = OwSensorType.valueOf(properties.get(PROPERTY_MODELID));
if (!supportedSensorTypes.contains(sensorType)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"sensor type not supported by this thing type");
return false;
}
lastRefresh = 0;
return true;
}
protected void configureThingChannels() {
ThingBuilder thingBuilder = editThing();
logger.debug("configuring sensors for {}", thing.getUID());
// remove unwanted channels
Set<String> existingChannelIds = thing.getChannels().stream().map(channel -> channel.getUID().getId())
.collect(Collectors.toSet());
Set<String> wantedChannelIds = SENSOR_TYPE_CHANNEL_MAP.get(sensorType).stream()
.map(channelConfig -> channelConfig.channelId).collect(Collectors.toSet());
existingChannelIds.stream().filter(channelId -> !wantedChannelIds.contains(channelId))
.forEach(channelId -> removeChannelIfExisting(thingBuilder, channelId));
// add or update wanted channels
SENSOR_TYPE_CHANNEL_MAP.get(sensorType).stream().forEach(channelConfig -> {
addChannelIfMissingAndEnable(thingBuilder, channelConfig);
});
updateThing(thingBuilder.build());
try {
sensors.get(0).configureChannels();
} catch (OwException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
return;
}
if (thing.getChannel(CHANNEL_PRESENT) != null) {
showPresence = true;
}
validConfig = true;
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE);
}
/**
* check if thing can be refreshed from the bridge handler
*
* @return true if thing can be refreshed
*/
public boolean isRefreshable() {
return super.isInitialized()
&& this.thing.getStatusInfo().getStatusDetail() != ThingStatusDetail.CONFIGURATION_ERROR
&& this.thing.getStatusInfo().getStatusDetail() != ThingStatusDetail.BRIDGE_OFFLINE;
}
/**
* refresh this thing
*
* needs proper exception handling for refresh errors if overridden
*
* @param bridgeHandler bridge handler to use for communication with ow bus
* @param now current time
*/
public void refresh(OwserverBridgeHandler bridgeHandler, long now) {
try {
Boolean forcedRefresh = lastRefresh == 0;
if (now >= (lastRefresh + refreshInterval)) {
logger.trace("refreshing {}", this.thing.getUID());
lastRefresh = now;
if (!sensors.get(0).checkPresence(bridgeHandler)) {
logger.trace("sensor not present");
return;
}
for (int i = 0; i < sensors.size(); i++) {
logger.trace("refreshing sensor {} ({})", i, sensors.get(i).getSensorId());
sensors.get(i).refresh(bridgeHandler, forcedRefresh);
}
}
} catch (OwException e) {
logger.debug("{}: refresh exception {}", this.thing.getUID(), e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "refresh exception");
}
}
/**
* update presence status to present state of slave
*
* @param presentState current present state
*/
public void updatePresenceStatus(State presentState) {
if (OnOffType.ON.equals(presentState)) {
updateStatus(ThingStatus.ONLINE);
if (showPresence) {
updateState(CHANNEL_PRESENT, OnOffType.ON);
}
} else if (OnOffType.OFF.equals(presentState)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "slave missing");
if (showPresence) {
updateState(CHANNEL_PRESENT, OnOffType.OFF);
}
} else {
updateStatus(ThingStatus.UNKNOWN);
if (showPresence) {
updateState(CHANNEL_PRESENT, UnDefType.UNDEF);
}
}
}
/**
* post update to channel
*
* @param channelId channel id
* @param state new channel state
*/
public void postUpdate(String channelId, State state) {
if (this.thing.getChannel(channelId) != null) {
updateState(channelId, state);
} else {
logger.warn("{} missing channel {} when posting update {}", this.thing.getUID(), channelId, state);
}
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE
&& getThing().getStatusInfo().getStatusDetail() == ThingStatusDetail.BRIDGE_OFFLINE) {
if (validConfig) {
updatePresenceStatus(UnDefType.UNDEF);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
}
} else if (bridgeStatusInfo.getStatus() == ThingStatus.OFFLINE) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
}
@Override
public void dispose() {
dynamicStateDescriptionProvider.removeDescriptionsForThing(thing.getUID());
super.dispose();
}
/**
* add this sensor to the property update list of the bridge handler
*
*/
protected void updateSensorProperties() {
Bridge bridge = getBridge();
if (bridge == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "bridge not found");
return;
}
OwserverBridgeHandler bridgeHandler = (OwserverBridgeHandler) bridge.getHandler();
if (bridgeHandler == null) {
logger.debug("bridgehandler for {} not available for scheduling property update, retrying in 5s",
thing.getUID());
scheduler.schedule(() -> {
updateSensorProperties();
}, 5000, TimeUnit.MILLISECONDS);
return;
}
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "required properties missing");
bridgeHandler.scheduleForPropertiesUpdate(thing);
}
/**
* thing specific update method for sensor properties
*
* called by the bridge handler
*
* @param bridgeHandler the bridge handler to be used
* @return properties to be added to the properties map
* @throws OwException
*/
public void updateSensorProperties(OwserverBridgeHandler bridgeHandler) throws OwException {
Map<String, String> properties = editProperties();
OwSensorType sensorType = bridgeHandler.getType(sensorId);
properties.put(PROPERTY_MODELID, sensorType.toString());
properties.put(PROPERTY_VENDOR, "Dallas/Maxim");
updateProperties(properties);
logger.trace("updated modelid/vendor to {} / {}", sensorType.name(), "Dallas/Maxim");
}
/**
* get the dynamic state description provider for this thing
*
* @return
*/
public @Nullable OwDynamicStateDescriptionProvider getDynamicStateDescriptionProvider() {
return dynamicStateDescriptionProvider;
}
/**
* remove a channel during initialization if it exists
*
* @param thingBuilder ThingBuilder of the edited thing
* @param channelId id of the channel
*/
protected void removeChannelIfExisting(ThingBuilder thingBuilder, String channelId) {
if (thing.getChannel(channelId) != null) {
thingBuilder.withoutChannel(new ChannelUID(thing.getUID(), channelId));
}
}
/**
* adds (or replaces) a channel and enables it within the sensor (configuration preserved, default sensor)
*
* @param thingBuilder ThingBuilder of the edited thing
* @param channelConfig a OwChannelConfig for the new channel
* @return the newly created channel
*/
protected Channel addChannelIfMissingAndEnable(ThingBuilder thingBuilder, OwChannelConfig channelConfig) {
return addChannelIfMissingAndEnable(thingBuilder, channelConfig, null, 0);
}
/**
* adds (or replaces) a channel and enables it within the sensor (configuration overridden, default sensor)
*
* @param thingBuilder ThingBuilder of the edited thing
* @param channelConfig a OwChannelConfig for the new channel
* @param configuration the new Configuration for this channel
* @return the newly created channel
*/
protected Channel addChannelIfMissingAndEnable(ThingBuilder thingBuilder, OwChannelConfig channelConfig,
Configuration configuration) {
return addChannelIfMissingAndEnable(thingBuilder, channelConfig, configuration, 0);
}
/**
* adds (or replaces) a channel and enables it within the sensor (configuration preserved)
*
* @param thingBuilder ThingBuilder of the edited thing
* @param channelConfig a OwChannelConfig for the new channel
* @param sensorNo number of sensor that provides this channel
* @return the newly created channel
*/
protected Channel addChannelIfMissingAndEnable(ThingBuilder thingBuilder, OwChannelConfig channelConfig,
int sensorNo) {
return addChannelIfMissingAndEnable(thingBuilder, channelConfig, null, sensorNo);
}
/**
* adds (or replaces) a channel and enables it within the sensor (configuration overridden)
*
* @param thingBuilder ThingBuilder of the edited thing
* @param channelConfig a OwChannelConfig for the new channel
* @param configuration the new Configuration for this channel
* @param sensorNo number of sensor that provides this channel
* @return the newly created channel
*/
protected Channel addChannelIfMissingAndEnable(ThingBuilder thingBuilder, OwChannelConfig channelConfig,
@Nullable Configuration configuration, int sensorNo) {
Channel channel = thing.getChannel(channelConfig.channelId);
Configuration config = configuration;
String label = channelConfig.label;
// remove channel if wrong type uid and preserve config if not overridden
if (channel != null && !channelConfig.channelTypeUID.equals(channel.getChannelTypeUID())) {
removeChannelIfExisting(thingBuilder, channelConfig.channelId);
if (config == null) {
config = channel.getConfiguration();
}
channel = null;
}
// create channel if missing
if (channel == null) {
ChannelBuilder channelBuilder = ChannelBuilder
.create(new ChannelUID(thing.getUID(), channelConfig.channelId),
ACCEPTED_ITEM_TYPES_MAP.get(channelConfig.channelId))
.withType(channelConfig.channelTypeUID);
if (label != null) {
channelBuilder.withLabel(label);
}
if (config != null) {
channelBuilder.withConfiguration(config);
}
channel = channelBuilder.build();
thingBuilder.withChannel(channel);
}
// enable channel in sensor
sensors.get(sensorNo).enableChannel(channelConfig.channelId);
return channel;
}
}

View File

@@ -0,0 +1,430 @@
/**
* 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.onewire.internal.handler;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
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.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.OwPageBuffer;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.binding.onewire.internal.owserver.OwfsDirectChannelConfig;
import org.openhab.binding.onewire.internal.owserver.OwserverConnection;
import org.openhab.binding.onewire.internal.owserver.OwserverConnectionState;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
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.ThingTypeUID;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link OwserverBridgeHandler} class implements the refresher and the interface for reading from the bridge
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwserverBridgeHandler extends BaseBridgeHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_OWSERVER);
private final Logger logger = LoggerFactory.getLogger(OwserverBridgeHandler.class);
protected boolean refreshable = false;
protected ScheduledFuture<?> refreshTask = scheduler.scheduleWithFixedDelay(this::refresh, 1, 1000,
TimeUnit.MILLISECONDS);
// thing update
private final Queue<@Nullable Thing> thingPropertiesUpdateQueue = new ConcurrentLinkedQueue<>();
private static final int RECONNECT_AFTER_FAIL_TIME = 5000; // in ms
private final OwserverConnection owserverConnection;
private final List<OwfsDirectChannelConfig> channelConfigs = new ArrayList<>();
public OwserverBridgeHandler(Bridge bridge) {
super(bridge);
this.owserverConnection = new OwserverConnection(this);
}
public OwserverBridgeHandler(Bridge bridge, OwserverConnection owserverConnection) {
super(bridge);
this.owserverConnection = owserverConnection;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
}
@Override
public void initialize() {
Configuration configuration = getConfig();
if (configuration.get(CONFIG_ADDRESS) != null) {
owserverConnection.setHost((String) configuration.get(CONFIG_ADDRESS));
}
if (configuration.get(CONFIG_PORT) != null) {
owserverConnection.setPort(((BigDecimal) configuration.get(CONFIG_PORT)).intValue());
}
for (Channel channel : thing.getChannels()) {
if (CHANNEL_TYPE_UID_OWFS_NUMBER.equals(channel.getChannelTypeUID())
|| CHANNEL_TYPE_UID_OWFS_STRING.equals(channel.getChannelTypeUID())) {
final OwfsDirectChannelConfig channelConfig = channel.getConfiguration()
.as(OwfsDirectChannelConfig.class);
if (channelConfig.initialize(channel.getUID(), channel.getAcceptedItemType())) {
channelConfigs.add(channelConfig);
} else {
logger.info("configuration mismatch: {}", channelConfig);
}
}
}
// makes it possible for unit tests to differentiate direct update and
// postponed update through the owserverConnection:
updateStatus(ThingStatus.UNKNOWN);
scheduler.execute(() -> {
synchronized (owserverConnection) {
owserverConnection.start();
}
});
if (refreshTask.isCancelled()) {
refreshTask = scheduler.scheduleWithFixedDelay(this::refresh, 1, 1000, TimeUnit.MILLISECONDS);
}
}
/**
* refresh all sensors on this bridge
*/
private void refresh() {
try {
long now = System.currentTimeMillis();
if (!refreshable) {
logger.trace("refresh requested by thread ID {} denied, as not refresheable",
Thread.currentThread().getId());
return;
}
// refresh thing channels
List<Thing> thingList = getThing().getThings();
int thingCount = thingList.size();
Iterator<Thing> childListIterator = thingList.iterator();
logger.trace("refreshTask with thread ID {} starts at {}, {} childs", Thread.currentThread().getId(), now,
thingCount);
while (childListIterator.hasNext() && refreshable) {
Thing owThing = childListIterator.next();
logger.trace("refresh: getting handler for {} ({} to go)", owThing.getUID(), thingCount);
OwBaseThingHandler owHandler = (OwBaseThingHandler) owThing.getHandler();
if (owHandler != null) {
if (owHandler.isRefreshable()) {
logger.trace("{} initialized, refreshing", owThing.getUID());
owHandler.refresh(OwserverBridgeHandler.this, now);
} else {
logger.trace("{} not initialized, skipping refresh", owThing.getUID());
}
} else {
logger.debug("{} handler missing", owThing.getUID());
}
thingCount--;
}
if (!refreshable) {
logger.trace("refresh aborted, as brige became non-refresheable.");
return;
}
refreshBridgeChannels(now);
// update thing properties (only one per refresh cycle)
if (!refreshable) {
logger.trace("refresh aborted, as brige became non-refresheable.");
return;
}
Thing updateThing = thingPropertiesUpdateQueue.poll();
if (updateThing != null) {
logger.trace("update: getting handler for {} ({} total in list)", updateThing.getUID(),
thingPropertiesUpdateQueue.size());
OwBaseThingHandler owHandler = (OwBaseThingHandler) updateThing.getHandler();
if (owHandler != null) {
try {
owHandler.updateSensorProperties(this);
owHandler.initialize();
logger.debug("{} sucessfully updated properties, removing from property update list",
updateThing.getUID());
} catch (OwException e) {
thingPropertiesUpdateQueue.add(updateThing);
logger.debug("updating thing properties for {} failed: {}, adding to end of list",
updateThing.getUID(), e.getMessage());
}
} else {
logger.debug("{} is missing handler, removing from property update list", updateThing.getUID());
}
}
} catch (RuntimeException e) {
// catching RuntimeException because scheduled tasks finish once an exception occurs
logger.error("refresh encountered exception of {}: {}, please report bug", e.getClass(), e.getMessage());
}
}
@Override
public void dispose() {
refreshable = false;
if (!refreshTask.isCancelled()) {
refreshTask.cancel(false);
}
owserverConnection.stop();
}
/**
* schedules a thing for updating the thing properties
*
* @param thing the thing to be updated
*/
public void scheduleForPropertiesUpdate(Thing thing) {
thingPropertiesUpdateQueue.add(thing);
}
/**
* get all sensors attached to this bridge
*
* @return a list of all sensor-IDs
*/
public List<SensorId> getDirectory(String basePath) throws OwException {
synchronized (owserverConnection) {
return owserverConnection.getDirectory(basePath);
}
}
/**
* check the presence of a sensor on the bus
*
* @param sensorId the sensor's full ID
* @return ON if present, OFF if missing
* @throws OwException
*/
public State checkPresence(SensorId sensorId) throws OwException {
synchronized (owserverConnection) {
return owserverConnection.checkPresence(sensorId.getFullPath());
}
}
/**
* get a sensors type string
*
* @param sensorId the sensor's full ID
* @return a String containing the sensor type
* @throws OwException
*/
public OwSensorType getType(SensorId sensorId) throws OwException {
OwSensorType sensorType = OwSensorType.UNKNOWN;
synchronized (owserverConnection) {
try {
sensorType = OwSensorType.valueOf(owserverConnection.readString(sensorId + "/type"));
} catch (IllegalArgumentException e) {
}
}
return sensorType;
}
/**
* get full sensor information stored in pages (not available on all sensors)
*
* @param sensorId the sensor's full ID
* @return a OwPageBuffer object containing the requested information
* @throws OwException
*/
public OwPageBuffer readPages(SensorId sensorId) throws OwException {
synchronized (owserverConnection) {
return owserverConnection.readPages(sensorId.getFullPath());
}
}
/**
* read a single decimal value from a sensor
*
* @param sensorId the sensor's full ID
* @param parameter device parameters needed for this request
* @return a DecimalType
* @throws OwException
*/
public State readDecimalType(SensorId sensorId, OwserverDeviceParameter parameter) throws OwException {
synchronized (owserverConnection) {
return owserverConnection.readDecimalType(parameter.getPath(sensorId));
}
}
/**
* read a BitSet value from a sensor
*
* @param sensorId the sensor's full ID
* @param parameter device parameters needed for this request
* @return a BitSet
* @throws OwException
*/
public BitSet readBitSet(SensorId sensorId, OwserverDeviceParameter parameter) throws OwException {
return BitSet.valueOf(new long[] { ((DecimalType) readDecimalType(sensorId, parameter)).longValue() });
}
/**
* read an array of decimal values from a sensor
*
* @param sensorId the sensor's full ID
* @param parameter device parameters needed for this request
* @return a list of DecimalType values
* @throws OwException
*/
public List<State> readDecimalTypeArray(SensorId sensorId, OwserverDeviceParameter parameter) throws OwException {
synchronized (owserverConnection) {
return owserverConnection.readDecimalTypeArray(parameter.getPath(sensorId));
}
}
/**
* read a string from a sensor
*
* @param sensorId the sensor's full ID
* @param parameter device parameters needed for this request
* @return a String
* @throws OwException
*/
public String readString(SensorId sensorId, OwserverDeviceParameter parameter) throws OwException {
synchronized (owserverConnection) {
return owserverConnection.readString(parameter.getPath(sensorId));
}
}
/**
* writes a DecimalType to the sensor
*
* @param sensorId the sensor's full ID
* @param parameter device parameters needed for this request
* @throws OwException
*/
public void writeDecimalType(SensorId sensorId, OwserverDeviceParameter parameter, DecimalType value)
throws OwException {
synchronized (owserverConnection) {
owserverConnection.writeDecimalType(parameter.getPath(sensorId), value);
}
}
/**
* writes a BitSet to the sensor
*
* @param sensorId the sensor's full ID
* @param parameter device parameters needed for this request
* @throws OwException
*/
public void writeBitSet(SensorId sensorId, OwserverDeviceParameter parameter, BitSet value) throws OwException {
writeDecimalType(sensorId, parameter, new DecimalType(value.toLongArray()[0]));
}
/**
* returns if this bridge is refreshable
*
* @return true if implementation reports communication ready
*/
public boolean isRefreshable() {
return refreshable;
}
/**
* updates the thing status with the current connection state
*
* @param connectionState current connection state
*/
public void reportConnectionState(OwserverConnectionState connectionState) {
logger.debug("Updating owserverconnectionstate to {}", connectionState);
switch (connectionState) {
case FAILED:
refreshable = false;
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
scheduler.schedule(() -> {
synchronized (owserverConnection) {
owserverConnection.start();
}
}, RECONNECT_AFTER_FAIL_TIME, TimeUnit.MILLISECONDS);
break;
case STOPPED:
refreshable = false;
break;
case OPENED:
case CLOSED:
refreshable = true;
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
break;
}
}
/**
* refreshes channels attached to the bridge
*
* @param now current time
*/
public void refreshBridgeChannels(long now) {
for (OwfsDirectChannelConfig channelConfig : channelConfigs) {
if (now > channelConfig.lastRefresh + channelConfig.refreshCycle) {
State value;
try {
synchronized (owserverConnection) {
if (channelConfig.acceptedItemType.equals("String")) {
value = new StringType(owserverConnection.readString(channelConfig.path));
} else if (channelConfig.acceptedItemType.equals("Number")) {
value = owserverConnection.readDecimalType(channelConfig.path);
} else {
logger.debug("mismatched configuration, itemType unknown for channel {}",
channelConfig.channelUID);
continue;
}
}
final ChannelUID channelUID = channelConfig.channelUID;
if (channelUID == null) {
throw new OwException("channelUID is null");
}
updateState(channelUID, value);
logger.trace("updated {} to {}", channelConfig.channelUID, value);
channelConfig.lastRefresh = now;
} catch (OwException e) {
logger.debug("could not read direct channel {}: {}", channelConfig.channelUID, e.getMessage());
}
}
}
}
}

View File

@@ -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.onewire.internal.owserver;
import java.math.BigDecimal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.ChannelUID;
/**
* The {@link OwfsDirectChannelConfig} defines config for owfsdirect channels
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwfsDirectChannelConfig {
public String path = "";
public BigDecimal refresh = new BigDecimal(300);
public long lastRefresh = 0;
public int refreshCycle = 300;
public @Nullable ChannelUID channelUID;
public String acceptedItemType = "";
public boolean initialize(ChannelUID channelUID, @Nullable String acceptedItemType) {
this.channelUID = channelUID;
this.acceptedItemType = acceptedItemType != null ? acceptedItemType : "";
refreshCycle = refresh.intValue() * 1000;
return !path.isEmpty();
}
}

View File

@@ -0,0 +1,518 @@
/**
* 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.onewire.internal.owserver;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.OwPageBuffer;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link OwserverConnection} defines the protocol for connections to owservers.
*
* Data is requested by using one of the read / write methods. In case of errors, an {@link OwException}
* is thrown. All other exceptions are caught and handled.
*
* The data request methods follow a general pattern:
* * build the appropriate {@link OwserverPacket} for the request
* * call {@link #request(OwserverPacket)} to ask for the data, which then
* * uses {@link #write(OwserverPacket)} to get the request to the server and
* * uses {@link #read(boolean)} to get the result
*
* Hereby, the resulting packet is examined on an appropriate return code (!= -1) and whether the
* expected payload is attached. If not, an {@link OwException} is thrown.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwserverConnection {
public static final int DEFAULT_PORT = 4304;
public static final int KEEPALIVE_INTERVAL = 1000;
private static final int CONNECTION_MAX_RETRY = 5;
private final Logger logger = LoggerFactory.getLogger(OwserverConnection.class);
private final OwserverBridgeHandler thingHandlerCallback;
private String owserverAddress = "";
private int owserverPort = DEFAULT_PORT;
private @Nullable Socket owserverSocket = null;
private @Nullable DataInputStream owserverInputStream = null;
private @Nullable DataOutputStream owserverOutputStream = null;
private OwserverConnectionState owserverConnectionState = OwserverConnectionState.STOPPED;
private boolean tryingConnectionRecovery = false;
// reset to 0 after successful request
private int connectionErrorCounter = 0;
public OwserverConnection(OwserverBridgeHandler owBaseBridgeHandler) {
this.thingHandlerCallback = owBaseBridgeHandler;
}
/**
* set the owserver host address
*
* @param address as String (IP or FQDN), defaults to localhost
*/
public void setHost(String address) {
this.owserverAddress = address;
if (owserverConnectionState != OwserverConnectionState.STOPPED) {
close();
}
}
/**
* set the owserver port
*
* @param port defaults to 4304
*/
public void setPort(int port) {
this.owserverPort = port;
if (owserverConnectionState != OwserverConnectionState.STOPPED) {
close();
}
}
/**
* start the owserver connection
*/
public void start() {
logger.debug("Trying to (re)start OW server connection - previous state: {}",
owserverConnectionState.toString());
connectionErrorCounter = 0;
tryingConnectionRecovery = true;
boolean success = false;
do {
success = open();
if (success && owserverConnectionState != OwserverConnectionState.FAILED) {
tryingConnectionRecovery = false;
}
} while (!success && (owserverConnectionState != OwserverConnectionState.FAILED || tryingConnectionRecovery));
}
/**
* stop the owserver connection and report new {@link OwserverConnectionState} to {@link #thingHandlerCallback}.
*/
public void stop() {
close();
owserverConnectionState = OwserverConnectionState.STOPPED;
thingHandlerCallback.reportConnectionState(owserverConnectionState);
}
/**
* list all devices on this owserver
*
* @return a list of device ids
*/
public @NonNullByDefault({}) List<SensorId> getDirectory(String basePath) throws OwException {
OwserverPacket requestPacket = new OwserverPacket(OwserverMessageType.DIRALL, basePath);
OwserverPacket returnPacket = request(requestPacket);
if ((returnPacket.getReturnCode() != -1) && returnPacket.hasPayload()) {
return Arrays.stream(returnPacket.getPayloadString().split(",")).map(this::stringToSensorId)
.filter(Objects::nonNull).collect(Collectors.toList());
} else {
throw new OwException("invalid of empty packet when requesting directory");
}
}
private @Nullable SensorId stringToSensorId(String s) {
try {
return new SensorId(s);
} catch (IllegalArgumentException e) {
return null;
}
}
/**
* check sensor presence
*
* Errors are caught and interpreted as sensor not present.
*
* @param path full owfs path to sensor
* @return OnOffType, ON=present, OFF=not present
*/
public State checkPresence(String path) {
State returnValue = OnOffType.OFF;
try {
OwserverPacket requestPacket;
requestPacket = new OwserverPacket(OwserverMessageType.PRESENT, path, OwserverControlFlag.UNCACHED);
OwserverPacket returnPacket = request(requestPacket);
if (returnPacket.getReturnCode() == 0) {
returnValue = OnOffType.ON;
}
} catch (OwException e) {
returnValue = OnOffType.OFF;
}
logger.trace("presence {} : {}", path, returnValue);
return returnValue;
}
/**
* read a decimal type
*
* @param path full owfs path to sensor
* @return DecimalType if successful
* @throws OwException
*/
public State readDecimalType(String path) throws OwException {
State returnState = UnDefType.UNDEF;
OwserverPacket requestPacket = new OwserverPacket(OwserverMessageType.READ, path);
OwserverPacket returnPacket = request(requestPacket);
if ((returnPacket.getReturnCode() != -1) && returnPacket.hasPayload()) {
try {
returnState = DecimalType.valueOf(returnPacket.getPayloadString().trim());
} catch (NumberFormatException e) {
throw new OwException("could not parse '" + returnPacket.getPayloadString().trim() + "' to a number");
}
} else {
throw new OwException("invalid or empty packet when requesting decimal type");
}
return returnState;
}
/**
* read a decimal type array
*
* @param path full owfs path to sensor
* @return a List of DecimalType values if successful
* @throws OwException
*/
public List<State> readDecimalTypeArray(String path) throws OwException {
List<State> returnList = new ArrayList<>();
OwserverPacket requestPacket = new OwserverPacket(OwserverMessageType.READ, path);
OwserverPacket returnPacket = request(requestPacket);
if ((returnPacket.getReturnCode() != -1) && returnPacket.hasPayload()) {
Arrays.stream(returnPacket.getPayloadString().split(","))
.forEach(v -> returnList.add(DecimalType.valueOf(v.trim())));
} else {
throw new OwException("invalid or empty packet when requesting decimal type array");
}
return returnList;
}
/**
* read a string
*
* @param path full owfs path to sensor
* @return requested String
* @throws OwException
*/
public String readString(String path) throws OwException {
OwserverPacket requestPacket = new OwserverPacket(OwserverMessageType.READ, path);
OwserverPacket returnPacket = request(requestPacket);
if ((returnPacket.getReturnCode() != -1) && returnPacket.hasPayload()) {
return returnPacket.getPayloadString().trim();
} else {
throw new OwException("invalid or empty packet when requesting string type");
}
}
/**
* read all sensor pages
*
* @param path full owfs path to sensor
* @return page buffer
* @throws OwException
*/
public OwPageBuffer readPages(String path) throws OwException {
OwserverPacket requestPacket = new OwserverPacket(OwserverMessageType.READ, path + "/pages/page.ALL");
OwserverPacket returnPacket = request(requestPacket);
if ((returnPacket.getReturnCode() != -1) && returnPacket.hasPayload()) {
return returnPacket.getPayload();
} else {
throw new OwException("invalid or empty packet when requesting pages");
}
}
/**
* write a DecimalType
*
* @param path full owfs path to the sensor
* @param value the value to write
* @throws OwException
*/
public void writeDecimalType(String path, DecimalType value) throws OwException {
OwserverPacket requestPacket = new OwserverPacket(OwserverMessageType.WRITE, path);
requestPacket.appendPayload(String.valueOf(value));
// request method throws an OwException in case of issues...
OwserverPacket returnPacket = request(requestPacket);
logger.trace("wrote: {}, got: {} ", requestPacket, returnPacket);
}
/**
* process a request to the owserver
*
* @param requestPacket the request to be send
* @return the raw owserver answer
* @throws OwException
*/
private OwserverPacket request(OwserverPacket requestPacket) throws OwException {
OwserverPacket returnPacket = new OwserverPacket(OwserverPacketType.RETURN);
// answer to value write is always empty
boolean payloadExpected = requestPacket.getMessageType() != OwserverMessageType.WRITE;
try {
// write request - error may be thrown
write(requestPacket);
// try to read data as long as we don't get any feedback and no error is thrown...
do {
if (requestPacket.getMessageType() == OwserverMessageType.PRESENT
|| requestPacket.getMessageType() == OwserverMessageType.NOP) {
returnPacket = read(true);
} else {
returnPacket = read(false);
}
} while (returnPacket.isPingPacket() || !(returnPacket.hasPayload() == payloadExpected));
} catch (OwException e) {
logger.debug("failed requesting {}->{} [{}]", requestPacket, returnPacket, e.getMessage());
throw e;
}
if (!returnPacket.hasControlFlag(OwserverControlFlag.PERSISTENCE)) {
logger.trace("closing connection because persistence was denied");
close();
}
// Success! Reset error counter.
connectionErrorCounter = 0;
return returnPacket;
}
/**
* open/reopen the connection to the owserver
*
* In case of issues, the connection is closed using {@link #closeOnError()} and false is returned.
* If the {@link #owserverConnectionState} is in STOPPED or FAILED, the method directly returns false.
*
* @return true if open
*/
private boolean open() {
try {
if (owserverConnectionState == OwserverConnectionState.CLOSED || tryingConnectionRecovery) {
// open socket & set timeout to 3000ms
final Socket owserverSocket = new Socket(owserverAddress, owserverPort);
owserverSocket.setSoTimeout(3000);
this.owserverSocket = owserverSocket;
owserverInputStream = new DataInputStream(owserverSocket.getInputStream());
owserverOutputStream = new DataOutputStream(owserverSocket.getOutputStream());
owserverConnectionState = OwserverConnectionState.OPENED;
thingHandlerCallback.reportConnectionState(owserverConnectionState);
logger.debug("OW connection state: opened to {}:{}", owserverAddress, owserverPort);
return true;
} else if (owserverConnectionState == OwserverConnectionState.OPENED) {
// socket already open, clear input buffer
logger.trace("owServerConnection already open, skipping input buffer");
final DataInputStream owserverInputStream = this.owserverInputStream;
while (owserverInputStream != null) {
if (owserverInputStream.skip(owserverInputStream.available()) == 0) {
return true;
}
}
logger.debug("input stream not available on skipping");
closeOnError();
return false;
} else {
return false;
}
} catch (IOException e) {
logger.debug("could not open owServerConnection to {}:{}: {}", owserverAddress, owserverPort,
e.getMessage());
closeOnError();
return false;
}
}
/**
* close connection and report connection state to callback
*/
private void close() {
this.close(true);
}
/**
* close the connection to the owserver instance.
*
* @param reportConnectionState true, if connection state shall be reported to callback
*/
private void close(boolean reportConnectionState) {
final Socket owserverSocket = this.owserverSocket;
if (owserverSocket != null) {
try {
owserverSocket.close();
owserverConnectionState = OwserverConnectionState.CLOSED;
logger.debug("closed connection");
} catch (IOException e) {
owserverConnectionState = OwserverConnectionState.FAILED;
logger.warn("could not close connection: {}", e.getMessage());
}
}
this.owserverSocket = null;
this.owserverInputStream = null;
this.owserverOutputStream = null;
if (reportConnectionState) {
thingHandlerCallback.reportConnectionState(owserverConnectionState);
}
}
/**
* check if the connection is dead and close it
*/
private void checkConnection() {
try {
int pid = ((DecimalType) readDecimalType("/system/process/pid")).intValue();
logger.debug("read pid {} -> connection still alive", pid);
return;
} catch (OwException e) {
closeOnError();
}
}
/**
* close the connection to the owserver instance after an error occured.
* if {@link #CONNECTION_MAX_RETRY} is exceeded, {@link #owserverConnectionState} is set to FAILED
* and state is reported to callback.
*/
private void closeOnError() {
connectionErrorCounter++;
close(false);
if (connectionErrorCounter > CONNECTION_MAX_RETRY) {
logger.debug("OW connection state: set to failed as max retries exceeded.");
owserverConnectionState = OwserverConnectionState.FAILED;
tryingConnectionRecovery = false;
thingHandlerCallback.reportConnectionState(owserverConnectionState);
} else if (!tryingConnectionRecovery) {
// as close did not report connections state and we are not trying to recover ...
thingHandlerCallback.reportConnectionState(owserverConnectionState);
}
}
/**
* write to the owserver
*
* In case of issues, the connection is closed using {@link #closeOnError()} and an
* {@link OwException} is thrown.
*
* @param requestPacket data to write
* @throws OwException
*/
private void write(OwserverPacket requestPacket) throws OwException {
try {
if (open()) {
requestPacket.setControlFlags(OwserverControlFlag.PERSISTENCE);
final DataOutputStream owserverOutputStream = this.owserverOutputStream;
if (owserverOutputStream != null) {
owserverOutputStream.write(requestPacket.toBytes());
logger.trace("wrote: {}", requestPacket);
} else {
logger.debug("output stream not available on write");
closeOnError();
throw new OwException("I/O Error: output stream not available on write");
}
} else {
// was not opened
throw new OwException("I/O error: could not open connection to send request packet");
}
} catch (IOException e) {
closeOnError();
logger.debug("couldn't send {}, {}", requestPacket, e.getMessage());
throw new OwException("I/O Error: exception while sending request packet - " + e.getMessage());
}
}
/**
* read from owserver
*
* In case of errors (which may also be due to an erroneous path), the connection is checked and potentially closed
* using {@link #checkConnection()}.
*
* @param noTimeoutException retry in case of read time outs instead of exiting with an {@link OwException}.
* @return the read packet
* @throws OwException
*/
private OwserverPacket read(boolean noTimeoutException) throws OwException {
OwserverPacket returnPacket = new OwserverPacket(OwserverPacketType.RETURN);
final DataInputStream owserverInputStream = this.owserverInputStream;
if (owserverInputStream != null) {
DataInputStream inputStream = owserverInputStream;
try {
returnPacket = new OwserverPacket(inputStream, OwserverPacketType.RETURN);
} catch (EOFException e) {
// Read suddenly ended ....
logger.warn("EOFException: exception while reading packet - {}", e.getMessage());
checkConnection();
throw new OwException("EOFException: exception while reading packet - " + e.getMessage());
} catch (OwException e) {
// Some other issue
checkConnection();
throw e;
} catch (IOException e) {
// Read time out
if (e.getMessage().equals("Read timed out") && noTimeoutException) {
logger.trace("timeout - setting error code to -1");
// will lead to re-try reading in request method!!!
returnPacket.setPayload("timeout");
returnPacket.setReturnCode(-1);
} else {
// Other I/O issue
checkConnection();
throw new OwException("I/O error: exception while reading packet - " + e.getMessage());
}
}
logger.trace("read: {}", returnPacket);
} else {
logger.debug("input stream not available on read");
closeOnError();
throw new OwException("I/O Error: input stream not available on read");
}
return returnPacket;
}
}

View File

@@ -0,0 +1,41 @@
/**
* 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.onewire.internal.owserver;
/**
* The {@link OwserverConnectionState} defines the state for connections to owservers
*
* @author Jan N. Klug - Initial contribution
*/
public enum OwserverConnectionState {
/**
* The {@link OwserverConnection} is being torn down (mostly due to dispose of handler).
* No refresh, etc. are possible.
*/
STOPPED,
/**
* The connection is open.
*/
OPENED,
/**
* The connection is closed. On next read / write it will be opened.
*/
CLOSED,
/**
* The connection is erroneous and was closed by the {@link OwserverConnection}. After due wait time, it
* is tried to reopen it by a scheduled task of
* {@link OwserverBridgeHandler#reportConnectionState(OwserverConnectionState)}.
*/
FAILED
}

View File

@@ -0,0 +1,57 @@
/**
* 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.onewire.internal.owserver;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link OwserverControlFlag} provides the owserver protocol control flag
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public enum OwserverControlFlag {
UNCACHED(0x00000020),
SAFEMODE(0x00000010),
ALIAS(0x00000008),
PERSISTENCE(0x00000004),
BUS_RET(0x00000002),
DEVICE_DISPLAY(0x00000000),
OWNET(0x00000100);
private final int controlFlag;
OwserverControlFlag(int controlFlag) {
this.controlFlag = controlFlag;
}
/**
* get the this flag's numeric representation
*
* @return integer value of this flag
*/
public int getValue() {
return controlFlag;
}
/**
* check if a this flag is set in the parameter
*
* @param controlFlags full control flag
* @return true if this flag is set in the parameter
*/
public boolean isSet(int controlFlags) {
return (this.getValue() & controlFlags) == this.getValue();
}
}

View File

@@ -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.onewire.internal.owserver;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.onewire.internal.SensorId;
/**
* The {@link OwserverDeviceParameter} device parameter definition for owserver bridge handler
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwserverDeviceParameter {
private String prefix = "";
private String path = "";
/**
* device parameter for owserver bridge handler
*
* @param prefix path prefix (e.g. "uncached/")
* @param path path without sensor id (e.g. "/humidity")
*/
public OwserverDeviceParameter(String prefix, String path) {
if (prefix.endsWith("/")) {
this.prefix = prefix.substring(0, prefix.length() - 1);
} else {
this.prefix = prefix;
}
if (path.startsWith("/")) {
this.path = path;
} else {
this.path = "/" + path;
}
}
/**
* device parameter for owserver bridge handler
*
* @param path path without sensor id (e.g. "/humidity")
*/
public OwserverDeviceParameter(String path) {
this("", path);
}
/**
* get the full owfs path for a given sensor id
*
* @param sensorId
*/
public String getPath(SensorId sensorId) {
return prefix + sensorId.getFullPath() + path;
}
@Override
public String toString() {
return prefix + "/sensorId" + path;
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
public boolean equals(@Nullable Object o) {
if (o == this) {
return true;
}
if (!(o instanceof OwserverDeviceParameter)) {
return false;
}
return ((OwserverDeviceParameter) o).toString().equals(toString());
}
}

View File

@@ -0,0 +1,66 @@
/**
* 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.onewire.internal.owserver;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link OwserverMessageType} provides the owserver protocol message type
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public enum OwserverMessageType {
ERROR(0x00000000),
NOP(0x00000001),
READ(0x00000002),
WRITE(0x00000003),
DIR(0x00000004),
SIZE(0x00000005),
PRESENT(0x00000006),
DIRALL(0x00000007),
GET(0x00000008),
DIRALLSLASH(0x00000009),
GETSLASH(0x0000000a);
private final int messageType;
OwserverMessageType(int messageType) {
this.messageType = messageType;
}
/**
* get the this message type's numeric representation
*
* @return integer value of this message type
*/
public int getValue() {
return messageType;
}
/**
* return a new OwMessageType from an integer
*
* @param messageType the message type as integer
* @return OwMessageType
*/
public static OwserverMessageType fromInt(int messageType) throws IllegalArgumentException {
for (OwserverMessageType value : values()) {
if (value.getValue() == messageType) {
return value;
}
}
throw new IllegalArgumentException();
}
}

View File

@@ -0,0 +1,347 @@
/**
* 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.onewire.internal.owserver;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.OwPageBuffer;
/**
* The {@link OwserverPacket} class provides a single packet for communication with the owserver
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwserverPacket {
public static final int PROTOCOL_VERSION = 0;
// 6x4 bytes
public static final int HEADER_SIZE = 24;
protected int payloadLength = 0;
protected final OwserverPacketType packetType;
protected int protocolVersion = PROTOCOL_VERSION;
protected int controlFlags;
protected int packetCode = 0;
protected int packetSize = 0;
protected int payloadOffset = 0;
protected byte payload[] = new byte[0];
/**
* constructor for new packet
*
* @param packetType packetType;
*/
public OwserverPacket(OwserverPacketType packetType) {
this.packetType = packetType;
setControlFlags(OwserverControlFlag.OWNET, OwserverControlFlag.DEVICE_DISPLAY);
}
/**
* constructor for reading packet from stream
*
* @param owInputStream input stream to read from
* @throws IOException
* @throws OwExeption
*/
public OwserverPacket(DataInputStream owInputStream, OwserverPacketType packetType)
throws IOException, OwException, EOFException {
this.packetType = packetType;
// header
protocolVersion = owInputStream.readInt();
payloadLength = owInputStream.readInt();
packetCode = owInputStream.readInt();
controlFlags = owInputStream.readInt();
packetSize = owInputStream.readInt();
payloadOffset = owInputStream.readInt();
// payload
if (payloadLength != -1) {
if ((protocolVersion != PROTOCOL_VERSION) || !OwserverControlFlag.OWNET.isSet(controlFlags)) {
throw new OwException("invalid data read");
}
if (payloadLength > 0) {
payload = new byte[payloadLength];
owInputStream.readFully(payload, 0, payloadLength);
}
}
}
/**
* constructor for a new request message
*
* @param owMessageType
* @param path
* @param owControlFlags
*/
public OwserverPacket(OwserverMessageType owMessageType, String path, OwserverControlFlag... owControlFlags) {
this(OwserverPacketType.REQUEST);
packetCode = owMessageType.getValue();
setPayload(path);
setTemperatureScale(OwserverTemperatureScale.CENTIGRADE);
setControlFlags(owControlFlags);
if (owMessageType == OwserverMessageType.WRITE) {
packetSize = 0x00000000;
} else {
packetSize = 0x00010000;
}
}
/**
* set one or more control flags for this packet
*
* @param flags one or more flags as OwControlFlag
*/
public void setControlFlags(OwserverControlFlag... flags) {
for (int i = 0; i < flags.length; i++) {
controlFlags |= flags[i].getValue();
}
}
/**
* check if a certain flag is set in this packet
*
* @param flag flag to be tested
* @return true if flag is set
*/
public boolean hasControlFlag(OwserverControlFlag flag) {
return flag.isSet(controlFlags);
}
/**
* set this packet's pressure scale
*
* @param pressureScale
*/
public void setPressureScale(OwserverPressureScale pressureScale) {
controlFlags = pressureScale.setFlag(controlFlags);
}
/**
* get this packets pressure scale
*
* @return
*/
public OwserverPressureScale getPressureScale() {
return OwserverPressureScale.getFlag(controlFlags);
}
/**
* set this packet's temperature scale
*
* @param pressureScale
*/
public void setTemperatureScale(OwserverTemperatureScale temperatureScale) {
controlFlags = temperatureScale.setFlag(controlFlags);
}
/**
* get this packets temperature scale
*
* @return
*/
public OwserverTemperatureScale getTemperatureScale() {
return OwserverTemperatureScale.getFlag(controlFlags);
}
/**
* set (or replace) this packet's payload from a string
*
* @param payload string representation of the payload
*/
public void setPayload(String payload) {
byte[] bytes = payload.getBytes();
payloadLength = bytes.length + 1;
this.payload = new byte[payloadLength];
System.arraycopy(bytes, 0, this.payload, 0, bytes.length);
}
/**
* append to this packet's payload from a string
*
* @param payload string representation of the payload to append
*/
public void appendPayload(String payload) {
byte appendBytes[] = payload.getBytes();
byte[] fullPayload = new byte[this.payload.length + appendBytes.length];
System.arraycopy(this.payload, 0, fullPayload, 0, this.payload.length);
System.arraycopy(appendBytes, 0, fullPayload, this.payload.length, appendBytes.length);
this.packetSize += appendBytes.length;
this.payloadLength = fullPayload.length;
this.payload = fullPayload;
}
/**
* set this packet payload from a OwPageBuffer
*
* @param payload string representation of the payload
*/
public void setPayload(OwPageBuffer payload) {
byte[] bytes = payload.getBytes();
payloadLength = bytes.length + 1;
this.payload = new byte[payloadLength];
System.arraycopy(bytes, 0, this.payload, 0, bytes.length);
}
/**
* get the payload of this packet
*
* @return string representation of this packet's payload
*/
public String getPayloadString() {
if (payloadLength > 0) {
// already null terminated strings skip the termination character
if (payload[payloadLength - 1] == 0) {
return new String(payload, 0, payloadLength - 1);
} else {
return new String(payload, 0, payloadLength);
}
} else {
return "";
}
}
/**
* set this packet's return code (0 is ok)
*
* @param returnCode an integer
*/
public void setReturnCode(int returnCode) {
if (packetType == OwserverPacketType.RETURN) {
this.packetCode = returnCode;
} else {
throw new IllegalStateException("setting return code not allowed in REQUEST packets");
}
}
/**
* get this packet's return code (0 is ok)
*
* @return
*/
public int getReturnCode() {
if (packetType == OwserverPacketType.RETURN) {
return packetCode;
} else {
throw new IllegalStateException("getting return code not allowed in REQUEST packets");
}
}
/**
* set this packet's message type
*
* @param messageType
*/
public void setMessageType(OwserverMessageType messageType) {
if (packetType == OwserverPacketType.REQUEST) {
packetCode = messageType.getValue();
} else {
throw new IllegalStateException("setting message type not allowed in RETURN packets");
}
}
/**
* get this packets message type
*
* @return
*/
public OwserverMessageType getMessageType() {
if (packetType == OwserverPacketType.REQUEST) {
return OwserverMessageType.fromInt(packetCode);
} else {
throw new IllegalStateException("getting message type not allowed in RETURN packets");
}
}
/**
* check if packed is valid return packet
*
* @return true if valid
*/
public boolean isValidReturnPacket() {
return (packetCode == 0 && packetType == OwserverPacketType.RETURN);
}
/**
* check if packed is valid return packet
*
* @return true if valid
*/
public boolean isPingPacket() {
return (payloadLength == -1 && packetType == OwserverPacketType.RETURN);
}
/**
* get the payload of this packet
*
* @return OwPageBuffer with this packet's payload
*/
public OwPageBuffer getPayload() {
OwPageBuffer byteBuffer = new OwPageBuffer(payload);
return byteBuffer;
}
/**
* check if this packet has a payload
*
* @return true if payload present
*/
public boolean hasPayload() {
return (payloadLength > 0);
}
/**
* convert this packet to an array of bytes
*
* @return array of bytes
*/
public byte[] toBytes() {
ByteBuffer byteBuffer = ByteBuffer.allocate(HEADER_SIZE + payloadLength);
byteBuffer.putInt(protocolVersion);
byteBuffer.putInt(payloadLength);
byteBuffer.putInt(packetCode);
byteBuffer.putInt(controlFlags);
byteBuffer.putInt(packetSize);
byteBuffer.putInt(payloadOffset);
if (payloadLength > 0) {
byteBuffer.put(payload);
}
return byteBuffer.array();
}
@Override
public String toString() {
String prefix;
if (packetType == OwserverPacketType.RETURN) {
prefix = String.format("return code %d", packetCode);
} else {
prefix = String.format("messageType %s", OwserverMessageType.fromInt(packetCode));
}
return String.format("%s, size %d, controlFlags 0x%08x, payload '%s'", prefix, HEADER_SIZE + payloadLength,
controlFlags, getPayloadString().replaceAll("\\p{C}", "?"));
}
}

View File

@@ -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.onewire.internal.owserver;
/**
* The {@link OwserverPacketType} defines owserver packet types
*
* @author Jan N. Klug - Initial contribution
*/
public enum OwserverPacketType {
REQUEST,
RETURN
}

View File

@@ -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.onewire.internal.owserver;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link OwserverPressureScale} provides the owserver protocol pressure scale flags
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public enum OwserverPressureScale {
MILLIBAR(0x00000000),
ATM(0x00040000),
MMHG(0x00080000),
INHG(0x000C0000),
PSI(0x00100000),
PASCAL(0x00140000);
private static final int CLEAR_MASK = 0x001C0000;
private final int flag;
OwserverPressureScale(int flag) {
this.flag = flag;
}
/**
* get numeric value of this flag
*
* @return
*/
public int getValue() {
return flag;
}
/**
* set this flag in a set of given flags
*
* @param flags aggregated flags
* @return parameter with this flag set
*/
public int setFlag(int flags) {
return (flags & ~CLEAR_MASK) | this.getValue();
}
/**
* get the pressure scale flag from a given set of flags
*
* @param flags set of flags
* @return pressure scale flag
* @throws IllegalArgumentException
*/
public static OwserverPressureScale getFlag(int flags) throws IllegalArgumentException {
for (OwserverPressureScale value : values()) {
if (value.getValue() == (flags & CLEAR_MASK)) {
return value;
}
}
throw new IllegalArgumentException("Pressure scale flag not found");
}
}

View File

@@ -0,0 +1,76 @@
/**
* 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.onewire.internal.owserver;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link OwserverTemperatureScale} provides the owserver protocol temperature scale flags
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public enum OwserverTemperatureScale {
CENTIGRADE(0x00000000),
FAHRENHEIT(0x00010000),
KELVIN(0x00020000),
RANKINE(0x00030000);
private static final int CLEAR_MASK = 0x00030000;
private final int flag;
OwserverTemperatureScale(int flag) {
this.flag = flag;
}
/**
* get numeric value of this flag
*
* @return
*/
public int getValue() {
return flag;
}
/**
* set this flag in a set of given flags
*
* @param flags aggregated flags
* @return parameter with this flag set
*/
public int setFlag(int flags) {
int tempFlags = flags;
tempFlags &= ~CLEAR_MASK;
tempFlags |= this.getValue();
return tempFlags;
}
/**
* get the temperature scale flag from a given set of flags
*
* @param flags set of flags
* @return temperature scale flag
* @throws IllegalArgumentException
*/
public static OwserverTemperatureScale getFlag(int flags) {
int tempFlags = flags;
tempFlags &= CLEAR_MASK;
for (OwserverTemperatureScale value : values()) {
if (value.getValue() == tempFlags) {
return value;
}
}
return CENTIGRADE;
}
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="onewire" 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>OneWire Binding</name>
<description>This is the binding for OneWire.</description>
<author>Jan N. Klug</author>
</binding:binding>

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<config-description:config-descriptions
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
<config-description uri="thing-type:onewire:basethingconfig">
<parameter name="id" type="text">
<label>Sensor ID</label>
<description>Sensor ID in format: xx.xxxxxxxxxxxx or a full path including hubs/branches</description>
<required>true</required>
</parameter>
<parameter name="refresh" type="integer" min="1">
<label>Refresh Time</label>
<description>Time in seconds after which the thing is refreshed</description>
<default>300</default>
<unitLabel>s</unitLabel>
<required>false</required>
</parameter>
</config-description>
<config-description uri="thing-type:onewire:mstxconfig">
<parameter name="id" type="text">
<label>Sensor ID</label>
<description>Sensor ID in format: xx.xxxxxxxxxxxx or a full path including hubs/branches</description>
<required>true</required>
</parameter>
<parameter name="refresh" type="integer" min="1">
<label>Refresh Time</label>
<description>Time in seconds after which the thing is refreshed</description>
<default>300</default>
<unitLabel>s</unitLabel>
<required>false</required>
</parameter>
<parameter name="manualsensor" type="text">
<label>Manual Sensor Type</label>
<description>Overrides detected sensor type</description>
<options>
<option value="DS2438">Generic</option>
<option value="MS_TH">MS-TH</option>
<option value="MS_TV">MS-TV</option>
<option value="MS_TL">MS-TL</option>
<option value="MS_TC">MS-TC</option>
</options>
<limitToOptions>true</limitToOptions>
<required>false</required>
<advanced>true</advanced>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="onewire"
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="bae091x">
<supported-bridge-type-refs>
<bridge-type-ref id="owserver"/>
</supported-bridge-type-refs>
<label>Multisensor BAE0910</label>
<description>1-wire multisensor (BAE0910-based)</description>
<properties>
<property name="sensorCount">1</property>
</properties>
<config-description>
<parameter name="id" type="text">
<label>Sensor ID</label>
<description>Sensor ID in format: xx.xxxxxxxxxxxx)</description>
<required>true</required>
</parameter>
<parameter name="refresh" type="integer" min="1">
<label>Refresh Time</label>
<description>Time in seconds after which the thing is refreshed</description>
<default>300</default>
<unitLabel>s</unitLabel>
</parameter>
<parameter name="pin1" type="text">
<label>Pin 1 Mode Configuration</label>
<options>
<option value="disabled">disabled</option>
<option value="counter">Counter</option>
</options>
<default>counter</default>
<limitToOptions>true</limitToOptions>
</parameter>
<parameter name="pin2" type="text">
<label>Pin 2 Mode Configuration</label>
<options>
<option value="disabled">disabled</option>
<option value="output">Digital Output</option>
<option value="pwm">Software PWM 4</option>
</options>
<default>output</default>
<limitToOptions>true</limitToOptions>
</parameter>
<parameter name="pin6" type="text">
<label>Pin 6 Mode Configuration</label>
<options>
<option value="disabled">disabled</option>
<option value="pio">PIO</option>
<option value="pwm">Software PWM 3</option>
</options>
<default>pio</default>
<limitToOptions>true</limitToOptions>
</parameter>
<parameter name="pin7" type="text">
<label>Pin 7 Mode Configuration</label>
<options>
<option value="disabled">disabled</option>
<option value="analog">Analog Input</option>
<option value="output">Digital Output</option>
<option value="pwm">Hardware PWM 2</option>
</options>
<default>analog</default>
<limitToOptions>true</limitToOptions>
</parameter>
<parameter name="pin8" type="text">
<label>Pin 8 Mode Configuration</label>
<options>
<option value="disabled">disabled</option>
<option value="input">Digital Input</option>
<option value="output">Digital Output</option>
<option value="pwm">Hardware PWM 1</option>
</options>
<default>output</default>
<limitToOptions>true</limitToOptions>
</parameter>
</config-description>
</thing-type>
<!-- PWM Channels -->
<channel-type id="bae-pwm-frequency">
<item-type>Number:Frequency</item-type>
<label>Frequency</label>
<description>Frequency of PWM output in Hz</description>
<config-description>
<parameter name="prescaler" type="integer">
<label>Range</label>
<description>defines the frequency range of PWM output</description>
<options>
<option value="0">245 Hz - 8 MHz</option>
<option value="1">123 Hz - 4 MHz</option>
<option value="2">62 Hz - 2 MHz</option>
<option value="3">31 Hz - 1 MHz</option>
<option value="4">16 Hz - 500 kHz</option>
<option value="5">8 Hz - 250 kHz</option>
<option value="6">4 Hz - 125 kHz</option>
<option value="7">2 Hz - 62.5 kHz</option>
</options>
<default>0</default>
<limitToOptions>true</limitToOptions>
</parameter>
<parameter name="reversePolarity" type="boolean">
<label>Reverse Polarity</label>
<default>false</default>
</parameter>
</config-description>
</channel-type>
<channel-type id="bae-pwm-duty">
<item-type>Number:Dimensionless</item-type>
<label>Duty Cycle</label>
<description>Duty cycle of PWM output in %</description>
</channel-type>
<!-- Digital Channels -->
<channel-type id="bae-pio">
<item-type>Switch</item-type>
<label>PIO</label>
<description>Programmable I/O channel</description>
<config-description>
<parameter name="mode" type="text">
<label>Mode</label>
<options>
<option value="input">Input</option>
<option value="output">Output</option>
</options>
<default>input</default>
<limitToOptions>true</limitToOptions>
</parameter>
<parameter name="pulldevice" type="text">
<label>Pull-Up/Pull-Down Resistor</label>
<options>
<option value="disabled">disabled</option>
<option value="pullup">Pull-Up</option>
<option value="pulldown">Pull-Down</option>
</options>
<default>disabled</default>
<limitToOptions>true</limitToOptions>
</parameter>
</config-description>
</channel-type>
<channel-type id="bae-do">
<item-type>Switch</item-type>
<label>Digital Out</label>
</channel-type>
<channel-type id="bae-di">
<item-type>Switch</item-type>
<label>Digital In</label>
</channel-type>
<!-- Analog In (ADC) -->
<channel-type id="bae-analog">
<item-type>Number:ElectricPotential</item-type>
<label>Analog Input</label>
<description>Analog input (ADC)</description>
<state readOnly="true" pattern="%.1f %unit%"/>
<config-description>
<parameter name="hires" type="boolean">
<label>Hires</label>
<description>High resolution Mode (10bit)</description>
<default>false</default>
</parameter>
</config-description>
</channel-type>
<!-- Counter Channel -->
<channel-type id="bae-counter">
<item-type>Number</item-type>
<label>Counter</label>
<state readOnly="true" pattern="%d"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="onewire"
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="basic">
<supported-bridge-type-refs>
<bridge-type-ref id="owserver"/>
</supported-bridge-type-refs>
<label>Basic 1 Wire Sensor</label>
<config-description-ref uri="thing-type:onewire:basethingconfig"/>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="onewire"
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="owserver" extensible="owfs-string,owfs-number">
<label>OW Server</label>
<description>An owserver instance</description>
<config-description>
<parameter name="network-address" type="text">
<context>network_address</context>
<label>Network Address</label>
<description>Network address of the host running the owserver</description>
<required>true</required>
</parameter>
<parameter name="port" type="integer">
<label>Port</label>
<description>Listening port of the owserver</description>
<default>4304</default>
<required>false</required>
</parameter>
</config-description>
</bridge-type>
<channel-type id="owfs-string">
<item-type>String</item-type>
<label>Direct Access to OWFS-Path (String)</label>
<description>Allows direct access to the OWFS</description>
<state readOnly="true"/>
<config-description>
<parameter name="path" type="text">
<label>OWFS Path</label>
<description>full path to the OWFS-node (e.g. statistics/errors/CRC8_errors)</description>
<required>true</required>
</parameter>
<parameter name="refresh" type="integer" min="1">
<label>Refresh Time</label>
<description>Time in seconds after which the channel is refreshed</description>
<default>300</default>
<unitLabel>s</unitLabel>
<required>false</required>
</parameter>
</config-description>
</channel-type>
<channel-type id="owfs-number">
<item-type>Number</item-type>
<label>Direct Access to OWFS-Path (Number)</label>
<description>Allows direct access to the OWFS</description>
<state readOnly="true"/>
<config-description>
<parameter name="path" type="text">
<label>OWFS Path</label>
<description>full path to the OWFS-node (e.g. statistics/errors/CRC8_errors)</description>
<required>true</required>
</parameter>
<parameter name="refresh" type="integer" min="1">
<label>Refresh Time</label>
<description>Time in seconds after which the channel is refreshed</description>
<default>300</default>
<unitLabel>s</unitLabel>
<required>false</required>
</parameter>
</config-description>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="onewire"
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">
<!-- Device Present Channel -->
<channel-type id="present">
<item-type>Switch</item-type>
<label>Present</label>
<description>ON if device present on OneWire bus</description>
<state readOnly="true"/>
</channel-type>
<!-- Temperature Channel -->
<channel-type id="temperature">
<item-type>Number:Temperature</item-type>
<label>Temperature</label>
<description>temperature value of this sensor</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="temperature-por">
<item-type>Number:Temperature</item-type>
<label>Temperature</label>
<description>temperature value of this sensor</description>
<state readOnly="true" pattern="%.1f %unit%"/>
<config-description>
<parameter name="ignorepor" type="boolean">
<label>Ignore POR-value</label>
<description>filters all 85°C readings (POR-value), may suppress valid readings if enabled</description>
<default>false</default>
<required>false</required>
</parameter>
</config-description>
</channel-type>
<channel-type id="temperature-por-res">
<item-type>Number:Temperature</item-type>
<label>Temperature</label>
<description>temperature value of this sensor</description>
<state readOnly="true" pattern="%.1f %unit%"/>
<config-description>
<parameter name="ignorepor" type="boolean">
<label>Ignore POR-value</label>
<description>filters all 85°C readings (POR-value), may suppress valid readings if enabled</description>
<default>false</default>
<required>false</required>
</parameter>
<parameter name="resolution" type="text">
<label>Sensor Resolution</label>
<options>
<option value="9">9 bit</option>
<option value="10">10 bit</option>
<option value="11">11 bit</option>
<option value="12">12 bit</option>
</options>
<default>10</default>
<limitToOptions>true</limitToOptions>
<required>false</required>
</parameter>
</config-description>
</channel-type>
<!-- Dewpoint Channel -->
<channel-type id="dewpoint">
<item-type>Number:Temperature</item-type>
<label>Dewpoint</label>
<description>dewpoint (calculated from temperature and relative humidity)</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<!-- Relative Humidity Channel -->
<channel-type id="humidity">
<item-type>Number:Dimensionless</item-type>
<label>Humidity</label>
<description>relative humidity (0-100%)</description>
<state readOnly="true" pattern="%d %%"/>
</channel-type>
<channel-type id="humidityconf">
<item-type>Number:Dimensionless</item-type>
<label>Humidity</label>
<description>relative humidity (0-100%)</description>
<state readOnly="true" pattern="%d %%"/>
<config-description>
<parameter name="humiditytype" type="text">
<label>Humidity Sensor-Type</label>
<limitToOptions>true</limitToOptions>
<options>
<option value="/humidity">HIH-3610</option>
<option value="/HIH4000/humidity">HIH-4000</option>
<option value="/HTM1735/humidity">HTM-1735</option>
<option value="/DATANAB/humidity">Datanab</option>
</options>
<default>/humidity</default>
<required>false</required>
</parameter>
</config-description>
</channel-type>
<!-- Absolute Humidity Channel -->
<channel-type id="absolutehumidity">
<item-type>Number:Density</item-type>
<label>Abs. Humidity</label>
<description>absolute humidity (calculated from temperature and relative humidity)</description>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Voltage Channel -->
<channel-type id="voltage">
<item-type>Number:ElectricPotential</item-type>
<label>Voltage</label>
<description>The voltage measured by the sensor</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<!-- Supply-Voltage Channel -->
<channel-type id="supplyvoltage">
<item-type>Number:ElectricPotential</item-type>
<label>Supply Voltage</label>
<description>The sensor's supply voltage</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<!-- Light Channel -->
<channel-type id="light">
<item-type>Number:Illuminance</item-type>
<label>Illuminance</label>
<description>Ambient light</description>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<!-- Current Channel -->
<channel-type id="current">
<item-type>Number:ElectricCurrent</item-type>
<label>Current</label>
<description>The current measured by the sensor</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<!-- Digital I/O Channel -->
<channel-type id="dio">
<item-type>Switch</item-type>
<label>Digital I/O</label>
<config-description>
<parameter name="mode" type="text">
<label>Mode</label>
<options>
<option value="input">Input</option>
<option value="output">Output</option>
</options>
<default>input</default>
<limitToOptions>true</limitToOptions>
</parameter>
<parameter name="logic" type="text">
<label>Channel Logic</label>
<options>
<option value="normal">normal</option>
<option value="inverted">inverted</option>
</options>
<default>normal</default>
<limitToOptions>true</limitToOptions>
</parameter>
</config-description>
</channel-type>
<!-- Pressure Channel -->
<channel-type id="pressure">
<item-type>Number:Pressure</item-type>
<label>Pressure</label>
<description>The pressure measured by the sensor</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<!-- Counter Channel -->
<channel-type id="counter">
<item-type>Number</item-type>
<label>Counter</label>
<description>A single counter (reset on power loss)</description>
<state readOnly="true" pattern="%d"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="onewire"
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="ms-tx">
<supported-bridge-type-refs>
<bridge-type-ref id="owserver"/>
</supported-bridge-type-refs>
<label>Multisensor (T, TC, TH, TL, TV, Generic)</label>
<description>A 1-wire multisensor (DS1923/DS2438-based)</description>
<config-description-ref uri="thing-type:onewire:mstxconfig"/>
</thing-type>
<thing-type id="bms">
<supported-bridge-type-refs>
<bridge-type-ref id="owserver"/>
</supported-bridge-type-refs>
<label>Multisensor BMS</label>
<description>1-wire multisensor (DS2438-based)</description>
<config-description>
<parameter name="id" type="text">
<label>TH(S) Sensor ID</label>
<description>Sensor ID of the DS2438 sensor in format: xx.xxxxxxxxxxxx or a full path including hubs/branches</description>
<required>true</required>
</parameter>
<parameter name="refresh" type="integer" min="1">
<label>Refresh Time</label>
<description>Time in seconds after which the thing is refreshed</description>
<default>300</default>
<unitLabel>s</unitLabel>
<required>false</required>
</parameter>
<parameter name="temperaturesensor" type="text">
<label>Temperature Sensor</label>
<options>
<option value="DS2438">internal (DS2438)</option>
<option value="DS18B20">external (DS18B20)</option>
</options>
<default>DS2438</default>
<limitToOptions>true</limitToOptions>
<required>false</required>
</parameter>
</config-description>
</thing-type>
<thing-type id="ams">
<supported-bridge-type-refs>
<bridge-type-ref id="owserver"/>
</supported-bridge-type-refs>
<label>Multisensor AMS</label>
<description>1-wire multisensor (DS2438-based)</description>
<config-description>
<parameter name="id" type="text">
<label>TH(S) Sensor ID</label>
<description>Sensor ID of the DS2438 sensor in format: xx.xxxxxxxxxxxx or a full path including hubs/branches</description>
<required>true</required>
</parameter>
<parameter name="refresh" type="integer" min="1">
<label>Refresh Time for Analog Channels</label>
<description>Time in seconds after which the thing is refreshed</description>
<default>300</default>
<unitLabel>s</unitLabel>
<required>false</required>
</parameter>
<parameter name="refreshdigital" type="integer" min="1">
<label>Refresh Time for Digital Channels</label>
<description>Time in seconds after which the digital I/Os are refreshed</description>
<default>10</default>
<unitLabel>s</unitLabel>
<required>false</required>
</parameter>
<parameter name="temperaturesensor" type="text">
<label>Temperature Sensor</label>
<options>
<option value="DS2438">internal (DS2438)</option>
<option value="DS18B20">external (DS18B20)</option>
</options>
<default>DS2438</default>
<limitToOptions>true</limitToOptions>
<required>false</required>
</parameter>
</config-description>
</thing-type>
<thing-type id="edsenv">
<supported-bridge-type-refs>
<bridge-type-ref id="owserver"/>
</supported-bridge-type-refs>
<label>Multisensor EDS</label>
<description>A 1-wire multisensor (EDS00xx-based)</description>
<properties>
<property name="sensorCount">1</property>
</properties>
<config-description>
<parameter name="id" type="text">
<label>Sensor ID</label>
<description>Sensor ID in format: xx.xxxxxxxxxxxx)</description>
<required>true</required>
</parameter>
<parameter name="refresh" type="integer" min="1">
<label>Refresh Time</label>
<description>Time in seconds after which the thing is refreshed</description>
<default>300</default>
<unitLabel>s</unitLabel>
<required>false</required>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,29 @@
humidity = Number:Dimensionless
absolutehumidity = Number:Density
dewpoint = Number:Temperature
temperature = Number:Temperature
light = Number:Illuminance
pressure = Number:Pressure
voltage = Number:ElectricPotential
supplyvoltage = Number:ElectricPotential
current = Number:ElectricCurrent
counter = Number
counter0 = Number
counter1 = Number
digital = Switch
digital0 = Switch
digital1 = Switch
digital2 = Switch
digital3 = Switch
digital4 = Switch
digital5 = Switch
digital6 = Switch
digital7 = Switch
digital8 = Switch
present = Switch
pwmduty1 = Number:Dimensionsless
pwmduty2 = Number:Dimensionsless
pwmduty3 = Number:Dimensionsless
pwmduty4 = Number:Dimensionsless
pwmfreq1 = Number:Frequency
pwmfreq2 = Number:Frequency

View File

@@ -0,0 +1,89 @@
#
# sensor.properties - This file defines the sensor properties
#
# Format: sensorType.channels = name:type:[label][,name:type:[label]]...
# sensorType.label = label
# sensorType.thingtype = thingtype
#
DS1420.channels = present:present:
DS1420.label = 1kb EEPROM
DS1420.thingtype = basic
DS1822.channels = temperature:temperature-por-res:
DS1822.label = Temperature Sensor
DS1822.thingtype = basic
DS18B20.channels = temperature:temperature-por-res:
DS18B20.label = Temperature Sensor
DS18B20.thingtype = basic
DS18S20.channels = temperature:temperature-por:
DS18S20.label = Temperature Sensor
DS18S20.thingtype = basic
DS1923.channels = temperature:temperature:,humidity:humidity:,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint
DS1923.label = Multisensor
DS1923.thingtype = ms-tx
DS2401.channels = present:present:
DS2401.label = iButton
DS2401.thingtype = basic
DS2405.channels = digital0:dio:Digital I/O 0
DS2405.label = Single Digital I/O
DS2405.thingtype = basic
DS2406.channels = digital0:dio:Digital I/O 0,digital1:dio:Digital I/O 1
DS2406.label = Dual Digital I/O
DS2406.thingtype = basic
DS2408.channels = digital0:dio:Digital I/O 0,digital1:dio:Digital I/O 1,digital2:dio:Digital I/O 2,digital3:dio:Digital I/O 3,digital4:dio:Digital I/O 4,digital5:dio:Digital I/O 5,digital6:dio:Digital I/O 6,digital7:dio:Digital I/O 7
DS2408.label = Octal Digital I/O
DS2408.thingtype = basic
DS2413.channels = digital0:dio:Digital I/O 0,digital1:dio:Digital I/O 1
DS2413.label = Dual Digital I/O
DS2413.thingtype = basic
DS2423.channels = counter0:counter:Counter 0,counter1:counter:Counter 1
DS2423.label = Dual Counter
DS2423.thingtype = basic
# AMS/BMS: humidity and temperature added by handler
AMS.channels = supplyvoltage:voltage:Supplyvoltage,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint,voltage:voltage:,digital0:dio:Digital I/O 0,digital1:dio:Digital I/O 1
AMS.label = Multisensor AMS
AMS.thingtype = ams
AMS_S.channels = supplyvoltage:voltage:Supplyvoltage,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint,light:light:,voltage:voltage:,digital0:dio:Digital I/O 0,digital1:dio:Digital I/O 1
AMS_S.label = Multisensor AMS
AMS_S.thingtype = ams
BMS.channels = supplyvoltage:voltage:Supplyvoltage,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint
BMS.label = Multisensor BMS
BMS.thingtype = bms
BMS_S.channels = supplyvoltage:voltage:Supplyvoltage,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint,light:light:
BMS_S.label = Multisensor BMS
BMS_S.thingtype = bms
# DS2438
DS2438.channels = supplyvoltage:voltage:Supplyvoltage,temperature:temperature:,voltage:voltage:,current:current:
DS2438.label = Multisensor (generic)
DS2438.thingtype = ms-tx
MS_TC.channels = supplyvoltage:voltage:Supplyvoltage,temperature:temperature:,voltage:voltage:
MS_TC.label = Multisensor TC
MS_TC.thingtype = ms-tx
MS_TH.channels = supplyvoltage:voltage:Supplyvoltage,temperature:temperature:,humidity:humidityconf:,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint
MS_TH.label = Multisensor TH
MS_TH.thingtype = ms-tx
MS_TL.channels = supplyvoltage:voltage:Supplyvoltage,temperature:temperature:,light:light:
MS_TL.label = Multisensor TL
MS_TL.thingtype = ms-tx
MS_TV.channels = supplyvoltage:voltage:Supplyvoltage,temperature:temperature:,voltage:voltage:
MS_TV.label = Multisensor TV
MS_TV.thingtype = ms-tx
# EDS
EDS0064.channels = temperature:temperature:
EDS0064.label = Multisensor EDS
EDS0064.thingtype = edsenv
EDS0065.channels = temperature:temperature:,humidity:humidity:,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint
EDS0065.label = Multisensor EDS
EDS0065.thingtype = edsenv
EDS0066.channels = temperature:temperature:,pressure:pressure:
EDS0066.label = Multisensor EDS
EDS0066.thingtype = edsenv
EDS0067.channels = temperature:temperature:,light:light:
EDS0067.label = Multisensor EDS
EDS0067.thingtype = edsenv
EDS0068.channels = temperature:temperature:,humidity:humidity:,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint,pressure:pressure:,light:light:
EDS0068.label = Multisensor EDS
EDS0068.thingtype = edsenv
# BAE091x
BAE0910.channels =
BAE0910.label = Multisensor BAE0910
BAE0910.thingtype = bae091x

View File

@@ -0,0 +1,104 @@
/**
* 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.onewire;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Assert;
import org.junit.Test;
import org.openhab.binding.onewire.internal.OwBindingConstants;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.binding.onewire.internal.handler.*;
/**
* Tests cases for binding completeness
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class CompletenessTest {
// internal/temporary types, DS2409 (MicroLAN Coupler), DS2431 (EEPROM)
private static final Set<OwSensorType> IGNORED_SENSOR_TYPES = Collections
.unmodifiableSet(Stream.of(OwSensorType.DS2409, OwSensorType.DS2431, OwSensorType.EDS, OwSensorType.MS_TH_S,
OwSensorType.BAE, OwSensorType.BAE0911, OwSensorType.UNKNOWN).collect(Collectors.toSet()));
private static final Set<OwSensorType> THINGHANDLER_SENSOR_TYPES = Collections.unmodifiableSet(Stream
.of(AdvancedMultisensorThingHandler.SUPPORTED_SENSOR_TYPES,
BasicMultisensorThingHandler.SUPPORTED_SENSOR_TYPES, BasicThingHandler.SUPPORTED_SENSOR_TYPES,
EDSSensorThingHandler.SUPPORTED_SENSOR_TYPES, BAE091xSensorThingHandler.SUPPORTED_SENSOR_TYPES)
.flatMap(Set::stream).collect(Collectors.toSet()));
@Test
public void allSupportedTypesInThingHandlerMap() {
for (OwSensorType sensorType : EnumSet.allOf(OwSensorType.class)) {
if (!OwBindingConstants.THING_TYPE_MAP.containsKey(sensorType)
&& !IGNORED_SENSOR_TYPES.contains(sensorType)) {
Assert.fail("missing thing type map for sensor type " + sensorType.name());
}
}
}
@Test
public void allSupportedTypesInThingChannelsMap() {
for (OwSensorType sensorType : EnumSet.allOf(OwSensorType.class)) {
if (!OwBindingConstants.SENSOR_TYPE_CHANNEL_MAP.containsKey(sensorType)
&& !IGNORED_SENSOR_TYPES.contains(sensorType)) {
Assert.fail("missing channel configuration map for sensor type " + sensorType.name());
}
}
}
@Test
public void allSensorsSupportedByThingHandlers() {
for (OwSensorType sensorType : EnumSet.allOf(OwSensorType.class)) {
if (!THINGHANDLER_SENSOR_TYPES.contains(sensorType) && !IGNORED_SENSOR_TYPES.contains(sensorType)) {
Assert.fail("missing thing handler for sensor type " + sensorType.name());
}
}
}
@Test
public void allSensorTypesInLabelMap() {
for (OwSensorType sensorType : EnumSet.allOf(OwSensorType.class)) {
if (!OwBindingConstants.THING_LABEL_MAP.containsKey(sensorType)
&& !IGNORED_SENSOR_TYPES.contains(sensorType)) {
Assert.fail("missing label for sensor type " + sensorType.name());
}
}
}
@Test
public void acceptedItemTypeMapCompleteness() throws OwException {
List<String> channels = Arrays.stream(OwBindingConstants.class.getDeclaredFields())
.filter(f -> Modifier.isStatic(f.getModifiers()))
.filter(f -> f.getName().startsWith("CHANNEL") && !f.getName().startsWith("CHANNEL_TYPE")).map(f -> {
try {
return (String) f.get(null);
} catch (IllegalAccessException e) {
Assert.fail("unexpected");
return null;
}
}).collect(Collectors.toList());
for (String channel : channels) {
if (!OwBindingConstants.ACCEPTED_ITEM_TYPES_MAP.containsKey(channel)) {
Assert.fail("missing accepted item type for channel " + channel);
}
}
}
}

View File

@@ -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.onewire;
import static org.junit.Assert.assertEquals;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
/**
* Tests cases for {@link SensorId}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwserverDeviceParameterTest {
private final SensorId sensorId = new SensorId("/1F.0123456789ab/main/00.1234567890ab");
@Test
public void withoutPrefixTest() {
OwserverDeviceParameter owserverDeviceParameter = new OwserverDeviceParameter("/humidity");
assertEquals("/1F.0123456789ab/main/00.1234567890ab/humidity", owserverDeviceParameter.getPath(sensorId));
owserverDeviceParameter = new OwserverDeviceParameter("humidity");
assertEquals("/1F.0123456789ab/main/00.1234567890ab/humidity", owserverDeviceParameter.getPath(sensorId));
}
public void withPrefixTest() {
OwserverDeviceParameter owserverDeviceParameter = new OwserverDeviceParameter("uncached", "/humidity");
assertEquals("/uncached/1F.0123456789ab/main/00.1234567890ab/humidity",
owserverDeviceParameter.getPath(sensorId));
owserverDeviceParameter = new OwserverDeviceParameter("uncached", "/humidity");
assertEquals("/uncached/1F.0123456789ab/main/00.1234567890ab/humidity",
owserverDeviceParameter.getPath(sensorId));
owserverDeviceParameter = new OwserverDeviceParameter("/uncached", "/humidity");
assertEquals("/uncached/1F.0123456789ab/main/00.1234567890ab/humidity",
owserverDeviceParameter.getPath(sensorId));
owserverDeviceParameter = new OwserverDeviceParameter("/uncached/", "/humidity");
assertEquals("/uncached/1F.0123456789ab/main/00.1234567890ab/humidity",
owserverDeviceParameter.getPath(sensorId));
owserverDeviceParameter = new OwserverDeviceParameter("uncached/", "/humidity");
assertEquals("/uncached/1F.0123456789ab/main/00.1234567890ab/humidity",
owserverDeviceParameter.getPath(sensorId));
}
}

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.onewire;
import static org.junit.Assert.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.onewire.internal.SensorId;
/**
* Tests cases for {@link SensorId}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class SensorIdTest {
@Test
public void bareSensorIdConstructionTest() {
SensorId sensorId = new SensorId("28.0123456789ab");
assertEquals("/28.0123456789ab", sensorId.getFullPath());
assertEquals("28.0123456789ab", sensorId.getId());
assertEquals("28", sensorId.getFamilyId());
sensorId = new SensorId("/28.0123456789ab");
assertEquals("/28.0123456789ab", sensorId.getFullPath());
assertEquals("28.0123456789ab", sensorId.getId());
assertEquals("28", sensorId.getFamilyId());
}
@Test
public void hubMainSensorIdConstructionTest() {
SensorId sensorId = new SensorId("1F.0123456789ab/main/28.0123456789ab");
assertEquals("/1F.0123456789ab/main/28.0123456789ab", sensorId.getFullPath());
assertEquals("28.0123456789ab", sensorId.getId());
assertEquals("28", sensorId.getFamilyId());
sensorId = new SensorId("/1F.0123456789ab/main/28.0123456789ab");
assertEquals("/1F.0123456789ab/main/28.0123456789ab", sensorId.getFullPath());
assertEquals("28.0123456789ab", sensorId.getId());
assertEquals("28", sensorId.getFamilyId());
}
@Test
public void hubAuxSensorIdConstructionTest() {
SensorId sensorId = new SensorId("1F.0123456789ab/aux/28.0123456789ab");
assertEquals("/1F.0123456789ab/aux/28.0123456789ab", sensorId.getFullPath());
assertEquals("28.0123456789ab", sensorId.getId());
assertEquals("28", sensorId.getFamilyId());
sensorId = new SensorId("/1F.0123456789ab/aux/28.0123456789ab");
assertEquals("/1F.0123456789ab/aux/28.0123456789ab", sensorId.getFullPath());
assertEquals("28.0123456789ab", sensorId.getId());
assertEquals("28", sensorId.getFamilyId());
}
@Test
public void equalsTest() {
SensorId sensorId1 = new SensorId("1F.0123456789ab/aux/28.0123456789ab");
SensorId sensorId2 = new SensorId("1F.0123456789ab/aux/28.0123456789ab");
SensorId sensorId3 = new SensorId("1F.0123456789ab/aux/28.0123456789ac");
assertTrue(sensorId1.equals(sensorId2));
assertFalse(sensorId1.equals(sensorId3));
}
}

View File

@@ -0,0 +1,55 @@
/**
* 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.onewire;
import static org.junit.Assert.assertEquals;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.onewire.internal.Util;
import org.openhab.core.library.dimension.Density;
import org.openhab.core.library.types.QuantityType;
/**
* Tests cases for {@link Util}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class UtilTest {
@Test
public void convertAbsoluteHumidityTest() {
QuantityType<Temperature> temperature = new QuantityType<>("20 °C");
QuantityType<Dimensionless> relativeHumidity = new QuantityType<>("75%");
@SuppressWarnings("unchecked")
QuantityType<Density> absoluteHumidity = (QuantityType<Density>) Util.calculateAbsoluteHumidity(temperature,
relativeHumidity);
assertEquals(12.93, absoluteHumidity.doubleValue(), 0.01);
}
@Test
public void dewPointTest() {
QuantityType<Temperature> temperature = new QuantityType<>("20 °C");
QuantityType<Dimensionless> relativeHumidity = new QuantityType<>("75%");
@SuppressWarnings("unchecked")
QuantityType<Temperature> dewPoint = (QuantityType<Temperature>) Util.calculateDewpoint(temperature,
relativeHumidity);
assertEquals(15.43, dewPoint.doubleValue(), 0.01);
}
}

View File

@@ -0,0 +1,342 @@
/**
* 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.onewire.device;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.device.BAE0910;
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.State;
/**
* Tests cases for {@link BAE0910}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class BAE0910Test extends DeviceTestParent<BAE0910> {
@Before
public void setupMocks() {
setupMocks(THING_TYPE_BAE091X, BAE0910.class);
}
// pin 1: counter
@Test
public void counter() {
addChannel(CHANNEL_COUNTER, "Number");
final BAE0910 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(
mockBridgeHandler.readDecimalType(eq(testSensorId), eq(new OwserverDeviceParameter("/counter"))))
.thenReturn(new DecimalType(34567));
testDevice.enableChannel(CHANNEL_COUNTER);
testDevice.configureChannels(mockBridgeHandler);
// refresh
ArgumentCaptor<State> stateArgumentCaptor = ArgumentCaptor.forClass(State.class);
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId),
eq(new OwserverDeviceParameter("/counter")));
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_COUNTER), stateArgumentCaptor.capture());
assertEquals(new DecimalType(34567), stateArgumentCaptor.getValue());
// write
assertFalse(testDevice.writeChannel(mockBridgeHandler, CHANNEL_COUNTER, new DecimalType(12345)));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
// pin 2: digital2 or pwm1
@Test
public void digitalOut2() {
addChannel(CHANNEL_DIGITAL2, "Switch");
digitalBaseChannel(CHANNEL_DIGITAL2, bitSet(3, 4), 0, "/out", bitSet(0), true);
}
@Test
public void pwm4() {
pwmBaseChannel(CHANNEL_PWM_FREQ2, CHANNEL_PWM_DUTY4, "/period2", "/duty4", 2);
}
// pin 6: pio or pwm 3
@Test
public void digital6PioIn() {
Map<String, Object> channelConfig = new HashMap<>();
channelConfig.put("pulldevice", "pulldown");
channelConfig.put("mode", "input");
addChannel(CHANNEL_DIGITAL6, "Switch", new Configuration(channelConfig));
digitalBaseChannel(CHANNEL_DIGITAL6, bitSet(1, 2, 3, 4), 1, "/pio", bitSet(0), false);
}
@Test
public void digital6PioOut() {
Map<String, Object> channelConfig = new HashMap<>();
channelConfig.put("mode", "output");
addChannel(CHANNEL_DIGITAL6, "Switch", new Configuration(channelConfig));
digitalBaseChannel(CHANNEL_DIGITAL6, bitSet(0, 3, 4), 1, "/pio", bitSet(0), true);
}
@Test
public void pwm3() {
pwmBaseChannel(CHANNEL_PWM_FREQ1, CHANNEL_PWM_DUTY3, "/period1", "/duty3", 1);
}
// pin 7: analog, output, pwm2
@Test
public void analog() {
Map<String, Object> channelConfig = new HashMap<>();
channelConfig.put("hires", "true");
addChannel(CHANNEL_VOLTAGE, "Number:ElectricPotential", new Configuration(channelConfig));
final BAE0910 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), eq(new OwserverDeviceParameter("/adc"))))
.thenReturn(new DecimalType(5.2));
testDevice.enableChannel(CHANNEL_VOLTAGE);
testDevice.configureChannels(mockBridgeHandler);
// test configuration
assertEquals(bitSet(3, 4), checkConfiguration(2));
// refresh
ArgumentCaptor<State> stateArgumentCaptor = ArgumentCaptor.forClass(State.class);
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId),
eq(new OwserverDeviceParameter("/adc")));
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_VOLTAGE), stateArgumentCaptor.capture());
assertEquals(new QuantityType<>("5.2 V"), stateArgumentCaptor.getValue());
// write (should fail)
assertFalse(testDevice.writeChannel(mockBridgeHandler, CHANNEL_VOLTAGE, new QuantityType<>("3 V")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void digitalOut7() {
addChannel(CHANNEL_DIGITAL7, "Switch");
digitalBaseChannel(CHANNEL_DIGITAL7, bitSet(4), 4, "/tpm2c", bitSet(4, 7), true);
}
@Test
public void pwm2() {
pwmBaseChannel(CHANNEL_PWM_FREQ2, CHANNEL_PWM_DUTY2, "/period2", "/duty2", 2);
}
// pin 8: digital in, digital out or pwm
@Test
public void digitalIn8() {
addChannel(CHANNEL_DIGITAL8, "Switch", new ChannelTypeUID(BINDING_ID, "bae-in"));
digitalBaseChannel(CHANNEL_DIGITAL8, bitSet(4, 5), 3, "/tpm1c", bitSet(4, 5, 7), false);
}
@Test
public void digitalOut8() {
addChannel(CHANNEL_DIGITAL8, "Switch");
digitalBaseChannel(CHANNEL_DIGITAL8, bitSet(4), 3, "/tpm1c", bitSet(4, 7), true);
}
@Test
public void pwm1() {
pwmBaseChannel(CHANNEL_PWM_FREQ1, CHANNEL_PWM_DUTY1, "/period1", "/duty1", 1);
}
/**
* base test for digital channels
*
* @param channel channel name
* @param configBitSet expected config register
* @param configRegister config register number
* @param channelParam channel parameter
* @param returnBitSet which bitset should be returned on read
* @param isOutput if this channel is an output
*/
private void digitalBaseChannel(String channel, BitSet configBitSet, int configRegister, String channelParam,
BitSet returnBitSet, boolean isOutput) {
final BAE0910 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readBitSet(eq(testSensorId), eq(new OwserverDeviceParameter(channelParam))))
.thenReturn(returnBitSet);
testDevice.enableChannel(channel);
testDevice.configureChannels(mockBridgeHandler);
// test configuration
assertEquals(configBitSet, checkConfiguration(configRegister));
// refresh
ArgumentCaptor<State> stateArgumentCaptor = ArgumentCaptor.forClass(State.class);
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readBitSet(eq(testSensorId),
eq(new OwserverDeviceParameter(channelParam)));
inOrder.verify(mockThingHandler).postUpdate(eq(channel), stateArgumentCaptor.capture());
assertEquals(OnOffType.ON, stateArgumentCaptor.getValue());
// write
if (isOutput) {
ArgumentCaptor<BitSet> bitSetArgumentCaptor = ArgumentCaptor.forClass(BitSet.class);
assertTrue(testDevice.writeChannel(mockBridgeHandler, channel, OnOffType.ON));
inOrder.verify(mockBridgeHandler).writeBitSet(eq(testSensorId),
eq(new OwserverDeviceParameter(channelParam)), bitSetArgumentCaptor.capture());
assertEquals(returnBitSet, bitSetArgumentCaptor.getValue());
} else {
assertFalse(testDevice.writeChannel(mockBridgeHandler, channel, OnOffType.ON));
}
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
/**
* base test case for PWM channels
*
* @param freqChannel channel name for frequency
* @param dutyChannel channel name for duty cycle
* @param freqParam owfs parameter for frequency
* @param dutyParam owfs parameter for duty cycle
* @param registerIndex index for TPM configuration register
*/
private void pwmBaseChannel(String freqChannel, String dutyChannel, String freqParam, String dutyParam,
int registerIndex) {
Map<String, Object> channelConfig = new HashMap<>();
channelConfig.put("prescaler", 5);
addChannel(freqChannel, "Number:Frequency", new Configuration(channelConfig));
addChannel(dutyChannel, "Number:Dimensionless");
final BAE0910 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(
mockBridgeHandler.readDecimalType(eq(testSensorId), eq(new OwserverDeviceParameter(freqParam))))
.thenReturn(new DecimalType(32768));
Mockito.when(
mockBridgeHandler.readDecimalType(eq(testSensorId), eq(new OwserverDeviceParameter(dutyParam))))
.thenReturn(new DecimalType(16384));
testDevice.enableChannel(freqChannel);
testDevice.enableChannel(dutyChannel);
testDevice.configureChannels(mockBridgeHandler);
// test configuration
assertEquals(bitSet(0, 2), checkConfiguration(registerIndex + 2));
// refresh
ArgumentCaptor<State> stateArgumentCaptor = ArgumentCaptor.forClass(State.class);
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId),
eq(new OwserverDeviceParameter(freqParam)));
inOrder.verify(mockThingHandler).postUpdate(eq(freqChannel), stateArgumentCaptor.capture());
assertEquals(new QuantityType<>("15.2587890625 Hz"), stateArgumentCaptor.getValue());
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId),
eq(new OwserverDeviceParameter(dutyParam)));
inOrder.verify(mockThingHandler).postUpdate(eq(dutyChannel), stateArgumentCaptor.capture());
assertEquals(new QuantityType<>("50 %"), stateArgumentCaptor.getValue());
// write
ArgumentCaptor<DecimalType> decimalTypeArgumentCaptor = ArgumentCaptor.forClass(DecimalType.class);
assertTrue(testDevice.writeChannel(mockBridgeHandler, freqChannel, new QuantityType<>("50000 Hz")));
inOrder.verify(mockBridgeHandler).writeDecimalType(eq(testSensorId),
eq(new OwserverDeviceParameter(freqParam)), decimalTypeArgumentCaptor.capture());
assertEquals(new DecimalType(10), decimalTypeArgumentCaptor.getValue());
testDevice.writeChannel(mockBridgeHandler, dutyChannel, new QuantityType<>("25 %"));
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId),
eq(new OwserverDeviceParameter(freqParam)));
inOrder.verify(mockBridgeHandler).writeDecimalType(eq(testSensorId),
eq(new OwserverDeviceParameter(dutyParam)), decimalTypeArgumentCaptor.capture());
assertEquals(new DecimalType(8192), decimalTypeArgumentCaptor.getValue());
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
/**
* check if all registers are written and return one
*
* @param registerIndex number of register to return
* @return this register's BitSet
* @throws OwException
*/
private BitSet checkConfiguration(int registerIndex) throws OwException {
ArgumentCaptor<BitSet> configArgumentCaptor = ArgumentCaptor.forClass(BitSet.class);
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
inOrder.verify(mockBridgeHandler).writeBitSet(eq(testSensorId), eq(new OwserverDeviceParameter("/outc")),
configArgumentCaptor.capture());
inOrder.verify(mockBridgeHandler).writeBitSet(eq(testSensorId), eq(new OwserverDeviceParameter("/pioc")),
configArgumentCaptor.capture());
inOrder.verify(mockBridgeHandler).writeBitSet(eq(testSensorId), eq(new OwserverDeviceParameter("/adcc")),
configArgumentCaptor.capture());
inOrder.verify(mockBridgeHandler).writeBitSet(eq(testSensorId), eq(new OwserverDeviceParameter("/tpm1c")),
configArgumentCaptor.capture());
inOrder.verify(mockBridgeHandler).writeBitSet(eq(testSensorId), eq(new OwserverDeviceParameter("/tpm2c")),
configArgumentCaptor.capture());
return configArgumentCaptor.getAllValues().get(registerIndex);
}
/**
* BitSet with pre-set bits
*
* @param bits which bits to set
* @return the BitSet
*/
private BitSet bitSet(int... bits) {
BitSet bitSet = new BitSet(8);
Arrays.stream(bits).forEach(b -> bitSet.set(b));
return bitSet;
}
}

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.onewire.device;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.device.DS18x20;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
/**
* Tests cases for {@link DS18x20}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS18x20Test extends DeviceTestParent<DS18x20> {
@Before
public void setupMocks() {
setupMocks(THING_TYPE_BASIC, DS18x20.class);
Map<String, Object> channelConfig = new HashMap<>();
channelConfig.put(CONFIG_IGNORE_POR, true);
addChannel(CHANNEL_TEMPERATURE, "Number:Temperature", new Configuration(channelConfig));
}
@Test
public void temperatureTest() {
final DS18x20 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(15.0));
testDevice.enableChannel(CHANNEL_TEMPERATURE);
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler, times(1)).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_TEMPERATURE), eq(new QuantityType<>("15.0 °C")));
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void temperatureIgnorePORTest() {
final DS18x20 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(85.0));
testDevice.enableChannel(CHANNEL_TEMPERATURE);
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler, times(1)).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler, times(0)).postUpdate(eq(CHANNEL_TEMPERATURE), any());
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
}

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.onewire.device;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.times;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.device.DS1923;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
/**
* Tests cases for {@link DS1923}.
*
* @author Jan N. Klug - Initial contribution
* @author Michał Wójcik - Adapted to DS1923
*/
@NonNullByDefault
public class DS1923Test extends DeviceTestParent<DS1923> {
@Before
public void setupMocks() {
setupMocks(THING_TYPE_MS_TX, DS1923.class);
addChannel(CHANNEL_TEMPERATURE, "Number:Temperature");
addChannel(CHANNEL_HUMIDITY, "Number:Dimensionless");
addChannel(CHANNEL_ABSOLUTE_HUMIDITY, "Number:Density");
addChannel(CHANNEL_DEWPOINT, "Number:Temperature");
}
@Test
public void temperatureChannel() {
final DS1923 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(10.0));
testDevice.enableChannel(CHANNEL_TEMPERATURE);
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_TEMPERATURE), eq(new QuantityType<>("10.0 °C")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void humidityChannel() {
final DS1923 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(10.0));
testDevice.enableChannel(CHANNEL_HUMIDITY);
testDevice.enableChannel(CHANNEL_ABSOLUTE_HUMIDITY);
testDevice.enableChannel(CHANNEL_DEWPOINT);
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler, times(2)).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_HUMIDITY), eq(new QuantityType<>("10.0 %")));
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_ABSOLUTE_HUMIDITY),
eq(new QuantityType<>("0.9381970824113001000 g/m³")));
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_DEWPOINT),
eq(new QuantityType<>("-20.31395053870025 °C")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
}

View File

@@ -0,0 +1,45 @@
/**
* 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.onewire.device;
import static org.openhab.binding.onewire.internal.OwBindingConstants.THING_TYPE_BASIC;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Before;
import org.junit.Test;
import org.openhab.binding.onewire.internal.device.DS2401;
import org.openhab.core.library.types.OnOffType;
/**
* Tests cases for {@link DS2401}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2401Test extends DeviceTestParent<DS2401> {
@Before
public void setupMocks() {
setupMocks(THING_TYPE_BASIC, DS2401.class);
}
@Test
public void presenceTestOn() {
presenceTest(OnOffType.ON);
}
@Test
public void presenceTestOff() {
presenceTest(OnOffType.OFF);
}
}

View File

@@ -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.onewire.device;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.times;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.BitSet;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.device.DS2405;
import org.openhab.core.library.types.OnOffType;
/**
* Tests cases for {@link DS2405}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2405Test extends DeviceTestParent<DS2405> {
@Before
public void setupMocks() {
setupMocks(THING_TYPE_BASIC, DS2405.class);
addChannel(channelName(0), "Switch");
}
@Test
public void digitalChannel() {
digitalChannelTest(OnOffType.ON, 0);
digitalChannelTest(OnOffType.OFF, 0);
}
private void digitalChannelTest(OnOffType state, int channelNo) {
final DS2405 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
BitSet returnValue = new BitSet(8);
if (state == OnOffType.ON) {
returnValue.flip(0, 7);
}
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readBitSet(eq(testSensorId), any())).thenReturn(returnValue);
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler, times(2)).readBitSet(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(channelName(channelNo)), eq(state));
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
private String channelName(int channelNo) {
return CHANNEL_DIGITAL + channelNo;
}
}

View File

@@ -0,0 +1,82 @@
/**
* 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.onewire.device;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.times;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.BitSet;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.device.DS2406_DS2413;
import org.openhab.core.library.types.OnOffType;
/**
* Tests cases for {@link DS2406_DS2413}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2406_DS2413Test extends DeviceTestParent<DS2406_DS2413> {
@Before
public void setupMocks() {
setupMocks(THING_TYPE_BASIC, DS2406_DS2413.class);
for (int i = 0; i < 2; i++) {
addChannel(channelName(i), "Switch");
}
}
@Test
public void digitalChannel() {
for (int i = 0; i < 2; i++) {
digitalChannelTest(OnOffType.ON, i);
digitalChannelTest(OnOffType.OFF, i);
}
}
private void digitalChannelTest(OnOffType state, int channelNo) {
final DS2406_DS2413 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
BitSet returnValue = new BitSet(8);
if (state == OnOffType.ON) {
returnValue.flip(0, 7);
}
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readBitSet(eq(testSensorId), any())).thenReturn(returnValue);
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler, times(2)).readBitSet(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(channelName(channelNo)), eq(state));
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
private String channelName(int channelNo) {
return CHANNEL_DIGITAL + channelNo;
}
}

View File

@@ -0,0 +1,82 @@
/**
* 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.onewire.device;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.times;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.BitSet;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.device.DS2408;
import org.openhab.core.library.types.OnOffType;
/**
* Tests cases for {@link DS2408}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2408Test extends DeviceTestParent<DS2408> {
@Before
public void setupMocks() {
setupMocks(THING_TYPE_BASIC, DS2408.class);
for (int i = 0; i < 8; i++) {
addChannel(channelName(i), "Switch");
}
}
@Test
public void digitalChannel() {
for (int i = 0; i < 8; i++) {
digitalChannelTest(OnOffType.ON, i);
digitalChannelTest(OnOffType.OFF, i);
}
}
private void digitalChannelTest(OnOffType state, int channelNo) {
final DS2408 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
BitSet returnValue = new BitSet(8);
if (state == OnOffType.ON) {
returnValue.flip(0, 8);
}
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readBitSet(eq(testSensorId), any())).thenReturn(returnValue);
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler, times(2)).readBitSet(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(channelName(channelNo)), eq(state));
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
private String channelName(int channelNo) {
return CHANNEL_DIGITAL + channelNo;
}
}

View File

@@ -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.onewire.device;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.times;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.device.DS2423;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.State;
/**
* Tests cases for {@link DS2423}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2423Test extends DeviceTestParent<DS2423> {
@Before
public void setupMocks() {
setupMocks(THING_TYPE_BASIC, DS2423.class);
for (int i = 0; i < 2; i++) {
addChannel(channelName(i), "Number");
}
}
@Test
public void counterChannelTest() {
List<State> returnValue = new ArrayList<>();
returnValue.add(new DecimalType(1408));
returnValue.add(new DecimalType(3105));
final DS2423 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalTypeArray(eq(testSensorId), any())).thenReturn(returnValue);
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler, times(1)).readDecimalTypeArray(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(channelName(0)), eq(returnValue.get(0)));
inOrder.verify(mockThingHandler).postUpdate(eq(channelName(1)), eq(returnValue.get(1)));
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
private String channelName(int channelNo) {
return CHANNEL_COUNTER + channelNo;
}
}

View File

@@ -0,0 +1,224 @@
/**
* 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.onewire.device;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.times;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.device.DS2438;
import org.openhab.binding.onewire.internal.device.DS2438.LightSensorType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
/**
* Tests cases for {@link DS2438}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class DS2438Test extends DeviceTestParent<DS2438> {
@Before
public void setupMocks() {
setupMocks(THING_TYPE_MS_TX, DS2438.class);
addChannel(CHANNEL_TEMPERATURE, "Number:Temperature");
addChannel(CHANNEL_HUMIDITY, "Number:Dimensionless");
addChannel(CHANNEL_ABSOLUTE_HUMIDITY, "Number:Density");
addChannel(CHANNEL_DEWPOINT, "Number:Temperature");
addChannel(CHANNEL_VOLTAGE, "Number:Voltage");
addChannel(CHANNEL_CURRENT, "Number:Current");
addChannel(CHANNEL_LIGHT, "Number:Illuminance");
addChannel(CHANNEL_SUPPLYVOLTAGE, "Number:Voltage");
}
@Test
public void temperatureChannel() {
final DS2438 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(10.0));
testDevice.enableChannel(CHANNEL_TEMPERATURE);
testDevice.configureChannels();
inOrder.verify(mockThingHandler).getThing();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_TEMPERATURE), eq(new QuantityType<>("10.0 °C")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void humidityChannel() {
final DS2438 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(10.0));
testDevice.enableChannel(CHANNEL_HUMIDITY);
testDevice.enableChannel(CHANNEL_ABSOLUTE_HUMIDITY);
testDevice.enableChannel(CHANNEL_DEWPOINT);
testDevice.configureChannels();
inOrder.verify(mockThingHandler).getThing();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler, times(2)).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_HUMIDITY), eq(new QuantityType<>("10.0 %")));
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_ABSOLUTE_HUMIDITY),
eq(new QuantityType<>("0.9381970824113001000 g/m³")));
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_DEWPOINT),
eq(new QuantityType<>("-20.31395053870025 °C")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void voltageChannel() {
final DS2438 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(2.0));
testDevice.enableChannel(CHANNEL_VOLTAGE);
testDevice.configureChannels();
inOrder.verify(mockThingHandler).getThing();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_VOLTAGE), eq(new QuantityType<>("2.0 V")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void currentChannel() {
final DS2438 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(2.0));
testDevice.enableChannel(CHANNEL_CURRENT);
testDevice.configureChannels();
inOrder.verify(mockThingHandler).getThing();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_CURRENT), eq(new QuantityType<>("2.0 mA")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void lightChannel() {
final DS2438 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(0.1));
testDevice.enableChannel(CHANNEL_LIGHT);
testDevice.configureChannels();
inOrder.verify(mockThingHandler).getThing();
testDevice.setLightSensorType(LightSensorType.ELABNET_V1);
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_LIGHT), eq(new QuantityType<>("97442 lx")));
testDevice.setLightSensorType(LightSensorType.ELABNET_V2);
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_LIGHT), eq(new QuantityType<>("134 lx")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void supplyVoltageChannel() {
final DS2438 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(2.0));
testDevice.enableChannel(CHANNEL_SUPPLYVOLTAGE);
testDevice.configureChannels();
inOrder.verify(mockThingHandler).getThing();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_SUPPLYVOLTAGE), eq(new QuantityType<>("2.0 V")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void noChannel() {
final DS2438 testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(2.0));
testDevice.configureChannels();
inOrder.verify(mockThingHandler).getThing();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
}

View File

@@ -0,0 +1,135 @@
/**
* 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.onewire.device;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.openhab.binding.onewire.internal.OwBindingConstants.CHANNEL_PRESENT;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Assert;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.device.AbstractOwDevice;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.*;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.type.ChannelTypeUID;
/**
* Abtract test class for onewire devices.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public abstract class DeviceTestParent<T extends AbstractOwDevice> {
private @Nullable Class<T> deviceTestClazz;
@Mock
@NonNullByDefault({})
protected OwBaseThingHandler mockThingHandler;
@Mock
@NonNullByDefault({})
protected OwserverBridgeHandler mockBridgeHandler;
@Mock
@NonNullByDefault({})
protected Thing mockThing;
protected SensorId testSensorId = new SensorId("00.000000000000");
public void setupMocks(ThingTypeUID thingTypeUID, Class<T> deviceTestClazz) {
this.deviceTestClazz = deviceTestClazz;
initMocks(this);
Mockito.when(mockThingHandler.getThing()).thenReturn(mockThing);
Mockito.when(mockThing.getUID()).thenReturn(new ThingUID(thingTypeUID, "testsensor"));
addChannel(CHANNEL_PRESENT, "Switch");
}
public void addChannel(String channelId, String itemType) {
Channel channel = ChannelBuilder.create(new ChannelUID(mockThing.getUID(), channelId), itemType).build();
Mockito.when(mockThing.getChannel(channelId)).thenReturn(channel);
}
public void addChannel(String channelId, String itemType, Configuration channelConfiguration) {
Channel channel = ChannelBuilder.create(new ChannelUID(mockThing.getUID(), channelId), itemType)
.withConfiguration(channelConfiguration).build();
Mockito.when(mockThing.getChannel(channelId)).thenReturn(channel);
}
public void addChannel(String channelId, String itemType, ChannelTypeUID channelTypeUID) {
Channel channel = ChannelBuilder.create(new ChannelUID(mockThing.getUID(), channelId), itemType)
.withType(channelTypeUID).build();
Mockito.when(mockThing.getChannel(channelId)).thenReturn(channel);
}
public T instantiateDevice() {
final Class<T> deviceTestClazz = this.deviceTestClazz;
if (deviceTestClazz == null) {
throw new IllegalStateException("deviceTestClazz is null");
}
try {
Constructor<T> constructor = deviceTestClazz.getConstructor(SensorId.class, OwBaseThingHandler.class);
T testDevice = constructor.newInstance(testSensorId, mockThingHandler);
Assert.assertNotNull(testDevice);
return testDevice;
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException
| InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
public T instantiateDevice(OwSensorType sensorType) {
final Class<T> deviceTestClazz = this.deviceTestClazz;
if (deviceTestClazz == null) {
throw new IllegalStateException("deviceTestClazz is null");
}
try {
Constructor<T> constructor = deviceTestClazz.getConstructor(SensorId.class, OwSensorType.class,
OwBaseThingHandler.class);
T testDevice = constructor.newInstance(testSensorId, sensorType, mockThingHandler);
Assert.assertNotNull(testDevice);
return testDevice;
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException
| InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
public void presenceTest(OnOffType state) {
final T testDevice = instantiateDevice();
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(state);
testDevice.checkPresence(mockBridgeHandler);
inOrder.verify(mockThingHandler).updatePresenceStatus(eq(state));
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
}

View File

@@ -0,0 +1,163 @@
/**
* 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.onewire.device;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.times;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.device.EDS006x;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
/**
* Tests cases for {@link EDS006x}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class EDS006xTest extends DeviceTestParent<EDS006x> {
@Before
public void setupMocks() {
setupMocks(THING_TYPE_EDS_ENV, EDS006x.class);
addChannel(CHANNEL_TEMPERATURE, "Number:Temperature");
addChannel(CHANNEL_HUMIDITY, "Number:Dimensionless");
addChannel(CHANNEL_ABSOLUTE_HUMIDITY, "Number:Density");
addChannel(CHANNEL_DEWPOINT, "Number:Temperature");
addChannel(CHANNEL_LIGHT, "Number:Illuminance");
addChannel(CHANNEL_PRESSURE, "Number:Pressure");
}
@Test
public void temperatureChannel() {
final EDS006x testDevice = instantiateDevice(OwSensorType.EDS0068);
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(10.0));
testDevice.enableChannel(CHANNEL_TEMPERATURE);
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_TEMPERATURE), eq(new QuantityType<>("10.0 °C")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void humidityChannel() {
final EDS006x testDevice = instantiateDevice(OwSensorType.EDS0068);
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(10.0));
testDevice.enableChannel(CHANNEL_HUMIDITY);
testDevice.enableChannel(CHANNEL_ABSOLUTE_HUMIDITY);
testDevice.enableChannel(CHANNEL_DEWPOINT);
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler, times(2)).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_HUMIDITY), eq(new QuantityType<>("10.0 %")));
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_ABSOLUTE_HUMIDITY),
eq(new QuantityType<>("0.9381970824113001000 g/m³")));
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_DEWPOINT),
eq(new QuantityType<>("-20.31395053870025 °C")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void pressureChannel() {
final EDS006x testDevice = instantiateDevice(OwSensorType.EDS0068);
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(2.0));
testDevice.enableChannel(CHANNEL_PRESSURE);
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_PRESSURE), eq(new QuantityType<>("2.0 mbar")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void lightChannel() {
final EDS006x testDevice = instantiateDevice(OwSensorType.EDS0068);
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(100));
testDevice.enableChannel(CHANNEL_LIGHT);
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_LIGHT), eq(new QuantityType<>("100 lx")));
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void noChannel() {
final EDS006x testDevice = instantiateDevice(OwSensorType.EDS0068);
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
try {
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(2.0));
testDevice.configureChannels();
testDevice.refresh(mockBridgeHandler, true);
inOrder.verifyNoMoreInteractions();
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
}

View File

@@ -0,0 +1,148 @@
/**
* 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.onewire.internal;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.openhab.binding.onewire.internal.OwBindingConstants.CONFIG_ID;
import static org.openhab.binding.onewire.internal.OwBindingConstants.THING_TYPE_BASIC;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.binding.onewire.internal.handler.BasicThingHandler;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.test.AbstractThingHandlerTest;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.builder.ThingBuilder;
/**
* Tests cases for {@link BasicThingHandler}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class BasicThingHandlerTest extends AbstractThingHandlerTest {
private static final String TEST_ID = "00.000000000000";
@Before
public void setup() throws OwException {
MockitoAnnotations.initMocks(this);
initializeBridge();
final Bridge bridge = this.bridge;
if (bridge == null) {
Assert.fail("bridge is null");
return;
}
thingConfiguration.put(CONFIG_ID, TEST_ID);
thing = ThingBuilder.create(THING_TYPE_BASIC, "testthing").withLabel("Test thing")
.withConfiguration(new Configuration(thingConfiguration)).withProperties(thingProperties)
.withBridge(bridge.getUID()).build();
final Thing thing = this.thing;
if (thing == null) {
Assert.fail("thing is null");
return;
}
thingHandler = new BasicThingHandler(thing, stateProvider) {
@Override
protected @Nullable Bridge getBridge() {
return bridge;
}
};
initializeHandlerMocks();
}
@Test
public void testInitializationEndsWithUnknown() throws OwException {
final ThingHandler thingHandler = this.thingHandler;
if (thingHandler == null) {
Assert.fail("thingHandler is null");
return;
}
Mockito.doAnswer(answer -> {
return OwSensorType.DS2401;
}).when(secondBridgeHandler).getType(any());
thingHandler.initialize();
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
}
@Test
public void testRefreshAnalog() throws OwException {
final OwBaseThingHandler thingHandler = this.thingHandler;
final InOrder inOrder = this.inOrder;
if (thingHandler == null || inOrder == null) {
Assert.fail("prerequisite is null");
return;
}
Mockito.doAnswer(answer -> {
return OwSensorType.DS18B20;
}).when(secondBridgeHandler).getType(any());
thingHandler.initialize();
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
thingHandler.refresh(bridgeHandler, System.currentTimeMillis());
inOrder.verify(bridgeHandler, times(1)).checkPresence(new SensorId(TEST_ID));
inOrder.verify(bridgeHandler, times(1)).readDecimalType(eq(new SensorId(TEST_ID)), any());
inOrder.verifyNoMoreInteractions();
}
@Test
public void testRefreshDigital() throws OwException {
final OwBaseThingHandler thingHandler = this.thingHandler;
final InOrder inOrder = this.inOrder;
if (thingHandler == null || inOrder == null) {
Assert.fail("prerequisite is null");
return;
}
Mockito.doAnswer(answer -> {
return OwSensorType.DS2408;
}).when(secondBridgeHandler).getType(any());
thingHandler.initialize();
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
thingHandler.refresh(bridgeHandler, System.currentTimeMillis());
inOrder.verify(bridgeHandler, times(1)).checkPresence(new SensorId(TEST_ID));
inOrder.verify(bridgeHandler, times(2)).readBitSet(eq(new SensorId(TEST_ID)), any());
inOrder.verifyNoMoreInteractions();
}
}

View File

@@ -0,0 +1,130 @@
/**
* 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.onewire.internal;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.openhab.binding.onewire.internal.handler.EDSSensorThingHandler;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.test.AbstractThingHandlerTest;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.*;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;
/**
* Tests cases for {@link EDSSensorThingHandler}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class EDSSensorThingHandlerTest extends AbstractThingHandlerTest {
private static final String TEST_ID = "00.000000000000";
private static final ThingUID THING_UID = new ThingUID(THING_TYPE_EDS_ENV, "testthing");
private static final ChannelUID CHANNEL_UID_TEMPERATURE = new ChannelUID(THING_UID, CHANNEL_TEMPERATURE);
private static final ChannelUID CHANNEL_UID_HUMIDITY = new ChannelUID(THING_UID, CHANNEL_HUMIDITY);
private static final ChannelUID CHANNEL_UID_ABSOLUTE_HUMIDITY = new ChannelUID(THING_UID,
CHANNEL_ABSOLUTE_HUMIDITY);
private static final ChannelUID CHANNEL_UID_DEWPOINT = new ChannelUID(THING_UID, CHANNEL_DEWPOINT);
@Before
public void setup() throws OwException {
MockitoAnnotations.initMocks(this);
initializeBridge();
final Bridge bridge = this.bridge;
if (bridge == null) {
Assert.fail("bridge is null");
return;
}
thingConfiguration.put(CONFIG_ID, TEST_ID);
channels.add(ChannelBuilder.create(CHANNEL_UID_TEMPERATURE, "Number:Temperature").build());
channels.add(ChannelBuilder.create(CHANNEL_UID_HUMIDITY, "Number:Dimensionless").build());
channels.add(ChannelBuilder.create(CHANNEL_UID_ABSOLUTE_HUMIDITY, "Number:Density").build());
channels.add(ChannelBuilder.create(CHANNEL_UID_DEWPOINT, "Number:Temperature").build());
thing = ThingBuilder.create(THING_TYPE_EDS_ENV, "testthing").withLabel("Test thing").withChannels(channels)
.withConfiguration(new Configuration(thingConfiguration)).withProperties(thingProperties)
.withBridge(bridge.getUID()).build();
final Thing thing = this.thing;
if (thing == null) {
Assert.fail("thing is null");
return;
}
thingHandler = new EDSSensorThingHandler(thing, stateProvider) {
@Override
protected @Nullable Bridge getBridge() {
return bridge;
}
};
initializeHandlerMocks();
Mockito.doAnswer(answer -> {
return new OwPageBuffer("EDS0065 ".getBytes());
}).when(secondBridgeHandler).readPages(any());
}
@Test
public void testInitializationEndsWithUnknown() {
final ThingHandler thingHandler = this.thingHandler;
if (thingHandler == null) {
Assert.fail("thingHandler is null");
return;
}
thingHandler.initialize();
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
}
@Test
public void testRefresh() throws OwException {
final OwBaseThingHandler thingHandler = this.thingHandler;
final InOrder inOrder = this.inOrder;
if (thingHandler == null || inOrder == null) {
Assert.fail("prerequisite is null");
return;
}
thingHandler.initialize();
// needed to determine initialization is finished
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
thingHandler.refresh(bridgeHandler, System.currentTimeMillis());
inOrder.verify(bridgeHandler, times(1)).checkPresence(new SensorId(TEST_ID));
inOrder.verify(bridgeHandler, times(2)).readDecimalType(eq(new SensorId(TEST_ID)), any());
inOrder.verifyNoMoreInteractions();
}
}

View File

@@ -0,0 +1,126 @@
/**
* 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.onewire.internal;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.openhab.binding.onewire.internal.OwBindingConstants.CONFIG_ID;
import static org.openhab.binding.onewire.internal.OwBindingConstants.THING_TYPE_MS_TX;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.openhab.binding.onewire.internal.device.OwSensorType;
import org.openhab.binding.onewire.internal.handler.BasicMultisensorThingHandler;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.test.AbstractThingHandlerTest;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.builder.ThingBuilder;
/**
* Tests cases for {@link BasicMultisensorThingHandler}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class MultisensorThingHandlerTest extends AbstractThingHandlerTest {
private static final String TEST_ID = "00.000000000000";
@Before
public void setup() throws OwException {
MockitoAnnotations.initMocks(this);
initializeBridge();
final Bridge bridge = this.bridge;
if (bridge == null) {
Assert.fail("bridge is null");
return;
}
thingConfiguration.put(CONFIG_ID, TEST_ID);
thing = ThingBuilder.create(THING_TYPE_MS_TX, "testthing").withLabel("Test thing").withChannels(channels)
.withConfiguration(new Configuration(thingConfiguration)).withProperties(thingProperties)
.withBridge(bridge.getUID()).build();
final Thing thing = this.thing;
if (thing == null) {
Assert.fail("thing is null");
return;
}
thingHandler = new BasicMultisensorThingHandler(thing, stateProvider) {
@Override
protected @Nullable Bridge getBridge() {
return bridge;
}
};
initializeHandlerMocks();
Mockito.doAnswer(answer -> {
return OwSensorType.DS2438;
}).when(secondBridgeHandler).getType(any());
Mockito.doAnswer(answer -> {
OwPageBuffer pageBuffer = new OwPageBuffer(8);
pageBuffer.setByte(3, 0, (byte) 0x19);
return pageBuffer;
}).when(secondBridgeHandler).readPages(any());
}
@Test
public void testInitializationEndsWithUnknown() {
final ThingHandler thingHandler = this.thingHandler;
if (thingHandler == null) {
Assert.fail("thingHandler is null");
return;
}
thingHandler.initialize();
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
}
@Test
public void testRefresh() throws OwException {
final OwBaseThingHandler thingHandler = this.thingHandler;
final InOrder inOrder = this.inOrder;
if (thingHandler == null || inOrder == null) {
Assert.fail("prerequisite is null");
return;
}
thingHandler.initialize();
// needed to determine initialization is finished
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
thingHandler.refresh(bridgeHandler, System.currentTimeMillis());
inOrder.verify(bridgeHandler, times(1)).checkPresence(new SensorId(TEST_ID));
inOrder.verify(bridgeHandler, times(3)).readDecimalType(eq(new SensorId(TEST_ID)), any());
inOrder.verifyNoMoreInteractions();
}
}

View File

@@ -0,0 +1,171 @@
/**
* 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.onewire.internal;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.binding.onewire.internal.owserver.OwserverConnection;
import org.openhab.binding.onewire.internal.owserver.OwserverConnectionState;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.test.java.JavaTest;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.binding.ThingHandlerCallback;
import org.openhab.core.thing.binding.builder.BridgeBuilder;
/**
* Tests cases for {@link OwserverBridgeHandler}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwserverBridgeHandlerTest extends JavaTest {
private static final String TEST_HOST = "foo.bar";
private static final int TEST_PORT = 4711;
Map<String, Object> bridgeProperties = new HashMap<>();
@Mock
@NonNullByDefault({})
private OwserverConnection owserverConnection;
@Mock
@NonNullByDefault({})
private ThingHandlerCallback thingHandlerCallback;
private @Nullable OwserverBridgeHandler bridgeHandler;
private @Nullable Bridge bridge;
@Before
public void setup() {
bridgeProperties.put(CONFIG_ADDRESS, TEST_HOST);
bridgeProperties.put(CONFIG_PORT, TEST_PORT);
initMocks(this);
bridge = BridgeBuilder.create(THING_TYPE_OWSERVER, "owserver").withLabel("owserver")
.withConfiguration(new Configuration(bridgeProperties)).build();
doAnswer(answer -> {
((Thing) answer.getArgument(0)).setStatusInfo(answer.getArgument(1));
return null;
}).when(thingHandlerCallback).statusUpdated(any(), any());
final Bridge bridge = this.bridge;
if (bridge == null) {
Assert.fail("bridge is null");
return;
}
final OwserverBridgeHandler bridgeHandler = new OwserverBridgeHandler(bridge, owserverConnection);
bridgeHandler.getThing().setHandler(bridgeHandler);
bridgeHandler.setCallback(thingHandlerCallback);
this.bridgeHandler = bridgeHandler;
}
@After
public void tearDown() {
final OwserverBridgeHandler bridgeHandler = this.bridgeHandler;
if (bridgeHandler != null) {
bridgeHandler.dispose();
}
}
@Test
public void testInitializationStartsConnectionWithOptions() {
final OwserverBridgeHandler bridgeHandler = this.bridgeHandler;
if (bridgeHandler == null) {
Assert.fail("bridgeHandler is null");
return;
}
bridgeHandler.initialize();
Mockito.verify(owserverConnection).setHost(TEST_HOST);
Mockito.verify(owserverConnection).setPort(TEST_PORT);
Mockito.verify(owserverConnection, timeout(5000)).start();
}
@Test
public void testInitializationReportsRefreshableOnSuccessfullConnection() {
final OwserverBridgeHandler bridgeHandler = this.bridgeHandler;
if (bridgeHandler == null) {
Assert.fail("bridgeHandler is null");
return;
}
Mockito.doAnswer(answer -> {
bridgeHandler.reportConnectionState(OwserverConnectionState.OPENED);
return null;
}).when(owserverConnection).start();
bridgeHandler.initialize();
ArgumentCaptor<ThingStatusInfo> statusCaptor = ArgumentCaptor.forClass(ThingStatusInfo.class);
waitForAssert(() -> {
verify(thingHandlerCallback, times(2)).statusUpdated(eq(bridge), statusCaptor.capture());
});
assertThat(statusCaptor.getAllValues().get(0).getStatus(), is(ThingStatus.UNKNOWN));
assertThat(statusCaptor.getAllValues().get(1).getStatus(), is(ThingStatus.ONLINE));
waitForAssert(() -> assertTrue(bridgeHandler.isRefreshable()));
}
@Test
public void testInitializationReportsNotRefreshableOnFailedConnection() {
final OwserverBridgeHandler bridgeHandler = this.bridgeHandler;
if (bridgeHandler == null) {
Assert.fail("bridgeHandler is null");
return;
}
Mockito.doAnswer(answer -> {
bridgeHandler.reportConnectionState(OwserverConnectionState.FAILED);
return null;
}).when(owserverConnection).start();
bridgeHandler.initialize();
ArgumentCaptor<ThingStatusInfo> statusCaptor = ArgumentCaptor.forClass(ThingStatusInfo.class);
waitForAssert(() -> {
verify(thingHandlerCallback, times(2)).statusUpdated(eq(bridge), statusCaptor.capture());
});
assertThat(statusCaptor.getAllValues().get(0).getStatus(), is(ThingStatus.UNKNOWN));
assertThat(statusCaptor.getAllValues().get(1).getStatus(), is(ThingStatus.OFFLINE));
waitForAssert(() -> assertFalse(bridgeHandler.isRefreshable()));
}
}

View File

@@ -0,0 +1,224 @@
/**
* 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.onewire.owserver;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.OwPageBuffer;
import org.openhab.binding.onewire.internal.SensorId;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.binding.onewire.internal.owserver.OwserverConnection;
import org.openhab.binding.onewire.internal.owserver.OwserverConnectionState;
import org.openhab.binding.onewire.test.OwserverTestServer;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.test.TestPortUtil;
import org.openhab.core.test.java.JavaTest;
import org.openhab.core.types.State;
/**
* Tests cases for {@link OwserverConnection}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwserverConnectionTest extends JavaTest {
private static final String TEST_HOST = "127.0.0.1";
private @Nullable OwserverTestServer testServer;
private @Nullable OwserverConnection owserverConnection;
@Mock
private @NonNullByDefault({}) OwserverBridgeHandler bridgeHandler;
private int testPort;
@Before
public void setup() throws Exception {
initMocks(this);
CompletableFuture<Boolean> serverStarted = new CompletableFuture<>();
testPort = TestPortUtil.findFreePort();
try {
final OwserverTestServer testServer = new OwserverTestServer(testPort);
testServer.startServer(serverStarted);
this.testServer = testServer;
} catch (IOException e) {
fail("could not start test server");
}
final OwserverConnection owserverConnection = new OwserverConnection(bridgeHandler);
owserverConnection.setHost(TEST_HOST);
owserverConnection.setPort(testPort);
this.owserverConnection = owserverConnection;
serverStarted.get(); // wait for the server thread to start
}
@After
public void tearDown() {
try {
final OwserverTestServer testServer = this.testServer;
if (testServer != null) {
testServer.stopServer();
}
} catch (IOException e) {
fail("could not stop test server");
}
}
@Test
public void successfullConnectionReportedToBridgeHandler() {
final OwserverConnection owserverConnection = this.owserverConnection;
if (owserverConnection == null) {
Assert.fail("connection is null");
return;
}
owserverConnection.start();
Mockito.verify(bridgeHandler).reportConnectionState(OwserverConnectionState.OPENED);
}
@Test
public void failedConnectionReportedToBridgeHandler() {
final OwserverConnection owserverConnection = this.owserverConnection;
if (owserverConnection == null) {
Assert.fail("connection is null");
return;
}
owserverConnection.setPort(1);
owserverConnection.start();
Mockito.verify(bridgeHandler, timeout(100)).reportConnectionState(OwserverConnectionState.FAILED);
}
@Test
public void testGetDirectory() {
final OwserverConnection owserverConnection = this.owserverConnection;
if (owserverConnection == null) {
Assert.fail("connection is null");
return;
}
owserverConnection.start();
try {
List<SensorId> directory = owserverConnection.getDirectory("/");
assertEquals(3, directory.size());
assertEquals(new SensorId("/00.0123456789ab"), directory.get(0));
assertEquals(new SensorId("/00.0123456789ac"), directory.get(1));
assertEquals(new SensorId("/00.0123456789ad"), directory.get(2));
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void testCheckPresence() {
final OwserverConnection owserverConnection = this.owserverConnection;
if (owserverConnection == null) {
Assert.fail("connection is null");
return;
}
owserverConnection.start();
State presence = owserverConnection.checkPresence("present");
assertEquals(OnOffType.ON, presence);
presence = owserverConnection.checkPresence("notpresent");
assertEquals(OnOffType.OFF, presence);
}
@Test
public void testReadDecimalType() {
final OwserverConnection owserverConnection = this.owserverConnection;
if (owserverConnection == null) {
Assert.fail("connection is null");
return;
}
owserverConnection.start();
try {
DecimalType number = (DecimalType) owserverConnection.readDecimalType("testsensor/decimal");
assertEquals(17.4, number.doubleValue(), 0.01);
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void testReadDecimalTypeArray() {
final OwserverConnection owserverConnection = this.owserverConnection;
if (owserverConnection == null) {
Assert.fail("connection is null");
return;
}
owserverConnection.start();
try {
List<State> numbers = owserverConnection.readDecimalTypeArray("testsensor/decimalarray");
assertEquals(3834, ((DecimalType) numbers.get(0)).intValue());
assertEquals(0, ((DecimalType) numbers.get(1)).intValue());
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void testGetPages() {
final OwserverConnection owserverConnection = this.owserverConnection;
if (owserverConnection == null) {
Assert.fail("connection is null");
return;
}
owserverConnection.start();
try {
OwPageBuffer pageBuffer = owserverConnection.readPages("testsensor");
assertEquals(31, pageBuffer.getByte(5, 7));
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
@Test
public void testWriteDecimalType() {
final OwserverConnection owserverConnection = this.owserverConnection;
if (owserverConnection == null) {
Assert.fail("connection is null");
return;
}
owserverConnection.start();
try {
owserverConnection.writeDecimalType("testsensor/decimal", new DecimalType(2009));
Mockito.verify(bridgeHandler, never()).reportConnectionState(OwserverConnectionState.FAILED);
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
}

View File

@@ -0,0 +1,143 @@
/**
* 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.onewire.test;
import static org.mockito.ArgumentMatchers.any;
import static org.openhab.binding.onewire.internal.OwBindingConstants.THING_TYPE_OWSERVER;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.After;
import org.junit.Assert;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.test.java.JavaTest;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerCallback;
import org.openhab.core.thing.binding.builder.BridgeBuilder;
/**
* Base class for thing handler tests.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public abstract class AbstractThingHandlerTest extends JavaTest {
protected Map<String, Object> bridgeProperties = new HashMap<>();
protected Map<String, String> thingProperties = new HashMap<>();
protected Map<String, Object> thingConfiguration = new HashMap<>();
protected Map<String, Object> channelProperties = new HashMap<>();
@Mock
@NonNullByDefault({})
protected ThingHandlerCallback thingHandlerCallback;
@Mock
@NonNullByDefault({})
protected OwDynamicStateDescriptionProvider stateProvider;
@Mock
@NonNullByDefault({})
protected ThingHandlerCallback bridgeHandlerCallback;
@Mock
@NonNullByDefault({})
protected OwserverBridgeHandler bridgeHandler;
@Mock
@NonNullByDefault({})
protected OwserverBridgeHandler secondBridgeHandler;
protected List<Channel> channels = new ArrayList<>();
protected @Nullable Bridge bridge;
protected @Nullable Thing thing;
protected @Nullable OwBaseThingHandler thingHandler;
protected @Nullable InOrder inOrder;
@After
public void tearDown() {
final ThingHandler thingHandler = this.thingHandler;
if (thingHandler != null) {
thingHandler.dispose();
}
}
protected void initializeHandlerMocks() {
final ThingHandler thingHandler = this.thingHandler;
if (thingHandler == null) {
Assert.fail("thingHandler is null");
return;
}
thingHandler.getThing().setHandler(thingHandler);
thingHandler.setCallback(thingHandlerCallback);
Mockito.doAnswer(answer -> {
((Thing) answer.getArgument(0)).setStatusInfo(answer.getArgument(1));
return null;
}).when(thingHandlerCallback).statusUpdated(any(), any());
inOrder = Mockito.inOrder(bridgeHandler);
}
public void initializeBridge() throws OwException {
bridgeProperties = new HashMap<>();
final Bridge bridge = BridgeBuilder.create(THING_TYPE_OWSERVER, "testbridge").withLabel("Test Bridge")
.withConfiguration(new Configuration(bridgeProperties)).build();
bridge.setHandler(bridgeHandler);
this.bridge = bridge;
Mockito.doAnswer(answer -> {
((Thing) answer.getArgument(0)).setStatusInfo(answer.getArgument(1));
return null;
}).when(bridgeHandlerCallback).statusUpdated(any(), any());
Mockito.doAnswer(answer -> OnOffType.ON).when(bridgeHandler).checkPresence(any());
Mockito.doAnswer(answer -> new DecimalType(10)).when(bridgeHandler).readDecimalType(any(), any());
Mockito.doAnswer(answer -> new BitSet(8)).when(bridgeHandler).readBitSet(any(), any());
Mockito.doAnswer(answer -> {
final OwBaseThingHandler thingHandler = this.thingHandler;
if (thingHandler == null) {
Assert.fail("thingHandler is null");
return null;
}
thingHandler.updateSensorProperties(secondBridgeHandler);
thingHandler.initialize();
return null;
}).when(bridgeHandler).scheduleForPropertiesUpdate(any());
}
}

View File

@@ -0,0 +1,142 @@
/**
* 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.onewire.test;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Assert;
import org.openhab.binding.onewire.internal.OwException;
import org.openhab.binding.onewire.internal.OwPageBuffer;
import org.openhab.binding.onewire.internal.owserver.OwserverPacket;
import org.openhab.binding.onewire.internal.owserver.OwserverPacketType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link OwserverTestServer} defines a server for testing the OwserverConnection class
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class OwserverTestServer {
private final Logger logger = LoggerFactory.getLogger(OwserverTestServer.class);
private final ServerSocket serverSocket;
private boolean isRunning = false;
public OwserverTestServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
public void startServer(CompletableFuture<Boolean> serverStarted) throws IOException {
isRunning = true;
new Thread() {
@Override
public void run() {
OwserverPacket receivedPacket;
List<OwserverPacket> answerPackets;
serverStarted.complete(true);
try {
while (isRunning) {
final Socket connectionSocket = serverSocket.accept();
final DataInputStream inputStream = new DataInputStream(connectionSocket.getInputStream());
final DataOutputStream outputStream = new DataOutputStream(connectionSocket.getOutputStream());
receivedPacket = new OwserverPacket(inputStream, OwserverPacketType.REQUEST);
logger.debug("received {}", receivedPacket);
answerPackets = processPacket(receivedPacket);
answerPackets.forEach(answerPacket -> {
logger.debug("answering {}", answerPacket);
try {
outputStream.write(answerPacket.toBytes());
} catch (IOException e) {
logger.error("I/O Error: {}", e.getMessage());
}
});
}
} catch (IOException e) {
logger.error("I/O Error: {}", e.getMessage());
} catch (OwException e) {
Assert.fail("caught unexpected OwException");
}
}
}.start();
}
public void stopServer() throws IOException {
isRunning = false;
serverSocket.close();
}
private List<OwserverPacket> processPacket(OwserverPacket inputPacket) {
List<OwserverPacket> returnPackets = new ArrayList<>();
OwserverPacket returnPacket = new OwserverPacket(OwserverPacketType.RETURN);
switch (inputPacket.getMessageType()) {
case NOP:
returnPacket.setPayload("");
returnPackets.add(returnPacket);
break;
case DIRALL:
returnPacket.setPayload("/00.0123456789ab,/00.0123456789ac,/00.0123456789ad,/statistics");
returnPackets.add(returnPacket);
returnPacket = new OwserverPacket(OwserverPacketType.RETURN);
break;
case PRESENT:
switch (inputPacket.getPayloadString()) {
case "present":
break;
default:
returnPacket.setReturnCode(-1);
}
returnPacket.setPayload(inputPacket.getPayloadString());
returnPackets.add(returnPacket);
break;
case READ:
switch (inputPacket.getPayloadString()) {
case "testsensor/pages/page.ALL":
OwPageBuffer pageBuffer = new OwPageBuffer(8);
pageBuffer.setByte(5, 7, (byte) 31);
returnPacket.setPayload(pageBuffer);
returnPackets.add(returnPacket);
break;
case "testsensor/decimal":
returnPacket.setPayload(" 17.4");
returnPackets.add(returnPacket);
break;
case "testsensor/decimalarray":
returnPacket.setPayload(" 3834, 0");
returnPackets.add(returnPacket);
break;
default:
}
break;
case WRITE:
returnPackets.add(returnPacket);
break;
default:
}
return returnPackets;
}
}