Receive data from the counters Mercury 203.2T via RS-485

Organizing a remote collection of readings from electricity meters is not a difficult task, the meters are getting smarter and smarter every year and we have to send everything ourselves, but no, of course there is information, but it is fragmented. Equipment manufacturers apparently also want to make money selling their software. I am writing this article to save time for everyone who has similar tasks.
Start
The company needed to automate the collection of readings from electricity meters, about twenty pieces. Make it required quickly and as cheaply as possible. Therefore, it was decided to collect data using the already deployed Zabbix, but to connect to the counter, it was necessary to write a small script, more on that below. It turned out that the collection of readings is only one of the parameters that need to be collected, the rest are responsible for a PC with Debian on board, so it was not difficult to connect to the meter via the COM port. Of course, for most, it will be more convenient to use a local network and get information from an industrial switchboard or interface converter.
Of the connection options, you can also consider an opto-port, though you will need to purchase an additional device, on the other hand, you do not need to remove the seal.

Terminals for connection to the meter are located under a sealed cover.
Therefore, we had to negotiate with the network company about the need to remove the seals, carry out the work, and re-seal the meters. But in the end, the agreements were reached and it was possible to calmly deal with the solution of the main task.

The solution of the problem
As follows from the official documentation.
The counter accepts a string of bytes in the format ADDR-CMD-CRC, and gives ADDR-CMD-DATA-CRC, where:
- ADDR - counter name (for mercury 203.2Т - same as the serial number)
- CMD - Team Code
- DATA - Data depends on the request.
- CRC is a 2 byte cyclic redundancy code calculated over all previous bytes of this packet. From this explanation it is not clear what to write in the checksum field.
The hyphen in the sequence is not used; here it is used to separate logical blocks.
First of all, let's connect to the counter using the standard konfigurator program and, with the help of a sniffer, look at the transmitted packets, find out what checksum needs to be added to the end. Below, the string received from the counter.

Using the online calculator CRC find out what you need to calculate the CRC-16 (Modbus) with the polynomial 0xA001.
Little python
There are enough links to the calculation algorithm, so I will not dwell on it. For development I used Python 3
defcrc16(data):
crc = 0xFFFF
l = len(data)
i = 0while i < l:
j = 0
crc = crc ^ data[i]
while j < 8:
if (crc & 0x1):
mask = 0xA001else:
mask = 0x00
crc = ((crc >> 1) & 0x7FFF) ^ mask
j += 1
i += 1if crc < 0:
crc -= 256
result = data + chr(crc % 256).encode() + chr(crc // 256).encode('latin-1')
return result
Now we will try to get its serial number from the counter and check the CRC. You will need to install the pyserial module .
import serial
import struct
import time
sn = 26222790# Открываем соединение
ser = serial.Serial('/dev/ttyUSB0', 9600, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE)
print ('Connected:', ser.isOpen())
# \x2f - Команда для получения серийного номера
chunk = struct.pack('>L', int(sn))
chunk += b'\x2f'
chunk = crc16(chunk)
# Отправим данные на счетчик и получим информацию с него
ser.write(chunk)
time.sleep(1)
out = ser.read_all()
ser.close()
print ('Check CRC:', out[-2:] == crc16(out[:-2])[-2:])
print ('Result string:', ':'.join('{:02x}'.format(c) for c in out))
Fine! Now we will get the values for the consumed energy according to the first and second tariffs, in fact, we only need to change the command field and parse the result.
chunk += b'\x27'
t1 = ''.join('{:02x}'.format(c) for c in out[5:9])
t2 = ''.join('{:02x}'.format(c) for c in out[9:13])
print ('T1 =', float(t1)*0.01, '(кВт*ч)', 'T2 =', float(t2)*0.01, '(кВт*ч)')
Everything is working. The final version of the script posted on git . In the future, I plan to add support for work on the local network.
A USB -> COM “Mercury-221” Adapter was used for development, but you can directly connect the meter to the COM port.
Links:
Useful information on connecting meters is located here.
Documentation on the official site.
Technical Support Site
About CRC on Wikipedia