Electrical Engineering Stack Exchange is a question and answer site for electronics and electrical engineering professionals, students, and enthusiasts. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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]
share|improve this question
    
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. – izak Mar 23 at 7:24
    
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. – Geeko Mar 23 at 7:40
    
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/… – izak Mar 23 at 8:48
    
Let me make an answer out of that – izak Mar 23 at 8:53
up vote 1 down vote accepted

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].

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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