Raspberry Pi 4のOSを64bitにした

非対応品を使う

Homebridgeを動かしているRaspberry Pi 4 (以下RPi) のOSを64bitにしました。作った当時は、「IoTサーバーなので、軽い32bitでも十分だ」と思ってました。しかし、32bitで動く最後のLTS (長期間サポート) Node.js v22が、2027年4月にサポート終了してしまいます。それに備えて、64bit OSに更新することにしました。

なお、今回の更新作業は、全面的にClaudeに手伝ってもらいました。AIは優秀ですね。

移行前のRPi環境

現状の環境は以下です。OSは、Raspberry Pi Imagerで32bit版Homebridgeイメージを指定して、インストールしたものです。Homebridge自体は、Node.jsで動くプログラムなので、32bitも64bitも関係ないのですが、組み込まれているOSとNode.jsの違いで、2種類のイメージが用意されています。

  • 本体:Raspberry Pi 4 Model B(メモリ2GB)
  • OS:Raspbian 11(bullseye)ソフトは32bit(armhf)
  • ストレージ:32GB SDカード
  • Homebridge:v2.4.0
  • Zigbee2MQTT:1.40.2
  • Zigbee2MQTT用のNode.js:v22.22.3(aptで導入)
  • Mosquitto:2.0.11
  • Zigbeeドングル:TI CC2652系(Z-Stack 3.x、USB変換はCH340)

このRPiには、Node.jsが2つ入っています。一つは、Homebridgeのイメージに入っていたNode.jsで、Homebridgeだけが使用します。 /opt/homebridge/bin/node にあります。

もう一つのNode.jsは、Zigbee2MQTTをインストールしたときにaptで導入したもので、/usr/bin/node にあります。こちらにパスが通っているので、Homebridge以外のソフトウェアは、これを使用します。

ややこしいので一本化しようとも思ったのですが、分けておくと、片方を更新してももう片方に影響しないメリットもあるかと思い、そのままです。

使用しているHomebridgeのプラグインは、シンプルに次の3つだけです。

  • homebridge-z2m:Zigbee2MQTTのZigbeeデバイスをHomeKitに出現させます
  • homebridge-mqttthing:MQTTのデバイスをHomeKitに出現させます
  • homebridge-camera-ffmpeg:ネットワークカメラをHomeKitに出現させます

このRPiを、Raspberry Pi Imagerで、64bit Homebridgeイメージを指定してインストールし直したところ、OSは Debian 13(trixie)になりました。

更新の方針

32bitのOSをそのまま64bitに上げる方法はないので、新しく64bit版を入れて、そこへ設定とデータを戻します。決めた方針は次の5つです。

  • 現行SDカードはバックアップして新規インストール:SDカードをMacに挿して、ddコマンドでイメージファイルをバックアップします。その後消去して、64bitイメージをインストールします。以下のバックアップで失敗しても、元に戻せます。
  • Homebridgeは、Homebridge UIのバックアップで移す:設定、HomeKitのペアリング情報、プラグインの一覧が入っています。これを戻せば、ホームアプリでペアリングし直さずに済みます。
  • Zigbee2MQTTとMosquittoの設定は、別にバックアップする:Homebridge UIのバックアップには、この2つは入りません。なので別途バックアップします。Claudeが、Homebridge以外を全部バックアップするスクリプトを作ってくれました。
  • Zigbee2MQTTは、移行前と同じ版を入れる:使用中のZigbee2MQTT 1.40は、実は古いです。最新版の2.x系への更新は、落ち着いてから別の日に行います。
  • 同じドングルと、同じ data フォルダを使う:Zigbeeのネットワークは、実はUSBドングルの中に保存されています。Zigbee2MQTTは起動するときに、configuration.yaml の設定とドングルの中身を照らし合わせます。2つが食い違うと、ネットワークが作り直されることがあります。

手順1:バックアップを取る

まずは、現行のRPiが動作している状態で、バックアップを取ります。

Homebridgeのバックアップ

MacのwebブラウザからHomebridge UIページを開きます。ページのメニューから「Settings / General / Backup & Restore」を開き、「Backup Now Generate and download an up-to-date backup file.」を選択します。すると、最新のバックアップファイルが作成されて、それをダウンロードできます。Macのダウンロードディレクトリに、homebridge-backup-xxxxxxx.tar.gz というような名前で保存されます。

それ以外のバックアップ

次のスクリプトを適当な名前、例えば、 ~/backup32.sh として保存し、実行します。ここでは、Zigbee2MQTTを数秒だけ止めてデータを固め、すぐに起動し直します。あとで復元したファイルが元と同じか確かめられるように、チェックサム(md5)も記録しています。またMosquittoの設定ファイルもバックアップしてます。そのほか、ネットワーク設定、ホームディレクトリもバックアップしてます。さらに、cronも利用していたので、そのバックアップもしています。

#!/bin/bash
set -e
D=~/migration-backup-$(date +%Y%m%d-%H%M)
mkdir -p "$D"
{ node -v; grep '"version"' /opt/zigbee2mqtt/package.json; mosquitto -h | head -1; lsusb | grep -i 1a86; } > "$D/versions.txt"

# Zigbee2MQTT(止めてからコピー、ログは除外)
sudo systemctl stop zigbee2mqtt
(cd /opt/zigbee2mqtt/data && md5sum configuration.yaml coordinator_backup.json database.db state.json) > "$D/z2m-md5.txt"
tar czf "$D/z2m-data.tar.gz" -C /opt/zigbee2mqtt --exclude=data/log data
sudo systemctl start zigbee2mqtt
systemctl cat zigbee2mqtt > "$D/zigbee2mqtt.service.txt"

# Mosquitto(設定・パスワード・保存データ)
sudo tar czf "$D/mosquitto.tar.gz" /etc/mosquitto /var/lib/mosquitto

# cron、ネットワーク設定、ホームディレクトリ
crontab -l > "$D/crontab-$USER.txt"
nmcli con show "Wired connection 1" | grep -E 'ipv4\.(method|addresses|gateway|dns)' > "$D/network.txt"
tar czf "$D/home-$USER.tar.gz" -C ~ \
  --exclude='./.cache' --exclude='./.npm' --exclude='*/node_modules' \
  --exclude='./migration-backup-*' .
sudo chown -R "$USER" "$D"
ls -la "$D"

できたフォルダは、Macから scp コマンドでコピーします。以下は、RPiのユーザ名がhogeだった場合の例です。タイムスタンプが違うものも全部コピーするためにパスにワイルドカード (*) を使ってます。この部分がシングルクォートで囲まれています。そうしないと、Macのzshが * を自分で展開しようとしてしまい、エラーになります。

scp -r 'hoge@192.168.xxx.xxx:~/migration-backup-*' ~/Desktop/

バックアップを取ったら、sudo shutdown -h now でPiを止めます。

SDカードのバックアップ

RPiが停止したら、SDカードを取り出して、Macに挿します。SDカードがマウントされたディスク番号を、diskutilコマンドの結果から特定して、ddコマンドでディスクイメージデータをバックアップします。32GBのカードのバックアップに、20分ほどかかりました。

diskutil list  # 容量などからSDカードを特定して、/dev/diskN のNを確認
diskutil unmountDisk /dev/diskN
sudo dd if=/dev/rdiskN bs=4m | gzip > ~/Desktop/pi4-32bit.img.gz

このようにイメージを作っておけば、以下のように、ddコマンドで元に戻すことができます。これで、この先の64bit移行作業で失敗しても安心です。バックアップし忘れた大事なデータがあっても元に戻れます。圧縮したファイルを復元するとSDカード容量と同じ巨大サイズのファイルになるので、復元しつつパイプでddコマンドに送ってます。

diskutil list  # カードの番号 N をもう一度確認
diskutil unmountDisk /dev/diskN
sudo -v        # 次の行でパスワードを聞かれると面倒なので、先に入れておく
gunzip -c ~/Desktop/pi4-32bit.img.gz | sudo dd of=/dev/rdiskN bs=4m
sync           # 念のため
diskutil eject /dev/diskN

ちなみに、Raspberry Pi ImagerのOS選択で「カスタムイメージを使う」を選び、pi4-32bit.img.gz を指定する方法でも書き込めます。(OSのカスタマイズは適用しないでください。)圧縮されたままのファイルを読めますし、書き込んだあとの検証も自動でしてくれます。ddコマンドよりも楽で安全です。

手順2:Pi Imagerで64bit版を書き込む

引き続きMacでの作業です。ddコマンドでバックアップしたRPiのSDカードに、Raspberry Pi Imagerで64bit版のHomebridgeイメージを書き込みます。

  1. Deviceに「Raspberry Pi 4」を選びます。
  2. OSは「Other specific-purpose OS」→「Home  automation」→「Homebridge」と進み、64-bit版を選びます。
  3. OSのカスタマイズ画面で、次のように設定します。
    • ホスト名:移行前と同じ (pi4という名前にしてました)
    • ユーザー名:移行前と同じ (ここでは仮にhogeとします。Zigbee2MQTTのサービスはこのユーザーで動きます)
    • WiFi : 有線のみを使用するので、何も設定しませんでした。
    • SSH:パスワードまたは鍵でSSHができるように指定しておきます
    • タイムゾーン:Asia/Tokyo
  4. SDカードに書き込みます。

Imagerのバージョンはv2.0.12で、書き込みと確認に7分ほどかかりました。

手順3:固定IPとHomebridgeを復元

出来上がったSDカードをRPiに挿して起動します。

SSHで接続する

まだDHCPのIPアドレスなので、pi4.local でつなぎます。また、OSを入れ直すとRPi側の鍵(ホスト鍵)が変わるので、パスワードでも鍵でも、Macに残っている古い記録を消してから接続します。

ssh-keygen -R 192.168.xxx.xxx; ssh-keygen -R pi4.local
ssh hoge@pi4.local

固定IPを設定する

新しいOSもNetworkManagerで、有線の接続名は移行前と同じ Wired connection 1 でした。<GW>と<DNS>には、バックアップの network.txt に控えた値を使います。たいていの場合は、ルーターがゲートウェイとDNSを担っているので、GWは、192.168.xxx.1のような値になります。DNSには、さらに外部のDNSサーバも追加されているかもしれません。DNSを複数指定する場合は、”192.168.xxx.1,8.8.8.8,1.1.1.1″のように、カンマかスペースで区切ります。

sudo nmcli con mod "Wired connection 1" ipv4.method manual \
ipv4.addresses 192.168.xxx.xxx/24 ipv4.gateway <GW> ipv4.dns "<DNS>"
sudo nmcli con up "Wired connection 1"

2行目でIPアドレスが変わるので、SSH接続は切れます。

ssh hoge@192.168.xxx.xxx

でつなぎ直します。

Homebridgeを戻す

ブラウザで http://192.168.xxx.xxx:8581 を開き、初期設定の画面で「Restore from Backup」を選んで、手順1のファイルをアップロードします。プラグインは自動で入り直します。復元が終わるまで1分ほどかかりました。

この時点ではまだMosquittoがないので、homebridge-z2mとhomebridge-mqttthingが接続エラーを出します。これは想定どおりです。

OSの確認のために、cat /etc/os-release すると Debian GNU/Linux 13 (trixie)、また、uname -m の結果は aarch64 でした。

手順4:Mosquittoを戻す

以降は、Macにあるバックアップのフォルダを、RPiにコピーしてから作業します。先の手順の逆です。Macから、

scp -r ~/Desktop/migration-backup-* hoge@192.168.xxx.xxx:~/ 

とタイプします。これで(複数あれば全部の)バックアップが、RPiに送られます。

次は、RPiでの作業です。以下を1行ずつ実行しました。最新版のバックアップフォルダの場所を、変数 B に入れておきます。aptでmosquittoをインストールして、バックアップフォルダから設定ファイルを戻し、mosquittoを起動します。

B=$(ls -d ~/migration-backup-* | tail -1); echo $B
sudo apt update
sudo apt upgrade
sudo apt install -y mosquitto mosquitto-clients
sudo systemctl stop mosquitto
sudo tar xzf $B/mosquitto.tar.gz -C /
sudo chown mosquitto:mosquitto /etc/mosquitto/password.txt
sudo chmod 600 /etc/mosquitto/password.txt
sudo systemctl start mosquitto

新しいMosquittoは、パスワードファイルを誰でも読める状態にしておくと警告を出します。chown と chmod はその対策です。動作は、mosquitto_sub と mosquitto_pub でメッセージをやり取りして確かめました。

手順5:Zigbee2MQTTを同じ版で入れ直す

使用していたZigbee2MQTTは最新版ではなかったのですが、その更新は後回しにして、現行通りの古い版をインストールします。順番は、最初にNode.jsを入れて、次にZigbee2MQTTを入れ、設定データを復元します。

Node.jsを入れる

trixieに標準で入るNode.jsは20系なので、移行前と同じ22系をNodeSourceから入れます。

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs git make g++ gcc libsystemd-dev

Zigbee2MQTT 1.40.2を入れる

バージョンを指定して、Zigbee2MQTTを入手します。以下の行を1行ずつ実行しました。

sudo mkdir /opt/zigbee2mqtt
sudo chown $USER:$USER /opt/zigbee2mqtt
git clone --depth 1 --branch 1.40.2 https://github.com/Koenkk/zigbee2mqtt.git /opt/zigbee2mqtt
cd /opt/zigbee2mqtt
npm ci
npm run build

データを戻して、元と同じか確かめる

Zigbee2MQTT 1.x系では、data/configuration.yaml がgitの管理下にあります。そのため git clone した直後は、初期状態の設定ファイルが置かれています。これをバックアップで上書きし、チェックサムで確かめます。

tar xzf $B/z2m-data.tar.gz -C /opt/zigbee2mqtt
cd /opt/zigbee2mqtt/data && md5sum -c $B/z2m-md5.txt

4つのファイルがすべて OK になれば、移行前とまったく同じ内容です。

ターミナルで動作確認

いきなりサービスにしないで、/opt/zigbee2mqtt && npm start で起動してログを見ます。適量のログが流れたら、Ctrl+Cで止めます。

[2026-10-16 16:13:50] info: z2m: Starting Zigbee2MQTT version 1.40.2 (commit #e06848d)
[2026-10-16 16:13:52] info: z2m: zigbee-herdsman started (resumed)
[2026-10-16 16:13:52] info: z2m: Coordinator firmware version: '{..."revision":20210120..."type":"zStack3x0"}'
[2026-10-16 16:13:52] info: z2m: Currently 34 devices are joined.
[2026-10-16 16:13:52] info: z2m: Connected to MQTT server
[2026-10-16 16:13:52] info: z2m: Started frontend on port 8080

一番大事なのは zigbee-herdsman started (resumed) の行です。ドングルに残っていたネットワークをそのまま使えた、という意味です。もし (reset) や Configuration is not consistent with adapter state/backup が出たら、すぐにCtrl+Cで止めてください。手順どおりに進めていれば出ないはずのエラーですが、対処法は記事末尾の「付録:Zigbee2MQTTのエラー対応」にまとめました。

サービスにする

移行前のサービス定義もバックアップから以下のようにして復元します。

sudo cp $B/zigbee2mqtt.service.txt /etc/systemd/system/zigbee2mqtt.service

移行前のサービス定義は、以前、このブログで紹介した内容でした。これまで問題なく動作していました。しかし、今回の移行で、Claudeがサービス定義を見直してくれて、以下の2か所の変更を提案してくれました。

  • ネットワークとMosquittoの準備ができてからZigbee2MQTTが起動するようにすること(Wants= と After=)と、
  • 失敗したときに10秒待ってからやり直すようにすること(RestartSec=)

の2点です。Zigbee2MQTTのフロントエンドは 192.168.xxx.xxx を指定して待ち受けているので、IPアドレスが付く前に起動すると失敗します。また、短い間に何度も失敗すると、systemdが再起動をあきらめてしまいます。

この提案をもとに、
/etc/systemd/system/zigbee2mqtt.service
を書き直しまし、Wants= と After= と RestartSec= の3行を追加しました。その結果、次の内容になりました。

[Unit]
Description=zigbee2mqtt
Wants=network-online.target
After=network-online.target mosquitto.service

[Service]
ExecStart=/usr/bin/npm start
WorkingDirectory=/opt/zigbee2mqtt
StandardOutput=inherit
StandardError=inherit
Restart=always
RestartSec=10s
User=hoge

[Install]
WantedBy=multi-user.target

User= は、仮にhogeとしてあります。ここには、Zigbee2MQTTを動かすユーザー名を入れます。

設定ファイルの準備ができたら、サービスを登録して起動し、動作確認します。

sudo systemctl daemon-reload
sudo systemctl enable --now zigbee2mqtt
systemctl status zigbee2mqtt --no-pager | head -5

最後のコマンドは、statusを見て動作確認するためです。active (running) になっていればokです。

そのほかの復元

設定していたcronは crontab $B/crontab-$USER.txt で戻しました。ホームディレクトリはいったん ~/old-home に展開して、authorized_keys や自作のスクリプトなど、必要に応じて戻します。以下では、.sshの情報を元に戻しています。

# cron(DDNSの更新)を戻す
which curl && crontab $B/crontab-$USER.txt && crontab -l | tail -2

# 古いホームディレクトリを ~/old-home に展開して、必要なものだけ戻す
mkdir -p ~/old-home && tar xzf $B/home-$USER.tar.gz -C ~/old-home
mkdir -p ~/.ssh && chmod 700 ~/.ssh
cat ~/old-home/.ssh/authorized_keys >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys

なお、ずっと$Bを使い続けてきましたが、この値は、SSHをつなぎ直したあとは消えてしまいます。その時は、
B=$(ls -d ~/migration-backup-* | tail -1)
の行をもう一度実行する必要があります。

手順6:再起動して動作確認

最後に sudo reboot で再起動し、すべてが自動で立ち上がるか確かめました。

$ systemctl is-active homebridge mosquitto zigbee2mqtt
active
active
active
$ journalctl -u zigbee2mqtt -b --no-pager | grep -E 'herdsman started|devices are joined|frontend'
... z2m: zigbee-herdsman started (resumed)
... z2m: Currently 34 devices are joined.
... z2m: Started frontend on port 8080

3つのサービスが動いていて、Zigbee2MQTTは再起動したあとも (resumed) で34台のデバイスを引き継いでいます。そのあと、次の点も確かめました。

  • ホームアプリで、Homebridgeのアクセサリが「応答なし」にならず操作できる
  • Zigbee2MQTT経由のZigbeeデバイスが操作できる
  • カメラの映像が見られる
  • Homebridge UIのログに、エラーが出続けていない

気づいた点

移行前も、カーネルだけは64bitでした。移行前に uname -m すると、 aarch64 と返ってきました。本当に64bitかどうかは、dpkg –print-architecture が arm64 かどうかで判断するそうです。

ffmpegは入れ直さなくてよかったです。移行前は /usr/local/bin/ffmpeg に32bit版を手で入れていました。homebridge-camera-ffmpegは、プラグインに付いてくるffmpegを使います。そのため、Homebridgeを復元するときに64bit版が自動で入りました。

まとめ

Homebridge、Mosquitto、Zigbee2MQTTの3つを、64bitのOSに移しました。HomeKitのペアリングも、Zigbeeデバイスのペアリングも、やり直しは一度もありませんでした。作業時間は、全部で半日ほどでした。うまくいった一番の理由は、Claudeに手伝ってもらったことです。システムの構築・更新・エラー対応には、AIが欠かせないですね。

Node.js 22系のサポートが終わる2027年4月までには、32bitのOSでHomebridgeやZigbee2MQTTを動かしている場合は、移行しておくとよいと思います。

付録:Zigbee2MQTTのエラー対応

手順5でZigbee2MQTTを初めて起動したときに、(resumed) 以外のメッセージが出た場合の対処法です。Claudeがまとめてくれました。私の環境ではどちらも出ませんでしたので、確認できていませんが、エラーが出た場合の参考にしてください。

どちらの場合も、命綱は手順1でMacに保存した z2m-data.tar.gz と、その中の coordinator_backup.json です。この2つは絶対に消さないでください。

Configuration is not consistent with adapter state/backup

意味:configuration.yaml のネットワーク設定が、ドングルの中身とも coordinator_backup.json とも合っていません。Zigbee2MQTTは安全のため、ドングルには何もせずに起動を止めます。ドングルの中身は無事です。

対処:

  1. md5sum -c で、data フォルダが移行前と同じかをもう一度確かめます。違っていたら、バックアップから展開し直します。
  2. 同じドングルが挿さっているかを、ls -l /dev/serial/by-id/ で確かめます。
  3. それでも直らなければ、古いSDカードに戻します。ドングルは無事なので、元どおり動きます。そのうえで、落ち着いて原因を調べます。

zigbee-herdsman started (reset)

意味:Zigbee2MQTTが、ドングルに新しいネットワークを作ってしまった状態です。ドングルの中身が書き換わるので、古いSDカードに戻すだけでは直りません。ただし、バックアップがあれば取り戻せます。

対処:

  1. すぐにZigbee2MQTTを止めます。
  2. data フォルダを、Macに保存したバックアップから展開し直します。Piの中にある coordinator_backup.json は使いません。Zigbee2MQTTが起動したあとで、新しいネットワークの内容で上書きされている可能性があるからです。
  3. もう一度起動します。設定とバックアップが一致していて、ドングルの中身だけが違う場合、Zigbee2MQTTはバックアップの内容をドングルに書き戻します。このときログには zigbee-herdsman started (restored) と出ます。
  4. 書き戻したあとは、デバイスがつながり直すまでに少し時間がかかることがあります。

この仕組みは、Zigbee2MQTTのページで推薦されているTexas Instruments社のCC2652を使用したドングル(TI CC2652系、Zigbee2MQTTでの種類は zstack)の場合のものです。このブログでも、おすすめドングルとして製品紹介しています。ほかの種類のドングルでは、動きが違うことがあります。

コメント

タイトルとURLをコピーしました