Search in sources :

Example 1 with ModbusPollerThingHandler

use of org.openhab.binding.modbus.handler.ModbusPollerThingHandler in project openhab-addons by openhab.

the class ModbusPollerThingHandlerTest method testRegistersPassedToChildDataThings.

@Test
public void testRegistersPassedToChildDataThings() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
    PollTask pollTask = Mockito.mock(PollTask.class);
    doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
    Configuration pollerConfig = new Configuration();
    pollerConfig.put("refresh", 150L);
    pollerConfig.put("start", 5);
    pollerConfig.put("length", 13);
    pollerConfig.put("type", "coil");
    poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID()).build();
    addThing(poller);
    verifyEndpointBasicInitInteraction();
    assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
    ArgumentCaptor<ModbusReadCallback> callbackCapturer = ArgumentCaptor.forClass(ModbusReadCallback.class);
    verify(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), callbackCapturer.capture(), notNull());
    ModbusReadCallback readCallback = callbackCapturer.getValue();
    assertNotNull(readCallback);
    ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
    ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
    ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
    assertNotNull(thingHandler);
    ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
    ModbusDataThingHandler child2 = Mockito.mock(ModbusDataThingHandler.class);
    AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
    // has one data child
    thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
    readCallback.handle(result);
    verify(child1).onReadResult(result);
    verifyNoMoreInteractions(child1);
    verifyNoMoreInteractions(child2);
    reset(child1);
    // two children (one child initialized)
    thingHandler.childHandlerInitialized(child2, Mockito.mock(Thing.class));
    readCallback.handle(result);
    verify(child1).onReadResult(result);
    verify(child2).onReadResult(result);
    verifyNoMoreInteractions(child1);
    verifyNoMoreInteractions(child2);
    reset(child1);
    reset(child2);
    // one child disposed
    thingHandler.childHandlerDisposed(child1, Mockito.mock(Thing.class));
    readCallback.handle(result);
    verify(child2).onReadResult(result);
    verifyNoMoreInteractions(child1);
    verifyNoMoreInteractions(child2);
}
Also used : ModbusDataThingHandler(org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler) PollTask(org.openhab.core.io.transport.modbus.PollTask) ModbusRegisterArray(org.openhab.core.io.transport.modbus.ModbusRegisterArray) Configuration(org.openhab.core.config.core.Configuration) ModbusReadRequestBlueprint(org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint) ModbusReadCallback(org.openhab.core.io.transport.modbus.ModbusReadCallback) ModbusPollerThingHandler(org.openhab.binding.modbus.handler.ModbusPollerThingHandler) AsyncModbusReadResult(org.openhab.core.io.transport.modbus.AsyncModbusReadResult) Thing(org.openhab.core.thing.Thing) Test(org.junit.jupiter.api.Test)

Example 2 with ModbusPollerThingHandler

use of org.openhab.binding.modbus.handler.ModbusPollerThingHandler in project openhab-addons by openhab.

the class ModbusPollerThingHandlerTest method testRefreshWithPreviousData.

/**
 * When there's no recently received data, refresh() will re-use that instead
 *
 * @throws IllegalArgumentException
 * @throws IllegalAccessException
 * @throws NoSuchFieldException
 * @throws SecurityException
 */
@Test
public void testRefreshWithPreviousData() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
    Configuration pollerConfig = new Configuration();
    pollerConfig.put("refresh", 0L);
    pollerConfig.put("start", 5);
    pollerConfig.put("length", 13);
    pollerConfig.put("type", "coil");
    pollerConfig.put("cacheMillis", 10000L);
    poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID()).build();
    addThing(poller);
    verifyEndpointBasicInitInteraction();
    ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
    ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
    assertNotNull(thingHandler);
    thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
    assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
    verify(comms, never()).submitOneTimePoll(any(), any(), any());
    // data is received
    ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
    ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
    ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
    AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
    pollerReadCallback.handle(result);
    // data child receives the data
    verify(child1).onReadResult(result);
    verifyNoMoreInteractions(child1);
    reset(child1);
    // call refresh
    // cache is still valid, we should not have real data poll this time
    thingHandler.refresh();
    verify(comms, never()).submitOneTimePoll(any(), any(), any());
    // data child receives the cached data
    verify(child1).onReadResult(result);
    verifyNoMoreInteractions(child1);
}
Also used : ModbusDataThingHandler(org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler) ModbusRegisterArray(org.openhab.core.io.transport.modbus.ModbusRegisterArray) Configuration(org.openhab.core.config.core.Configuration) ModbusReadRequestBlueprint(org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint) ModbusReadCallback(org.openhab.core.io.transport.modbus.ModbusReadCallback) ModbusPollerThingHandler(org.openhab.binding.modbus.handler.ModbusPollerThingHandler) AsyncModbusReadResult(org.openhab.core.io.transport.modbus.AsyncModbusReadResult) Thing(org.openhab.core.thing.Thing) Test(org.junit.jupiter.api.Test)

Example 3 with ModbusPollerThingHandler

use of org.openhab.binding.modbus.handler.ModbusPollerThingHandler in project openhab-addons by openhab.

the class ModbusPollerThingHandlerTest method testRefreshWithOldPreviousData.

@Test
public void testRefreshWithOldPreviousData() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, InterruptedException {
    Configuration pollerConfig = new Configuration();
    pollerConfig.put("refresh", 0L);
    pollerConfig.put("start", 5);
    pollerConfig.put("length", 13);
    pollerConfig.put("type", "coil");
    pollerConfig.put("cacheMillis", 10L);
    poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID()).build();
    addThing(poller);
    verifyEndpointBasicInitInteraction();
    ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
    assertNotNull(thingHandler);
    ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
    thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
    assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
    verify(comms, never()).submitOneTimePoll(any(), any(), any());
    // data is received
    ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
    ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
    ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
    AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
    pollerReadCallback.handle(result);
    // data child should receive the data
    verify(child1).onReadResult(result);
    verifyNoMoreInteractions(child1);
    reset(child1);
    // Sleep to ensure cache expiry
    Thread.sleep(15L);
    // call refresh. Since cache expired, will poll for more
    verify(comms, never()).submitOneTimePoll(any(), any(), any());
    thingHandler.refresh();
    verify(comms).submitOneTimePoll(any(), any(), any());
}
Also used : ModbusDataThingHandler(org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler) ModbusRegisterArray(org.openhab.core.io.transport.modbus.ModbusRegisterArray) Configuration(org.openhab.core.config.core.Configuration) ModbusReadRequestBlueprint(org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint) ModbusReadCallback(org.openhab.core.io.transport.modbus.ModbusReadCallback) ModbusPollerThingHandler(org.openhab.binding.modbus.handler.ModbusPollerThingHandler) AsyncModbusReadResult(org.openhab.core.io.transport.modbus.AsyncModbusReadResult) Thing(org.openhab.core.thing.Thing) Test(org.junit.jupiter.api.Test)

Example 4 with ModbusPollerThingHandler

use of org.openhab.binding.modbus.handler.ModbusPollerThingHandler in project openhab-addons by openhab.

the class ModbusDataThingHandler method requestFromCommand.

@Nullable
private ModbusWriteRequestBlueprint requestFromCommand(ChannelUID channelUID, Command origCommand, ModbusDataConfiguration config, Command transformedCommand, Integer writeStart) {
    ModbusWriteRequestBlueprint request;
    boolean writeMultiple = config.isWriteMultipleEvenWithSingleRegisterOrCoil();
    String writeType = config.getWriteType();
    ModbusPollerThingHandler pollerHandler = this.pollerHandler;
    if (writeType == null) {
        // disposed thing
        return null;
    }
    if (writeType.equals(WRITE_TYPE_COIL)) {
        Optional<Boolean> commandAsBoolean = ModbusBitUtilities.translateCommand2Boolean(transformedCommand);
        if (!commandAsBoolean.isPresent()) {
            logger.warn("Cannot process command {} with channel {} since command is not OnOffType, OpenClosedType or Decimal trying to write to coil. Do not know how to convert to 0/1. Transformed command was '{}'", origCommand, channelUID, transformedCommand);
            return null;
        }
        boolean data = commandAsBoolean.get();
        request = new ModbusWriteCoilRequestBlueprint(slaveId, writeStart, data, writeMultiple, config.getWriteMaxTries());
    } else if (writeType.equals(WRITE_TYPE_HOLDING)) {
        ValueType writeValueType = this.writeValueType;
        if (writeValueType == null) {
            // Should not happen in practice, since we are not in configuration error (checked above)
            // This will make compiler happy anyways with the null checks
            logger.warn("Received command but write value type not set! Ignoring command");
            return null;
        }
        final ModbusRegisterArray data;
        if (writeValueType.equals(ValueType.BIT)) {
            if (writeSubIndex.isEmpty()) {
                // Should not happen! should be in configuration error
                logger.error("Bug: sub index not present but writeValueType=BIT. Should be in configuration error");
                return null;
            }
            Optional<Boolean> commandBool = ModbusBitUtilities.translateCommand2Boolean(transformedCommand);
            if (commandBool.isEmpty()) {
                logger.warn("Data thing is configured to write individual bit but we received command that is not convertible to 0/1 bit. Ignoring.");
                return null;
            } else if (pollerHandler == null) {
                logger.warn("Bug: sub index present but not child of poller. Should be in configuration erro");
                return null;
            }
            // writing bit of an individual register. Using cache from poller
            AtomicReference<@Nullable ModbusRegisterArray> cachedRegistersRef = pollerHandler.getLastPolledDataCache();
            ModbusRegisterArray mutatedRegisters = cachedRegistersRef.updateAndGet(cachedRegisters -> cachedRegisters == null ? null : combineCommandWithRegisters(cachedRegisters, writeStart, writeSubIndex.get(), commandBool.get()));
            if (mutatedRegisters == null) {
                logger.warn("Received command to thing with writeValueType=bit (pointing to individual bit of a holding register) but internal cache not yet populated. Ignoring command");
                return null;
            }
            // extract register (first byte index = register index * 2)
            byte[] allMutatedBytes = mutatedRegisters.getBytes();
            int writeStartRelative = writeStart - pollStart;
            data = new ModbusRegisterArray(allMutatedBytes[writeStartRelative * 2], allMutatedBytes[writeStartRelative * 2 + 1]);
        } else {
            data = ModbusBitUtilities.commandToRegisters(transformedCommand, writeValueType);
        }
        writeMultiple = writeMultiple || data.size() > 1;
        request = new ModbusWriteRegisterRequestBlueprint(slaveId, writeStart, data, writeMultiple, config.getWriteMaxTries());
    } else {
        // We keep this here for future-proofing the code (new writeType values)
        throw new IllegalStateException(String.format("writeType does not equal %s or %s and thus configuration is invalid. Should not end up this far with configuration error.", WRITE_TYPE_COIL, WRITE_TYPE_HOLDING));
    }
    return request;
}
Also used : ModbusBindingConstantsInternal(org.openhab.binding.modbus.internal.ModbusBindingConstantsInternal) LoggerFactory(org.slf4j.LoggerFactory) OnOffType(org.openhab.core.library.types.OnOffType) DateTimeType(org.openhab.core.library.types.DateTimeType) ModbusConstants(org.openhab.core.io.transport.modbus.ModbusConstants) BitArray(org.openhab.core.io.transport.modbus.BitArray) DateTimeItem(org.openhab.core.library.items.DateTimeItem) HexUtils(org.openhab.core.util.HexUtils) BigDecimal(java.math.BigDecimal) Nullable(org.eclipse.jdt.annotation.Nullable) ModbusWriteCoilRequestBlueprint(org.openhab.core.io.transport.modbus.ModbusWriteCoilRequestBlueprint) ThingHandlerCallback(org.openhab.core.thing.binding.ThingHandlerCallback) Duration(java.time.Duration) Map(java.util.Map) ModbusCommunicationInterface(org.openhab.core.io.transport.modbus.ModbusCommunicationInterface) NumberItem(org.openhab.core.library.items.NumberItem) EndpointNotInitializedException(org.openhab.binding.modbus.handler.EndpointNotInitializedException) NonNullByDefault(org.eclipse.jdt.annotation.NonNullByDefault) Collection(java.util.Collection) UnDefType(org.openhab.core.types.UnDefType) BaseThingHandler(org.openhab.core.thing.binding.BaseThingHandler) BridgeHandler(org.openhab.core.thing.binding.BridgeHandler) ModbusReadFunctionCode(org.openhab.core.io.transport.modbus.ModbusReadFunctionCode) CascadedValueTransformationImpl(org.openhab.binding.modbus.internal.CascadedValueTransformationImpl) ModbusTransportException(org.openhab.core.io.transport.modbus.exception.ModbusTransportException) BundleContext(org.osgi.framework.BundleContext) Objects(java.util.Objects) List(java.util.List) ValueType(org.openhab.core.io.transport.modbus.ModbusConstants.ValueType) AsyncModbusWriteResult(org.openhab.core.io.transport.modbus.AsyncModbusWriteResult) Optional(java.util.Optional) ModbusPollerThingHandler(org.openhab.binding.modbus.handler.ModbusPollerThingHandler) ModbusReadRequestBlueprint(org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint) OpenClosedType(org.openhab.core.library.types.OpenClosedType) DimmerItem(org.openhab.core.library.items.DimmerItem) AsyncModbusFailure(org.openhab.core.io.transport.modbus.AsyncModbusFailure) ModbusRegisterArray(org.openhab.core.io.transport.modbus.ModbusRegisterArray) ModbusWriteRequestBlueprint(org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint) SwitchItem(org.openhab.core.library.items.SwitchItem) LocalDateTime(java.time.LocalDateTime) ValueTransformation(org.openhab.binding.modbus.internal.ValueTransformation) HashMap(java.util.HashMap) AtomicReference(java.util.concurrent.atomic.AtomicReference) ModbusDataConfiguration(org.openhab.binding.modbus.internal.config.ModbusDataConfiguration) ModbusBitUtilities(org.openhab.core.io.transport.modbus.ModbusBitUtilities) ModbusWriteRegisterRequestBlueprint(org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint) Thing(org.openhab.core.thing.Thing) ChannelUID(org.openhab.core.thing.ChannelUID) ThingStatusInfo(org.openhab.core.thing.ThingStatusInfo) WriteRequestJsonUtilities(org.openhab.core.io.transport.modbus.json.WriteRequestJsonUtilities) DecimalType(org.openhab.core.library.types.DecimalType) ModbusConnectionException(org.openhab.core.io.transport.modbus.exception.ModbusConnectionException) ModbusConfigurationException(org.openhab.binding.modbus.internal.ModbusConfigurationException) ThingStatus(org.openhab.core.thing.ThingStatus) Command(org.openhab.core.types.Command) Logger(org.slf4j.Logger) RollershutterItem(org.openhab.core.library.items.RollershutterItem) State(org.openhab.core.types.State) RefreshType(org.openhab.core.types.RefreshType) ThingStatusDetail(org.openhab.core.thing.ThingStatusDetail) TimeUnit(java.util.concurrent.TimeUnit) ModbusEndpointThingHandler(org.openhab.binding.modbus.handler.ModbusEndpointThingHandler) StringItem(org.openhab.core.library.items.StringItem) ContactItem(org.openhab.core.library.items.ContactItem) AsyncModbusReadResult(org.openhab.core.io.transport.modbus.AsyncModbusReadResult) SingleValueTransformation(org.openhab.binding.modbus.internal.SingleValueTransformation) Collections(java.util.Collections) FrameworkUtil(org.osgi.framework.FrameworkUtil) Bridge(org.openhab.core.thing.Bridge) ModbusRegisterArray(org.openhab.core.io.transport.modbus.ModbusRegisterArray) ModbusWriteRequestBlueprint(org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint) Optional(java.util.Optional) ValueType(org.openhab.core.io.transport.modbus.ModbusConstants.ValueType) AtomicReference(java.util.concurrent.atomic.AtomicReference) ModbusPollerThingHandler(org.openhab.binding.modbus.handler.ModbusPollerThingHandler) ModbusWriteRegisterRequestBlueprint(org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint) Nullable(org.eclipse.jdt.annotation.Nullable) ModbusWriteCoilRequestBlueprint(org.openhab.core.io.transport.modbus.ModbusWriteCoilRequestBlueprint) Nullable(org.eclipse.jdt.annotation.Nullable)

Example 5 with ModbusPollerThingHandler

use of org.openhab.binding.modbus.handler.ModbusPollerThingHandler in project openhab-addons by openhab.

the class ModbusDataThingHandler method handleCommand.

@Override
public synchronized void handleCommand(ChannelUID channelUID, Command command) {
    logger.trace("Thing {} '{}' received command '{}' to channel '{}'", getThing().getUID(), getThing().getLabel(), command, channelUID);
    ModbusDataConfiguration config = this.config;
    if (config == null) {
        return;
    }
    if (RefreshType.REFRESH == command) {
        ModbusPollerThingHandler poller = pollerHandler;
        if (poller == null) {
            // There is no data to update
            return;
        }
        // We *schedule* the REFRESH to avoid dead-lock situation where poller is trying update this
        // data thing with cached data (resulting in deadlock in two synchronized methods: this (handleCommand) and
        // onRegisters.
        scheduler.schedule(() -> poller.refresh(), 0, TimeUnit.SECONDS);
        return;
    } else if (hasConfigurationError()) {
        logger.debug("Thing {} '{}' command '{}' to channel '{}': Thing has configuration error so ignoring the command", getThing().getUID(), getThing().getLabel(), command, channelUID);
        return;
    } else if (!isWriteEnabled) {
        logger.debug("Thing {} '{}' command '{}' to channel '{}': no writing configured -> aborting processing command", getThing().getUID(), getThing().getLabel(), command, channelUID);
        return;
    }
    Optional<Command> transformedCommand = transformCommandAndProcessJSON(channelUID, command);
    if (transformedCommand == null) {
        // transformCommandAndProcessJSON javadoc
        return;
    }
    // We did not have JSON output from the transformation, so writeStart is absolute required. Abort if it is
    // missing
    Optional<Integer> writeStart = this.writeStart;
    if (writeStart.isEmpty()) {
        logger.debug("Thing {} '{}': not processing command {} since writeStart is missing and transformation output is not a JSON", getThing().getUID(), getThing().getLabel(), command);
        return;
    }
    if (!transformedCommand.isPresent()) {
        // transformation failed, return
        logger.warn("Cannot process command {} (of type {}) with channel {} since transformation was unsuccessful", command, command.getClass().getSimpleName(), channelUID);
        return;
    }
    ModbusWriteRequestBlueprint request = requestFromCommand(channelUID, command, config, transformedCommand.get(), writeStart.get());
    if (request == null) {
        return;
    }
    logger.trace("Submitting write task {} to endpoint {}", request, comms.getEndpoint());
    comms.submitOneTimeWrite(request, this::onWriteResponse, this::handleWriteError);
}
Also used : ModbusDataConfiguration(org.openhab.binding.modbus.internal.config.ModbusDataConfiguration) ModbusWriteRequestBlueprint(org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint) Command(org.openhab.core.types.Command) ModbusPollerThingHandler(org.openhab.binding.modbus.handler.ModbusPollerThingHandler)

Aggregations

ModbusPollerThingHandler (org.openhab.binding.modbus.handler.ModbusPollerThingHandler)14 ModbusReadRequestBlueprint (org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint)9 Test (org.junit.jupiter.api.Test)8 ModbusDataThingHandler (org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler)8 Configuration (org.openhab.core.config.core.Configuration)8 Thing (org.openhab.core.thing.Thing)8 AsyncModbusReadResult (org.openhab.core.io.transport.modbus.AsyncModbusReadResult)7 ModbusReadCallback (org.openhab.core.io.transport.modbus.ModbusReadCallback)7 ModbusRegisterArray (org.openhab.core.io.transport.modbus.ModbusRegisterArray)6 Bridge (org.openhab.core.thing.Bridge)4 ModbusDataConfiguration (org.openhab.binding.modbus.internal.config.ModbusDataConfiguration)3 AsyncModbusFailure (org.openhab.core.io.transport.modbus.AsyncModbusFailure)3 Nullable (org.eclipse.jdt.annotation.Nullable)2 EndpointNotInitializedException (org.openhab.binding.modbus.handler.EndpointNotInitializedException)2 ModbusEndpointThingHandler (org.openhab.binding.modbus.handler.ModbusEndpointThingHandler)2 ModbusConfigurationException (org.openhab.binding.modbus.internal.ModbusConfigurationException)2 BitArray (org.openhab.core.io.transport.modbus.BitArray)2 ModbusWriteRequestBlueprint (org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint)2 PollTask (org.openhab.core.io.transport.modbus.PollTask)2 BridgeHandler (org.openhab.core.thing.binding.BridgeHandler)2