ModbusAttr
ModbusAttr | |
---|---|
Zweck / Funktion | |
Extract information from devices with a Modbus interface or send information to such devices | |
Allgemein | |
Typ | Gerätemodul |
Details | |
Dokumentation | EN / DE Thema |
Support (Forum) | Sonstiges |
Modulname | 98_ModbusAttr.pm |
Ersteller | StefanStrobel (Forum / Wiki) |
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref! |
ModbusAttr provides a generic way to retrieve data objects from devices with a Modbus Interface and store these objects in Readings, or modify such objects by sending write commands to such devices.
The devices can be connected via RS232, RS485, or IP network, and the supported protocols are Modbus RTU, Modbus ASCII or Modbus TCP.
The data objects to be used and the correspondig readings are defined by attributes in a way similar to HTTPMOD. They are continuously updated in the interval specified with the define command. This behavior can be modified with attribues to have some data objects updated at a lower frequency or only once and after each change.
There are several attributes that modify the way data objects are converted before they are stored in readings. They can be modified by a perl expression defined in an atribute, formatted with a format string defined in another attribute or mapped to a table defined in an attribute.
Readings can directly correspond to one data object or they can span several objects. A float value for example might be stored in two input or holding registers in the Modbus device. By specifying attributes that define the length of a reading in objects and by specifying the unpack code to get from a raw string to perl variables, all these cases can be described by attributes and no perl coding is necessary.
Availability
The module has been checked in.
Prerequisites
This module uses the Modbus base module 98_Modbus.pm which uses the DevIO module
Define for Modbus RTU over serial lines / RS485 bus
define <iodevice> Modbus /dev/device@baudrate,bits,parity,stop define <name> ModbusAttr <Id> <Interval> <RTU|ASCII>
In this case, a physical serial interface device is defined first using the Modbus module. Then a ModbusAttr device is defined for each Modbus device connected to the serial line. For a RS485 bus, several Modbus devices with different Ids can be connected to the same bus.
Example:
define ModbusRS485 Modbus /dev/rs485@9600,8,E,1 define PWP ModbusAttr 5 60 RTU attr PWP obj-h256-reading Temp_Wasser attr PWP obj-h256-unpack n attr PWP obj-h256-expr $val/10 attr PWP obj-h256-poll 1 attr PWP obj-h262-reading Pressure attr PWP obj-h262-unpack f> attr PWP obj-h262-len 2 attr PWP obj-h262-poll 1 attr PWP obj-h262-showGet 1
This defines a physical Modbus interface connected to /dev/rs485 that uses 9600 Bps, 8 data bits, even parity and one stop bit. Most of these parameters are optional. by default 8,N,1 is assumed. the logical device is defined with Modbus id 5 and a polling interval of 60 seconds. The protocol is Modbus RTU. It defines two readings (Temp_Wasser and Pressure) that are stored in holding registers with the decimal addresses 256 and 262.
The reading Temp_Wasser is stored in the device in just one holding register. The unpack code n specifies that the raw value is a signed 16 bit integer value. The Temperature in this example is stored in the Modbus device as the real temperature multiplied by 10 so the module hast to divide the raw value by 10 before putting it into the Fhem reading. With the poll attribute the module is instructed to request the value automatically in the above defined interval.
The reading Pressure is stored in the device as a floating point number. Floating point numbers typically need two holding registers (32 bit) in a Modbus device. Therefore the module needs to request two holding registers (len 2). The unpack code f> specifies that the raw value is to be interpreted as a 32 bit big endian float value. the showGet creates will show a get-Option in Fhemweb.
Another Example:
define ModbusRS485 Modbus /dev/ttyUSB0@38400 define PWP ModbusAttr 1 0 ASCII attr PWP enableControlSet 1 attr PWP obj-h258-reading Target attr PWP obj-h258-unpack n attr PWP obj-h258-showGet 1 attr PWP obj-h258-set 1 attr PWP obj-h258-max 5 attr PWP obj-h258-min 32
In this example the device speaks Modbus ASCII over a serial line. The interval is set to 0 which means that there will be no automatic polling. Instead a get option is created (showGet) and a set option allows writing the value to the Modbus device.
enableControlSet adds many more set options like interval, reread, reconnect, stop, start, scanModbusId, scanModbusObjects and scanStop. These are described later.
Define for Modbus TCP or Modbus RTU over TCP
define <name> ModbusAttr <Id> <Interval> <Address:Port> <RTU|ASCII|TCP>
In this case no serial interface device is necessary and ModbusAttr connects to the Modbus device directly via TCP using either Modbus TCP or Modbus RTU over TCP.
Example:
define PWP ModbusAttr 1 30 192.168.1.115 TCP attr PWP obj-h256-reading Temp_Wasser_ein attr PWP obj-h256-unpack n attr PWP obj-h256-poll 1
defines a Modbus TCP device at ip address 192.168.1.115 with the default port 502 for Modbus TCP.
Example:
define PWP ModbusAttr 1 30 192.168.1.115:1234 RTU attr PWP obj-h256-reading Temp_Wasser_ein attr PWP obj-h256-unpack n attr PWP obj-h256-poll 1
defines a Modbus device at ip address 192.168.1.115 that communicates with Modbus RTU over the TCP-Port 1234 (probably this is some TCP to RS232 or RS485 converter)
Set-Commands
can be defined for holding registers and coils by using attributes.
Every object for which an attribute like obj-xy-set
is set to 1 will create a valid set option.
Additionally the attribute enableControlSet
enables the set options interval
, stop
, start
, reread
as well as scanModbusObjects
, scanStop
and scanModbusIds
(for devices connected with RTU / ASCII over a serial line).
interval <Interval>
- modifies the interval that was set during define.
stop
- stops the interval timer that is used to automatically poll objects through Modbus.
start
- starts the interval timer that is used to automatically poll objects through Modbus.
- If an interval is specified during the define command then the interval timer is started automatically.
- However if you stop it with the command
set <mydevice> stop
- then you can start it again with
set <mydevice> start
.
reread
- causes a read of all objects that are set to be polled in the defined interval. The interval timer is not modified.
scanModbusObjects <startObj> - <endObj> <reqLen>
- scans the device objects and automatically creates attributes for each reply it gets.
- This might be useful for exploring devices without proper documentation.
- The following example starts a scan and queries the holding registers with addresses between 100 and 120.
set MyModbusAttrDevice scanModbusObjects h100-120
- For each reply it gets, the module creates a reading like
scan-h100 hex=0021, string=.!, s=8448, s>=33, S=8448, S>=33
- the representation of the result as hex is 0021 and
- the ASCII representation is .!. s, s>, S and S> are different representations with their Perl pack-code.
scanModbusIds <startId> - <endId> <knownObj>
- scans for Modbus Ids on an RS485 Bus. The following set command for example starts a scan:
set Device scanModbusId 1-7 h770
- since many Modbus devices don't reply at all if an object is requested that does not exist,
- scanModbusId needs the adress of an object that is known to exist.
- If a device with Id 5 replies to a read request for holding register 770, a reading like the following will be created:
scanId-5-Response-h770 hex=0064, string=.d, s=25600, s>=100, S=25600, S>=100
scanStop
- stops any running scans.
Get-Commands
Every reading can be manually requested by a Get.
Internally a Get command triggers the corresponding Modbus request to the device and the module then interprets the data and sets the right Fhem readings. To avoid huge option lists in FHEMWEB, the objects visible as Get in FHEMWEB can be defined by setting an attribute obj-xy-showget
to 1.
Simple Attributes
Attributes to define data objects start with obj- followed by a code that identifies the type and address
of the data object.
Modbus devices offer the following types of data objects:
- holding registers (16 bit objects that can be read and written)
- input registers (16 bit objects that can only be read)
- coils (single bit objects that can be read and written)
- discrete inputs (single bit objects that can only be read)
Bigger Example:
define PWP ModbusAttr 1 30 192.168.1.115:502 TCP attr PWP obj-h256-reading Temp_Wasser_Ein attr PWP obj-h256-expr $val/10 attr PWP obj-h258-reading Temp_Wasser_Aus attr PWP obj-h258-expr $val/10 attr PWP obj-h262-reading Temp_Luft attr PWP obj-h262-expr $val / 10 attr PWP obj-h770-reading Temp_Soll attr PWP obj-h770-expr $val / 10 attr PWP obj-h770-set 1 attr PWP obj-h770-setexpr $val * 10 attr PWP obj-h770-max 32 attr PWP obj-h770-min 10 attr PWP obj-h770-hint 8,10,20,25,28,29,30,30.5,31,31.5,32 attr PWP dev-h-combine 5 attr PWP dev-h-defPoll 1
The module uses the first character of Modbus data object types to define attributes. Thus h770 refers to a holding register with the decimal address 770 and c120 refers to a coil with address 120. The address has to be specified as pure decimal number and counting starts at address 0.
attr PWP obj-h258-reading Temp_Wasser_Aus
defines a reading with the name Temp_Wasser_Aus that is read from the Modbus holding register at address 258.
With the attribute ending on -expr
you can define a perl expression to do some conversion or calculation on the raw value read from the device. In the above example the raw value has to be devided by 10 to get the real temperature value.
An object attribute ending on -set
creates a fhem set option. In the above example the reading Temp_Soll can be changed to 12 degrees by the user with the fhem command set PWP Temp_Soll 12
The object attributes ending on -min
and -max
define min and max values for input validation and the attribute ending on -hint
will tell fhem to create a selection list so the user can graphically select the defined values.
To define general properties of the device you can specify attributes starting with dev-
. E.g. with dev-timing-timeout
you can specify the timeout when waiting for a response from the device.
With dev-h-
you can specify several default values or general settings for all holding registers like the function code to be used when reading or writing holding registers. These attributes are optional and the module will use defaults that work in most cases.
dev-h-combine 5
for example allows the module to combine read requests to objects having an address that differs 5 or less into one read request. Without setting this attribute the module will start individual read requests for each object. Typically the documentation for the Modbus interface of a given device states the maximum number of objects that can be read in one function code 3 request.
More complex example
define MD ModbusAttr 1 30 192.168.1.115:502 TCP attr MD dev-i-combine 10 # combine read for up to 10 adjacent input registers attr MD dev-i-read 4 # use function code 4 to read input registers (this would be the default anyway) attr MD dev-i-defLen 2 # input registers define objects that span 2 registers by default attr MD dev-i-defUnpack f> # default unpack code for all objects that don't specify anything else will be f> (big endian 32 bit float, see perldoc pack) attr MD dev-i-defFormat %.1f # format values with one digit after the comma by default if nothing else is specified for individual readings attr MD dev-h-read 3 # this can be omitted since 3 is the default anyways attr MD dev-h-write 16 # use function code 16 instead of 6 to write holding registers attr MD dev-h-defPoll 1 # include all readings for holding registers in the update unless overwritten per object attr MD dev-h-defShowGet 1 # show a get option in fhemweb for all readings based on holding registers attr MD obj-i1010-reading Temp_Wasser_Ein # given the above defaults, this will be # a float unpacked with f> that spans 2 input registers attr MD obj-i1020-reading HystMode attr MD obj-i1020-len 1 # this overrides the default specified with dev-i-defLen above attr MD obj-i1020-format %s # override default set above attr MD obj-i1020-map 0:mittig, 1:oberhalb, 2:unterhalb # convert the raw value 0 to "mittig", the value 1 to "oberhalb" and "2" to "unterhalb" attr MD obj-i1020-pollDelay x10 # only update this reading every 10th iteration
All Attributes
- readingFnAttributes
- the usual Fhem attributes for all devices
- alignTime
- Aligns each periodic read request for the defined interval to this base time.
- This is typcally something like 00:00 (see the Fhem at command)
- enableControlSet
- enables the built in set commands like interval, stop, start and reread (see above)
the following list of attributes can be applied to any data object by specifying the objects type and address in the variable part. For many attributes you can also specify default values per object type (see dev- attributes later) or you can specify an object attribute without type and address (e.g. obj-len) which then applies as default for all objects:
- obj-[cdih][1-9][0-9]*-reading
- define the name of a reading that corresponds to the Modbus data object of type c,d,i or h and a decimal address (e.g. obj-h225-reading).
- obj-[cdih][1-9][0-9]*-name
- defines an optional internal name of this data object (this has no meaning for fhem and serves mainly documentation purposes.
- obj-[cdih][1-9][0-9]*-set
- if set to 1 then this data object can be changed (works only for holding registers and coils since discrete inputs and input registers can not be modified by definition.
- obj-[cdih][1-9][0-9]*-min
- defines a lower limit to the value that can be written to this data object. This ist just used for input validation.
- obj-[cdih][1-9][0-9]*-max
- defines an upper limit to the value that can be written to this data object. This ist just used for input validation.
- obj-[cdih][1-9][0-9]*-hint
- this is used for set options and tells fhemweb what selection to display for the set option (list or slider etc.)
- obj-[cdih][1-9][0-9]*-expr
- defines a perl expression that converts the raw value read from the device.
- obj-[cdih][1-9][0-9]*-ignoreExpr
- defines a perl expression that returns 1 if a value should be ignored and the existing reading should not be modified
- obj-[cdih][1-9][0-9]*-map
- defines a map to convert values read from the device to more convenient values when the raw value is read from the device or back when the value to write has to be converted from the user value to a raw value that can be written. Example: 0:mittig, 1:oberhalb, 2:unterhalb
- obj-[cdih][1-9][0-9]*-setexpr
- defines a perl expression that converts the user specified value in a set to a raw value that can be sent to the device. This is typically the inversion of -expr above.
- obj-[cdih][1-9][0-9]*-format
- defines a format string to format the value read e.g. %.1f
- obj-[cdih][1-9][0-9]*-len
- defines the length of the data object in registers. It defaults to 1. Some devices store 32 bit floating point values in two registers. In this case you can set this attribute to two.
- obj-[cdih][1-9][0-9]*-unpack
- defines the unpack code to convert the raw data string read from the device to a reading. For an unsigned integer in big endian format this would be "n", for a signed 16 bit integer in big endian format this would be "s>" and for a 32 bit big endian float value this would be "f>". (see the perl documentation of the pack function).
- obj-[cdih][1-9][0-9]*-revRegs
- this is only applicable to objects that span several input registers or holding registers.
- when they are read then the order of the registers will be reversed before
- further interpretation / unpacking of the raw register string.
- The same happens before the object is written with a set command.
- obj-[cdih][1-9][0-9]*-bswapRegs
- this is applicable to objects that span several input or holding registers.
- After the registers have been read and before they are writtem,
- all 16-bit values are treated big-endian and are reversed to little-endian by swapping the two 8 bit bytes.
- This functionality is most likely used for reading (ASCII) strings from the device
- that are stored as big-endian 16-bit values.
- example: original reading is "324d3130203a57577361657320722020". After applying bswapRegs,
- the value will be "4d3230313a2057576173736572202020" which will result in the ASCII string
- "M201: WWasser ".
- Should be used with "(a*)" as -unpack value.
- obj-[cdih][1-9][0-9]*-decode
- defines an encoding to be used in a call to the perl function decode to convert the raw data string
- read from the device to a reading.
- This can be used if the device delivers strings in an encoding like cp850 instead of utf8.
- obj-[cdih][1-9][0-9]*-encode
- defines an encoding to be used in a call to the perl function encode to convert the raw data string
- read from the device to a reading.
- This can be used if the device delivers strings in an encoding like cp850 and after decoding it you want to reencode it to e.g. utf8.
- obj-[cdih][1-9][0-9]*-showget
- every reading can also be requested by a get command. However these get commands are not automatically offered in fhemweb. By specifying this attribute, the get will be visible in fhemweb.
- obj-[cdih][1-9][0-9]*-poll
- if set to 1 then this obeject is included in the cyclic update request as specified in the define command. If not set, then the object can manually be requested with a get command, but it is not automatically updated each interval. Note that this setting can also be specified as default for all objects with the dev- atributes described later.
- obj-[cdih][1-9][0-9]*-polldelay
- this attribute allows to poll objects at a lower rate than the interval specified in the define command. you can either specify a time in seconds or number prefixed by "x" which means a multiple of the interval of the define command. if you specify a normal numer then it is interpreted as minimal time between the last read and another automatic read. Please note that this does not create an individual interval timer. Instead the normal interval timer defined by the interval of the define command will check if this reading is due or not yet. So the effective interval will always be a multiple of the interval of the define.
- dev-([cdih]-)*read
- specifies the function code to use for reading this type of object. The default is 3 for holding registers, 1 for coils, 2 for discrete inputs and 4 for input registers.
- dev-([cdih]-)*write
- specifies the function code to use for writing this type of object. The default is 6 for holding registers and 5 for coils. Discrete inputs and input registers can not be written by definition.
- dev-([cdih]-)*combine
- defines how many adjacent objects can be read in one request. If not specified, the default is 1
- dev-([cdih]-)*defLen
- defines the default length for this object type. If not specified, the default is 1
- dev-([cdih]-)*defFormat
- defines a default format string to use for this object type in a sprintf function on the values read from the device.
- dev-([cdih]-)*defExpr
- defines a default Perl expression to use for this object type to convert raw values read.
- dev-([cdih]-)*defIgnoreExpr
- defines a default Perl expression to decide when values should be ignored.
- dev-([cdih]-)*defUnpack
- defines the default unpack code for this object type.
- dev-([cdih]-)*defRevRegs
- defines that the order of registers for objects that span several registers will be reversed before
- further interpretation / unpacking of the raw register string
- dev-([cdih]-)*defBswapRegs
- per device default for swapping the bytes in Registers (see obj-bswapRegs above)
- dev-([cdih]-)*defDecode
- defines a default for decoding the strings read from a different character set e.g. cp850
- dev-([cdih]-)*defEncode
- defines a default for encoding the strings read (or after decoding from a different character set) e.g. utf8
- dev-([cdih]-)*defPoll
- if set to 1 then all objects of this type will be included in the cyclic update by default.
- dev-([cdih]-)*defShowGet
- if set to 1 then all objects of this type will have a visible get by default.
- dev-timing-timeout
- timeout for the device (defaults to 2 seconds)
- dev-timing-sendDelay
- delay to enforce between sending two requests to the device. Default ist 0.1 seconds.
- dev-timing-commDelay
- delay between the last read and a next request. Default ist 0.1 seconds.
- dev-([cdih]-)*allowShortResponses
- if set to 1 the module will accept a response with valid checksum but data lengh < lengh in header
- dev-timing-timeout
- timeout for the device (defaults to 2 seconds)
- dev-timing-sendDelay
- delay to enforce between sending two requests to the device. Default ist 0.1 seconds.
- dev-timing-commDelay
- delay between the last read and a next request. Default ist 0.1 seconds.
- nextOpenDelay
- delay for Modbus-TCP connections.
- This defines how long the module should wait after a failed TCP connection attempt before the next reconnection attempt.
- This defaults to 60 seconds.
- openTimeout
- timeout to be used when opening a Modbus TCP connection (defaults to 3)
- timeoutLogLevel
- log level that is used when logging a timeout. Defaults to 3.
- silentReconnect
- if set to 1, then it will set the loglevel for "disconnected" and "reappeared" messages to 4 instead of 3
- maxTimeoutsToReconnect
- this attribute is only valid for TCP connected devices.
- In such cases a disconnected device might stay undetected and lead to timeouts until the TCP connection is reopened.
- This attribute specifies after how many timeouts an automatic reconnect is tried.
- dev-h-brokenFC3
- workaround for some broken Modbus function code 3 implementations
- disable
- stop communication with the device while this attribute is set to 1. For Modbus over TCP this also closes the TCP connection.
Links
- Modbus.org
- About Modbus (English / German)
- Perl unpack codes