I’m querying PV inverters using the SunSpec binding and wonder how to retrieve values such as home consumption or grid feed that originate from an inverter-(RS485-)connected smart meter.
Some inverters that come bundled with a smart meter from the same vendor have proprietary modbus registers for this but I’m looking to implement this for the generic case using SunSpec.
Can I create a smart meter sunspec binding thing and point it to the modbus TCP/IP bridge of the inverter ? Or would I need a separate interfac into the meter ?
Has anyone gotten this to work?
Thanks for any enlightenment of mine.
I guess ultimately my question is: does anyone know what SunSpec specifies about this ?
Does it specify separate register numbers for the channels that a sunspec meter thing offers ?
Could I request them from the inverter by “masking” the inverter as a meter ? It should recognize requests by the register numbers as being a request to a meter.
I’ve created a meter thing for a test and pointed it to the inverter bridge. It remains in ‘unknown’ state and throws exceptions:
2021-10-13 17:43:41.203 [WARN ] [rt.modbus.internal.ModbusManagerImpl] - Execution of scheduled (5000ms) poll task BasicPollTask [getEndpoint=ModbusIPSlaveEndpoint [address=192.168.178.123, port=1502], request=ModbusReadRequestBlueprint [slaveId=71, functionCode=READ_MULTIPLE_REGISTERS, start=40000, length=61, maxTries=3], getResultCallback()=org.openhab.binding.modbus.sunspec.internal.handler.AbstractSunSpecHandler$$Lambda$1615/0x54584028@17a297f, getFailureCallback()=org.openhab.binding.modbus.sunspec.internal.handler.AbstractSunSpecHandler$$Lambda$1616/0x54581828@115be4a] failed unexpectedly. Ignoring exception, polling again according to poll interval.
java.lang.IllegalArgumentException: Index=122 with type=int32 is out-of-bounds given registers of size 61
at org.openhab.core.io.transport.modbus.ModbusBitUtilities.assertIndexAndType(ModbusBitUtilities.java:164) ~[?:?]
at org.openhab.core.io.transport.modbus.ModbusBitUtilities.extractSInt32(ModbusBitUtilities.java:338) ~[?:?]
at org.openhab.core.io.transport.modbus.ModbusBitUtilities.extractStateFromRegisters(ModbusBitUtilities.java:122) ~[?:?]
at org.openhab.binding.modbus.sunspec.internal.parser.AbstractBaseParser.extractOptionalAcc32(AbstractBaseParser.java:88) ~[?:?]
at org.openhab.binding.modbus.sunspec.internal.parser.MeterModelParser.parse(MeterModelParser.java:91) ~[?:?]
at org.openhab.binding.modbus.sunspec.internal.handler.MeterHandler.handlePolledData(MeterHandler.java:56) ~[?:?]
at java.util.Optional.ifPresent(Optional.java:183) ~[?:?]
at org.openhab.binding.modbus.sunspec.internal.handler.AbstractSunSpecHandler.lambda$2(AbstractSunSpecHandler.java:337) ~[?:?]
at org.openhab.core.io.transport.modbus.internal.ModbusLibraryWrapper.invokeCallbackWithResponse(ModbusLibraryWrapper.java:333) ~[?:?]
at org.openhab.core.io.transport.modbus.internal.ModbusManagerImpl$PollOperation.lambda$1(ModbusManagerImpl.java:216) ~[?:?]
at org.openhab.core.io.transport.modbus.internal.SimpleStopWatch.timeRunnable(SimpleStopWatch.java:152) ~[?:?]
at org.openhab.core.io.transport.modbus.internal.ModbusManagerImpl$PollOperation.accept(ModbusManagerImpl.java:216) ~[?:?]
at org.openhab.core.io.transport.modbus.internal.ModbusManagerImpl$PollOperation.accept(ModbusManagerImpl.java:1) ~[?:?]
at org.openhab.core.io.transport.modbus.internal.ModbusManagerImpl.executeOperation(ModbusManagerImpl.java:614) ~[?:?]
at org.openhab.core.io.transport.modbus.internal.ModbusManagerImpl$ModbusCommunicationInterfaceImpl.lambda$1(ModbusManagerImpl.java:812) ~[?:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) [?:?]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) [?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
at java.lang.Thread.run(Thread.java:829) [?:?]
Quick look at the code indicates that meter thing is configured with the wrong length property, and it will poll too little data because of that, thus parsing of the data fails. I might be mistaken of course, I am not familiar with the device intricacies.
Discovery should handle this automatically I presume. Have you used manual thing configuration?
From my sunnyboy experience in one installation (where sunspec didnt fly very well) I can tell you that if inverter does anything then it is a fairly basic math with time coordination.
From meter you have import and export - both power and energy.
Building consumption can be estimated through (grid import + (inverter production - grid export)).
Same rule apply for power and energy.
You definitelly can have better results if you retrieve calculations from inverter which might do some data alignment. I saw cases where different polling/reporting cycles resulted in negative building power consumption.
Anyhow - look if your inverter can report meter read outs. I found rhat sunspec had many optional parts which differ from one manufacturer to other.
The sunspec specification uses “pages” or “block” to collect report data. Each device is free to decide what to implement. There is a discovery method built into the specification, so one can start from the beginning, read and identify all the blocks exported, and skip those that are not understood by the reader.
Our sunspec implementation in OH does this too. If you turn on auto discovery on the modbus bridge, and your device exports any of the known blocks, then they will show up in the auto discovery as things that you can use.
If however the meter type does not show up, it is very likely that it is not supported by your device, or uses a proprietary/newer block type than what is implemented at the moment.
If you turn on logging for the modbus package you could see the autodiscovery iterating through the block types found, this could be an indication of what is happening.
The manual setup is there for a last resort. Use this only, if you’re pretty sure that there is a block that matches the one we’re looking for, but for whatever reason autodiscovery did not found it. But it’s really a “hackers tool”, and not for everyday use.