ブレーカー落ちた
洗濯機の乾燥機能が動かなくなり、修理に来てもらって無事動いたのはいいけど、夜にブレーカーが落ちた。
自宅サーバへの被害も考え、UPS電源の電圧を APCUPSD でモニタリングしていて、電源電圧が下がると、google-home で警告メッセージが流れるようにしてあるんだが、動作せずに落ちてる。nagios4 の LOG をみると、電圧低下は検出しているけど、通知が発動していない。なんでやねん。
(2023-12-03追記)
別のタイミングでは、警告メッセージの読み上げは動いていた。夜間はスピーカ音量を落としているので、気づきにくい音になってたけど。
Switchbot Plug の制御
電気毛布が必要な時期、外出時の電源を切り忘れるのを防ぐために、昨年導入していた Switchbot Plug 。
スマホの SwitchBot アプリのタイマー機能で朝に強制オフの制御していたけど、寝る時にスイッチを入れるのは、自分が不在の時だとムダだし、homebridge や cron で制御するのも面白そう。
switchbot-utility のインストール
ということで、Raspberry-Pi に、switchbot-utility をインストール。
((( 事前にSwitchbot アプリは設定済み ))) $ sudo pip3 install switchbot-utility $ cd /usr/local/lib/python3.9/dist-packages/switchbot_utility
制御するには、Switchbot アプリのトークンと秘密鍵が必要なので、アプリを起動して「プロフィール」、「設定」の画面を開いて、「アプリバージョン」の表示を 10 回連打すると、「開発者向けオプション」を表示できる。この画面を開いてトークンとクライアントシークレットをコピーし、上記の switchbot_utility のフォルダ内に、settings.json のファイル名で保存。

Python で以下のスクリプトを実行すると、switchbot-utility で扱えるデバイスの一覧 deviceList.txt が作られる。
((( settings.json )))
// Switchbot アプリで取得したトークンとシークレットを、
// switchbot_utilitiy のフォルダに settings.json で保存しておく
{
"token": "xxxxx....",
"secret": "yyyyy...."
}
((( devicelist.py )))
// Python で以下のスクリプトを実行すると、deviceList.txt が作られる。
// 以下を devicelist.py で保存し、python3 devicelist.py で実行!
from switchbot_utility.switchbot import Switchbot
switchbot = Switchbot()
switchbot.devicelist()
((( deviceList.txt )))
441793xxxxxx, 電気毛布, Plug, 000000000000
C5B496xxxxxx, エアコン, Bot, 000000000000
実際に、Switchbot Plug を動かすために、下記のscriptでスイッチを制御できるようにしてみた。
#!/usr/bin/python3
# -*- mode: python; coding: utf-8; tab-width: 4 ; -*-
# SwitchBot をON/OFFする
import sys
import time
import os
from switchbot_utility.switchbot_plug import SwitchbotPlug
# ~~~~~~~~~~~~~~ ~~~~~~~~~~~~~
# 制御するSwitchBot に合わせて、上記~~~ を書き換える。
sb_dir = '/usr/local/lib/python3.9/dist-packages/switchbot_utility'
# Switch Bot Plug MAC ADDR
# deviceList.txt 調べた MACアドレスを記入
sb_plug_macaddr = '441793xxxxxx'
# コマンドライン引数プロセス名
script_file_name = sys.argv.pop( 0 )
# コマンドライン引数 -d <デバイスID>
while len( sys.argv ) >= 2 and sys.argv[0] == '-d' :
sys.argv.pop( 0 )
sb_plug_macaddr = sys.argv.pop( 0 )
# setting.jsonを読み込むため
os.chdir( sb_dir )
# SwitchBot Plug に接続
sb_plug = SwitchbotPlug( sb_plug_macaddr )
# ~~~~~~~~~~~~~ この部分に制御対象用のコンストラクタを書けばいい
if len( sys.argv ) == 0 :
# 引数なしは、状態を表示
print( sb_plug.get_power() )
elif len( sys.argv ) == 1 :
# status | on | off | toggle or turn
arg = sys.argv.pop()
if arg == 'status' :
# exitでスイッチ状態を返す
sys.exit( 0 if sb_plug.get_power() == 'on' else 1 )
elif arg == 'on' :
sb_plug.turn_on() # ON
elif arg == 'off' :
sb_plug.turn_off() # OFF
elif arg == 'toggle' or arg == 'turn' :
# スイッチを反転
pw = sb_plug.get_power()
if pw == 'on' :
sb_plug.turn_off()
elif pw == 'off' :
sb_plug.turn_on()
このプログラムを、homebridge-cmdswitch2 の設定に加える。
{
"platform": "cmdSwitch2",
"name": "cmdSwitch2",
"switches": [
{
"name": "電気毛布",
"on_cmd": "/usr/local/bin/switchbot-plug.py on",
"off_cmd": "/usr/local/bin/switchbot-plug.py off",
"state_cmd": "/usr/local/bin/switchbot-plug.py status"
}
]
}
ということで、「OK Google, 電気毛布を点ける」でON、朝は起床時間にあわせたタイマーでOFF完成。
google-home-playerをインストール
Raspberry Pi で動かしていた homebridge だけど、nodejs.20.x が出ているとのことで、更新をかけた。しかしこの反動で、google-home-notifier が喋らなくなった。以前より google-home-notifier の内部で利用している google-tts-api のバージョンがあがると動かなくなるトラブルが発生していた。この状況下で、この後継となる google-home-player が出ているので、これを契機に乗り換え。
google-home-player のインストール
google-home-player を使うと、Google Home mini, Google Nest mini で自然なに英語や日本語をしゃべらせることができる。
$ sudo npm install -g google-home-player
Rapberry-Pi の更新で GPIO が動かない
64bit OS の arm64 で動かしている Raspberry-Pi で、rpi-update を実行したら、kernel が Linux 6.1.61-v8+ となり、自作スクリプトのいくつかが動かなくなった。原因は wiringPi や GPIO など絡んだ処理の中では、/proc/cpuinfo にアクセスして “Hardware” を取得しその値に合わせてアクセスするポートなどを切り替えているみたい。しかしながら、linux-6.x になったら /proc/cpuinfo で Hardware 情報が取れなくなったため、wiringPi, GPIO関連のプログラムが動かなくなった。
BME280 温湿度センサーを GPIO 経由から ioctl() から I2C を制御する処理に書き換え
$ ./bme280 Oops: Unable to determine board revision from /proc/cpuinfo -> No "Hardware" line -> You'd best google the error to find out why.
参考にしていたプログラムが wiringPi 経由で I2C 接続の温湿度センサー bme280 を使っていたけど、仕方がないのでプログラムを修正し、ioctl() 経由に修正。
bit 演算が多用されていて、unsigned char と char の宣言を手抜きしたら、異常値が出るようになった。char型の部分を unsigned char に修正したら、大きな値にずれる異常値はなくなった。でも、その後も時々小さな値となる異常値が発生した。どうも nagios やら munin で監視していると時々同じタイミングで bme280 の値取得の処理が起動されるようで、I2C デバイスの競合が発生していると思われた。このため、I2C デバイス /dev/i2c-* を開く際に flock() による、排他処理も追加した。
OLED ディスプレィ SSD1306 の処理を Adafruit_CircuitPython_SSD1306 に変更
Adafruit_Python_SSD1306 を使って表示させていた処理が動かなくなる。内部で WiringPi などを使っているのか “RuntimeError: Could not determine platform…” といったメッセージが出て動かなくなる。これも GPIO あたりのトラブル。調べていると Adafruit_CircuitPython_SSD1306 なら動きそう。
$ sudo pip3 install adafruit-circuitpython-ssd1306
若干のプログラム修正で動くようになった。
gcalcli が dpkg_resources is deprecated…の警告
gcalcli を使っている自作スクリプトが、以下のような警告メッセージを吐くようになった。
$ gcal.pl /usr/bin/gcalcli:6: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html from pkg_resources import load_entry_point
python で dpkg_resources が廃止されたことによる警告。調べてみたけど、現時点では他の python のプログラムでも同様のエラーが出てるみたい。ひとまずは標準エラーに出力される警告なので、自作スクリプトには、gcalcli を呼出す処理の後ろに “2>/dev/null” をつけて黙らせた。
debian trixie/testing
最近、aptitude safe-upgrade かけてもパッケージの更新が少ないなぁ…と思ってたけど、bookworm は 6 月に stable になってたのね。
気づかず半年間、寝かせていたからか testing/trixie で大量の更新がかかったけど、競合ですぐに更新されないパッケージもあったけど、半年の間に testing といえども安定していたのか、トラブル無しで更新が終わった。
debian trixie/testing
以前、apt/souces.list.d を stable と testing で記述してたけど、更新のタイミングを見逃すと、急に大量の更新がかかってびっくりしたので、bullseye とか bookworm とかで記述するようにしていた。
/etc/apt/preferences が邪魔をしているかと思って消して更新かかったけど、大した量じゃなかったし。

linux 6.1 to 6.5
testing を追いかけていなかったから、linux-image も 6.1.0-13 から 6.5.0-2 にジャンプアップ。
postfixの設定見直し
自宅サーバに届く迷惑メールの設定はそれなりにやってるつもりだけど、相変わらず届く。
迷惑メールの送信側も、DKIM や SPF といった迷惑メールに誤認されない対策をして送ってきている。そこで改めて postfix の設定を見直す。
RBLサイトの整理, 正引き・逆引きチェック
迷惑メール送信者のデータベース(RBL)の設定をしていたけど、all.rbl.jp, zen.spamhaus.org はサービスを停止しているようで、nslookup all.rbl.jp とかも失敗するし設定を削除。
Dynamic DNS サイトのような迷惑メールサイトからのメールを拒否するために、reject_unknown_reverse_client_hostname を設定していたけど、DKIM, SPF まで設定した迷惑メールサーバも多いので、設定をさらに厳しく reject_unknown_client_hostname に変更。
この設定を変更すると、逆引きと正引きが一致しない Dynamic DNS サイト(まさに自サイト tsaitoh.net はこの状態)からのメールを拒否することになる。しかし、迷惑メールの制限を強化したいし、身の回りの 逆引きと正引きが一致しない所からのメールは、smtpd_client_regexp で受信許可するようにしよう。
((( /etc/postfix/main.cf )))
smtpd_client_restrictions = permit_mynetworks,
check_client_access regexp:/etc/postfix/smtpd_client_regexp
- reject_rbl_client all.rbl.jp, # サービス停止
- reject_rbl_client zen.spamhaus.org, # サービス停止
reject_rbl_client bl.spamcop.net,
- reject_unknown_reverse_client_hostname, # 逆引きだけをチェック
+ reject_unknown_client_hostname, # IP->name->IPのチェックあり
permit
nodejs の更新方法の”更新”と hb-service
自宅で動かしている HomeBridge 、定期的に node-js の更新のために、”hb-service update-node” を実行しているけど、途中に警告メッセージがでるようになった。どうも https://deb.nodesource.com/setup_X での更新は非推奨で https://deb.nodesource.com/node_XX.x での更新に変更となったらしい。単純に警告で表示された URL にアクセスし、新しいインストール方法に従って、下記を実行する。
$ sudo apt-get update $ sudo apt-get install -y ca-certificates curl gnupg $ sudo mkdir -p /etc/apt/keyrings $ sudo curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \ | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg $ NODE_MAJOR=18 $ echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" \ | sudo tee /etc/apt/sources.list.d/nodesource.list $ sudo apt-get update $ sudo apt-get install nodejs -y
自作スクリプトのエラー対策 try-catch
自宅で動かしているスクリプト、自前だから手抜きもあって、サーバトラブル時には他の機器が巻き込まれてエラーが増えることも多い。自室の homebridge などを動かしている Raspberry-Pi が暑さもあってか、再起動させたら一時的に気絶。復旧は問題なかったけど、気絶中に他の外気温測定のRaspberry-Pi がブローカーとなっている Raspberry-Pi が落ちているため、MQTT のデータ送信に失敗のエラーを出してる。
ちゃんと、connect で出るエラーを try-except で例外処理を追加した。
try : client = mqtt.Client( ... ) client.connect( BROKER ) client.publish( ... ) except ValueError as err : print( err ) except OSError as err : print( err )
以前から、トラブル時にウザいのが、Perl で書かれた RSS 情報をまとめるスクリプト。Perl での try-catch もどきということで eval{} if ( $@ ) … でエラー対策してるつもりなんだけどトラブル時のエラーがうまく動いていないような。今回あらためて、Perl try-catch で検索したら、Perl 5.34 で try-catch が実験的にサポートされているらしいので使ってみた。
use feature qw( try ) ;
no warnings "experimental::try" ;
:
try {
$feed->merge( $rss ) ;
} catch( $e ) {
print "catch $e" ;
}
# eval { $feed->merge( $rss ) ; } ;
# if ( $@ ) {
# warn "..." ;
# }
スクリプト言語の比較
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 かな。



