やっつけな日常(21) NodeRedダッシュボードからIO Expander制御

Joseph Halfmoon

前回、ラズパイ3機のI2Cバスを5V化した先に接続したIO Expander MCP23017の動作確認をPython使って行いました。今回はIO Expanderの持つA、B2つの8ビットポートのうちAポートについて、ブラウザに表示されているNode-REDダッシュボードから点灯/消灯操作を出来るようにしてみました。

Node-REDのダッシュボードには、ATOMLiteとかmicro:bitとか各マイコン毎にタブを作ってあり、実験できるようになっておるのです。しかし、Node-REDサーバであるRaspberry Pi 3 model B+機のタブはありません。今回タブを初追加となります。

とりあえずの「見た目」はこんな感じです。ビット毎のスイッチが並べてあり、そのスイッチを操作しておいて上部のSENDボタンを押すとスイッチに対応するIO ExpanderのPort Aのビットに取り付けられているLEDが点灯する、と。

NodeRedDashboard

Node-REDのフロー

今回追加のNode-REDのフローの構成要素は以下です。

  • Sendを指示するボタン。Functionノードに処理を指示するとともに、DashboardのSwitchノード(ダッシュボードでないSwitchノードもあるので要注意)を初期化。
  • ビット毎8個のダッシュボードSwitchノード
  • Switchノードに後続するChangeノード
  • SwitchノードのON/OFF結果を集計し、Sendボタンが押されたら 実行にトリガをかける Functionノード
  • 実際にIO Expanderを制御するPythonスクリプトを起動する Execノード
  • デバッグ用のDebugノード

フローは以下に。

NodeRedFlow

Dashboardのswitchノードの設定が以下に。初期化にPass throughモードを使ってます。また、スイッチがONのときにfalse設定になっているのは、後に出てくる回路図見ていただくと対応とれますが、LED点灯時がLOWアクティブなためです。

DashBoardSwitchNode

changeノードの設定が以下に、OFFのときがマイナスになっているのは、スイッチをON/OFF何度か操作した後に、SENDと押しても大丈夫なように、ONでもOFFでもFunctionノードが保持している値を操作するためです。

ChangeNode

Functionノードでは、スイッチのON/OFFに応じてcontextに保持した値を操作していき、Sendが押されると保持した値を送り出すようになっています。

FunctionNode

Execノードでは、実際にIO Expanderを操作するためのPythonスクリプトにFunctionノードが生成したON/OFF状態をエンコードした値を引数として与えて起動しています。

ExecNode

IO Expanderを制御するPythonスクリプト

やっていることは前回の動作確認用スクリプトとあまり変わらない(前回機能を包含)のですが、コマンドライン引数の処理など入ったので、大分長くなってしまいました。こんな感じ。

#! /usr/bin/python3
# coding: utf-8
import argparse
import smbus
import sys
import time

versionSTR = "ioexpander.py v0.0"

i2c = smbus.SMBus(1)

IOEX0 = 0x20
IOEX1 = 0x21
IOCONA = 0x0A
IOCONB = 0x0B
IODIRA = 0x00
IODIRB = 0x01
GPIOA = 0x12
GPIOB = 0x13
OLATA = 0x14
OLATB = 0x15
device = IOEX0

def errPrint(mes, opt=True):
    sys.stderr.write(mes)
    if opt:
        sys.stderr.write('\n')

def initMCP23017():
    """initialize MCP23017 IO expander
    
    IOCON config
    BANK=0, MIRROR=0, SEQOP=1(NO ADDR POINTER INC), DISSLW=0, ...
    """
    i2c.write_byte_data(device, IOCONA, 0x20)
    i2c.write_byte_data(device, IODIRA, 0x00) #OUTPUT
    i2c.write_byte_data(device, IODIRB, 0x00) #OUTPUT
    i2c.write_byte_data(device, OLATA,  0xFF) #LATCH=0xFF
    i2c.write_byte_data(device, OLATB,  0xFF) #LATCH=0xFF

def testMode():
    """test Mode
    
    Output test pattern to PortA/B. 
    """
    while (1):
        err = i2c.write_byte_data(device, OLATB,  0xAA)
        if err:
            print("ERROR")
        i2c.write_byte_data(device, OLATA,  0xAA)
        time.sleep(0.1)
        i2c.write_byte_data(device, OLATB,  0x55)
        i2c.write_byte_data(device, OLATA,  0x55)
        time.sleep(0.1)    

def outputPORT(prt, dat):
    """output Port
    
    prt=0(A)/1(B), dat=8bit int
    """
    OLAT = OLATA
    if prt:
        OLAT = OLATB
    ov = int(dat) & 0xFF
    i2c.write_byte_data(device, OLAT, ov)

def main():
    parser = argparse.ArgumentParser(description=versionSTR)
    parser.add_argument('--OUTA', nargs=1, help='Message.')
    parser.add_argument('--OUTB', nargs=1, help='Message.')
    parser.add_argument('-T', dest='TEST', help='Start Test Mode.', action='store_true', default=False)
    parser.add_argument('-V', dest='VERSION', help='Show Version, then exit', action='store_true', default=False)
    args = parser.parse_args()
    if args.VERSION:
        errPrint(versionSTR, opt=False)
        sys.exit(1)
    initMCP23017()
    if args.TEST:
        testMode()
        sys.exit(2) #Never!
    if args.OUTA is not None:
        outputPORT(0, args.OUTA[0])
    if args.OUTB is not None:
        outputPORT(1, args.OUTB[0])
# Normal End
    sys.exit(0)

if __name__ == "__main__":
    main()
IO Expander周りの回路と実ボードの動作

回路図的には前回と変わっているのは、外部5V電源をPCA9306のREFA電源に与えたことです(前回はラズパイ側の5Vだった。)これで、外部電源がOFFのときにPCA9306のEN端子がディセーブルになり、5V側のI2Cバスとラズパイ側のI2C端子の間はHiZ化されます。

DUT_Schematic

実際にPort Aを全点灯させているところが以下に。ダッシュボードのスイッチをOFFしてSENDすると、該当ビットが消灯します。

DUT

これで、パソコン上に開いたブラウザ画面から、ラズパイ3機に接続したIO Expanderが制御できるようになったです。まあやっつけ仕事だな。いつものことだい。

やっつけな日常(20) Raspberry Pi 3、5V IO Expander動作確認 へ戻る

やっつけな日常(22) ラズパイ、IO Expander制御、入力モード追加 へ進む