OpenHab and Eastron SDM230 configuration example via Modbus TCP (Volison ADM-5850G)

A couple of days ago I wrote about connecting Wellpro relays and inputs/outputs modules to OpenHab, today I want to share with you my configuration for Eastron SDM230 energy meter. I think that configuration should be very similar also for such models as SDM220, SDM120, SDM630.

Modbus TCP Gateway

As I already wrote about it in previous configuration - I will not stop on it again. You can check previous tutorial.

SDM230 Documentation

You can found user manual here (the one is also included in the box with device itself).
And here is the Modbus protocol implementation details.
There are two important details from the modbus documentation:

Each request for data must be restricted to 40 parameters or less. Exceeding the 40 parameter limit will cause a Modbus Protocol exception code to be returned.

Each parameter is held in two consecutive 4X registers

That means that we only can fetch length of 80 consecutive registers. After looking of amount of parameters of this energy meter and their addresses we can conlcude that if we want to fetch all data from this device - we need to use 4 separate pollers.

modbus.things configuration

As we know from Modbus Wikipedia article:

input register numbers start with 3 and span from 30001 to 39999

Let’s add these 4 pollers to our modbus.things configuration file:

Bridge modbus:tcp:sdm230_1 [ host="192.168.1.2", port=502, id=3 ] {
    Bridge poller inputRegisters [ start=0, length=80, refresh=1000, type="input" ] {
        Thing data Voltage                       "Voltage"                              [ readStart="0", readValueType="float32" ]
        Thing data Current                       "Current"                              [ readStart="6", readValueType="float32" ]
        Thing data ActivePower                   "Active Power"                         [ readStart="12", readValueType="float32" ]
        Thing data ApparentPower                 "Apparent Power"                       [ readStart="18", readValueType="float32" ]
        Thing data ReactivePower                 "Reactive Power"                       [ readStart="24", readValueType="float32" ]
        Thing data PowerFactor                   "Power Factor"                         [ readStart="30", readValueType="float32" ]
        Thing data PhaseAngle                    "Phase Angle"                          [ readStart="36", readValueType="float32" ]
        Thing data Frequency                     "Frequency"                            [ readStart="70", readValueType="float32" ]
        Thing data ImportActiveEnergy            "Import Active Energy"                 [ readStart="72", readValueType="float32" ]
        Thing data ExportActiveEnergy            "Export Active Energy"                 [ readStart="74", readValueType="float32" ]
        Thing data ImportReactiveEnergy          "Import Reactive Energy"               [ readStart="76", readValueType="float32" ]
        Thing data ExportReactiveEnergy          "Export Reactive Energy"               [ readStart="78", readValueType="float32" ]
    }
}
Bridge modbus:tcp:sdm230_2 [ host="192.168.1.2", port=502, id=3 ] {
    Bridge poller inputRegisters [ start=84, length=12, refresh=1000, type="input" ] {
        Thing data TotalSysPowerDemand           "Total system power demand"            [ readStart="84", readValueType="float32" ]
        Thing data MaxTotalSysPowerDemand        "Maximum total system power demand"    [ readStart="86", readValueType="float32" ]
        Thing data CurrentSysPositivePowerDemand "Current system positive power demand" [ readStart="88", readValueType="float32" ]
        Thing data MaxSysPositivePowerDemand     "Maximum system positive power demand" [ readStart="90", readValueType="float32" ]
        Thing data CurrentSysReversePowerDemand  "Current system reverse power demand"  [ readStart="92", readValueType="float32" ]
        Thing data MaxSysReversePowerDemand      "Maximum system reverse power demand"  [ readStart="94", readValueType="float32" ]
    }
}
Bridge modbus:tcp:sdm230_3 [ host="192.168.1.2", port=502, id=3 ] {
    Bridge poller inputRegisters [ start=258, length=8, refresh=1000, type="input" ] {
        Thing   data    CurrentDemand           "Current demand"            [ readStart="258", readValueType="float32" ]
        Thing   data    MaximumCurrentDemand    "Maximum current Demand"    [ readStart="264", readValueType="float32" ]
    }
}
Bridge modbus:tcp:sdm230_4 [ host="192.168.1.2", port=502, id=3 ] {
    Bridge poller inputRegisters [ start=342, length=4, refresh=1000, type="input" ] {
        Thing   data    TotalActiveEnergy      "Total Active Energy"   [ readStart="342", readValueType="float32" ]
        Thing   data    TotalReactiveEnergy    "Total Reactive Energy" [ readStart="344", readValueType="float32" ]
    }
}

I set pollers’ refresh interval to 1000 ms and id is 3 for me because this is 3rd device connected to my modbus gateway and I set address 3 in its settings (great thing that you can set SDM230’s modbus address directly from the device’s menu operating with buttons). As always don’t forget that all devices in a specific modbus network should have same baud rate.

sdm230.items

Add sdm230.items file with the following content:

Number Voltage                       "Voltage [%.3f Volts]"                          <poweroutlet> { channel="modbus:data:sdm230_1:inputRegisters:Voltage:number" }
Number Current                       "Current [%.3f Amps]"                           <poweroutlet> { channel="modbus:data:sdm230_1:inputRegisters:Current:number" }
Number ActivePower                   "Active Power [%.3f Watts]"                     <poweroutlet> { channel="modbus:data:sdm230_1:inputRegisters:ActivePower:number" }
Number ApparentPower                 "Apparent Power [%.3f VoltAmps]"                <poweroutlet> { channel="modbus:data:sdm230_1:inputRegisters:ApparentPower:number" }
Number ReactivePower                 "Reactive Power [%.3f VAr]"                     <poweroutlet> { channel="modbus:data:sdm230_1:inputRegisters:ReactivePower:number" }
Number PowerFactor                   "Power Factor [%.3f]"                           <poweroutlet> { channel="modbus:data:sdm230_1:inputRegisters:PowerFactor:number" }
Number PhaseAngle                    "Phase Angle [%.3f °]"                          <poweroutlet> { channel="modbus:data:sdm230_1:inputRegisters:PhaseAngle:number" }
Number Frequency                     "Frequency [%.3f Hz]"                           <poweroutlet> { channel="modbus:data:sdm230_1:inputRegisters:Frequency:number" }
Number ImportActiveEnergy            "Import Active Energy [%.3f kWh]"               <poweroutlet> { channel="modbus:data:sdm230_1:inputRegisters:ImportActiveEnergy:number" }
Number ExportActiveEnergy            "Export Active Energy [%.3f kWh]"               <poweroutlet> { channel="modbus:data:sdm230_1:inputRegisters:ExportActiveEnergy:number" }
Number ImportReactiveEnergy          "Import Reactive Energy [%.3f kVArh]"           <poweroutlet> { channel="modbus:data:sdm230_1:inputRegisters:ImportReactiveEnergy:number" }
Number ExportReactiveEnergy          "Export Reactive Energy [%.3f kVArh]"           <poweroutlet> { channel="modbus:data:sdm230_1:inputRegisters:ExportReactiveEnergy:number" }

Number TotalSysPowerDemand           "Total system power demand [%.3f W]"            <poweroutlet> { channel="modbus:data:sdm230_2:inputRegisters:TotalSysPowerDemand:number" }
Number MaxTotalSysPowerDemand        "Maximum total system power demand [%.3f W]"    <poweroutlet> { channel="modbus:data:sdm230_2:inputRegisters:MaxTotalSysPowerDemand:number" }
Number CurrentSysPositivePowerDemand "Current system positive power demand [%.3f W]" <poweroutlet> { channel="modbus:data:sdm230_2:inputRegisters:CurrentSysPositivePowerDemand:number" }
Number MaxSysPositivePowerDemand     "Maximum system positive power demand [%.3f W]" <poweroutlet> { channel="modbus:data:sdm230_2:inputRegisters:MaxSysPositivePowerDemand:number" }
Number CurrentSysReversePowerDemand  "Current system reverse power demand [%.3f W]"  <poweroutlet> { channel="modbus:data:sdm230_2:inputRegisters:CurrentSysReversePowerDemand:number" }
Number MaxSysReversePowerDemand      "Maximum system reverse power demand [%.3f W]"  <poweroutlet> { channel="modbus:data:sdm230_2:inputRegisters:MaxSysReversePowerDemand:number" }

Number CurrentDemand                 "Current demand [%.3f Amps]"                    <poweroutlet> { channel="modbus:data:sdm230_3:inputRegisters:CurrentDemand:number" }
Number MaximumCurrentDemand          "Maximum current Demand [%.3f Amps]"            <poweroutlet> { channel="modbus:data:sdm230_3:inputRegisters:MaximumCurrentDemand:number" }

Number TotalActiveEnergy             "Total Active Energy [%.3f kWh]"                <poweroutlet> { channel="modbus:data:sdm230_4:inputRegisters:TotalActiveEnergy:number" }
Number TotalReactiveEnergy           "Total Reactive Energy [%.3f kVArh]"            <poweroutlet> { channel="modbus:data:sdm230_4:inputRegisters:TotalReactiveEnergy:number" }

Sitemap

Let’s add new frame for Modbus devices and put ā€œEnergy Meterā€ subsection to it:

Frame label="Modbus" {
    Text label="Energy Meter" icon="energy" {
        Text item=Voltage                       label="Voltage [%.3f Volts]"
        Text item=Current                       label="Current [%.3f Amps]"
        Text item=ActivePower                   label="Active Power [%.3f Watts]"                    
        Text item=ApparentPower                 label="Apparent Power [%.3f VoltAmps]"               
        Text item=ReactivePower                 label="Reactive Power [%.3f VAr]"                    
        Text item=PowerFactor                   label="Power Factor [%.3f]"                          
        Text item=PhaseAngle                    label="Phase Angle [%.3f °]"                         
        Text item=Frequency                     label="Frequency [%.3f Hz]"                          
        Text item=ImportActiveEnergy            label="Import Active Energy [%.3f kWh]"              
        Text item=ExportActiveEnergy            label="Export Active Energy [%.3f kWh]"              
        Text item=ImportReactiveEnergy          label="Import Reactive Energy [%.3f kVArh]"          
        Text item=ExportReactiveEnergy          label="Export Reactive Energy [%.3f kVArh]"          
        Text item=TotalSysPowerDemand           label="Total system power demand [%.3f W]"           
        Text item=MaxTotalSysPowerDemand        label="Maximum total system power demand [%.3f W]"   
        Text item=CurrentSysPositivePowerDemand label="Current system positive power demand [%.3f W]"
        Text item=MaxSysPositivePowerDemand     label="Maximum system positive power demand [%.3f W]"
        Text item=CurrentSysReversePowerDemand  label="Current system reverse power demand [%.3f W]" 
        Text item=MaxSysReversePowerDemand      label="Maximum system reverse power demand [%.3f W]" 
        Text item=CurrentDemand                 label="Current demand [%.3f Amps]"        
        Text item=MaximumCurrentDemand          label="Maximum current Demand [%.3f Amps]"
        Text item=TotalActiveEnergy             label="Total Active Energy [%.3f kWh]"    
        Text item=TotalReactiveEnergy           label="Total Reactive Energy [%.3f kVArh]"
    }
}

And here is our result:

2 Likes

Hi! I’m new here. I’ve installed OpenHAB4 and am trying to integrate an identical meter into my system using ModbusRTU (without TCP). All the instructions I’ve read haven’t led to a positive result. I managed to poll the meter, but I can’t figure out where the data read via Modbus goes and how I can use it. Can anyone help?

Can you please share your Things and Items configuration. Without, it is difficult to help.

I’d like to share that after two days of intense effort, I managed to get data from the SDM230 meter. I suspect I didn’t do it in the most elegant way—I used a massive number of Bindings, and there’s probably a cleaner solution. I’m still confused by the terminology and don’t know where the configuration files are located in OH4 yet.


Configuration is stored under userdata/jsondb, but that was not what I asked for.
Every Thing has a code tab when oprning in MainUI, thatā€˜s what I wanted to see.
Screenshots are hard to read on a mobile and canā€˜t be quoted.
In general, you should create one serial Bridge Thing and one Poller linked to that Bridge for every datapoint you want to read.
Then you need one Data Thing for each datapoint, linked to the according Poller.
A consistent naming for Poller and Data Things is really helpfull (EnergyPoller/EnergyData …)
At last, link the Item to the channel of your Data Thing.

Here is my main Modbus bridge:

UID: modbus:serial:ade9315b69
label: Modbus_Bridge_uart3
thingTypeUID: modbus:serial
configuration:
  baud: 9600
  connectMaxTries: 1
  timeBetweenTransactionsMillis: 35
  stopBits: "1.0"
  parity: none
  receiveTimeoutMillis: 1500
  dataBits: 8
  echo: false
  encoding: rtu
  flowControlIn: none
  flowControlOut: none
  port: /dev/ttyS3
  connectTimeoutMillis: 10000
  afterConnectionDelayMillis: 0
  id: 1
  enableDiscovery: false

Here is my first poller (I have two of them) for example:

UID: modbus:poller:ade9315b69:508a939d33
label: SDM230_first_poller
thingTypeUID: modbus:poller
configuration:
  length: 80
  start: 0
  refresh: 300
  maxTries: 3
  cacheMillis: 50
  type: input
bridgeUID: modbus:serial:ade9315b69

Here is my voltage extractor (I have 9 of that sort). Starts from register ā€œ0ā€ and takes two registers as ā€œfloat32ā€:

UID: modbus:data:508a939d33:2431916c44
label: SDM230_Voltage_extractor
thingTypeUID: modbus:data
configuration:
  readValueType: float32
  readTransform: default
  writeTransform: default
  readStart: "0"
  updateUnchangedValuesEveryMillis: 100
  writeMultipleEvenWithSingleRegisterOrCoil: false
  writeMaxTries: 3
bridgeUID: modbus:poller:ade9315b69:508a939d33
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: {}

Ok, so what is your issue now, ad this config looks ok?