2月 212023
 

ソフトウェアの制作

土壌センサからデータを読み込んでExcelの表にまとめるProgram例をupしておきますので参照して下さい。 通信テストと同様、 Excellの表をあらかじめ用意してCellの表記形式などを設定しておいたり、データが書き込まれた後のデータ処理などを行うためにWindows11 PC上でProgramの作成や実行を行います。 Programでデータの書き込みを行ったExcelの表は表-1です。 Pythonを使うとこのようなExcelの表を簡単に扱うことができます。

Windows11 PCにはあらかじめPythonをinstallしておいて下さい。 installや仮想環境の設定に関しては下記のURLを参考にして下さい。
Pythonがすでにinstallされている場合、 pyserial(通信テストを行った場合はすでにinstall済です)、openpyxl というライブラリをpipでinstallしておく必要があります。 datetimeライブラリはdefaultでinstall済ですのであらためてinstallする必要はありません。
pyserial openpyxIライブラリのinstallは仮想環境に移動した後に行わないと実行時にErrorが出て止まってしまいますので注意して下さい。

土壌センサとの通信部分はList#2を参照して下さい。 前章の通信テストProgramではセンサに送るコマンドとして仕様書の例(CRC16値として計算済の値を使用)を使用しましたが、 実際にコマンドを送る場合、 CRC16を計算してコマンドの最後尾2バイトにセットしてから送信しなければなりません。
PythonのCRC16のライブラリはCCITT準拠(同期通信などで使用される)のものやUSBなどで使用されている多項式のものです。 ムラタの土壌センサはModBusのCRC16に準拠しているとのことですが、CRC生成多項式のbit列を逆順にして右シフトで計算して求めた値を使用しています。
したがって、 仕様書のフローチャートに従ってPythonでprogramを作成し、 仕様書のコマンド例のCRC16値と一致するか検算をしておいて下さい。
CRC16_ModBus計算ルーチンはList#3を参照して下さい。


#  crc16.py
# -*- coding: utf-8 -*-


def crc16_Modbus(data : bytearray, offset , length):

# Modbus-RTU polynomial 0x1021  X16 + X15 + X2 + X0 11000 0000 0000 0101 --> reverse bit order --> 0xa001

    if data is None or offset < 0 or offset > len(data)- 1 and offset+length > len(data):
        return 0
    crc = 0xFFFF
    for i in range(0, length):
        crc ^= data[offset + i]
        for j in range(0,8):
            if (crc & 0x0001) == 1:      # check LSB
                crc =(crc >> 1) ^ 0xa001 
            else:
                crc = crc >> 1
    return crc.to_bytes(2, 'big')

  

# start here
data = b"\x02\x07\x01\x01"
offset = 0
length = 4

crc16mb = crc16_Modbus(data, offset, length)
crc16U = crc16mb[0]
crc16L = crc16mb[1]
print( "CRC16U : ", f'{crc16U:x}')
print( "CRC16L : ", f'{crc16L:x}')

Programの通信部で考えなければならない点はセンサの応答の受信部です。 pyserial にはserial.read(n), serial.readin(), serial.read_all()の3種類があります。 最初のserialread(n)はnで指定したバイト数のデータを受信後戻ってきます。 二番目のserial.readIn()はデリミタ(ETX,CR,LFなど)を受信すると戻ってきますがムラタの土壌センサからの応答にはデリミタがありませんのでこの関数は使えません。 最後のserial.read_all()は受信バッファ内の受信データをすべて取り出しますが最後尾のデータを受け取った後、 Timeout=xxで指定した秒数が経過した後戻って来るため実行時間がかかります。 あまりTimeout指定を短くするとセンサが応答する前にserial.read_all()から戻ってきてしまって何も受信できなきなってしまいます。 ムラタの土壌センサの応答はデリミタもなく、 Error 発生時など応答の文字数が異なりますので固定長の受信を対象としたserial.read(n)も使いにくいところがあります。 そのため最初に3バイト受信し、 先頭バイトのmsb(b7)が1’であればError Codeとして次に進み、 Function Codeであれば3バイト目のBytes (データ部のバイト長)を取り出し、 その値に+2(CRC16の2バイト)した文字数(n)を引数として serial.read(n) を実行するようにしています。 ただし、土壌のデータは短時間で時々刻々と変化するものではなく1日に1回か2回程度で測定すればよいと思いますのでserial.read_all()とTimeout=10sec.でも問題はありません。

List3 通信テストProgram(抜粋)


import serial
import time
# COM="COM4"       #USB60F
COM="COM5"       #SG61
bitRate=9600

print("Serial port & SLT5006 communication test ")
ser = serial.Serial(COM, bitRate, timeout=10 )

def receive_response():
    rcv_hdr = ser.read( 3 )       # get header    
    f_code = rcv_hdr[0]           # get response code
    if f_code >= 0x80:
        er_code = rcv_hdr[1]      # pick up ERROR CODE
        er_crc  = ser.read( 1 )   # get CRCL
        rcv_msg = rcv_hdr + er_crc
    
    else:
        bcnt = rcv_hdr[2]             # get data byte count
        rcv_data = ser.read( bcnt + 2 )
        er_code = 0
        rcv_msg  = rcv_hdr + rcv_data
        # print( rcv_msg )

    return rcv_msg

途中省略


#  get data
f_code = 1      #0x02 start
register = 0x13  #0x07 SNSR_CTR register
B_size = 0x10        # 0x01 Byte size
CRC_16U = 0xFC      # 0x0d CRC_16 Upper byte
CRC_16L = 0x2C     # 0x70 CRC_16 Lower byte

start_cmd = bytes([ f_code, register, B_size, CRC_16U, CRC_16L ])
ser.write( start_cmd )
rcv_resp = receive_response()
if len(rcv_resp) <= 4:
    print( "ERROR CODE : ", rcv_resp[1])
else:
    print( "Recive Data :", rcv_resp  )
    #
    # temp = (( rcv_resp[4] << 8 ) | ( rcv_resp[3] & 0x00ff )) * 0.0625
    temp = (( rcv_resp[4] << 8 ) | ( rcv_resp[3] & 0x00ff ))
    if temp >= 0x800:
        temp_dt = ((0x1000 - temp ) * -1 ) * 0.0625
    else:
        temp_dt = temp * 0.0625
    print( "Temparature :", temp_dt )
    
    ec_bulk = (( rcv_resp[6] << 8 ) | ( rcv_resp[5] & 0x00ff )) * 0.001
    print( "EC_BULK :", ec_bulk )
    vwc = (( rcv_resp[10] << 8 ) | ( rcv_resp[9] & 0x00ff )) * 0.1
    print( "VWC :", vwc )
    ec_pore = (( rcv_resp[16] << 8 ) | ( rcv_resp[15] & 0x00ff )) * 0.001
    print( "EC_PORE :", ec_pore )

ser.close()

Excelの表のCellに書き込む部分はList#5を参照して下さい。 import openpysl実行後、 あらかじめ作成しCellの書式指定などをしておいたExcelの表をopenします。 その後はCellを指定してデータを代入してゆくだけで表にデータを書き込んでゆくことができます。 本programでは何行目までデータが書
き込まれているかということを示す値を特定のCell に入れておき。 実行時にはその値を読み出してその値が示す行の次の行にデータを書き込んでゆくようにしています。 1回実行させればデータが1行追加されるようにしています。 1日に必要な回数実行し、実行後にExcelの表をCopy/RenameしてExcel
を使ってデータ処理を行えば実用になります。

List4 Excel file access テストProgram


# Excel .xlsx file read/write test program
#  c:\Users\USER\farmIoT\sl5006_data_01.xlsx
#
import datetime
import openpyxl
wb = openpyxl.load_workbook('sl5006_data_01.xlsx')
sheet = wb['Sheet1']  # sheet = wb.get_sheet_by_name('Sheet1')
for i in range( 1, 8 ):
    print( sheet.cell( row = 5, column = i).value )

nextrow = ( sheet['G3'].value ) + 1
print("Next row :", nextrow )

# input test data
temp = int(input("Temp ( -2048 to 2047 ) :"))
ec_bulk = int(input("EC.Bulk ( 0 to 65535 ) :"))
vwc = int(input("VWC ( 0 to 1000 ):"))
ec_po = int(input("EC_PORE ( 0 to 65535 ):"))
comment = input("Comment :")


# Write data to CELL
today = datetime.date.today()
t_now = datetime.datetime.now().time()
sheet.cell( row = nextrow, column = 1 ).value = today
sheet.cell( row = nextrow, column = 2 ).value = t_now
sheet.cell( row = nextrow, column = 3 ).value = temp * 0.0625
sheet.cell( row = nextrow, column = 4 ).value = ec_bulk * 0.001
sheet.cell( row = nextrow, column = 5 ).value = vwc * 0.1
sheet.cell( row = nextrow, column = 6 ).value = ec_po * 0.001
sheet.cell( row = nextrow, column = 7 ).value = comment 

sheet['G3'].value = nextrow

# Close xlsx
wb.save('sl5006_data_01.xlsx')
wb.close()

Programの全体はe2e Storeからdownloadすることができます。

>>サンプルスクリプトの全体はこちら⇒[別ウィンドウでサンプルスクリプト全体を表示]

RS-SG61ではなくREX-USB60FPWを使用して有線で使用する場合は下記のようにserial portの宣言部のCOMポート番号を変更するだけでOKです。 REX-USB60FPWはe2e Store専売商品ですのでe2e Storeから直接ご購入下さい。 土壌セン
サとしてRS485 インターフェイスのSLT5009を使用する場合はREX-USB70を使用することができますが、その場合も1番端子からUSB_BusPowerのDC+5Vを土壌センサに供給できるように改造する必要があります。 また、 マルチドロップ接続で土壌センサを使用する場合は一番端子から供給するDC+5Vの容量が500mAを超えないように土壌センサの数を16個くらいに抑える必要があります。 また、 センサを土中に埋めてしまう前に1台づつ各センサ固有のSlave Numberをあらかじめ1対1接続で書き込んでおかなくてはなりません。 さらに通信フォーマットやレジスタマップもSLT5006とは異なりますので本programの改造が必要です。

春たけなわの頃になればキュウリやトマト、ナスやズッキーニなど夏野菜を植える時季となりますので施肥や石灰をまくとデータがどう変化するのか楽しみです。
 

 返信する

以下のHTML タグと属性が利用できます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(必須)

(必須)

*