Node-RED の Grove Base HAT ノードが動かなくなっていたので、ひとまず手元で動くように修正したメモです。
この記事は Seeed UG Advent Calendar 2022 の 16 日目の記事です。
背景
私が作った node-red-contrib-grove-base-hat ノードが、
- 2022/8 ごろのバージョンの Raspberry Pi OS
- 2022/11 ごろのバージョンの grove.py
の組み合わせで動かなくなっていたことに、最近イチからセットアップしたら気づきました。
以前の私のリリースから長い時間が経過しているので、どれがクリティカルな原因か分からないのですが、以前のバージョンはひとまず固定して、
Release v0.0.10 · 1ft-seabass/node-red-contrib-grove-base-hat
手元で動くようにして方針が見えたら次のバージョンで修正してみます。
以前のコード
まず、 Node-RED ノードの仕組み。grove-led を例に。
var path = require('path'); module.exports = function(RED) { function GroveLedNode(config) { // console.log(path.join(__dirname , 'grove-led.py')); // console.log("__dirname " , __dirname ); RED.nodes.createNode(this,config); this.port_number = config.port_number; this.port_name = "D" + this.port_number; this.status({fill:"blue",shape:"dot",text:this.port_name}); var node = this; node.on('input', function(msg) { // msg.payload = msg.payload.toLowerCase(); const gpio_pin = this.port_number; const exec = require('child_process').exec; this.status({fill:"yellow",shape:"ring",text:this.port_name + " connecting"}); exec('python -u ' + path.join( __dirname , 'grove-led.py') + ' ' + gpio_pin + ' ' + msg.payload, (err, stdout, stderr) => { if (err) { console.log(err); } // console.log(stdout); this.status({fill:"green",shape:"dot",text:this.port_name + " connected"}); }); // node.send(msg); }); } RED.nodes.registerType("grove-led",GroveLedNode); }
いたってシンプル。ここは問題なく動いてました。grove.py を参考にして作った後述する grove-led.py という python コードを実行するものです。
以下は grove-led.py の v0.0.10 での中身です。
#!/usr/bin/env python # -*- coding: utf-8 -*- # # The MIT License (MIT) # # Grove Base Hat for the Raspberry Pi, used to connect grove sensors. # Copyright (C) 2018 Seeed Technology Co.,Ltd. ''' This is the code for - `Grove - Red LED <https://www.seeedstudio.com/Grove-Red-LED-p-1142.html>`_ - `Grove - Green LED <https://www.seeedstudio.com/Grove-Green-LED-p-1144.html>`_ - `Grove - Purple LED <https://www.seeedstudio.com/Grove-Purple-LED-3m-p-1143.html>`_ - `Grove - White LED <https://www.seeedstudio.com/Grove-White-LED-p-1140.html>`_ Examples: .. code-block:: python import time from grove.grove_led import GroveLed # connect to pin 5(slot D5) PIN = 5 led = GroveLed(PIN) while True: led.on() time.sleep(1) led.off() time.sleep(1) ''' import time import os # add for node-red import json # add for node-red import sys #add for node-red from grove.gpio import GPIO __all__ = ['GroveLed', 'GPIO'] class GroveLed(GPIO): ''' Class for Grove - XXXX Led Args: pin(int): number of digital pin the led connected. ''' def __init__(self, pin): super(GroveLed, self).__init__(pin, GPIO.OUT) def on(self): ''' light on the led ''' self.write(1) def off(self): ''' light off the led ''' self.write(0) Grove = GroveLed def main(): # print disable sys.stdout = open(os.devnull, 'w') from grove.helper import SlotHelper sh = SlotHelper(SlotHelper.GPIO) pin = sh.argv2pin() argvs = sys.argv #add for node-red led = GroveLed(pin) # print enable sys.stdout = sys.__stdout__ control = argvs[2] # print (control == "1") if (control == "1"): led.on() if (control == "0"): led.off() if __name__ == '__main__': main()
Node-RED から出された指示を実行してるんですが、2 年くらい前の grove.py の LED を動かすソースコードを、そのままコピーで持って来て使ってたんです。
これが、どうも最新の grove.py がある状態だと、うまく動かない様子。
アプローチ変更したら成功
grove.py を良く読んでいると、どうも、grove.py 自体はライブラリとして使って、自分の書いたコードで呼び出す使い方が良いようです。
ということで、grove-led.py の内容を以下のように変えてみました。
#!/usr/bin/env python # -*- coding: utf-8 -*- import time import os # add for node-red import json # add for node-red import sys #add for node-red from grove.grove_led import GroveLed def main(): # print disable # sys.stdout = open(os.devnull, 'w') argvs = sys.argv #add for node-red pin = int(argvs[1]) led = GroveLed(pin) # print enable # sys.stdout = sys.__stdout__ control = argvs[2] # print (control == "1") if (control == "1"): led.on() if (control == "0"): led.off() if __name__ == '__main__': main()
こうしてみたところ、Node-RED からこの python への指示を出す部分は一切変更せずに、LED が光るのが復活しました!
他でも同じように修正してみたらうまくいった
超音波距離センサーとボタンについても、同じように grove.py 自体はライブラリとして使って、自分の書いたコードで呼び出す方式で試してみたところ、うまく動きました。
ライブラリとしての使い方を、ちゃんとドキュメント読み込まないといけないのはありましたが、今後も grove.py が更新されても、ライブラリとして呼ぶ形で動作を保つと思うので、今回のやりかたのほうが、ちゃんと動く強度がありそうです。
たしかに、前回のやり方は、今思うと、そのときのライブラリの仕組みをコピーして持ってくるので、ライブラリ自体が更新されると不都合が起きそうな建付けですね。勉強になりました。
近々、もう少し念入りに動作確認をしつつ Grove Base HAT ノードを修正してアップデートしてみます!