Modbus-RTU対応の温湿度計をRaspberry PIとPythonでGPIO経由で利用してみた

はじめに

仕事でModbusを勉強する必要が出てきたので、試しに何か動かそうとAmazon探して、Modbus-RTU対応の温湿度系のこいつを動かしてみることにしました。

商品名には記載が無いですが、写真にある XY-MD02 という名前で調べるとドキュメントも見つかります。

f:id:yomon8:20200831215454p:plain

↓ドキュメント

http://www.sah.co.rs/media/sah/techdocs/xy-md02-manual.pdf

Modbus(モドバス)って?

PLCとお話するためのプロトコルです。詳しくはググると上の方に出てくるページで色々わかりますが、Modbusの中身は以下の資料がわかりやすいです。

Modbus プロトコル概説書 - M-System

PCのUSBから繋いでみる

プロトコルはModbusを使うのですが、まずは通信できる経路を準備する必要があります。

XY-MD02 はRS485で接続する必要があるので、まずUSB to RS485変換アダプタ使って繋いでみます。

以下のブログを参考にさせていただくとサクッと繋がります。

future-architect.github.io

なお、上記ブログ内で使っている温湿度系は見た目そっくりですが、今回使っている XY-MD02 とは別ものの WTR10-E という型番です。中身の仕様も異なります。

ただ、それでもとても参考になる記事でしたので、私もブログ参考にしながら繋いでみました。ちょうど電池のユニットが転がってたので、ブレッドボードすら無しで動きました。

PC接続すれば、PCで使えるModbus用のデバッグアプリが豊富にあります。参考にしたブログに倣ってこちらのツールを使いました。

機器に送信するコマンドはドキュメントに書いてあるこちらです。

f:id:yomon8:20200831221339p:plain

ツールから実行してみます。図の中にコメント書いたように16進数で取得されるので、10進数に直してみると、温度と湿度が取得できてそうです。

f:id:yomon8:20200831222045p:plain

GPIOから繋いでみる

ここからはRaspberry PIのGPIOを通してPythonで同じことしていきたいと思います。

Raspberry PIでUART通信の準備

raspi-configを使ってシリアル通信を有効化し、UART(Universal Asynchronous Receiver Transmitter)通信ができるようにします。

sudo raspi-config

画像だけペタペタ貼っておきます。

最後に再起動で完了です。

sudo reboot

MAX485購入(UART -> RS485変換)

先程はUSB to RS485の変換器を使いましたが、GPIOからも直接RS485は使えません。

Raspberry PIのUART通信をRS485に変換するため以下を購入しました。これを使っていきます

配線

配線をします。Raspberry PIのGPIOから見ていきます。

GPIO 接続先
5V XY-MD02(VCC)
GND XY-MD02(GND)
3V MAX485(VCC)
GND MAX485(GND)
BMC17 MAX485(RE)
BMC18 MAX485(DE)
BMC14 MAX485(DI)
BMC15 MAX485(RO)

MAX485のAとXY-MD02のA、MAX485のBとXY-MD02のBをそれぞれ接続します。

配線後の写真です。

f:id:yomon8:20200831231707j:plain

Pythonで通信してみる

これで利用する準備ができたので、Pythonで動かしてみます。modbus制御用のモジュールなどもありますが、シンプルに使ってみようと思います。

import serial
import time
import RPi.GPIO as GPIO


#### GPIOの設定
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
#  RE(Receiver Enable)はLowでOnになり受信可能になる
GPIO.setup(17, GPIO.OUT) 
GPIO.output(17, False)
# DE(Driver Enable)はHighでOnになり受信可能になる
GPIO.setup(18, GPIO.OUT) 
GPIO.output(18, True)


#### シリアル通信の設定
# Raspberry PI 3以降は/dev/ttyS0
# それ以前は/dev/ttyAMA0
ser = serial.Serial('/dev/ttyS0', 9600, timeout=None)


# ドキュメントの記載読んでコマンドを作る
TEMPERATURE_CMD = bytes.fromhex('010400010001600A')
HUMIDITY_CMD = bytes.fromhex('010400020001900A')

# 温度の取得・表示
ser.write(TEMPERATURE_CMD)
time.sleep(1)
temperature_res = ser.read_all()  # -> 入力コマンドと結果の両方が返ってくるから少しおかしいかも
temperature = int(temperature_res.hex()[22:26],16)/10
print(f"Temperatur:\t{temperature} ℃")

# 湿度の取得・表示
ser.write(HUMIDITY_CMD)
time.sleep(1)
humidity_res = ser.read_all() # -> 入力コマンドと結果の両方が返ってくるから少しおかしいかも
humidity  = int(humidity_res.hex()[22:26],16)/10
print(f"Humidity:\t{humidity} %")

# お掃除
GPIO.cleanup()
ser.close()

これで部屋の温度と湿度が表示できました。

f:id:yomon8:20200831234921p:plain

参考URL

zoe6120.com

future-architect.github.io