0
\$\begingroup\$

I am trying to read energy meter(EM6400) voltage values in python by using modbus protocol. But there are issues when I am reading values. I think the issue is with, I am not reading values in proper way i.e. in the line ----->

buf = ser.read(11) # reading 11 bytes from energy meter

Here is detailed of my implementation :

Request:

01 03 0F56 0002 270F
01: Slave address
03: Function code for read holding registers
0F56: Data Address of the first requested register (address for voltage phase1 to neutral)
(0F56 hex = 3927, +40001 offset = 43928)
0002: Total number of registers requested
270F: CRC (Cyclic Redundancy Check) for error checking (LSB first)

Response:

01 03 04 2921 4373 D2B0
01: Slave address
03: Function code for read holding registers
04: Total number of bytes read
2921: Data in 1st requested register
4373: Data in 2st requested register
D2B0: CRC for error checking (LSB first)

Values in required register are 43732921 in hex (since obtained values are being read in little endian format) which is 243.16 when converted to floating point using IEEE 754 norms. Obtained value is a voltage (phase1 to neutral) which is 243.16 Volts.

Here is the code for the same:

import os
import sys
cwd=os.getcwd()
(setpath,Examples)=os.path.split(cwd)
print setpath
sys.path.append(setpath)

from PyArduino import *

import struct


port=locateport()
ser = serial.Serial(port, 9600)

ser.write("\x01\x03\x15\x86\x00\x02\x39\x15")
buf=ser.read(11)

b1=b2=b3=b4=0

a1=buf[3]

if (a1<16):
    b1=1
    a1=int(a1,16)
if (b1):
    a1='0'+str(a1)


a2=buf[4]
if (a2<16):
    b2=1
    a2=int(a2,16)
if (b2):
    a2='0'+str(a2)



a3=buf[5]
if (a3<16):
    b3=1
    a3=int(a3,16)
if (b3):
    a3='0'+str(a3)

a4=buf[6]
if (a4<16):
    b4=1
    a4=int(a4,16)
if (b4):
    a4='0'+str(a4)


a5=[a3,a4,a1,a2];
a6=''.join(a5)


print struct.unpack('!f', a6.decode('hex'))[0]
\$\endgroup\$
  • \$\begingroup\$ Have you tried using pymodbus? I used it over the weekend to read voltage values off a Morningstar charge controller and it was literally about 5 lines of code. \$\endgroup\$ – izak Mar 23 '16 at 7:24
  • \$\begingroup\$ thanks...i haven't tried pymodbus as i want to go for pyserial module.could you please provide a sample code for the same based on pymodbus. \$\endgroup\$ – Geeko Mar 23 '16 at 7:40
  • \$\begingroup\$ I copied from this guy, changed the number of registers to read to 16 (instead of 37) because I only need the bottom 16, and that was that. Pymodbus uses pyserial for serial devices. github.com/brocktice/tristar-python-modbus/blob/master/… \$\endgroup\$ – izak Mar 23 '16 at 8:48
  • \$\begingroup\$ Let me make an answer out of that \$\endgroup\$ – izak Mar 23 '16 at 8:53
1
\$\begingroup\$

You could try using pymodbus instead. This is a layer that sits on top of pyserial that handles the complexities for you. It depends on twisted, but it will work without twisted for this simple case.

from pymodbus.client.sync import ModbusSerialClient as ModbusClient
modbus = ModbusClient(method='rtu', port='/dev/ttyUSB3', baudrate=9600, timeout=1)
modbus.connect()
r = modbus.read_holding_registers(0x0F56, 2, unit=1)

The data you're looking for should then be in r.registers[0] and r.registers[1].

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.