读取串行接口时编码问题(我认为)

时间:2014-08-06 21:20:34

标签: python pyserial

我正试图通过P1界面读出我的智能电表。 一些python脚本发布在网上这样做,我尝试了它们,但似乎从我的串行接口中得到了一些部分垃圾(不完全 - 所以我的假设是串行设置是正确的。但是因为我是从其他似乎正常工作的脚本中复制它。

当尝试使用cu命令读出接口时,它确实显示正确的输出,所以我的硬件似乎工作。

我正在运行:Linux版本3.10.25+(dc4 @ dc4-arm-01)(gcc版本4.7.2 20120731(预发布)(crosstool-NG linaro-1.13.1 + bzr2458 - Linaro GCC 2012.08) )#622 PREEMPT 1月3日星期五18:41:00 GMT 2014

输出应该是什么样子 - 通过以下方式检索:

命令:

cu -l /dev/ttyUSB0 -s 9600 --parity=none

输出

/INTENTIONALLY ALTERED
0-0:96.1.1(39373936353532302020202020202020)
1-0:1.8.1(05090.742*kWh)
1-0:1.8.2(06618.743*kWh)
1-0:2.8.1(00000.000*kWh)
1-0:2.8.2(00000.000*kWh)
0-0:96.14.0(0001)
1-0:1.7.0(0000.71*kW)
1-0:2.7.0(0000.00*kW)
0-0:17.0.0(999*A)
0-0:96.3.10(1)
0-0:96.13.1()
0-0:96.13.0()
0-1:96.1.0(3238303131303038323033333632313132)
0-1:24.1.0(03)
0-1:24.3.0(140806220000)(2C)(60)(1)(0-1:24.2.0)(m3)
(03447.404)
0-1:24.4.0(1)
!

当我使用以下 Python代码:

# DSMR P1 uitlezen
# (c) 10-2012 - GJ - gratis te kopieren en te plakken
versie = "1.0"
import sys
import serial


##############################################################################
#Main program
##############################################################################
print ("DSMR P1 uitlezen",  versie)
print ("Control-C om te stoppen")
print ("Pas eventueel de waarde ser.port aan in het python script")

#Set COM port config
ser = serial.Serial()
ser.baudrate = 9600
ser.bytesize=serial.SEVENBITS
ser.parity=serial.PARITY_EVEN
ser.stopbits=serial.STOPBITS_ONE
ser.xonxoff=0
ser.rtscts=0
ser.timeout=20
ser.port="/dev/ttyUSB0"

#Open COM port
try:
    ser.open()
except:
    sys.exit ("Fout bij het openen van %s. Aaaaarch."  % ser.name)


#Initialize
#p1_teller is mijn tellertje voor van 0 tot 20 te tellen
p1_teller=0

while p1_teller < 20:
    p1_line=''
#Read 1 line van de seriele poort
    try:
        p1_raw = ser.readline()
        print str(p1_teller),':', p1_raw
    except:
        sys.exit ("Seriele poort %s kan niet gelezen worden. Aaaaaaaaarch." % ser.name )

    #p1_str=str(p1_raw)
    #p1_line=p1_str.strip()
# als je alles wil zien moet je de volgende line uncommenten
    #print (p1_line.encode('ascii','ignore'))
    p1_teller = p1_teller +1

#Close port and show status
try:
    ser.close()
except:
    sys.exit ("Oops %s. Programma afgebroken. Kon de seriele poort niet sluiten." % ser.name )

输出变为:

('DSMR P1 uitlezen', '1.0')
Control-C om te stoppen
Pas eventueel de waarde ser.port aan in het python script
0 : INTENTIONALLY ALTERED BUT ALSO WITH THE ? SYMBOLS IN THE ORIGINAL OUTPUT

1 : �

2 : 0-0:96.�.�(393�393635353�30�0�0�0�0�0�0�0�0��

3 : �-0:�.�.�(05090.�9����詍

4 : �-0:�.�.�(066��.��3���詍

5 : �-0:�.�.�(00000.000���詍

6 : �-0:�.�.�(00000.000���詍

7 : 0-0:96.��.0(000���

8 : �-0:�.�.0(0000.�0��ש�

9 : �-0:�.�.0(0000.00��ש�

10 : 0-0:��.0.0(999�A��

11 : 0-0:96.3.�0(���

12 : 0-0:96.�3.�(��

13 : 0-0:96.�3.0(��

14 : 0-�:96.�.0(3�3�303�3�30303�3�303333363�3�3�3���

15 : 0-�:��.�.0(03��

16 : 0-�:��.3.0(��0�06��0000�(�é(60�(��(0-�:��.�.0�(�3��

17 : (03���.�0���

18 : 0-�:��.�.0(���

19 : !�

所以我的python输出中有很多 字符,我希望是一些编码问题..但不确定并且不确定如何解决这个问题...所以任何帮助都会受到赞赏。

5 个答案:

答案 0 :(得分:1)

看起来您读取的字节可能仍包含奇偶校验位,使其成为无效字符。试试这个删除第8位:

p1_raw = ''.join(chr(ord(ch) & 0x7f) for ch in p1_raw)

答案 1 :(得分:1)

我想这与某些数据解码有关。使用textIOWrapper解码对我来说很好。希望你能对我对案件的看法做任何事情:

为了尽可能简单地读出p1协议,我建议使用前面提到的TextIOWrapper,这样你仍然可以用readline方法读取串口。 &#34;!&#34;始终结束P1电报,因此可用于检测消息的结束而不是使用计数器。收到完整电报后,可以处理电报。例如:

import io
import serial

serialport = serial.Serial(  # Configure Serial communication port
                            port     = "/dev/ttyUSB0"
                            baudrate = 9600,
                            timeout  = 11,
                            bytesize = serial.SEVENBITS,
                            parity   = serial.PARITY_EVEN,
                            stopbits = serial.STOPBITS_ONE )

p1port = io.TextIOWrapper(io.BufferedReader(serialport, buffer_size=1), newline='\n', encoding='ascii')

P1Message = []

while True:
    try:
         rawline = p1port.readline()
    except UnicodeDecodeError:
         print "Encode error on readline"

    if '!' in rawline:
        # Process your P1Message here

        P1Message = [] # Clear message, wait for new one
    else:
        P1Message.append(rawline)
祝你好运!

答案 2 :(得分:1)

这就是我最终修复它的方法 - 也会尝试Ldevries方法....看起来很干净:

#
# MBSolget P1 Telegram Catch
#

version = "v1.00"
import sys
import os
import stat
import serial
import datetime
import locale

###############################################################################################################
# Main program
###############################################################################################################
#Initialize
p1_telegram  = False
p1_timestamp = ""
p1_teller    = 0
p1_log       = True

#Set COM port config
ser          = serial.Serial()
ser.baudrate = 9600
ser.bytesize = serial.EIGHTBITS
ser.parity   = serial.PARITY_NONE
ser.stopbits = serial.STOPBITS_ONE
ser.xonxoff  = 1
ser.rtscts   = 0
ser.timeout  = 30
ser.port     = "/dev/ttyUSB0"

#Show startup arguments
print ("MBSolget P1 Telegram Catch %s" % version)
print ("Control-C om af te breken")
print ("Poort: (%s)" % (ser.name) )

#Open COM port
try:
    ser.open()
except:
    sys.exit ("Fout bij het openen van poort %s. "  % ser.name)

while p1_log:
    p1_line = ''
    try:
        p1_raw = ser.readline()
    except:
        sys.exit ("Fout bij het lezen van poort %s. " % ser.name )
        ser.close()


    p1_raw = ''.join(chr(ch & 0x7f) for ch in p1_raw)
#    for ch in p1_raw:
       # print(chr(ch & 0x7f))
#        print( chr(ord(ch) & 0x7f))
#    print(p1_raw)
    p1_str  = p1_raw #str(p1_raw ,"utf-8",errors="ignore")
    p1_line = p1_str.strip()
    print (p1_line)

    if p1_line[0:1] == "/":
        p1_telegram = True
        p1_teller   = p1_teller + 1
        f=open("/home/geoffrey/p1_temp.log", "w")
    elif p1_line[0:1] == "!":
        if p1_telegram:
            p1_teller   = 0
            p1_telegram = False
            p1_log      = False
            f.write (p1_line)
            f.write ('\r\n')
            f.close()
            os.chmod("/home/geoffrey/p1_temp.log", stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
    if p1_telegram:
        f.write (p1_line)
        f.write ('\r\n')

#Close port and show status
try:
    ser.close()
except:
    sys.exit ("Fout bij het sluiten van %s. Programma afgebroken." % ser.name )

答案 3 :(得分:0)

在代码中,将字节大小更改为EIGHTBITS,将奇偶校验更改为PARITY_NONE。那些与cu正在使用的相匹配(也是PySerial的默认值)。

答案 4 :(得分:0)

感谢Geoffrey,我终于想出了如何设置我的C#SerialPort。

private static SerialPort CreateP1SerialPort(string name)
{
    return new SerialPort
    {
        BaudRate = 115200,
        DataBits = 8,
        Handshake = Handshake.XOnXOff,
        Parity = Parity.None,
        PortName = name,
        RtsEnable = false,
        StopBits = StopBits.One,
        ReadTimeout = 10 * 1000,
        WriteTimeout = 1000
    };
}

简单的例子:

public static void Main()
{
   // this will help you find your com port name
   var portNames = SerialPort.GetPortNames().OrderBy(x => x).ToArray();

   // Create a new SerialPort object with default settings.
   var serialPort = CreateP1SerialPort("COM7");
   serialPort.Open(); 

   while (true)
   {
       var line = serialPort.ReadExisting();
       if (string.IsNullOrEmpty(line))
       {
           Thread.Sleep(10000); // one message every 10 seconds
       } else 
           Console.WriteLine(line);
    }
}