Modbus custom command

Hi All

I’m using a low cost AC power meter which requires the following command to reset the “energy” counter.
Slave address + 0x42 + CRC high + CRC low.
Is there a way to send such a command executed by a button? I could not figure it out using the docs or google.

Reading values works fine. Here is the configuration for the .things file I use:

Bridge modbus:serial:ext_power_sensor_230v [ port="/dev/ttyMODBUS2", baud=9600, stopBits="1.0", parity="none", dataBits=8, encoding="rtu", id=1] {
     Bridge poller input [ start=0, length=10, refresh=2500, type="input" ] {
          Thing data voltage       [ readStart="0", readValueType="uint16", readTransform="JS(divide_by_10.js)" ]
          Thing data current       [ readStart="1", readValueType="uint32_swap", readTransform="JS(divide_by_2000.js)" ]
          Thing data power         [ readStart="3", readValueType="uint32_swap", readTransform="JS(divide_by_20.js)" ]
          Thing data energy        [ readStart="5", readValueType="uint32_swap", readTransform="JS(divide_by_2.js)" ]
          Thing data frequency     [ readStart="7", readValueType="uint16", readTransform="JS(divide_by_10.js)" ]
          Thing data power_factor  [ readStart="8", readValueType="uint16", readTransform="JS(divide_by_100.js)" ]
          Thing data alarm_status  [ readStart="9", readValueType="uint16" ]
     }
}

Really sure? That does not seem enough to make a valid Modbus message.

You’ll want to use this “write using JSON” feature

I’ve not seen any Modbus command not give an address word and count or data words,but if that’s what you want you could try a JS that just

return ( "[{\"functionCode\": 66}]"

I don’t know if that will work.

According to the instructions this weird command is required. This is the sensor I’m using:

see section

2.5 Reset energy
The command format of the master to resetthe slave’s energyis (total 4 bytes):Slave address + 0x42 + CRC check high byte + CRC check low byte.Correct reply: slave address + 0x42 + CRC check high byte + CRC check low byte.Error Reply: Slave address + 0xC2 + Abnormal code+ CRC check high byte + CRC check low byte

I tried your approach but I’m getting an exception and I’m not yet fully sure why.

.things

Bridge modbus:serial:ext_power_sensor_230v [ port="/dev/ttyExtPowerSensor", baud=9600, stopBits="1.0", parity="none", dataBits=8, encoding="rtu", id=1] {
     Bridge poller input [ start=0, length=10, refresh=2500, type="input" ] {
          Thing data voltage       [ readStart="0", readValueType="uint16", readTransform="JS(divide_by_10.js)" ]
          Thing data current       [ readStart="1", readValueType="uint32_swap", readTransform="JS(divide_by_2000.js)" ]
          Thing data power         [ readStart="3", readValueType="uint32_swap", readTransform="JS(divide_by_20.js)" ]
          Thing data energy        [ readStart="5", readValueType="uint32_swap", readTransform="JS(divide_by_2.js)" ]
          Thing data frequency     [ readStart="7", readValueType="uint16", readTransform="JS(divide_by_10.js)" ]
          Thing data power_factor  [ readStart="8", readValueType="uint16", readTransform="JS(divide_by_100.js)" ]
          Thing data alarm_status  [ readStart="9", readValueType="uint16" ]

          Thing data reset_energy [  writeTransform="JS(reset_energy_counter.js)" ]
     }
}

.items

Switch ext_power_230v_reset_enerty  "reset  [%s]"  <power> ["power"] { channel="modbus:data:ext_power_sensor_230v:input:reset_energy:switch" }

reset_energy_counter.js

(function( cmd ) {
   return ("[{\"functionCode\": 66}]");
})(input)

exception

[ERROR] [nal.common.AbstractInvocationHandler] - An error occurred while calling method 'ThingHandler.handleCommand()' on 'org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler@1d07e51': null
java.lang.NullPointerException: null
	at org.openhab.core.io.transport.modbus.json.WriteRequestJsonUtilities.constructBluerint(WriteRequestJsonUtilities.java:125) ~[?:?]
	at org.openhab.core.io.transport.modbus.json.WriteRequestJsonUtilities.lambda$0(WriteRequestJsonUtilities.java:103) ~[?:?]
	at java.lang.Iterable.forEach(Iterable.java:75) ~[?:?]
	at org.openhab.core.io.transport.modbus.json.WriteRequestJsonUtilities.fromJson(WriteRequestJsonUtilities.java:102) ~[?:?]
	at org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler.processJsonTransform(ModbusDataThingHandler.java:308) ~[?:?]
	at org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler.transformCommandAndProcessJSON(ModbusDataThingHandler.java:242) ~[?:?]
	at org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler.handleCommand(ModbusDataThingHandler.java:188) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at org.openhab.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:154) [bundleFile:?]
	at org.openhab.core.internal.common.InvocationHandlerSync.invoke(InvocationHandlerSync.java:59) [bundleFile:?]
	at com.sun.proxy.$Proxy225.handleCommand(Unknown Source) [?:?]
	at org.openhab.core.thing.internal.profiles.ProfileCallbackImpl.handleCommand(ProfileCallbackImpl.java:80) [bundleFile:?]
	at org.openhab.core.thing.internal.profiles.SystemDefaultProfile.onCommandFromItem(SystemDefaultProfile.java:48) [bundleFile:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at org.openhab.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:154) [bundleFile:?]
	at org.openhab.core.internal.common.Invocation.call(Invocation.java:52) [bundleFile:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	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:834) [?:?]

I expect it’s looking for the address JSON that isn’t there.

Why do you need to reset it?

I would like to count the used energy over a given time. Like monthly or daily.
Since the sensor has the API I tried to use it but if it’s not trivial to solve I work around it by buffering the start value and calculate the difference after a given time.

Yeh, most meters either offer no re-zero at all, or require a great song and dance to achieve it.

If you have a persistence service running, you could just log the accumulated value each day. To find usage over a period, query the start and end values and calculate the difference. There might even be a way to do that directly in the database query.

The advantage of this method is you aren’t tied to a single reset schedule, you can always query between any two readings.

Yes this sounds like a good approach