Modbus Python Plugin
Purpose
Purpose of this plugin is to read from Modbus Servers via Python.
Usage
You run a log to send data to the cloud, or a discover to only display information. There must be a config file when running log or a discover. The config file defines which variables need to be collected, what names they appear on the the Ardexa cloud, units and scaling, what table(s) they variables will be sent to, and the source name(s). Example config file as follows. Always verify data accuracy by running a discover first, before committing the plugin to collect data.
#
# This is the Modbus config file
#
# Commands
# These are the commands to run
_cmd, mbpoll -m tcp -r 1101 -c 110 -t 4 -1 -p {PORT} {ENDPOINT}
_cmd, mbpoll -m tcp -r 1275 -c 10 -t 4 -1 -p {PORT} {ENDPOINT} --translate 50000
# Table, Source Name, Variable Name, Register, Num of Regs, Type, Units, Scale, RO/RW/INV, Lookup Table, Sum/Conditional Registers, Conditional Bit
solar, inverter, AC Voltage 1, 1101, 1, dec, V, 1+10, RO,
solar, inverter, Grid Freq, 1104, 1, dec, Hz, 0.01, RO,
solar, inverter, Cos Phi, 1111, 1, dec, ., 100, RO,
solar, inverter, Temperature, 1167, 1, udec, C, 1, RO,
turbine, eng, Status, 1275, 1, int8, , 1, RO, /home/ardexa/status.dict
turbine, eng, Minutes, 75, 1, lo8, , 1, RO,
turbine, eng, Seconds, 76, 1, hi8, , 1, RO,
turbine, eng, Total Hours, 1208, 1, ge_fix, h, 0.1, RO,
turbine, eng, Total Hours, 1208, 1, dec, h, 0.1, RO,
turbine, eng, DC Current 1, 1221, 1, dec, A, 1, RO,
PLC_710, hec, DC Current 2, 1222, 1, swap16, A, 0.1, RO,
PLC_710, hec, DC Current Sum, 0, 1, sum, A, 1, RO, , 1221 1222 1223 1224 1225
PLC_710, hec, Total Energy, 0, 1, after, Wh, 1, RO, , 1194 1196
PLC_710, hec, Setpoint Mode, 77, 1, bitb, bool, 1, RO, 1
PLC_710, hec, Run Auto, 71, 1, bitb, bool, 1, RO, 2
PLC_710, hec, Run Manual, 71, 1, bitb_int, bool, 1, RO, 3
PLC_710, hec, Key Switch, 30227, 1, str, , 1, RO, /home/ardexa/sma_central/mode.dict
PLC_710, hec, Key Switch2, 30227, 1, str_rep, , 1, RO, /home/ardexa/sma_central/mode.dict
PLC_710, pid_box, Voltage, 17, 1, int, V, 1, RO,
PLC_710, pid_box, Current, 18, 1, int, mA, 1, RO,
Station, alarm, Alarm 0 Keyword, 4000, 1, bit, , 1, RO, /home/ardexa/ess_modbus/dict/container_alarm0.dict
Station, alarm, Alarm 1 Keyword, 4001, 1, bit, , 1, RO, /home/ardexa/ess_modbus/dict/container_alarm1.dict
Station, alarm, Alarm 2 Keyword, 4002, 1, bit, , 1, RO, /home/ardexa/ess_modbus/dict/container_alarm2.dict
Station, alarm, Alarm 3 Keyword, 4003, 1, bit, , 1, RO, /home/ardexa/ess_modbus/dict/container_alarm3.dict
Station, alarm, Alarm 1, 4001, 1, bool, , 1, RO,
Station, alarm, Alarm 2, 4002, 1, bool, , 1, RO,
Station, alarm, Alarm 3, 4003, 1, bool, , 1, RO,
Station, alarm, Alarm 4, 4004, 1, int_bool, , 1, RO,
weather, status, Status1, 35, 1, cond_bit, , 1, RO, /home/ardexa/conditional.dict, 45, 1
weather, status, Status2, 36, 1, cond_bit, , 1, RO, /home/ardexa/conditional.dict, 45, 2
weather, status, Status3, 37, 1, cond_bit, , 1, RO, /home/ardexa/conditional.dict, 45, 3
weather, status, Daytime Status, 309, 1, mask, , 1, RO, /home/ardexa/daytime.dict, 2, 4
weather, hyc, Total Current, 12, 1, dec, h, 0.1, >100000,
weather, status, Binary Status Raw, 356, 1, bin, , 1, RO,
weather, ATC, AC Power 1, 365, 1, log_scale, W, 3, RO, 569
battery, module, DC Current 1, 64, 1, depend, A, 0.1, RO, 2456, 1
battery, module, DC Current 2, 65, 1, depend, A, 0.1, RO, 2457, 2
battery, module, DC Current 3, 66, 1, depend, A, 0.1, RO, 2458, 1
battery, module, DC Current 4, 67, 1, depend, A, 0.1, RO, 2459, 2
battery, module, AC Power, 87, 1, master, W, 1, RO, 110
battery, module, AC Power, 97, 1, slave, W, 1, RO, 111Notes:
_cmdis the commands to run. Onlymodpollor thembpollgithub command OR theModbus Ruby CLI(see the readme file) to read and write to modbus registers.mbpollis preferred. The registers being collected MUST MATCH the registers listed in the configuration items. If not, you will have empty fields when running adiscover. If the registers in_cmdcommands overlap, then there could be unexpected errors. Make sure each output of the_cmdcommands do not overlap. The phrase--translatecan be included in a modbus command. It MUST appear in lower case and at the end of the command. If used, it will scale (by adding), all the register values. It will hence have the effect of translating them to another set of registers, so as they do not "collide" with the registers from another command.Scalewill only be used fordecimalandintegertypes. An error will be reported if you try and divide an integer, or multiply by anything other than a whole number. The scale can also be a value such as0.75-9, where the-9is a BIAS value (addition or subtraction). In which case it will FIRST subtract the 9, THEN multiply by 0.75. If using a bias value, then it can ONLY be used with adecimaltype.RO/RW/INV. This column will only do the following task": If an entry starts with>, it will invalidate ALL entries in a configuration file, if the absolute value (+ or -) for this entry is greater than the specified amount. For example; if theRO/RW/INVcolumn entry is>10000, then a value of 12,000 will ensure ALL readings in the configuration file are invalidated. Use this item with caution. Also, it will ONLY work ondecvalues. This invalidation feature is intended for those machines that have poor quality control, and sometimes transmit wildly wrong values.In
Num of Regs; Sometimes you may need to read 2 consecutive registers, to form a floating point (32 bit) number, rather than a single register (16 bit). Rarely, we may want to read a number of (perhaps) non-consecutive registers to form a string. Usually, it is best for thembpollormodpollto handle this translation. Note that if you use a number value of2e, it will reverse the endianess, fordecandintvalues.In
Lookup Table; Sometimes you want to convert an INT to a keyword, through a lookup table. Or you may want to get a register bit and convert it to a keyword.Allowable
Typeare as follows:
dec... Converts the modbus register to a decimal. Can be scaled (including division).udec... This will convert the register to unsigned first, then convert the modbus register to a decimal. Can be scaled (including division). Only works on 16 bit registers.swap16... Swaps the modbus register and converts it to a decimal. Can be scaled (including division).int... Converts the modbus register to an integer. Can only be scaled upwards (not divided). So ascalevalue that is not a whole number will be rejected. See also the explanation forscaleabove, since it can include a bias and scale factor.bit... Used with a lookup table (in theLookup Tablecolumn) to define a bit being turned or off. See example contents of file below. Bits start at "1" (not "0"), and are defined in theLookup Tablecolumn.bitb... If a bit in the modbus register is turned on/off, it will reflect a boolean ("True"/"False") output.bitb_int... If a bit in the modbus register is turned on/off, it will reflect a boolean ("1"/"0") output.str... Treated as an ASCII character. If it can't be converted, it will output an empty fieldstr_rep... Same asstr, but it will clear\0values in the resultant string.bool... Modbus register is converted to an INT. This value is then check as follows: Anything other than0will output aTrue. Else, output will beFalse.int_bool... Modbus register is converted to an INT. This value is then check as follows: Anything other than0will output a1. Else, output will be0.bin... Converts the modbus register to an integer, then to a binary reprentation.int8... Mask out the first 8 bits of an Modbus integer, then use a lookup filehi8... Mask out the first (low) 8 bits of an Modbus integerlo8... Mask out the last (high) 8 bits of an Modbus integersum... This is to sum the values of specific registers. In this case theRegisterfield MUST be set to0and the registers to sum is a list in Summation Registers separated by spaces onlyafter... This is the same assum, but each register is added AFTER the scale and bias line. You MUST have theregisterset to0This means 2 things: a. The register to be added must exist as a separate line, and b. Theafterline must appear AFTER ALL the registers to be added.cond_bit... This type will use the CONTENTS of the register listed in theSum/Conditional Registersand whether the bit detailed in theRegisterandConditional Bitcolumn are 1 to then display the result of the lookup table. See the entry below on how this feature works.mask... Mask out the Modbus integer based on the bits listed in the last 2 entries (bits 2 to 4 in the example - Bits start at "1" (not "0")) And use the resultant integer to lookup up and keywordlog_scale... This will log scale the register, based on the contents of another register. In the example above, the final result will be:result = scale * (contents_of_register(365) * 10 ** (contents_of_register(569)-3)))depend... This will read the contents of the Lookup Table, the "depend register" (2456/7/8/9in the above example). If the depend number, which is the next column in the config file, exceeds the value of the contents of the "depend register", then the particular line will be ignored. Otherwise it will collect the data and treat it as a DECIMAL value.master... This will read the contents of the Lookup Table, the "master register" (110in the above example). If the master register content is 1, it will collect the data and treat it as a DECIMAL value. If it is 0, then the particular line will be ignored.slave... This will read the contents of the Lookup Table, the "master register" (111in the above example). If the master register content is 0, it will collect the data and treat it as a DECIMAL value. If it is 1, then the particular line will be ignored.ge_fix... This is used to convert a modbus integer to a signed integer using the "Signed Magnitude Method" discussed in: https://www.geeksforgeeks.org/representation-of-negative-binary-numbers/ The conversion will be handled during the early parts of processing, and then the value will be converted to DECIMAL
There are up to 11 columns. Only the first 8 (up to and including the
RO/RWcolumn) are required.A lookup file must be defined for the type
bitandcond_bit
Arguments
Arguments are as follows:
endpoint. This is either a serial device like/dev/ttyS0or an IP or DNS like192.168.1.15bus_addresses. A Modbus address in the range 2-255. This can be a hyphenated list like3-10or a list like2,5,7,9--port. This is an optional parameter used in an Ethernet gateway, and is the TCP port used for the gateway. Default is502--attempts. This is an optional parameter, and determines how many times to times to attempt to read an inverter value. Default is1--delay. This is the delay in seconds between inverter send and receive commands, AND ifattempts> 1. Fractions like0.3can be used. Default is0.05--stop_on_any_command_fail. If this is specified, then any Modbus commands that fail will stop all further queries for all bus addresses and attempts.--serial_lock. If this is set, the program can only be run one at a time (so as not to overload a Modbus device). If the device being queried is a serial device, this will automatically be set to "on". For IP addresses it is optional.--sampling_rate. If this is defined, and the sampling rate is greater than 1, then allDECIMALandSWAP16values will be collected as an average. In other words; it will take a sample at the nominated frequency. After X samples defined bysampling_rate, a record will be written and sent to the cloud.
Example of "bit" lookup
File would be something like:
/home/ardexa/ess_modbus/dict/container_alarm0.dictBit starts at
1. Include a0value to display something (or blank) if no bits are turned on
0 :
1 : electric leakage sensor#1
2 : AC surge protection device
3 : key-operated switch
4 : scram button
5 : switcher signal from UC PCB Control Board
6 : electric leakage sensor#2
7 : electric leakage sensor#4
8 : electric leakage sensor#3
9 : signal 8 abnormal
10 : energy-saving contractor KM1 return signal
11 : electric bad leakage sensor#2
12 : electric bad leakage sensor#1
13 : electric bad leakage sensor#4
14 : electric bad leakage sensor#2
15 : signal 14 abnormal
16 : signal 14 abnormalExample of "str" lookup file
File would be something like:
/home/ardexa/dict/mode.dictNumbers can be anything, since they are read from a single modbus (16 bit) register
-1 :
51 : Closed
267 : Inverter
276 : Instantaneous value
295 : MPP
303 : Off
308 : On
309 : Operation
311 : Open
336 : Contact the manufacturer
337 : Contact the installer
338 : Invalid
381 : Stop
455 : Warning
569 : Activated
1041 : LeadingExample of a "conditional lookup" file
This is a lookup file used by the
cond_bittype. It operates by using the CONTENTS of the register listed in theSum/Conditional Registers, and whether the bit detailed in theRegisterandConditional Bitcolumn are 1/true, to then display the result of the lookup table. The file contents example is as below. There are 2 keys separated by a colon ":". The first item is the contents of theSum/Conditional Registers, and the second key is the bit detailed in theRegisterandConditional Bitcolumn. If this bit is true, then the third item is displayed.
44 : 1 : Start 1
44 : 2 : Stop
44 : 3 : Emergency Stop
44 : 4 : Cabinet OpenWas this helpful?