[gce] Avoid conflicts with things file defined (#13526)
* Avoiding dynamic creation of channels when channels already exists Signed-off-by: clinique <gael@lhopital.org>
This commit is contained in:
parent
c63e596680
commit
e3d0039675
|
@ -14,7 +14,6 @@ package org.openhab.binding.gce.internal;
|
||||||
|
|
||||||
import static org.openhab.binding.gce.internal.GCEBindingConstants.IPXV3_THING_TYPE;
|
import static org.openhab.binding.gce.internal.GCEBindingConstants.IPXV3_THING_TYPE;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
@ -36,7 +35,7 @@ import org.osgi.service.component.annotations.Component;
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.gce")
|
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.gce")
|
||||||
public class GCEHandlerFactory extends BaseThingHandlerFactory {
|
public class GCEHandlerFactory extends BaseThingHandlerFactory {
|
||||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(IPXV3_THING_TYPE);
|
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(IPXV3_THING_TYPE);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class Ipx800DeviceConnector extends Thread {
|
||||||
private static final String ENDL = "\r\n";
|
private static final String ENDL = "\r\n";
|
||||||
|
|
||||||
private final String hostname;
|
private final String hostname;
|
||||||
public final int portNumber;
|
private final int portNumber;
|
||||||
private @Nullable M2MMessageParser parser;
|
private @Nullable M2MMessageParser parser;
|
||||||
|
|
||||||
private @NonNullByDefault({}) Socket client;
|
private @NonNullByDefault({}) Socket client;
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -79,11 +80,12 @@ public class Ipx800v3Handler extends BaseThingHandler implements Ipx800EventList
|
||||||
|
|
||||||
private @NonNullByDefault({}) Ipx800Configuration configuration;
|
private @NonNullByDefault({}) Ipx800Configuration configuration;
|
||||||
private @NonNullByDefault({}) Ipx800DeviceConnector connector;
|
private @NonNullByDefault({}) Ipx800DeviceConnector connector;
|
||||||
private @Nullable M2MMessageParser parser;
|
|
||||||
private @NonNullByDefault({}) StatusFileInterpreter statusFile;
|
private @NonNullByDefault({}) StatusFileInterpreter statusFile;
|
||||||
private @Nullable ScheduledFuture<?> refreshJob;
|
|
||||||
|
|
||||||
private final Map<String, PortData> portDatas = new HashMap<>();
|
private Optional<M2MMessageParser> parser = Optional.empty();
|
||||||
|
private Optional<ScheduledFuture<?>> refreshJob = Optional.empty();
|
||||||
|
|
||||||
|
private final Map<String, @Nullable PortData> portDatas = new HashMap<>();
|
||||||
|
|
||||||
private class LongPressEvaluator implements Runnable {
|
private class LongPressEvaluator implements Runnable {
|
||||||
private final ZonedDateTime referenceTime;
|
private final ZonedDateTime referenceTime;
|
||||||
|
@ -97,10 +99,10 @@ public class Ipx800v3Handler extends BaseThingHandler implements Ipx800EventList
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("PMD.CompareObjectsWithEquals")
|
|
||||||
public void run() {
|
public void run() {
|
||||||
PortData currentData = portDatas.get(port);
|
PortData currentData = portDatas.get(port);
|
||||||
if (currentData != null && currentData.getValue() == 1 && currentData.getTimestamp() == referenceTime) {
|
if (currentData != null && currentData.getValue() == 1
|
||||||
|
&& referenceTime.equals(currentData.getTimestamp())) {
|
||||||
triggerChannel(eventChannelId, EVENT_LONG_PRESS);
|
triggerChannel(eventChannelId, EVENT_LONG_PRESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +115,6 @@ public class Ipx800v3Handler extends BaseThingHandler implements Ipx800EventList
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
|
|
||||||
configuration = getConfigAs(Ipx800Configuration.class);
|
configuration = getConfigAs(Ipx800Configuration.class);
|
||||||
|
|
||||||
logger.debug("Initializing IPX800 handler for uid '{}'", getThing().getUID());
|
logger.debug("Initializing IPX800 handler for uid '{}'", getThing().getUID());
|
||||||
|
@ -124,55 +125,57 @@ public class Ipx800v3Handler extends BaseThingHandler implements Ipx800EventList
|
||||||
discoverAttributes();
|
discoverAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
connector = new Ipx800DeviceConnector(configuration.hostname, configuration.portNumber, getThing().getUID());
|
|
||||||
parser = new M2MMessageParser(connector, this);
|
|
||||||
|
|
||||||
updateStatus(ThingStatus.UNKNOWN);
|
|
||||||
|
|
||||||
refreshJob = scheduler.scheduleWithFixedDelay(statusFile::read, 3000, configuration.pullInterval,
|
|
||||||
TimeUnit.MILLISECONDS);
|
|
||||||
|
|
||||||
connector.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
if (refreshJob != null) {
|
|
||||||
refreshJob.cancel(true);
|
|
||||||
refreshJob = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connector != null) {
|
|
||||||
connector.destroyAndExit();
|
|
||||||
}
|
|
||||||
parser = null;
|
|
||||||
|
|
||||||
portDatas.values().stream().forEach(portData -> {
|
|
||||||
portData.destroy();
|
|
||||||
});
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void discoverAttributes() {
|
|
||||||
final Map<String, String> properties = new HashMap<>();
|
|
||||||
|
|
||||||
properties.put(Thing.PROPERTY_VENDOR, "GCE Electronics");
|
|
||||||
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, statusFile.getElement(StatusEntry.VERSION));
|
|
||||||
properties.put(Thing.PROPERTY_MAC_ADDRESS, statusFile.getElement(StatusEntry.CONFIG_MAC));
|
|
||||||
updateProperties(properties);
|
|
||||||
|
|
||||||
ThingBuilder thingBuilder = editThing();
|
|
||||||
List<Channel> channels = new ArrayList<>(getThing().getChannels());
|
List<Channel> channels = new ArrayList<>(getThing().getChannels());
|
||||||
|
ThingBuilder thingBuilder = editThing();
|
||||||
PortDefinition.asStream().forEach(portDefinition -> {
|
PortDefinition.asStream().forEach(portDefinition -> {
|
||||||
int nbElements = statusFile.getMaxNumberofNodeType(portDefinition);
|
int nbElements = statusFile.getMaxNumberofNodeType(portDefinition);
|
||||||
for (int i = 0; i < nbElements; i++) {
|
for (int i = 0; i < nbElements; i++) {
|
||||||
createChannels(portDefinition, i, channels);
|
createChannels(portDefinition, i, channels);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
thingBuilder.withChannels(channels);
|
thingBuilder.withChannels(channels);
|
||||||
updateThing(thingBuilder.build());
|
updateThing(thingBuilder.build());
|
||||||
|
|
||||||
|
connector = new Ipx800DeviceConnector(configuration.hostname, configuration.portNumber, getThing().getUID());
|
||||||
|
parser = Optional.of(new M2MMessageParser(connector, this));
|
||||||
|
|
||||||
|
updateStatus(ThingStatus.UNKNOWN);
|
||||||
|
|
||||||
|
refreshJob = Optional.of(scheduler.scheduleWithFixedDelay(statusFile::read, 3000, configuration.pullInterval,
|
||||||
|
TimeUnit.MILLISECONDS));
|
||||||
|
|
||||||
|
connector.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
refreshJob.ifPresent(job -> job.cancel(true));
|
||||||
|
refreshJob = Optional.empty();
|
||||||
|
|
||||||
|
if (connector != null) {
|
||||||
|
connector.destroyAndExit();
|
||||||
|
}
|
||||||
|
parser = Optional.empty();
|
||||||
|
|
||||||
|
portDatas.values().stream().forEach(portData -> {
|
||||||
|
if (portData != null) {
|
||||||
|
portData.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void discoverAttributes() {
|
||||||
|
updateProperties(Map.of(Thing.PROPERTY_VENDOR, "GCE Electronics", Thing.PROPERTY_FIRMWARE_VERSION,
|
||||||
|
statusFile.getElement(StatusEntry.VERSION), Thing.PROPERTY_MAC_ADDRESS,
|
||||||
|
statusFile.getElement(StatusEntry.CONFIG_MAC)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addIfChannelAbsent(ChannelBuilder channelBuilder, List<Channel> channels) {
|
||||||
|
Channel newChannel = channelBuilder.build();
|
||||||
|
if (channels.stream().noneMatch(c -> c.getUID().equals(newChannel.getUID()))) {
|
||||||
|
channels.add(newChannel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createChannels(PortDefinition portDefinition, int portIndex, List<Channel> channels) {
|
private void createChannels(PortDefinition portDefinition, int portIndex, List<Channel> channels) {
|
||||||
|
@ -184,32 +187,32 @@ public class Ipx800v3Handler extends BaseThingHandler implements Ipx800EventList
|
||||||
ChannelTypeUID channelType = new ChannelTypeUID(BINDING_ID, advancedChannelTypeName);
|
ChannelTypeUID channelType = new ChannelTypeUID(BINDING_ID, advancedChannelTypeName);
|
||||||
switch (portDefinition) {
|
switch (portDefinition) {
|
||||||
case ANALOG:
|
case ANALOG:
|
||||||
channels.add(ChannelBuilder.create(mainChannelUID, CoreItemFactory.NUMBER)
|
addIfChannelAbsent(ChannelBuilder.create(mainChannelUID, CoreItemFactory.NUMBER)
|
||||||
.withLabel("Analog Input " + ndx).withType(channelType).build());
|
.withLabel("Analog Input " + ndx).withType(channelType), channels);
|
||||||
channels.add(ChannelBuilder
|
addIfChannelAbsent(
|
||||||
.create(new ChannelUID(groupUID, ndx + "-voltage"), "Number:ElectricPotential")
|
ChannelBuilder.create(new ChannelUID(groupUID, ndx + "-voltage"), "Number:ElectricPotential")
|
||||||
.withLabel("Voltage " + ndx).withType(new ChannelTypeUID(BINDING_ID, CHANNEL_VOLTAGE)).build());
|
.withType(new ChannelTypeUID(BINDING_ID, CHANNEL_VOLTAGE)).withLabel("Voltage " + ndx),
|
||||||
|
channels);
|
||||||
break;
|
break;
|
||||||
case CONTACT:
|
case CONTACT:
|
||||||
channels.add(ChannelBuilder.create(mainChannelUID, CoreItemFactory.CONTACT).withLabel("Contact " + ndx)
|
addIfChannelAbsent(ChannelBuilder.create(mainChannelUID, CoreItemFactory.CONTACT)
|
||||||
.withType(channelType).build());
|
.withLabel("Contact " + ndx).withType(channelType), channels);
|
||||||
channels.add(ChannelBuilder.create(new ChannelUID(groupUID, ndx + "-event"), null)
|
addIfChannelAbsent(ChannelBuilder.create(new ChannelUID(groupUID, ndx + "-event"), null)
|
||||||
.withLabel("Contact " + ndx + " Event").withKind(ChannelKind.TRIGGER)
|
|
||||||
.withType(new ChannelTypeUID(BINDING_ID, TRIGGER_CONTACT + (portIndex < 8 ? "" : "Advanced")))
|
.withType(new ChannelTypeUID(BINDING_ID, TRIGGER_CONTACT + (portIndex < 8 ? "" : "Advanced")))
|
||||||
.build());
|
.withLabel("Contact " + ndx + " Event").withKind(ChannelKind.TRIGGER), channels);
|
||||||
break;
|
break;
|
||||||
case COUNTER:
|
case COUNTER:
|
||||||
channels.add(ChannelBuilder.create(mainChannelUID, CoreItemFactory.NUMBER).withLabel("Counter " + ndx)
|
addIfChannelAbsent(ChannelBuilder.create(mainChannelUID, CoreItemFactory.NUMBER)
|
||||||
.withType(channelType).build());
|
.withLabel("Counter " + ndx).withType(channelType), channels);
|
||||||
break;
|
break;
|
||||||
case RELAY:
|
case RELAY:
|
||||||
channels.add(ChannelBuilder.create(mainChannelUID, CoreItemFactory.SWITCH).withLabel("Relay " + ndx)
|
addIfChannelAbsent(ChannelBuilder.create(mainChannelUID, CoreItemFactory.SWITCH)
|
||||||
.withType(channelType).build());
|
.withLabel("Relay " + ndx).withType(channelType), channels);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
channels.add(ChannelBuilder.create(new ChannelUID(groupUID, ndx + "-duration"), "Number:Time")
|
addIfChannelAbsent(ChannelBuilder.create(new ChannelUID(groupUID, ndx + "-duration"), "Number:Time")
|
||||||
.withLabel("Previous state duration " + ndx)
|
.withType(new ChannelTypeUID(BINDING_ID, CHANNEL_LAST_STATE_DURATION))
|
||||||
.withType(new ChannelTypeUID(BINDING_ID, CHANNEL_LAST_STATE_DURATION)).build());
|
.withLabel("Previous state duration " + ndx), channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -227,16 +230,11 @@ public class Ipx800v3Handler extends BaseThingHandler implements Ipx800EventList
|
||||||
if (portDefinition == PortDefinition.ANALOG) { // For analog values, check histeresis
|
if (portDefinition == PortDefinition.ANALOG) { // For analog values, check histeresis
|
||||||
AnalogInputConfiguration config = configuration.as(AnalogInputConfiguration.class);
|
AnalogInputConfiguration config = configuration.as(AnalogInputConfiguration.class);
|
||||||
long hysteresis = config.hysteresis / 2;
|
long hysteresis = config.hysteresis / 2;
|
||||||
if (newValue <= prevValue + hysteresis && newValue >= prevValue - hysteresis) {
|
return (newValue <= prevValue + hysteresis && newValue >= prevValue - hysteresis);
|
||||||
return true;
|
} else if (portDefinition == PortDefinition.CONTACT) { // For contact values, check debounce
|
||||||
}
|
|
||||||
}
|
|
||||||
if (portDefinition == PortDefinition.CONTACT) { // For contact values, check debounce
|
|
||||||
DigitalInputConfiguration config = configuration.as(DigitalInputConfiguration.class);
|
DigitalInputConfiguration config = configuration.as(DigitalInputConfiguration.class);
|
||||||
if (config.debouncePeriod != 0
|
return (config.debouncePeriod != 0
|
||||||
&& now.isBefore(portData.getTimestamp().plus(config.debouncePeriod, ChronoUnit.MILLIS))) {
|
&& now.isBefore(portData.getTimestamp().plus(config.debouncePeriod, ChronoUnit.MILLIS)));
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -338,9 +336,7 @@ public class Ipx800v3Handler extends BaseThingHandler implements Ipx800EventList
|
||||||
&& PortDefinition.fromGroupId(groupId) == PortDefinition.RELAY) {
|
&& PortDefinition.fromGroupId(groupId) == PortDefinition.RELAY) {
|
||||||
RelayOutputConfiguration config = channel.getConfiguration().as(RelayOutputConfiguration.class);
|
RelayOutputConfiguration config = channel.getConfiguration().as(RelayOutputConfiguration.class);
|
||||||
String id = channelUID.getIdWithoutGroup();
|
String id = channelUID.getIdWithoutGroup();
|
||||||
if (parser != null) {
|
parser.ifPresent(p -> p.setOutput(id, (OnOffType) command == OnOffType.ON ? 1 : 0, config.pulse));
|
||||||
parser.setOutput(id, (OnOffType) command == OnOffType.ON ? 1 : 0, config.pulse);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.debug("Can not handle command '{}' on channel '{}'", command, channelUID);
|
logger.debug("Can not handle command '{}' on channel '{}'", command, channelUID);
|
||||||
|
@ -368,20 +364,16 @@ public class Ipx800v3Handler extends BaseThingHandler implements Ipx800EventList
|
||||||
super.channelUnlinked(channelUID);
|
super.channelUnlinked(channelUID);
|
||||||
PortData portData = portDatas.remove(channelUID.getId());
|
PortData portData = portDatas.remove(channelUID.getId());
|
||||||
if (portData != null) {
|
if (portData != null) {
|
||||||
portData.destroy();
|
portData.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetCounter(int counter) {
|
public void resetCounter(int counter) {
|
||||||
if (parser != null) {
|
parser.ifPresent(p -> p.resetCounter(counter));
|
||||||
parser.resetCounter(counter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
if (parser != null) {
|
parser.ifPresent(M2MMessageParser::resetPLC);
|
||||||
parser.resetPLC();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
package org.openhab.binding.gce.internal.model;
|
package org.openhab.binding.gce.internal.model;
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link PortData} is responsible for holding data regarding current status of a port.
|
* The {@link PortData} is responsible for holding data regarding current status of a port.
|
||||||
|
@ -27,16 +27,14 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||||
public class PortData {
|
public class PortData {
|
||||||
private double value = -1;
|
private double value = -1;
|
||||||
private ZonedDateTime timestamp = ZonedDateTime.now();
|
private ZonedDateTime timestamp = ZonedDateTime.now();
|
||||||
private @Nullable ScheduledFuture<?> pulsing;
|
private Optional<ScheduledFuture<?>> pulsing = Optional.empty();
|
||||||
|
|
||||||
public void cancelPulsing() {
|
public void cancelPulsing() {
|
||||||
if (pulsing != null) {
|
pulsing.ifPresent(pulse -> pulse.cancel(true));
|
||||||
pulsing.cancel(true);
|
pulsing = Optional.empty();
|
||||||
}
|
|
||||||
pulsing = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy() {
|
public void dispose() {
|
||||||
cancelPulsing();
|
cancelPulsing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +52,7 @@ public class PortData {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPulsing(ScheduledFuture<?> pulsing) {
|
public void setPulsing(ScheduledFuture<?> pulsing) {
|
||||||
this.pulsing = pulsing;
|
this.pulsing = Optional.of(pulsing);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInitializing() {
|
public boolean isInitializing() {
|
||||||
|
|
Loading…
Reference in New Issue