スクリプト言語の比較
Raspberry Pi で、自宅内の温湿度管理とか色々やっていて、shell や perl や python などのスクリプトを使っているけど、ただでさえ遅い Raspberry-Pi だし、少しでも軽く動いてほしくて、lua なども使っている。
でも、shell だと、bash で書いているけど、高機能な分だけ遅いし、少しでも軽くなればと、インストールされているスクリプト言語のサイズを改めて比較をしてみた。
$ ls -al <いろいろ> -rwxr-xr-x 1 root root 14000 1月 2 2021 /usr/bin/lua50 -rwxr-xr-x 1 root root 91904 12月 10 2020 /bin/dash -rwxr-xr-x 1 root root 92292 12月 22 2018 /bin/sed -rwxr-xr-x 1 root root 120704 2月 17 2020 /usr/bin/mawk -rwxr-xr-x 1 root root 133048 8月 1 2016 /usr/bin/lua5.1 -rwxr-xr-x 1 root root 974312 3月 28 2022 /bin/bash -rwxr-xr-x 2 root root 3201036 9月 25 2021 /usr/bin/perl5.32.1 -rwxr-xr-x 1 root root 4703672 3月 12 2021 /usr/bin/python3.9
個人的には、軽いスクリプトというと、sed < awk < lua < bash < perl < python というイメージで使い分けをしていた。
しかし、これを見ると、bash と dash で10倍の差、軽くなればと使っていた lua だけど、lua5.1 と lua50 でも 10 倍の差がある。perl だと bash の 3倍、python だと bash の5倍。バイナリのサイズが単純に処理速度に反映される訳ではないけど、これを見る限り、自分で書いている手抜きスクリプトであれば、dash や lua50 で動かした方がよさそうだな。
また、下手に Perl を使うぐらいなら、bash の中で sed や awk を交えながらスクリプトを書くことも多いけど、下手に bash の中で sed や awk をガシガシ使ったら、あんまり早くなさそうだな。
これからは、lua50 < dash < sed , awk < bash < perl < python かな。
Raspberry-Pi MZ80C のボード差し替え
RPi model A+ が異常
以前に購入した Raspberry-Pi model A+ の MZ80C だけど、ボードがおかしくなっているのか、CPU 負荷がアイドル状態なのに 100% となっている。同様の Rapberry Pi と処理速度も変わらないし、何か変。RPi3 のボードに比べると処理速度も遅いし、RPi 3 model A+ のボードが同じ RPi3 model B より割安なのでボード差し替えをやってみる。
RPi 3 model A+ に差し替え
せっかくだし、表示部分も I2C 接続の SSD1306 の OLED Display を買う。
https://github.com/adafruit/Adafruit_Python_SSD1306
((( SSD1306 ))) GND VCC SCL SDA 黒 白 灰 紫 ((( BME280 ))) VDD GND NC SDI SDO SCK VDD GND -- SDA --- SCL 白 赤 × 黄 × 青 ((( Raspberry-Pi ))) 3.3 SDA SCK × GND
BME280, Adafruit SSD1306を使えるように
この RPi は、2Fのトイレに設置して、2Fの廊下全体の温度を測っていた。なので、載せ替えした RPi にも同様の機能を移植。
なんとか動くようになったかな。
ただ、syslog を見ると、電源電圧不足の警告が出ているし、たまに繋がらなくなる。確認すると再起動してる。USB電源アダプタ電流とれるやつに差し替えが必要だな。
Raspberry Pi の bullseye 更新
いつも大きい更新をかける時は、依存関係でトラブルから、利用頻度の低いパッケージを削除したり、重要なパッケージだけ個別に更新していたけど、”apt-upgrade –without-new-pkgs” は、便利なコマンド。これなら、ディスク容量が少ない Raspberry-Pi でも途中で容量不足で止まったりといった心配も少ない。
((( busterで更新 ))) $ sudo aptitude update ; sudo aptitude safe-upgrade ((( bullseyeの登録 ))) $ sudo vi /etc/apt/sources.list.d/11-bullseye.list deb http://raspbian.raspberrypi.org/raspbian/ bullseye main contrib non-free rpi deb-src http://raspbian.raspberrypi.org/raspbian/ bullseye main contrib non-free rpi ((( 最小限アップグレード ))) $ sudo aptitude $ sudo apt upgrade --without-new-pkgs $ sudo aptitude safe-upgrade
2台まとめての buster→bullseye 更新でいくつか、自分の家専用の処理が動かなくなったが、ボチボチと修正し復帰かな。
WiFiスキャンをさせてみた
自宅内のネットワークに繋がらない時があって悩んだら、外で使っていたモバイルルータがつけっぱなしで、自宅内ネットワークのサービスに接続できないのが原因だったりする。パケットも無駄に消費するので、自宅内でモバイルルータが動いていたら警告させるようにしたい。
wifi scan
メインサーバは有線だけなので、有線LAN接続で WiFi が空いている Raspberry-Pi で監視させてみた。
$ sudo iw dev wlan0 scan | grep "SSID: ルータのSSID"
最初は homebridge の homebridge-cmdswitch2 の state_cmd に仕込んでみたけど、モバイルルータが動いていたら警告してほしい。Siri のオートメーション経由で警告することもできるかもしれないけど、スマホに頼る形になるなぁ。
nagios で警告させたいけど、raspberry-pi に nagios を入れるのは資源のムダに思える。ということで、Raspberry-Pi には nagios の監視をリモートで呼び出す nagios-nrpe-server を 入れて、上記 iw コマンドを動かす check スクリプトを書いてみた。
check_iwscan
nagios-nrpe-server から呼出す際に、Raspberry-Pi で動かすのもあるし、OS 負荷が軽くなるように Lua で書いてみた。
#!/usr/bin/lua -- 見つけるべきSSID local check_list = {} check_list[ "tsaitoh.net" ] = "ok" check_list[ "tsaitoh.net_e5785" ] = "warning" check_list[ "tsaitoh.net_hwd14" ] = "critical" -- 見つけたSSID毎の数 local count = {} count[ "ok" ] = 0 count[ "warning" ] = 0 count[ "critical" ] = 0 -- スキャン結果を処理 local handle = io.popen( "/usr/bin/sudo /sbin/iw dev wlan0 scan" , "r" ) if handle then for line in handle:lines() do -- SSID を抽出 ssid = string.match( line , "^%s*SSID: (.+)$" ) if ssid then -- SSID のカウント local lv = check_list[ssid] if lv then count[lv] = count[lv] + 1 end -- print( ssid ) ; end end handle:close() end -- カウント結果に応じたexit値を決める local status = 0 local st_mess = "Ok" if count["critical"] > 0 then status = 2 st_mess = "Critical" elseif count[ "warning" ] > 0 then status = 1 st_mess = "Warning" end -- 結果の表示 print( string.format( "IWSCAN %s - ok:%d/warn:%d/critical:%d" , st_mess , count["ok"] , count["warning"] , count["critical"] ) ) os.exit( status )
MQTTの設定
MQTTとホームオートメーション
自宅サーバで、ホームオートメーションもどきで遊んでいるけど、デバイスとのデータのやり取りは軽量の MQTT プロトコルがあるらしい。M5Stack ATOM Lite などからの情報を上げる時などで遊べそうなので、実験してみよう。
# 現状では センサー側の Raspberry-Pi では inetd.conf などで問合せポートにアクセスがあったら測定値を echo バックするような設定となっている。
mosquittoのインストール
でもひとまずは、MQTT ブローカー のオープンソース実装 mosquitto をインストール。
ブローカーとなる Raspberry-Pi には、mosquitto, mosquitto-clients をインストール。
((( ブローカーで mosquitto のインストール ))) $ sudo aptitude install mosquitto mosquitto-clients
温湿度センサーを搭載したパブリッシャー側の Raspberry-Pi には、mosquitto-clients のみをインストール。最終的には Net::MQTT::Simple を使うようにしたから不要だけど動作試験には使える。
((( パプリッシャー側は mosquitto-client だけ入れる ))) $ sudo aptitude install mosquitto-clients
mosquitto はデフォルトで外部接続を受けないので、外部接続の設定を追加。Debian流で /etc/mosquitto/conf.d/00-remote-access.conf にリモートアクセスを受ける設定を追記。
# listener<tab>1883 だとエラーになった。項目区切りで tab 使えんのか???
後のブラウザで確認するために、websocket の機能も設定しておく。
((( 最小限の生接続でひとまず実験 ))) $ sudo vi /etc/mosquitto/conf.d/00-remote-access.conf listener 1883 # 1883 ポートで受信 allow_anonymous true # パスワード無し ((( Websocket の設定 ))) $ sudo vi /etc/mosquitto/conf.d/10-websocket.conf listener 15675 protocol websockets ((( mosquitto を再起動 ))) $ sudo systemctl restart mosquitto ((( パスワード認証を使うなら ))) $ sudo mosquitto_passwd -c /etc/mosquitto/passwd mqtt $ sudo vi /etc/mosquitto/mosquitto.conf (先頭に) per_listener_settings true $ sudo vi /etc/mosquitto/conf.d/00-remote-access.conf (追記) password_file /etc/mosquitto/passwd $ sudo systemctl restart mosquitto
MQTTの基本的な導通テスト
まずは基本的な導通テスト
((( ブローカー側 ))) $ sudo mosquitto_sub -d -t /sensor/place/temperature/host ((( パブリッシャー側 ))) $ mosquitto_pub -h ブローカーホスト名 -d -t /sensor/place/temperature/host -m 12.34 ((( 実験結果 ))) $ sudo mosquitto_sub -d -t /sensor/place/+/host Client (null) sending CONNECT Client (null) received CONNACK (0) Client (null) sending SUBSCRIBE (Mid: 1, Topic: /sensor/place/+/host, QoS: 0, Options: 0x00) Client (null) received SUBACK Subscribed (mid: 1): 0 Client (null) received PUBLISH (d0, q0, r0, m0, '/sensor/place/temperature/host', ... (4 bytes)) 12.34
パブリッシャー側のプログラム
外気?温度(トイレ)で温度湿度を測っている Raspberry Pi の温度情報更新処理の中に Perl でブローカー宛にパプリッシュする処理を埋め込むのなら、Net::MQTT::Simple で書くのが簡単。
Net::MQTT::Simple が HTTP::Tiny を使うけど、CPAN でインストールするパッケージは最小にしたいので、HTTP::Tiny は apt-get でインストール。
((( HTTP::Tiny をインストール ))) $ sudo aptitude install libhttp-tiny-perl ((( CPANで Net::MQTT::Simple をインストール ))) $ sudo perl -MCPAN -e shell cpan[..]> install Net::MQTT::Simple
retain(…) でメッセージを送る際に、複数の項目を連続で送る場合は、各項目毎に 30msec 50msec ほどの遅延が必要だった。
# パブリッシャー側の問題?/ブローカー側の問題? 20msec だと後続の retain が失敗した。30msecだと最後の retain が失敗(不安定)
use Net::MQTT::Simple; use Time::HiRes 'usleep' ; my $mqtt = Net::MQTT::Simple->new("ブローカーホスト名") ; # brokerのホスト名 $mqtt->retain( "/sensor/place/temperature/host" => "12.3" ) ; # センサーの値を送る時 usleep( 50000 ) ; # 50msecの遅延が必要 $mqtt->retain( "/sensor/place/humidity/host" => "67.8" ) ; # センサーの値を送る時 usleep( 50000 ) ; $mqtt->retain( "/sensor/place/pressuore/host" => "1023.4" ) ; # センサーの値を送る時
ひとまずサブスクライバの代わりに Web ブラウザで mosquitto の結果を見るための HTML , js をダウンロード。
$ cd /var/www/html $ sudo mkdir mqtt $ cd mqtt $ sudo wget https://raw.githubusercontent.com/rabbitmq/rabbitmq-web-mqtt-examples/master/priv/echo.html $ sudo wget https://raw.githubusercontent.com/rabbitmq/rabbitmq-web-mqtt-examples/master/priv/mqttws31.js
echo.html の受信するトピックの設定を修正。
((( 84行目 ))) var print_first = pipe('#first', function(data) { message = new Paho.MQTT.Message(data); message.destinationName = "/sensor/place/+/host"; // トピックを修正 debug("SEND ON " + message.destinationName + " PAYLOAD " + data); client.send(message); }); ((( 108行目 ))) var options = { timeout: 3, keepAliveInterval: 30, onSuccess: function () { debug("CONNECTION SUCCESS"); client.subscribe("/sensor/place/+/host", {qos: 1}); // トピックを修正 }, onFailure: function (message) { debug("CONNECTION FAILURE - " + message.errorMessage); } };
hb-service upgrade-node で更新
Raspberry-Pi で動かしている homebridge だけど、node.js の更新は curl とか使ってたけど、hb-service でインストールできるんだ。便利。
$ sudo hb-service update-node
node.js もメジャーバージョンが、16 から 18 に以降したうえで、最新の node.js 19 が発表されたみたい。
raspberry-pi bullseye で cec-client が動かない
最近は、google-home や Siri 経由で TVやチューナー の ON/OFF させるのに cec-client を使っているので、これが使えないと致命的。
症状
単純に apt で入った cec-client 6.0.2 では、デバイスが見つからない。(どうも 非 RPi のパッケージが入るらしい)
$ sudo aptitude install cec-client $ echo 'scan' | cec-client -s -d 1 autodetect FAILED. $ cec-client -l Found devices: NONE $ dpkg -l | grep cec ii cec-utils 6.0.2
バージョンを落としてみたけど、動かない。
$ sudo aptitude install cec-client/buster $ echo 'scan' | cec-client -s -d 1 反応なし..^C でも止まらない $ dpkg -l | grep cec ii cec-utils 4.0.7
記事を漁ると bullseye では cec-client が動かないとかいう記事もあるなか、libCEC-6.0.2 を github よりインストールを行う。
github より libCEC をインストール
((( 最初に競合しそうな cec 関連を消す ))) $ sudo aptitude purge libcec4 libcec6 cec-utils ((( 資料を参考に... ))) $ sudo apt-get update $ sudo apt-get install cmake libudev-dev libxrandr-dev python3-dev swig git ((( raspberry-pi 用の platform をインストール ))) $ cd $ git clone https://github.com/Pulse-Eight/platform.git $ mkdir platform/build $ cd platform/build $ cmake .. $ make $ sudo make install ((( libcec のインストール ))) $ cd $ git clone https://github.com/Pulse-Eight/libcec.git $ mkdir libcec/build $ cd libcec/build $ cmake -DRPI_INCLUDE_DIR=/opt/vc/include -DRPI_LIB_DIR=/opt/vc/lib .. $ make -j4 $ sudo make install $ sudo ldconfig
これが入って、ようやく cec-client が動き出す。Google Home や Siri のホームオートメーションはやっぱり便利。