はじめに
仕事でModbusを勉強する必要が出てきたので、試しに何か動かそうとAmazon探して、Modbus-RTU対応の温湿度系のこいつを動かしてみることにしました。
WINGONEER温度および湿度センサートランスミッター高精度工業グレード測定RS485 SHT20プローブ
- メディア: エレクトロニクス
商品名には記載が無いですが、写真にある XY-MD02
という名前で調べるとドキュメントも見つかります。
↓ドキュメント
http://www.sah.co.rs/media/sah/techdocs/xy-md02-manual.pdf
Modbus(モドバス)って?
PLCとお話するためのプロトコルです。詳しくはググると上の方に出てくるページで色々わかりますが、Modbusの中身は以下の資料がわかりやすいです。
PCのUSBから繋いでみる
プロトコルはModbusを使うのですが、まずは通信できる経路を準備する必要があります。
XY-MD02
はRS485で接続する必要があるので、まずUSB to RS485変換アダプタ使って繋いでみます。
以下のブログを参考にさせていただくとサクッと繋がります。
なお、上記ブログ内で使っている温湿度系は見た目そっくりですが、今回使っている XY-MD02
とは別ものの WTR10-E
という型番です。中身の仕様も異なります。
ただ、それでもとても参考になる記事でしたので、私もブログ参考にしながら繋いでみました。ちょうど電池のユニットが転がってたので、ブレッドボードすら無しで動きました。
PC接続すれば、PCで使えるModbus用のデバッグアプリが豊富にあります。参考にしたブログに倣ってこちらのツールを使いました。
機器に送信するコマンドはドキュメントに書いてあるこちらです。
ツールから実行してみます。図の中にコメント書いたように16進数で取得されるので、10進数に直してみると、温度と湿度が取得できてそうです。
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をそれぞれ接続します。
配線後の写真です。
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()
これで部屋の温度と湿度が表示できました。