Help with Modbus power control

Hi,

I’m new to using the Modbus protocol, already read the binding page how to use it: https://www.openhab.org/addons/bindings/modbus/ and for some part, I understand how to use it. I want to do two things: 1. read data 2. control power

The first part, reading the data, is working. There is a manual (here) where you can find the right addresses for the different subject.

But now the second part, I can’t to figure out. There is another manual about the control part (here) and the specifically page 12, Max active power I’m interested in controlling. When I can set a value (0 for off) I can shutdown my solar panels when the price turns negative and you’ll have to pay per kWh. I already successfully read the current price so openHAB knows when it turns negative, now I only need to understand how to use this F304 address with the Modbus protocol.

There is also a HomeAssistent plugin (here) on Github that does exactly what I’m looking for, but I don’t know how to translate this into a openHAB configuration.

There is a SolarEdge binding for OH. SolarEdge - Bindings | openHAB Does this not do what you need?

Unfortunately not, I did try the binding though, but it only reads data, it doesn’t offer the power control options…

Maybe for some people it is piece of cake how to configure this, in the end I just need to know how to write to address 0xF304 via Modbus over TCP, but I couldn’t find any openHAB examples as well.

To begin with, do I need to decode this value into another data type before configuring it, or is there a way to use this kind of addresses right away?

I don’t use modbus and modbus is one of the lowest level bindings meaning it’s much closer to the hardware than most.

Based on the docs in the add-on, I believe the steps are:

  1. create modbus tcp Thing.
  2. create a modbus poller Thing using the tcp Thing as the bridge
  3. create a modbus data Thing using the poller Thing as the bridge
  4. link the switch Channel to a Switch Item

Sending a command to the Switch Item will go to the modbus binding and out to the device.

As for the details for each one of those steps I can’t help with. I don’t really know modbus. I believe the address you have is in hexadecimal and OH will require that to be converted to decimal (i.e. 62212) which will be used for the writeStart properties of the data Thing. Presumably the readStart would be a different address? You’ll also need to know the data type of the value (e.g. bit, int32, etc.).

Once you have the Item though, it’s all OH stuff and the fact that it’s modbus no longer matters. See Getting Started and the Docs for details on what you want to do with this Item (command it, show it on an UI, chart it, etc.).

Yes, the first part already worked with the Modbus, on that part in the sunspec documentation they already gave the right address in decimal format so I could just use those.

But on the power control document, they use these hexidecimal, like you mentioned it should be converted to a decimal type.

But when I google a hex converter to decimal, I don’t get a value between 0 - 4999 but a mich bigger number, this is what the manual of the modbus binding says:

Comment On Addressing

Modbus Wikipedia article (opens new window)summarizes this excellently:

In the traditional standard, [entity] numbers for those entities start with a digit, followed by a number of four digits in range 1–9,999:

  • coils numbers start with a zero and then span from 00001 to 09999
  • discrete input numbers start with a one and then span from 10001 to 19999
  • input register numbers start with a three and then span from 30001 to 39999
  • holding register numbers start with a four and then span from 40001 to 49999

This translates into [entity] addresses between 0 and 9,998 in data frames.

Note that entity begins counting at 1, data frame address at 0.

What am I missing to get the right register number from this hexidecinal value?
For example, if I convert 0xF30C to decimal, I’ll get 62220 wich is out of range of these register numbers.

For that you’ll need someone who knows and understands modbus. That’s not me unfortunately.

Yea me neither, hopefully someone can explain how this works and what to do to get a valid value.

Just found out (from another manufacturer manual) there is another function code (21) with a range of 60001 - 65535.
This isn’t documented at this moment (and probably not supported) in the documentation of the modbus binding, anyone knows if you can still use it, if so, what register is it called, in the manual it says general.

Functiona in area other than holding/discrete input/register are very rare. Most common functions are write single or multiple. Within modbus elementa you can specify write register, its transformation (i.e. divide) and write function which might point to other kind of data than you actually fetched.
One of confusions present everywhere around mosbus is what registers are. Some documents mix finction code with register (i.e fc04 == register 4xxxx), some mix hex and decimal representation.
Try maybe with basic tools such modbus poll, which give you option to read and write registers. Development, or actually try-fail cycle, is then much faster. After confirming actual register you can quickly turn whole thing into openHAB config.

I can’t read HA code now on my phone, but it should be rather basic.

I already tried some tools but wasn’t successful yet. But am I right that I could just use an online converted from hex to decimal, for example 0xF001 converts to 61441? From what I read online, this range 60001 - 65535 belongs to the function code 21.

So, how I understand it (correct me if I’m wrong), the first 6xxxx is corresponding with a certain register and the address is 1441 + 1 = 1442 in this case. The tools that I found are using the same FC as openHAB right now so I can’t test this either. I assume if I use the FC04 holding register on this address it would translate to (4)1442 or did I misunderstood?

So I’ve been reading more about Modbus, although it is really confusing because it is such a old protocol and there is so much different information and interpretation it is hard to find what you’re looking for.

But after some poking around with some other tools, I got it almost fully working, my thing file:

Bridge modbus:tcp:SE2200TCP [ host="192.168.0.214", port=1502, id=1, timeBetweenTransactionsMillis=60, 
timeBetweenReconnectMillis=0, connectMaxTries=3, reconnectAfterMillis=0, connectTimeoutMillis=10000 ] {

    Bridge poller Registers [ start=69, length=50, refresh=5000, type="holding" ] {
      // Setting polling to 1000 ms sometimes led to strange values in I_AC_POWER

     //   Thing data C_DeviceAddress   [ readStart="69", readValueType="uint16" ]        // MODBUS Unit ID
     //   Thing data C_SunSpec_DID     [ readStart="69", readValueType="uint16" ]        // 101 = single phase, 102 = split phase, 103 = three phase 
     //   Thing data C_SunSpec_Length  [ readStart="70", readValueType="uint16" ]        // 50 = Length of model block
     //   Thing data I_AC_Current      [ readStart="71", readValueType="uint16" ]        // AC Total Current value
     //   Thing data I_AC_CurrentA     [ readStart="72", readValueType="uint16" ]        // AC Phase A Current value
     //   Thing data I_AC_CurrentB     [ readStart="73", readValueType="uint16" ]        // AC Phase B Current value
     //   Thing data I_AC_CurrentC     [ readStart="74", readValueType="uint16" ]        // AC Phase C Current value
     //   Thing data I_AC_Current_SF   [ readStart="75", readValueType="int16"  ]        // AC Current scale factor
     //   Thing data I_AC_VoltageAB    [ readStart="76", readValueType="uint16" ]        // AC Voltage Phase AB value
     //   Thing data I_AC_VoltageBC    [ readStart="77", readValueType="uint16" ]        // AC Voltage Phase BC value
     //   Thing data I_AC_VoltageCA    [ readStart="78", readValueType="uint16" ]        // AC Voltage Phase CA value
     //   Thing data I_AC_VoltageAN    [ readStart="79", readValueType="uint16" ]        // AC Voltage Phase A to N value
     //   Thing data I_AC_VoltageBN    [ readStart="80", readValueType="uint16" ]        // AC Voltage Phase B to N value
     //   Thing data I_AC_VoltageCN    [ readStart="81", readValueType="uint16" ]        // AC Voltage Phase C to N value
     //   Thing data I_AC_Voltage_SF   [ readStart="82", readValueType="int16"  ]        // AC Voltage scale factor
     //   Thing data I_AC_Power        [ readStart="83", readValueType="int16"  ]        // AC Power value
     //   Thing data I_AC_Power_SF     [ readStart="84", readValueType="int16"  ]        // AC Power scale factor
     //   Thing data I_AC_Frequency    [ readStart="85", readValueType="uint16" ]        // AC Frequency value
     //   Thing data I_AC_Frequency_SF [ readStart="86", readValueType="int16"  ]        // Scale factor
     //   Thing data I_AC_VA           [ readStart="87", readValueType="int16"  ]        // Apparent Power
     //   Thing data I_AC_VA_SF        [ readStart="88", readValueType="int16"  ]        // Scale factor
     //   Thing data I_AC_VAR          [ readStart="89", readValueType="int16"  ]        // Reactive Power
     //   Thing data I_AC_VAR_SF       [ readStart="90", readValueType="int16"  ]        // Scale factor
     //   Thing data I_AC_PF           [ readStart="91", readValueType="int16"  ]        // Power Factor
     //   Thing data I_AC_PF_SF        [ readStart="92", readValueType="int16"  ]        // Scale factor
     //   Thing data I_AC_Energy_WH    [ readStart="93", readValueType="acc32"  ]        // AC Lifetime Energy Production
     //   Thing data I_AC_Energy_WH_SF [ readStart="95", readValueType="uint16" ]        // Scale factor
     //   Thing data I_DC_Current      [ readStart="96", readValueType="uint16" ]        // DC Current value
     //   Thing data I_DC_Current_SF   [ readStart="97", readValueType="int16"  ]        // Scale factor
     //   Thing data I_DC_Voltage      [ readStart="98", readValueType="uint16" ]        // DC Voltage value
     //   Thing data I_DC_Voltage_SF   [ readStart="99", readValueType="int16"  ]        // Scale factor
     //   Thing data I_DC_Power        [ readStart="100", readValueType="int16" ]        // DC Power value
     //   Thing data I_DC_Power_SF     [ readStart="101", readValueType="int16" ]        // Scale factor
     //   Thing data I_Temp_Sink       [ readStart="103", readValueType="int16" ]        // Heat sink temperature
     //   Thing data I_Temp_SF         [ readStart="106", readValueType="int16" ]        // Scale factor
        Thing data I_Status          [ readStart="107", readValueType="uint16"]        // Operating state
     //   Thing data I_Status_Vendor   [ readStart="109", readValueType="uint16"]        // Vendor-defined operating state and error codes
     //   Thing data Dyn_Power_Cntrl   [ readStart="300", readValueType="uint16"]        // on address 0xF300 is disabled (=0) by default and should be enabled (1) for dynamic power control functionality
    }
    Bridge poller Registers2 [ start=61440, length=10, refresh=5000, type="holding" ] {
       //Setting polling to 1000 ms sometimes led to strange values in I_AC_POWER

        Thing data Act_Power_Ctrl   [ readStart="61441", readValueType="uint16", writeStart="61441", writeValueType="int16", writeType="holding"]        // R/W to "Active Power Control Limit" on address 0xF001

    }}

And the item file:

//SolarEdge modbus
Number Sensor_SE2200_ModBus_I_Status "Invertor status [MAP(SE2200_status.map):%s]" <energy> {channel="modbus:data:SE2200TCP:Registers:I_Status:number", autoupdate="false" }
Dimmer Sensor_SE2200_ModBus_Active_Power_Control_Limit "Active power control" {channel="modbus:data:SE2200TCP:Registers2:Act_Power_Ctrl:dimmer", autoupdate="false" }

The only “issue” I can’t wrap my head around right now is that the dimmer is working if I send 0 or 100, the value on the inverter will change. But, when I send 50 for example (or any other value between 1-99) it will always change to 100.

I’m not sure, but I could it has something to do with " writeValueType=“int16” " inside the data thing for address 61441, in the SolarEdge manual they say the type is uint16 (I assume for write and read then). But when I change the writeValueType to uint16, in the openHAB logging it says that this value isn’t allowed (although I see older topic’s using this value):

2024-05-20 13:07:58.631 [INFO ] [ab.event.ThingStatusInfoChangedEvent] - Thing 'modbus:data:SE2200TCP:Registers2:Act_Power_Ctrl' changed from ONLINE to UNINITIALIZED (HANDLER_CONFIGURATION_PENDING): {writeValueType=The value uint16 does not match allowed parameter options. Allowed options are: [ParameterOption [value="int64", label="64bit positive or negative integer, 4 registers (int64, uint64)"], ParameterOption [value="int64_swap", label="64bit positive or negative integer, 4 registers but with 16bit words/registers in reverse order (dcba) (int64_swap, uint64_swap)"], ParameterOption [value="float32", label="32bit floating point (float32)"], ParameterOption [value="float32_swap", label="32bit floating point, 16bit words swapped (float32_swap)"], ParameterOption [value="int32", label="32bit positive or negative integer, 2 registers (int32, uint32)"], ParameterOption [value="int32_swap", label="32bit positive or negative integer, 2 registers but with 16bit words/registers in reverse order (ba) (int32_swap, uint32_swap)"], ParameterOption [value="int16", label="16bit positive or negative integer, 1 register (int16, uint16)"], ParameterOption [value="bit", label="individual bit (bit)"]]}

Any thoughts?

Did you get this working? I just got it working with an SE5000.

61441 needs to be uint16 - 61762 needs to be uint32

Finally, you need to commit the changes via 61696 - which according to the docs is int16 - I get an error writing the commit, but the changes work.

Hi Paul,

would you please share your Things and Items files, Thanks.
Further have you tried to use 0xF30C / 62220 which should allow to set the active power direct in W?
Thx. Tom

I use the GUI to administer the Things/items but I’ll try and describe it, and also include the ‘code’ from the gui…

  1. Modbus Controller - just needs the IP and port.
UID: modbus:tcp:e9b3fa4b05
label: SolarEdge Modbus Controller
thingTypeUID: modbus:tcp
configuration:
  rtuEncoded: false
  connectMaxTries: 1
  reconnectAfterMillis: 1000
  timeBetweenTransactionsMillis: 200
  port: 502
  timeBetweenReconnectMillis: 0
  connectTimeoutMillis: 5000
  host: 192.168.1.68
  afterConnectionDelayMillis: 1000
  id: 1
  enableDiscovery: true
location: Garage
  1. Thing for Modbus data - Advanced Power Enable 61762
UID: modbus:data:e9b3fa4b05:eff74927c3
label: SolarEdge - Modbus Data - Advanced Power Control Enable  - 61762
thingTypeUID: modbus:data
configuration:
  readTransform:
    - default
  writeTransform:
    - default
  writeType: holding
  updateUnchangedValuesEveryMillis: 1000
  writeValueType: int32
  writeMultipleEvenWithSingleRegisterOrCoil: false
  writeMaxTries: 1
  writeStart: "61762"
bridgeUID: modbus:tcp:e9b3fa4b05
channels:
  - id: number
    channelTypeUID: modbus:number-type
    label: Value as Number
    description: Number item channel
    configuration: {}
  - id: switch
    channelTypeUID: modbus:switch-type
    label: Value as Switch
    description: Switch item channel
    configuration: {}
  - id: contact
    channelTypeUID: modbus:contact-type
    label: Value as Contact
    description: Contact item channel
    configuration: {}
  - id: dimmer
    channelTypeUID: modbus:dimmer-type
    label: Value as Dimmer
    description: Dimmer item channel
    configuration: {}
  - id: datetime
    channelTypeUID: modbus:datetime-type
    label: Value as DateTime
    description: DateTime item channel
    configuration: {}
  - id: string
    channelTypeUID: modbus:string-type
    label: Value as String
    description: String item channel
    configuration: {}
  - id: rollershutter
    channelTypeUID: modbus:rollershutter-type
    label: Value as Rollershutter
    description: Rollershutter item channel
    configuration: {}
  - id: lastReadSuccess
    channelTypeUID: modbus:last-successful-read-type
    label: Last Successful Read
    description: Date of last read
    configuration: {}
  - id: lastReadError
    channelTypeUID: modbus:last-erroring-read-type
    label: Last Erroring Read
    description: Date of last read error
    configuration: {}
  - id: lastWriteSuccess
    channelTypeUID: modbus:last-successful-write-type
    label: Last Successful Write
    description: Date of last write
    configuration: {}
  - id: lastWriteError
    channelTypeUID: modbus:last-erroring-write-type
    label: Last Erroring Write
    description: Date of last write error
    configuration: {}
  1. Thing for Modbus data - Active Power Limit 61441
UID: modbus:data:e9b3fa4b05:8334aecace
label: SolarEdge -  Modbus Data -  Active Power Limit - 61441
thingTypeUID: modbus:data
configuration:
  readValueType: int16
  readTransform:
    - default
  writeTransform:
    - default
  writeType: holding
  readStart: "61441"
  updateUnchangedValuesEveryMillis: 1000
  writeValueType: int16
  writeMultipleEvenWithSingleRegisterOrCoil: false
  writeMaxTries: 1
  writeStart: "61441"
bridgeUID: modbus:poller:e9b3fa4b05:f49269a440
channels:
  - id: number
    channelTypeUID: modbus:number-type
    label: Value as Number
    description: Number item channel
    configuration: {}
  - id: switch
    channelTypeUID: modbus:switch-type
    label: Value as Switch
    description: Switch item channel
    configuration: {}
  - id: contact
    channelTypeUID: modbus:contact-type
    label: Value as Contact
    description: Contact item channel
    configuration: {}
  - id: dimmer
    channelTypeUID: modbus:dimmer-type
    label: Value as Dimmer
    description: Dimmer item channel
    configuration: {}
  - id: datetime
    channelTypeUID: modbus:datetime-type
    label: Value as DateTime
    description: DateTime item channel
    configuration: {}
  - id: string
    channelTypeUID: modbus:string-type
    label: Value as String
    description: String item channel
    configuration: {}
  - id: rollershutter
    channelTypeUID: modbus:rollershutter-type
    label: Value as Rollershutter
    description: Rollershutter item channel
    configuration: {}
  - id: lastReadSuccess
    channelTypeUID: modbus:last-successful-read-type
    label: Last Successful Read
    description: Date of last read
    configuration: {}
  - id: lastReadError
    channelTypeUID: modbus:last-erroring-read-type
    label: Last Erroring Read
    description: Date of last read error
    configuration: {}
  - id: lastWriteSuccess
    channelTypeUID: modbus:last-successful-write-type
    label: Last Successful Write
    description: Date of last write
    configuration: {}
  - id: lastWriteError
    channelTypeUID: modbus:last-erroring-write-type
    label: Last Erroring Write
    description: Date of last write error
    configuration: {}
  1. Thing for Modbus data - Commit Power Data
UID: modbus:data:e9b3fa4b05:022f765fb0
label: SolarEdge - Modbus Data - Commit Power Control - 61696
thingTypeUID: modbus:data
configuration:
  readTransform:
    - default
  writeTransform:
    - default
  writeType: holding
  updateUnchangedValuesEveryMillis: 1000
  writeValueType: int16
  writeMultipleEvenWithSingleRegisterOrCoil: false
  writeMaxTries: 1
  writeStart: "61696"
bridgeUID: modbus:tcp:e9b3fa4b05
channels:
  - id: number
    channelTypeUID: modbus:number-type
    label: Value as Number
    description: Number item channel
    configuration: {}
  - id: switch
    channelTypeUID: modbus:switch-type
    label: Value as Switch
    description: Switch item channel
    configuration: {}
  - id: contact
    channelTypeUID: modbus:contact-type
    label: Value as Contact
    description: Contact item channel
    configuration: {}
  - id: dimmer
    channelTypeUID: modbus:dimmer-type
    label: Value as Dimmer
    description: Dimmer item channel
    configuration: {}
  - id: datetime
    channelTypeUID: modbus:datetime-type
    label: Value as DateTime
    description: DateTime item channel
    configuration: {}
  - id: string
    channelTypeUID: modbus:string-type
    label: Value as String
    description: String item channel
    configuration: {}
  - id: rollershutter
    channelTypeUID: modbus:rollershutter-type
    label: Value as Rollershutter
    description: Rollershutter item channel
    configuration: {}
  - id: lastReadSuccess
    channelTypeUID: modbus:last-successful-read-type
    label: Last Successful Read
    description: Date of last read
    configuration: {}
  - id: lastReadError
    channelTypeUID: modbus:last-erroring-read-type
    label: Last Erroring Read
    description: Date of last read error
    configuration: {}
  - id: lastWriteSuccess
    channelTypeUID: modbus:last-successful-write-type
    label: Last Successful Write
    description: Date of last write
    configuration: {}
  - id: lastWriteError
    channelTypeUID: modbus:last-erroring-write-type
    label: Last Erroring Write
    description: Date of last write error
    configuration: {}

The items are nothing special - they are just ‘value as number’

You’ll note I’m not trying to read back the modbus values - I was seeing timeout errors - perhaps as I’m detecting changes in household usage too often, and trying to adjust the inverter too often?

I’ve never tried 62220 - will need to read up on it. What I’ve described has been working well for several months now :slight_smile:

Sing out if you have more questions :slight_smile:

Thanks Paul, was just about to head the GUI way myself as I do not see what is wrong with my definitions.

Question, I’m running the SE7K with display and SW 3.2537.0000 are you on the same or is it some SW differences?

1 Like