Community
OpenEnergyMonitor

Community

Monitor Fronius Primo 5

modbus
fronius
Tags: #<Tag:0x00007f1be6233300> #<Tag:0x00007f1be62330f8>

(Paul) #21

This is a common quirk of modbus, I have been working with many modbus devices recently and found as many docs use address as register, and sometimes the terms are used interchangeably, this seems to be rooted in the age old fact that the “first” position in an array is always index 0 etc, although I have written my own universal modbus reading code, I too have to +1 on some devices, but not all, it depends on what is documented, so even if you rewrite emonhub to +1 automatically, there would then be instances where some users have to -1 depending on the published documentation (and recognizing the difference, which even some manufacturers seem unable to do).


(Anthony Vassallo) #22

Hi All
I am also trying to connect to my Fronius Primo (8.2) unit, but not having any success. I can poll the inverter using a python script and get results, but can’t seem to get past square 1 (or 0 in linux…) with configuring emonhub. Here is my config file extract:

[[ModbusTCP]]
# this interfacer retrieves register information from modbusTCP clients
# retrieve register information from modbus TCP documentation for your inverter.
# Information here is designed for Fronius Symo 3 phase inverter. #changed to check operation of Primo 
    Type = EmonModbusTcpInterfacer
    [[[init_settings]]]
	    modbus_IP = 10.0.0.9   # ip address of client to retrieve data from
	    modbus_port = 502          # Portclient listens on
    [[[runtimesettings]]]
        # list of names of items being retrieved
	      rName = ID,L,A,W,Hz,VA,VAr,PF,WH,DCW
        # 
        # List of starting registers for items listed above
	      register = 40070,40071,40072,40092,40094,40096,40098,40100,40102,40108
        # 
        # List of # of registers used for each item
	      nReg = 1,1,2,2,2,2,2,2,2,2
        # Data type for each item above
	      rType = uint16,uint16,float32,float32,float32,float32,float32,float32,float32,float32
        # nodeid used to match with node definition in nodes section below. Can be set to any integer value not previously used.
	      nodeId = 30
        # Channel to publish data to should leave as ToEmonCMS
        pubchannels = ToEmonCMS,
        # time in seconds between checks, This is in addition to emonhub_interfacer.run() sleep time of .01
        # use this value to set the frequency of data retrieval from modbus client
        interval = 10

[[MQTT]]

    Type = EmonHubMqttInterfacer
    [[[init_settings]]]
        mqtt_host = 127.0.0.1
        mqtt_port = 1883
        mqtt_user = emonpi
        mqtt_passwd = emonpimqtt2016

    [[[runtimesettings]]]
        pubchannels = ToRFM12,
        subchannels = ToEmonCMS,

        # emonhub/rx/10/values format
        # Use with emoncms Nodes module
        node_format_enable = 1
        node_format_basetopic = emonhub/

        # emon/emontx/power1 format - use with Emoncms MQTT input
        # http://github.com/emoncms/emoncms/blob/master/docs/RaspberryPi/MQTT.md
        nodevar_format_enable = 1
        nodevar_format_basetopic = emon/

and my nodes section:

[[30]]
    nodename = fronius
    [[[rx]]]
       names = ID,L,A,W,Hz,VA,VAr,PF,WH,DCW
       datacodes = H,H,f,f,f,f,f,f,f,f
       scale = 1
       units = V,W,kWh,Wh,W,W,V,V,V,V,V

I’ve install pymodbus and pymodbusTCCP onto my emonbase, but no matter what I try, I can’t seem to get any output from node 30…
I’m using the latest versions as far as I can tell:

Emoncms	Version	low-write 9.9.5
Modules	Administration | App v1.2.0 | Backup v1.1.6 | EmonHub Config v1.0.0 | Dashboard v1.3.1 | Device v1.2.0 | EventProcesses | Feed | Graph v1.2.1 | Input | Postprocess v1.0.0 | CoreProcess | Schedule | Network Setup v1.0.0 | sync | Time | User | Visualisation | WiFi v1.3.0

but nothing from node 30 to be seen in inputs or using
mosquitto_sub -v -u 'emonpi' -P 'emonpimqtt2016' -t '#'
I’ve looked at the emonhub logs but no mention of fronius or node 30…
Can anyone suggest a way forward?


(klx) #23

Hi,

What python script are you using to test, can you give more details about this script?

scale must be defined by all registers, see this example:

https://github.com/openenergymonitor/emonhub/blob/emon-pi/conf/interfacer_examples/modbus/modbusTCP.emonhub.conf

Missatge de Anthony Vassallo [email protected] del dia dl., 31 de des. 2018 a les 6:38:


(klx) #24

Well,

finally seems that I can obtain data and graphs! Great!

Now I only have one problem, I cna obtain a value of daywh by day from fronius, but I can generate a daily graphs from this daily ouput, anybody can give informatin how to do this with this daily value from fronius?

I see another option generatin from power consumption but also is not working or I don’t know ho to do this power to kwh, any suggestion?

Thanks!

Missatge de Anthony Vassallo [email protected] del dia dl., 31 de des. 2018 a les 6:38:


(Anthony Vassallo) #25

Python script is basic, but uses Rcihard Stobor’s type translation. It took some effort to find and use the Primo modbus registers, but is now working OK. Note all the register lines from 40070 down are commented out in the script, but I had to remove the quotes to past here:

from pyModbusTCP.client import ModbusClient
import time

import ctypes
#
# byte translation from: https://github.com/stoberblog/sunspec-modbus/blob/master/sunspecModbus.py
# Fronius Primo has 62 registers starting at 40070
# reg 0 should be inverter model 111 (unint16)
# reg 1 should be length of reg blocks = 60 (unint16)
# next 23 are 2 register blocks of float32
# then 2 single register blocks
# then final six 2 register blocks
# from docs:
# -----following should be commented out ---------------
40070	40070	1	ID	Uniquely identifies this as a SunSpec Inverter Float Modbus Map; 111: single phase, 112: split phase, 113: three phase	uint16
40071	40071	1	L	Length of inverter model block	uint16
40072	40073	2	A	AC Total Current value	float32
40074	40075	2	AphA	AC Phase-A Current value	float32
40076	40077	2	AphB	AC Phase-B Current value	float32
40078	40079	2	AphC	AC Phase-C Current value	float32
40080	40081	2	PPVphAB	AC Voltage Phase-AB value	float32
40082	40083	2	PPVphBC	AC Voltage Phase-BC value	float32
40084	40085	2	PPVphCA	AC Voltage Phase-CA value	float32
40086	40087	2	PhVphA	AC Voltage Phase-A-to-neutral value	float32
40088	40089	2	PhVphB	AC Voltage Phase-B-to-neutral value	float32
40090	40091	2	PhVphC	AC Voltage Phase-C-to-neutral value	float32
40092	40093	2	W	AC Power value	float32
40094	40095	2	Hz	AC Frequency value	float32
40096	40097	2	VA	Apparent Power	float32
40098	40099	2	VAr	Reactive Power	float32
40100	40101	2	PF	Power Factor	float32
40102	40103	2	WH	AC Lifetime Energy production	float32
40104	40105	2	DCA	DC Current value	float32
40106	40107	2	DCV	DC Voltage value	float32
40108	40109	2	DCW	DC Power value	float32
40110	40111	2	TmpCab	Cabinet Temperature	float32
40112	40113	2	TmpSnk	Coolant or Heat Sink Temperature	float32
40114	40115	2	TmpTrns	Transformer Temperature	float32
40116	40117	2	TmpOt	Other Temperature	float32
40118	40118	1	St	Operating State	enum16
40119	40119	1	StVnd	Vendor Defined Operating State	enum16
40120	40121	2	Evt1	Event Flags (bits 0-31)	uint32
40122	40123	2	Evt2	Event Flags (bits 32-63)	uint32
40124	40125	2	EvtVnd1	Vendor Defined Event Flags (bits 0-31)	uint32
40126	40127	2	EvtVnd2	Vendor Defined Event Flags (bits 32-63)	uint32
40128	40129	2	EvtVnd3	Vendor Defined Event Flags (bits 64-95)	uint32
40130	40131	2	EvtVnd4	Vendor Defined Event Flags (bits 96-127)	uint32

so read 62 registers at once, then pull out what is required and convert bytes according to type
eg AC power value will be 2 registers 24,25 corresponding to regs[22,23] 

this from the 2MPPT model specs

40264	40264	1	ID	A well-known value 160.  Uniquely identifies this as a SunSpec Multiple MPPT Inverter Extension Model Mode	unit16			160
40265	40265	1	L	Length of Multiple MPPT Inverter Extension Model	uint16			48
40266	40266	1	DCA_SF	Current Scale Factor	sunssf			
40267	40267	1	DCV_SF	Voltage Scale Factor	sunssf			
40268	40268	1	DCW_SF	Power Scale Factor	sunssf			
40269	40269	1	DCWH_SF	Energy Scale Factor	sunssf			
40270	40271	2	Evt	Global Events	bitfield32			
40272	40272	1	N	Number of Modules	uint16			2
40273	40273	1	TmsPer	Timestamp Period	uint16			Not supported
40274	40274	1	1_ID	Input ID	uint16			1
40275	40282	8	1_IDStr	Input ID Sting	String16			"String 1"
40283	40283	1	1_DCA	DC Current	uint16	A	DCA_SF	
40284	40284	1	1_DCV	DC Voltage	uint16	V	DCV_SF	
40285	40285	1	1_DCW	DC Power	uint16	W	DCW_SF	
40286	40287	2	1_DCWH	Lifetime Energy	acc32	Wh	DCWH_SF	
40288	40289	2	1_Tms	Timestamp	uint32	Secs		
40290	40290	1	1_Tmp	Temperature	int16	C		
40291	40291	1	1_DCSt	Operating State	enum16			
40292	40293	2	1_DCEvt	Module Events	bitfield32			
40294	40294	1	2_ID	Input ID	uint16			2
40295	40302	8	2_IDStr	Input ID Sting	String16	
# ---------commented out to here-------------------------------------
'''

'''
 These classes/structures/unions, allow easy conversion between
 modbus 16bit registers and ctypes (a useful format)
'''

# Single register (16 bit) based types
class convert1(ctypes.Union):
    _fields_ = [("u16", ctypes.c_uint16),
                ("s16", ctypes.c_int16)]
    
# Two register (32 bit) based types
class x2u16Struct(ctypes.Structure):
    _fields_ = [("h", ctypes.c_uint16),
                ("l", ctypes.c_uint16)]
class convert2(ctypes.Union):
    _fields_ = [("float", ctypes.c_float),
                ("u16", x2u16Struct),
                ("sint32", ctypes.c_int32),
                ("uint32", ctypes.c_uint32)]
    
# Four register (64 bit) based types
class x4u16Struct(ctypes.Structure):
    _fields_ = [("hh", ctypes.c_uint16),
                ("hl", ctypes.c_uint16),
                ("lh", ctypes.c_uint16),
                ("ll", ctypes.c_uint16)]
class convert4(ctypes.Union):
    _fields_ = [("u16", x4u16Struct),
                ("sint64", ctypes.c_int64),
                ("uint64", ctypes.c_uint64)]

counterA = 0
SERVER_HOST = "10.0.0.9"
SERVER_PORT = 502
c = ModbusClient()
# uncomment this line to see debug message
# c.debug(True)
# define modbus server host, port
c.host(SERVER_HOST)
c.port(SERVER_PORT)
while True:
    # open or reconnect TCP to server
    counterA += 1
    if not c.is_open():
        if not c.open():
            print("unable to connect to "+SERVER_HOST+":"+str(SERVER_PORT))
    # if open() is ok, read register (modbus function 0x03)
    if c.is_open():
        # read 60 registers at address subtracting 1, store result in regs list
        # first series is std inverter functions
        # second series is the multiple string modes
        regs1 = c.read_holding_registers(40070-1, 62)
        regs2 = c.read_holding_registers(40264-1, 50)
        # if success display MPT identifier once
        if (regs2 and counterA ==1):
            print("Success")
            Translate = convert1()
            Translate.u16 = regs2[0]
            print("Multiple MPT value = "+str(Translate.u16))
    # sleep 2s before next polling
    time.sleep(2)
    # check if MPPT
    Translate = convert1()
    Translate.u16 = regs2[0]
    # 
    # check AC power from regs 40093,4
    Translate=convert2()
    Translate.u16.h = regs1[23]
    Translate.u16.l = regs1[22]
    print("Site Power="+str(Translate.float))
    # check AC frequency
    Translate.u16.h = regs1[25]
    Translate.u16.l = regs1[24]
    ACFreq = Translate.float
    print("AC Frequency = "+str('{:g}'.format(ACFreq)))
    # check DC power
    Translate.u16.h = regs1[39]
    Translate.u16.l = regs1[38]
    DCPower = Translate.float
    print("DC Power = " + str('{:g}'.format(DCPower)))
    # check DC voltage
    # first get scale factor, which is signed 16 bit as exponent
    Translate=convert1()
    Translate.s16 = regs2[3]
    DCV_SF = Translate.s16
    # now get voltage value, which is u16 from MPPT ID 1 and 2
    Translate2=convert1()
    Translate2.u16 = regs2[20]
    DCMPPT1 = Translate2.u16*10**DCV_SF
    Translate2.u16 = regs2[40]
    DCMPPT2 = Translate2.u16*10**DCV_SF
    print("DC Voltage 1 ="+str('{:g}'.format(DCMPPT1)))    
    print("DC Voltage 2 ="+str('{:g}'.format(DCMPPT2))) 

(klx) #26

Hi, Gret that now is working.
One question, I also have a smart meter and I’m trying to obtain total consumption but from smart meter I only receive + o -, depending if consumption is from solar or from grid, do you know here to obtain total consumption?

Thanks

Missatge de Anthony Vassallo [email protected] del dia dl., 31 de des. 2018 a les 9:58:


(Anthony Vassallo) #27

If you are asking how to access the Fronius smart meter you have to use its unit ID which is 240. This is used by pyModbusTCP.client import ModbusClient in a different script.
Then you poll the register(s) you want. There are at least 2 - total imported and total exported.
I have used this in the past but need to go back and find my script if you need it.


(klx) #28

Hi,

Thanks with ID240 and nUnit=240 I can obtian smart meter values, my problema is that I need to obtain total consumption grid + solar but I can’t find any value from modbus… any suggestion how to obtain this value from modbus?

Thanks

Missatge de Anthony Vassallo [email protected] del dia dl., 31 de des. 2018 a les 10:55:


(Anthony Vassallo) #29

Wouldn’t it just be import + generation - export?


(klx) #30

How can I configure this to be calculated and showed as graph?

Thanks

El dl., 31 de des. 2018, 11:22, Anthony Vassallo [email protected] va escriure:


(Anthony Vassallo) #31

If you have these values as inputs, then I think it should be easy to use the process list. This isn’t something I have done, but looking at this post might give you a start: heatpump


(klx) #32

I have tried from postprocess but only I can make +, I can’t find where I can use - in postprocess. You screenshot is from inputs and I don’t know how to integrate postprocess and inputs in this siutations…
Sorry but I’m new with this situation

Thanks

Missatge de Anthony Vassallo [email protected] del dia dl., 31 de des. 2018 a les 12:13:


(klx) #33

Hi,

I think I have calculated as you suggested but result is not consumption, what is wrong?

Thanks

Missatge de klxout [email protected] del dia dl., 31 de des. 2018 a les 12:31:


(Anthony Vassallo) #34

The values you are using are already in kWh - why are you adding Power to kWh?


(klx) #35

I think that this values are wh no kwh.

I removed but results are the same, any suggestion?

Missatge de klxout [email protected] del dia dl., 31 de des. 2018 a les 13:01:


(Alexandre CUER) #36

@icenov : It seems you are using an old version of the interfacer, not working with recent version of pymodbus…you should update with the last version of EmonHub
The configuration of the interfacer is simplified - cf klxout link


Moreover you are having 11 units and 10 datacodes


(Anthony Vassallo) #37

AFAIK it is the latest version - pulled from github following @TrystanLea Emonbase started hanging randomly
this from my emonhub a few minutes ago:

fc60e98180cf14e36203ae68c54e296114638fc2
[email protected]:~/emonhub $ git status
On branch emon-pi
Your branch is up-to-date with 'origin/emon-pi'.
nothing to commit, working tree clean
[email protected]:~/emonhub $ git pull origin emon-pi
From https://github.com/openenergymonitor/emonhub
 * branch            emon-pi    -> FETCH_HEAD
Already up-to-date.
[email protected]:~/emonhub $ 

Thanks for pointing out excess units - I’ve removed one.


(Alexandre CUER) #38

Ok fine
Have you simplified the interfacer section in emonhub.conf ? You dont need anymore nReg, rType,rName in the interfacer section…

[[ModbusTCP]]
Type = EmonModbusTcpInterfacer
[[[init_settings]]]
    modbus_IP = 10.0.0.9   # ip address of client to retrieve data from
    modbus_port = 502          # Portclient listens on
[[[runtimesettings]]]
    # List of starting registers for items listed above
          register = 40070,40071,40072,40092,40094,40096,40098,40100,40102,40108
    # nodeid used to match with node definition in nodes section below. Can be set to any integer value not previously used.
          nodeId = 30
    # Channel to publish data to should leave as ToEmonCMS
          pubchannels = ToEmonCMS,
    # time in seconds between checks, This is in addition to emonhub_interfacer.run() sleep time of .01
    # use this value to set the frequency of data retrieval from modbus client
          interval = 10

by the way, you have to give the registers values +1 when yu declare them in the interfacer section of emonhub.conf, but maybe it is not needed with the Fronius (This I dont know)

what do yu have in the emonhub log ?

please note that if you want to access to different slave id, you have to declare this in the interfacer section…if your device id is 1, it is OK yu dont have to do anything but if your device id is different, you have to specifiy it…for example :

nUnit = 1,1,1,1,1,1,1,1,1,2

in this version if yu want to access to id 2 with ten registers your have to do

nUnit = 2,2,2,2,2,2,2,2,2,2

Alex


(Anthony Vassallo) #39

Thanks @alexandrecuer - OK, some things being logged now! I went to check the logs but found it stopped logging yesterday as it was full. Cleared that out then checked new log to find message that no pymodbus installed (I used pip install without sudo first time) Now it is sending through data.

For others that might come across this topic later, I didn’t have to add a +1 to each register. In my python scripts I normally have to subtract a 1, which I think is because python starts arrays at 0. But I just used the actual register values in the interfacer (eg register 40070 is the inverter ID, which is 111 for my model (2xMPPT).

Some of the values need division by 100, but I should be able to sort that out easily.
Many thanks!
BTW I have a python script to probe the Fronius Primo inverter if anyone needs it.


(Anthony Vassallo) #40

Now to work on the Fronius smart meter which logs consumption etc. But its ID is 240, so will have to try your nUnit like 240,240,240,240…