Modbus Channels are set to "null"

Hello,

I recently got the problem that the modbus API is setting the channel values to null directly after setting a new value. Since that error wasn’t there at the beginning, I don’t know what can cause it. Do you have any idea?

2025-05-14T10:12:37,841 [modbusPI] INFO  [.element.AbstractModbusElement] Element [UnsignedWordElementtype=INTEGER;ref=5108/0x13f4;DEBUG]] set value to [7747].
2025-05-14T10:12:37,841 [modbusPI] INFO  [.element.AbstractModbusElement] Element [UnsignedWordElementtype=INTEGER;ref=5108/0x13f4;DEBUG]] set value to [null].
2025-05-14T10:12:37,841 [modbusPI] INFO  [.element.AbstractModbusElement] Element [UnsignedWordElementtype=INTEGER;ref=5108/0x13f4;DEBUG]] set value to [null].

Thanks a lot for any help!

Regards
Alex

I digged a little bit deeper and found that this function is throwing an exception:

package io.openems.edge.bridge.modbus.api.task

class: AbstractReadTask

	@Override
	public ExecuteState execute(AbstractModbusBridge bridge) {
		try {
			var response = this.executeRequest(bridge, this.createModbusRequest());
			// On error a log message has already been logged

			try {
				var result = this.parseResponse(response);
				validateResponse(result, this.length);

				// NOTE: onExecute has to be called before filling elements; but OK could be
				// wrong if fillElements throws an exception.
				this.onExecute.accept(ExecuteState.OK);
				this.fillElements(result);

				return ExecuteState.OK;

			} catch (OpenemsException e1) {
				logError(this.log, e1, "Parsing Response failed.");
				throw e1;
			}

		} catch (Exception e) {
			var executeState = new ExecuteState.Error(e);
			this.onExecute.accept(executeState);
			// Invalidate Elements
			Stream.of(this.elements).forEach(el -> el.invalidate(bridge));
			return executeState;
		}
	}

The exception:

Exception in AbstractReadTask: java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.Double (java.lang.Integer and java.lang.Double are in module java.base of loader ‘bootstrap’)

Current Workaround:
When commenting out that channels are set to “null” when an invalidValueCounter > 0 helps. But I don’t think its a good solution :upside_down_face:

package io.openems.edge.bridge.modbus.api.element
AbstractModbusElement

	@Override
	public final void invalidate(AbstractModbusBridge bridge) {
		this.invalidValueCounter++;
		if (bridge.invalidateElementsAfterReadErrors() <= this.invalidValueCounter) {
			// this.setInputValue(null); // Workaround
		}
	}

Can you please share your code. It seems there is some incompatibility between your Channel definitions and Modbus mapping, that causes a conversion from Integer to Double.

Thats the code where the Modbus-Protocoll is defined. Did you mean that or additional code?

protected ModbusProtocol defineModbusProtocol() {ModbusProtocol modbusProtocol = new ModbusProtocol(this,

  new FC3ReadRegistersTask(5095, Priority.HIGH,
    m(SkaleEss.ChannelId.SKALE_ESS_STATE, new UnsignedWordElement(5095)),

...

    m(SymmetricEss.ChannelId.CAPACITY, new UnsignedWordElement(5104),ElementToChannelConverter.SCALE_FACTOR_3),
    m(EssTesvoltSkale.ChannelId.CAPACITY_AH, new UnsignedWordElement(5105)),
    m(EssTesvoltSkale.ChannelId.SOH, new UnsignedWordElement(5106),ElementToChannelConverter.SCALE_FACTOR_MINUS_2),
    m(SymmetricEss.ChannelId.SOC, new UnsignedWordElement(5107),ElementToChannelConverter.SCALE_FACTOR_MINUS_2),
    m(EssDcCharger.ChannelId.VOLTAGE, new UnsignedWordElement(5108),ElementToChannelConverter.SCALE_FACTOR_2),
    new DummyRegisterElement(5109, 5110),
    m(EssTesvoltSkale.ChannelId.MAX_OPERATIONAL_VOLTAGE, new UnsignedWordElement(5111),ElementToChannelConverter.SCALE_FACTOR_2),
    m(EssTesvoltSkale.ChannelId.MIN_OPERATIONAL_VOLTAGE, new UnsignedWordElement(5112), ElementToChannelConverter.SCALE_FACTOR_2),

...

I guess I found the problem:

I had an error in a Channel-Callback. Since I solved it, the problem is gone.

1 Like