use of org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint in project openhab-addons by openhab.
the class ModbusDataThingHandler method validateWriteIndex.
private void validateWriteIndex() throws ModbusConfigurationException {
@Nullable ModbusReadRequestBlueprint readRequest = this.readRequest;
if (!writeStart.isPresent() || !writeSubIndex.isPresent()) {
//
return;
} else if (readRequest == null) {
// should not happen, already validated
throw new ModbusConfigurationException("Must poll data with writeStart=X.Y");
}
if (writeSubIndex.isPresent() && (writeSubIndex.get() + 1) > 16) {
// the sub index Y (in X.Y) is above the register limits
String errmsg = String.format("readStart=X.Y, the value Y is too large");
throw new ModbusConfigurationException(errmsg);
}
// Determine bit positions polled, both start and end inclusive
int pollStartBitIndex = readRequest.getReference() * 16;
int pollEndBitIndex = pollStartBitIndex + readRequest.getDataLength() * 16 - 1;
// Determine bit positions read, both start and end inclusive
int writeStartBitIndex = writeStart.get() * 16 + readSubIndex.orElse(0);
int writeEndBitIndex = writeStartBitIndex - 1;
if (writeStartBitIndex < pollStartBitIndex || writeEndBitIndex > pollEndBitIndex) {
String errmsg = String.format("Out-of-bounds: Poller is reading from index %d to %d (inclusive) but this thing configured to write starting from element %d. Must write within polled limits", pollStartBitIndex / 16, pollEndBitIndex / 16, writeStart.get());
throw new ModbusConfigurationException(errmsg);
}
}
use of org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint in project openhab-addons by openhab.
the class ModbusDataThingHandler method initialize.
@Override
public synchronized void initialize() {
// Long running initialization should be done asynchronously in background.
try {
logger.trace("initialize() of thing {} '{}' starting", thing.getUID(), thing.getLabel());
ModbusDataConfiguration localConfig = config = getConfigAs(ModbusDataConfiguration.class);
updateUnchangedValuesEveryMillis = localConfig.getUpdateUnchangedValuesEveryMillis();
Bridge bridge = getBridge();
if (bridge == null || !bridge.getStatus().equals(ThingStatus.ONLINE)) {
logger.debug("Thing {} '{}' has no bridge or it is not online", getThing().getUID(), getThing().getLabel());
updateStatusIfChanged(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "No online bridge");
return;
}
BridgeHandler bridgeHandler = bridge.getHandler();
if (bridgeHandler == null) {
logger.warn("Bridge {} '{}' has no handler.", bridge.getUID(), bridge.getLabel());
String errmsg = String.format("Bridge %s '%s' configuration incomplete or with errors", bridge.getUID(), bridge.getLabel());
throw new ModbusConfigurationException(errmsg);
}
if (bridgeHandler instanceof ModbusEndpointThingHandler) {
// Write-only thing, parent is endpoint
ModbusEndpointThingHandler endpointHandler = (ModbusEndpointThingHandler) bridgeHandler;
slaveId = endpointHandler.getSlaveId();
comms = endpointHandler.getCommunicationInterface();
childOfEndpoint = true;
functionCode = null;
readRequest = null;
} else {
ModbusPollerThingHandler localPollerHandler = (ModbusPollerThingHandler) bridgeHandler;
pollerHandler = localPollerHandler;
ModbusReadRequestBlueprint localReadRequest = localPollerHandler.getRequest();
if (localReadRequest == null) {
logger.debug("Poller {} '{}' has no read request -- configuration is changing or bridge having invalid configuration?", bridge.getUID(), bridge.getLabel());
updateStatusIfChanged(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, String.format("Poller %s '%s' has no poll task", bridge.getUID(), bridge.getLabel()));
return;
}
readRequest = localReadRequest;
slaveId = localReadRequest.getUnitID();
functionCode = localReadRequest.getFunctionCode();
comms = localPollerHandler.getCommunicationInterface();
pollStart = localReadRequest.getReference();
childOfEndpoint = false;
}
validateAndParseReadParameters(localConfig);
validateAndParseWriteParameters(localConfig);
validateMustReadOrWrite();
updateStatusIfChanged(ThingStatus.ONLINE);
} catch (ModbusConfigurationException | EndpointNotInitializedException e) {
logger.debug("Thing {} '{}' initialization error: {}", getThing().getUID(), getThing().getLabel(), e.getMessage());
updateStatusIfChanged(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
} finally {
logger.trace("initialize() of thing {} '{}' finished", thing.getUID(), thing.getLabel());
}
}
use of org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint in project openhab-addons by openhab.
the class ModbusPollerThingHandler method registerPollTask.
/**
* Register poll task
*
* @throws EndpointNotInitializedException in case the bridge initialization is not complete. This should only
* happen in transient conditions, for example, when bridge is initializing.
*/
@SuppressWarnings("null")
private synchronized void registerPollTask() throws EndpointNotInitializedException {
logger.trace("registerPollTask()");
if (pollTask != null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
logger.debug("pollTask should be unregistered before registering a new one!");
return;
}
ModbusEndpointThingHandler slaveEndpointThingHandler = getEndpointThingHandler();
if (slaveEndpointThingHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, String.format("Bridge '%s' is offline", Optional.ofNullable(getBridge()).map(b -> b.getLabel()).orElse("<null>")));
logger.debug("No bridge handler available -- aborting init for {}", this);
return;
}
ModbusCommunicationInterface localComms = slaveEndpointThingHandler.getCommunicationInterface();
if (localComms == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, String.format("Bridge '%s' not completely initialized", Optional.ofNullable(getBridge()).map(b -> b.getLabel())));
logger.debug("Bridge not initialized fully (no communication interface) -- aborting init for {}", this);
return;
}
this.comms = localComms;
ModbusReadFunctionCode localFunctionCode = functionCode;
if (localFunctionCode == null) {
return;
}
ModbusReadRequestBlueprint localRequest = new ModbusReadRequestBlueprint(slaveEndpointThingHandler.getSlaveId(), localFunctionCode, config.getStart(), config.getLength(), config.getMaxTries());
this.request = localRequest;
if (config.getRefresh() <= 0L) {
logger.debug("Not registering polling with ModbusManager since refresh disabled");
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, "Not polling");
} else {
logger.debug("Registering polling with ModbusManager");
pollTask = localComms.registerRegularPoll(localRequest, config.getRefresh(), 0, callbackDelegator, callbackDelegator);
assert pollTask != null;
updateStatus(ThingStatus.ONLINE);
}
}
use of org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint in project openhab-core by openhab.
the class SmokeTest method testRegularReadEvery150msWithCoil.
/**
* Testing regular polling of coils
*
* Amount of requests is timed, and average poll period is checked
*
* @throws Exception
*/
@Test
public void testRegularReadEvery150msWithCoil() throws Exception {
generateData();
ModbusSlaveEndpoint endpoint = getEndpoint();
AtomicInteger unexpectedCount = new AtomicInteger();
CountDownLatch callbackCalled = new CountDownLatch(5);
AtomicInteger dataReceived = new AtomicInteger();
long start = System.currentTimeMillis();
try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, null)) {
comms.registerRegularPoll(new ModbusReadRequestBlueprint(SLAVE_UNIT_ID, ModbusReadFunctionCode.READ_COILS, 1, 15, 1), 150, 0, result -> {
Optional<BitArray> bitsOptional = result.getBits();
if (bitsOptional.isPresent()) {
BitArray bits = bitsOptional.get();
dataReceived.incrementAndGet();
try {
assertThat(bits.size(), is(equalTo(15)));
testCoilValues(bits, 1);
} catch (AssertionError e) {
unexpectedCount.incrementAndGet();
}
} else {
unexpectedCount.incrementAndGet();
}
callbackCalled.countDown();
}, failure -> {
unexpectedCount.incrementAndGet();
callbackCalled.countDown();
});
assertTrue(callbackCalled.await(60, TimeUnit.SECONDS));
long end = System.currentTimeMillis();
assertPollDetails(unexpectedCount, dataReceived, start, end, 145, 500);
}
}
use of org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint in project openhab-core by openhab.
the class SmokeTest method testConnectionCloseAfterLastCommunicationInterfaceClosed.
@Test
public void testConnectionCloseAfterLastCommunicationInterfaceClosed() throws Exception {
assumeFalse(isRunningInCI(), "Running in CI! Will not test timing-sensitive details");
ModbusSlaveEndpoint endpoint = getEndpoint();
assumeTrue(endpoint instanceof ModbusTCPSlaveEndpoint, "Connection closing test supported only with TCP slaves");
// Generate server data
generateData();
EndpointPoolConfiguration config = new EndpointPoolConfiguration();
config.setReconnectAfterMillis(9_000_000);
// 1. capture open connections at this point
long openSocketsBefore = getNumberOfOpenClients(SOCKET_SPY);
assertThat(openSocketsBefore, is(equalTo(0L)));
// 2. make poll, binding opens the tcp connection
try (ModbusCommunicationInterface comms = modbusManager.newModbusCommunicationInterface(endpoint, config)) {
{
CountDownLatch latch = new CountDownLatch(1);
comms.submitOneTimePoll(new ModbusReadRequestBlueprint(1, ModbusReadFunctionCode.READ_COILS, 0, 1, 1), response -> {
latch.countDown();
}, failure -> {
latch.countDown();
});
assertTrue(latch.await(60, TimeUnit.SECONDS));
}
waitForAssert(() -> {
// 3. ensure one open connection
long openSocketsAfter = getNumberOfOpenClients(SOCKET_SPY);
assertThat(openSocketsAfter, is(equalTo(1L)));
});
try (ModbusCommunicationInterface comms2 = modbusManager.newModbusCommunicationInterface(endpoint, config)) {
{
CountDownLatch latch = new CountDownLatch(1);
comms.submitOneTimePoll(new ModbusReadRequestBlueprint(1, ModbusReadFunctionCode.READ_COILS, 0, 1, 1), response -> {
latch.countDown();
}, failure -> {
latch.countDown();
});
assertTrue(latch.await(60, TimeUnit.SECONDS));
}
assertThat(getNumberOfOpenClients(SOCKET_SPY), is(equalTo(1L)));
// wait for moment (to check that no connections are closed)
Thread.sleep(1000);
// no more than 1 connection, even though requests are going through
assertThat(getNumberOfOpenClients(SOCKET_SPY), is(equalTo(1L)));
}
Thread.sleep(1000);
// Still one connection open even after closing second connection
assertThat(getNumberOfOpenClients(SOCKET_SPY), is(equalTo(1L)));
}
// 4. close (the last) comms
// ensure that open connections are closed
// (despite huge "reconnect after millis")
waitForAssert(() -> {
long openSocketsAfterClose = getNumberOfOpenClients(SOCKET_SPY);
assertThat(openSocketsAfterClose, is(equalTo(0L)));
});
}
Aggregations