Search in sources :

Example 1 with ModbusDataConfiguration

use of org.openhab.binding.modbus.internal.config.ModbusDataConfiguration 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 2 with ModbusDataConfiguration

use of org.openhab.binding.modbus.internal.config.ModbusDataConfiguration 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)

Example 3 with ModbusDataConfiguration

use of org.openhab.binding.modbus.internal.config.ModbusDataConfiguration 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());
    }
}
Also used : ModbusDataConfiguration(org.openhab.binding.modbus.internal.config.ModbusDataConfiguration) ModbusEndpointThingHandler(org.openhab.binding.modbus.handler.ModbusEndpointThingHandler) BridgeHandler(org.openhab.core.thing.binding.BridgeHandler) ModbusConfigurationException(org.openhab.binding.modbus.internal.ModbusConfigurationException) ModbusReadRequestBlueprint(org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint) ModbusPollerThingHandler(org.openhab.binding.modbus.handler.ModbusPollerThingHandler) EndpointNotInitializedException(org.openhab.binding.modbus.handler.EndpointNotInitializedException) Bridge(org.openhab.core.thing.Bridge)

Aggregations

ModbusPollerThingHandler (org.openhab.binding.modbus.handler.ModbusPollerThingHandler)3 ModbusDataConfiguration (org.openhab.binding.modbus.internal.config.ModbusDataConfiguration)3 EndpointNotInitializedException (org.openhab.binding.modbus.handler.EndpointNotInitializedException)2 ModbusEndpointThingHandler (org.openhab.binding.modbus.handler.ModbusEndpointThingHandler)2 ModbusConfigurationException (org.openhab.binding.modbus.internal.ModbusConfigurationException)2 ModbusReadRequestBlueprint (org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint)2 ModbusWriteRequestBlueprint (org.openhab.core.io.transport.modbus.ModbusWriteRequestBlueprint)2 Bridge (org.openhab.core.thing.Bridge)2 BridgeHandler (org.openhab.core.thing.binding.BridgeHandler)2 Command (org.openhab.core.types.Command)2 BigDecimal (java.math.BigDecimal)1 Duration (java.time.Duration)1 LocalDateTime (java.time.LocalDateTime)1 Collection (java.util.Collection)1 Collections (java.util.Collections)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Map (java.util.Map)1 Objects (java.util.Objects)1 Optional (java.util.Optional)1