2013-09-25 45 views
0

我是Python新手,想用Raspberry Pi和Python閱讀我的智能儀表P1端口。問題:輸入看起來像一些組件醉了。 我相信這很容易解決,但經過幾個小時的搜索和嘗試,不得不尋求幫助。來自readline的'Drunk'輸入,來自其他程序的OK(讀取智能儀表P1端口)

當用CU等讀取P1端口時,一切都很好,所以硬件等都可以。使用串行到USB轉換器從dx.com(this one

指揮(部分)的輸出:立方米-l的/ dev/ttyUSB0 -s 9600 --parity =無

0-0:96.1.1(205A414246303031363631323463949271) 
1-0:1.8.1(03118.000*kWh) 

然而,試圖從Python中讀它的時候,輸入變爲亂碼(但至少那種洽的):

0-0:96.±.±(²05A´±´²´630303±39363±3²3´639·3±3²© 
±-0:±.¸.±(03±±¸.000ªë×è© 

如何解決這一問題?我正在使用的代碼是:

import serial 

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" 

ser.close() 
ser.open() 
print ("Waiting for P1 output on " + ser.portstr) 

counter=0 
#read 20 lines  
while counter < 20: 
    print ser.readline() 
    counter=counter+1 

try: 
    ser.close() 
    print ("Closed serial port.") 
except: 
    sys.exit ("Couldn't close serial port.") 

已經嘗試與波特率等雜亂但沒有任何區別。

+0

您是否嘗試過所有可能的奇偶校驗設置值,同時保持其他設置不變?它看起來像是一個平價問題。 –

回答

0

UPDATE:通過更換頑皮的人物找到了解決辦法。 這可能適用於其他人有同樣的問題,但我不知道壞字符是否完全一樣。所以更換零件可能需要一些工作才能使其適用於其他零件。

這不完全是一個解決方案,因爲來電仍然混亂,但下面的代碼將解決這個問題。我的電報現在完全乾淨。

我現在使用的代碼的相關部分:

#Define 2 variables 
P1_numbers = {'±':'1', '²':'2', '´':'4', '·':'7', '¸':'8'} 
P1_rest = {'¯':'/', 'ª':'*', '©':')', 'Æ':'F', 'ë':'k', '×':'W', 'è':'h', 'í':'m'} 

# Define function to read the telegram. Calls a function to clean it. 
def P1_read(stack): 
    counter = 0 
    while counter < TelegramLength: 
     stack.append(P1_clean(ser.readline())) 
     counter=counter+1 
    return stack 

# Define function to clean up P1 output 
def P1_clean(line): 
    for i, j in P1_numbers.iteritems(): 
     line = line.replace(i, j) 
    for i, j in P1_rest.iteritems(): 
     line = line.replace(i, j) 
    return line 
1

我不是很熟悉的serial模塊,但我注意到,你的cu命令假設沒有校驗位(--parity=none),但你的Python腳本假設有一個偶校驗位(ser.parity=serial.PARITY_EVEN)。我會嘗試

ser.parity=serial.PARITY_NONE 

如果沒有校驗位,你也可能會想

ser.bytesize=serial.EIGHTBITS 
+0

好點,編輯答案。 – Brionius

+0

謝謝,但不幸的是,它沒有任何區別。 – Tom

0

我quess您有P1協議智能電錶:DSMR 3.0嗎? 那麼這些都是正確的串行端口設置,您已經有了:

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

也許有些編碼或對數據的解釋在你身邊是怎麼了。下面是另一種讀取智能電錶的方法:

爲了使讀出的p1協議儘可能簡單,我建議使用TextIOWrapper,這樣你可以用readline方法讀取串口。 「!」總是結束P1報文,這樣可以用來檢測報文的結束。當收到完整的電報時,可以處理電報。例如:

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

P1Message = [] 

while True: 
    try: 
     rawline = self.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) 
0

的OP是一長串走了,但問題是足夠普遍關心的,所以這裏是一個新的答案。 User @ Brionius是正確的:看一下涉及的位模式,這顯然是一個奇偶校驗問題。以下是如何檢查字符"1""±"的位模式:

>>> "{0:b}".format(ord("1")) 
'110001' 
>>> "{0:b}".format(ord("±")) 
'10110001' 

明白了嗎?通過打開高位(第8位),字符被破壞。或者你也可以通過設置ASCII "1"的高位看到這一點:現在

>>> chr(ord("1") | 0b10000000) 
'±' 

"1", "2""4"設置有三個位(奇校驗),和被損壞。 "0", "3", "5",等有偶校驗(2或4位設置),並保留。所以通信信道使用偶校驗,在接收端沒有正確解碼。

0

我也有同樣的問題,在P1智能儀表端口的情況下,我花了很長時間才發現它。

'cu'顯示正確的數據,但Python不是(也不是其他一些程序)。很顯然,奇偶校驗位不能正確處理。下面的解決了這個問題:

p1_raw = ser.readline() 
print 'raw:', p1_raw 

decoded = ''.join(chr(ord(ch) & 0x7f) for ch in p1_raw) 
print 'decoded:', decoded 

我還覺得奇怪,這種情況正在發生,因爲這是實際發生的事情,當我試圖讀取智能儀表的第二次輸出。我已經有一個腳本成功地在另一個房子監控另一臺智能電錶幾年,我從來沒有遇到過這個問題。

也許在USB-串行適配器有一個小的差異導致這個?!?