use of org.openhab.core.io.transport.modbus.ModbusConstants.ValueType 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;
}
use of org.openhab.core.io.transport.modbus.ModbusConstants.ValueType in project openhab-addons by openhab.
the class ModbusDataThingHandler method validateReadIndex.
private void validateReadIndex() throws ModbusConfigurationException {
@Nullable ModbusReadRequestBlueprint readRequest = this.readRequest;
ValueType readValueType = this.readValueType;
if (!readIndex.isPresent() || readRequest == null) {
return;
}
assert readValueType != null;
// bits represented by the value type, e.g. int32 -> 32
int valueTypeBitCount = readValueType.getBits();
int dataElementBits;
switch(readRequest.getFunctionCode()) {
case READ_INPUT_REGISTERS:
case READ_MULTIPLE_REGISTERS:
dataElementBits = 16;
break;
case READ_COILS:
case READ_INPUT_DISCRETES:
dataElementBits = 1;
break;
default:
throw new IllegalStateException(readRequest.getFunctionCode().toString());
}
boolean bitQuery = dataElementBits == 1;
if (bitQuery && readSubIndex.isPresent()) {
String errmsg = String.format("readStart=X.Y is not allowed to be used with coils or discrete inputs!");
throw new ModbusConfigurationException(errmsg);
}
if (valueTypeBitCount >= 16 && readSubIndex.isPresent()) {
String errmsg = String.format("readStart=X.Y notation is not allowed to be used with value types larger than 16bit! Use readStart=X instead.");
throw new ModbusConfigurationException(errmsg);
} else if (!bitQuery && valueTypeBitCount < 16 && !readSubIndex.isPresent()) {
// User has specified value type which is less than register width (16 bits).
// readStart=X.Y notation must be used to define which data to extract from the 16 bit register.
String errmsg = String.format("readStart=X.Y must be used with value types (readValueType) less than 16bit!");
throw new ModbusConfigurationException(errmsg);
} else if (readSubIndex.isPresent() && (readSubIndex.get() + 1) * valueTypeBitCount > 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() * dataElementBits;
int pollEndBitIndex = pollStartBitIndex + readRequest.getDataLength() * dataElementBits - 1;
// Determine bit positions read, both start and end inclusive
int readStartBitIndex = readIndex.get() * dataElementBits + readSubIndex.orElse(0) * valueTypeBitCount;
int readEndBitIndex = readStartBitIndex + valueTypeBitCount - 1;
if (readStartBitIndex < pollStartBitIndex || readEndBitIndex > pollEndBitIndex) {
String errmsg = String.format("Out-of-bounds: Poller is reading from index %d to %d (inclusive) but this thing configured to read '%s' starting from element %d. Exceeds polled data bounds.", pollStartBitIndex / dataElementBits, pollEndBitIndex / dataElementBits, readValueType, readIndex.get());
throw new ModbusConfigurationException(errmsg);
}
}
use of org.openhab.core.io.transport.modbus.ModbusConstants.ValueType in project openhab-addons by openhab.
the class ModbusDataThingHandler method validateAndParseWriteParameters.
private void validateAndParseWriteParameters(ModbusDataConfiguration config) throws ModbusConfigurationException {
boolean writeTypeMissing = config.getWriteType() == null || config.getWriteType().isBlank();
boolean writeStartMissing = config.getWriteStart() == null || config.getWriteStart().isBlank();
boolean writeValueTypeMissing = config.getWriteValueType() == null || config.getWriteValueType().isBlank();
boolean writeTransformationMissing = config.getWriteTransform() == null || config.getWriteTransform().isBlank();
writeTransformation = new CascadedValueTransformationImpl(config.getWriteTransform());
boolean writingCoil = WRITE_TYPE_COIL.equals(config.getWriteType());
writeParametersHavingTransformationOnly = (writeTypeMissing && writeStartMissing && writeValueTypeMissing && !writeTransformationMissing);
//
boolean allMissingOrAllPresentOrOnlyNonDefaultTransform = // read-only thing, no write specified
(writeTypeMissing && writeStartMissing && writeValueTypeMissing) || // mandatory write parameters provided. With coils one can drop value type
(!writeTypeMissing && !writeStartMissing && (!writeValueTypeMissing || writingCoil)) || // only transformation provided
writeParametersHavingTransformationOnly;
if (!allMissingOrAllPresentOrOnlyNonDefaultTransform) {
String errmsg = String.format("writeType=%s, writeStart=%s, and writeValueType=%s should be all present, or all missing! Alternatively, you can provide just writeTransformation, and use transformation returning JSON.", config.getWriteType(), config.getWriteStart(), config.getWriteValueType());
throw new ModbusConfigurationException(errmsg);
} else if (!writeTypeMissing || writeParametersHavingTransformationOnly) {
isWriteEnabled = true;
// all write values are present
if (!writeParametersHavingTransformationOnly && !WRITE_TYPE_HOLDING.equals(config.getWriteType()) && !WRITE_TYPE_COIL.equals(config.getWriteType())) {
String errmsg = String.format("Invalid writeType=%s. Expecting %s or %s!", config.getWriteType(), WRITE_TYPE_HOLDING, WRITE_TYPE_COIL);
throw new ModbusConfigurationException(errmsg);
}
final ValueType localWriteValueType;
if (writeParametersHavingTransformationOnly) {
// Placeholder for further checks
localWriteValueType = writeValueType = ModbusConstants.ValueType.INT16;
} else if (writingCoil && writeValueTypeMissing) {
localWriteValueType = writeValueType = ModbusConstants.ValueType.BIT;
} else {
try {
localWriteValueType = writeValueType = ValueType.fromConfigValue(config.getWriteValueType());
} catch (IllegalArgumentException e) {
String errmsg = String.format("Invalid writeValueType=%s!", config.getWriteValueType());
throw new ModbusConfigurationException(errmsg);
}
}
try {
if (!writeParametersHavingTransformationOnly) {
String localWriteStart = config.getWriteStart();
if (localWriteStart == null) {
String errmsg = String.format("Thing %s invalid writeStart: %s", getThing().getUID(), config.getWriteStart());
throw new ModbusConfigurationException(errmsg);
}
String[] writeParts = localWriteStart.split("\\.", 2);
try {
writeStart = Optional.of(Integer.parseInt(writeParts[0]));
if (writeParts.length == 2) {
writeSubIndex = Optional.of(Integer.parseInt(writeParts[1]));
} else {
writeSubIndex = Optional.empty();
}
} catch (IllegalArgumentException e) {
String errmsg = String.format("Thing %s invalid writeStart: %s", getThing().getUID(), config.getReadStart());
throw new ModbusConfigurationException(errmsg);
}
}
} catch (IllegalArgumentException e) {
String errmsg = String.format("Thing %s invalid writeStart: %s", getThing().getUID(), config.getWriteStart());
throw new ModbusConfigurationException(errmsg);
}
if (writingCoil && !ModbusConstants.ValueType.BIT.equals(localWriteValueType)) {
String errmsg = String.format("Invalid writeValueType: Only writeValueType='%s' (or undefined) supported with coils. Value type was: %s", ModbusConstants.ValueType.BIT, config.getWriteValueType());
throw new ModbusConfigurationException(errmsg);
} else if (writeSubIndex.isEmpty() && !writingCoil && localWriteValueType.getBits() < 16) {
// trying to write holding registers with < 16 bit value types. Not supported
String errmsg = String.format("Invalid writeValueType: Only writeValueType with larger or equal to 16 bits are supported holding registers. Value type was: %s", config.getWriteValueType());
throw new ModbusConfigurationException(errmsg);
}
if (writeSubIndex.isPresent()) {
if (writeValueTypeMissing || writeTypeMissing || !WRITE_TYPE_HOLDING.equals(config.getWriteType()) || !ModbusConstants.ValueType.BIT.equals(localWriteValueType) || childOfEndpoint) {
String errmsg = String.format("Thing %s invalid writeType, writeValueType or parent. Since writeStart=X.Y, one should set writeType=holding, writeValueType=bit and have the thing as child of poller", getThing().getUID(), config.getWriteStart());
throw new ModbusConfigurationException(errmsg);
}
ModbusReadRequestBlueprint readRequest = this.readRequest;
if (readRequest == null || readRequest.getFunctionCode() != ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS) {
String errmsg = String.format("Thing %s invalid. Since writeStart=X.Y, expecting poller reading holding registers.", getThing().getUID());
throw new ModbusConfigurationException(errmsg);
}
}
validateWriteIndex();
} else {
isWriteEnabled = false;
}
}
use of org.openhab.core.io.transport.modbus.ModbusConstants.ValueType in project openhab-addons by openhab.
the class ModbusDataThingHandler method onRegisters.
private synchronized void onRegisters(ModbusReadRequestBlueprint request, ModbusRegisterArray registers) {
if (hasConfigurationError()) {
return;
} else if (!isReadEnabled) {
return;
}
ValueType readValueType = this.readValueType;
if (readValueType == null) {
return;
}
State numericState;
// extractIndex:
// e.g. with bit, extractIndex=4 means 5th bit (from right) ("10.4" -> 5th bit of register 10, "10.4" -> 5th bit
// of register 10)
// bit of second register)
// e.g. with 8bit integer, extractIndex=3 means high byte of second register
//
// with <16 bit types, this is the index of the N'th 1-bit/8-bit item. Each register has 16/2 items,
// respectively.
// with >=16 bit types, this is index of first register
int extractIndex;
if (readValueType.getBits() >= 16) {
// Invariant, checked in initialize
assert readSubIndex.orElse(0) == 0;
extractIndex = readIndex.get() - pollStart;
} else {
int subIndex = readSubIndex.orElse(0);
int itemsPerRegister = 16 / readValueType.getBits();
extractIndex = (readIndex.get() - pollStart) * itemsPerRegister + subIndex;
}
numericState = ModbusBitUtilities.extractStateFromRegisters(registers, extractIndex, readValueType).map(state -> (State) state).orElse(UnDefType.UNDEF);
boolean boolValue = !numericState.equals(DecimalType.ZERO);
Map<ChannelUID, State> values = processUpdatedValue(numericState, boolValue);
logger.debug("Thing {} channels updated: {}. readValueType={}, readIndex={}, readSubIndex(or 0)={}, extractIndex={} -> numeric value {} and boolValue={}. Registers {} for request {}", thing.getUID(), values, readValueType, readIndex, readSubIndex.orElse(0), extractIndex, numericState, boolValue, registers, request);
}
Aggregations