【ミーア】ESP32のOTAアップデート機能実装:Firmwareアップデートのアプリ通知
はじめに
前回、こちらの記事でESP32のOTAアップデートに関して、デバイス側のみ実装した。
今回は新しいFirmwareを開発者がアップロードした時に、ユーザーに対してアプリ通知行う部分を実装する。
Firmwareアップデートのアプリ通知
全体の流れ
AWS s3のfirmwareディレクトリに新しいFirmwareバイナリを開発者がバージョン指定してアップロードする。
各ユーザーのFirmwareのバージョン(=データベースのUserテーブルのfirmware_versionカラムの値)と開発者がアップロードした最新のFirmwareバージョンを比較し、異なる場合にFlutterアプリに「新しいFirmware(Firmwareバージョン)をインストール可能です」と通知する。
サーバー(Go)側の実装
ユーザーのファームウェアバージョンを管理(カラムと構造体)
Userテーブルに新しくFirmwareのバージョンを格納する。
-
カラム名:
firmware_version
-
型:
VARCHAR
-
長さ: バージョン番号の構造によるが、一般的に**
VARCHAR(10)
からVARCHAR(20)
**の範囲で十分な場合が多い。 - 初期値: 1.0.0
$ cd scripts/migrations
$ migrate create -ext sql -format 2006010215 add_firmware_version_to_users
upとdownのsqlファイルが作成されるので、下記のように記載。
// 2024040407_add_firmware_version_to_users.up.sql
ALTER TABLE users
ADD COLUMN firmware_version VARCHAR(20) DEFAULT '1.0.0';
// 2024040407_add_firmware_version_to_users.down.sql
ALTER TABLE users
DROP COLUMN firmware_version;
migration適用して、fimware_versionカラムをUserテーブルに追加した。
User
構造体にFirmwareVersion
フィールドを追加
**users
テーブルのfirmware_version
カラムに対応するフィールド。User
構造体を通じてfirmware_version
**カラムのデータを読み書きできるようにする。
// user_db.go
type User struct {
ID int `db:"id" json:"id"`
UID string `db:"uid" json:"uid"`
DeviceID types.NullString `db:"device_id" json:"device_id"`
// ... その他のフィールド ...
SleepTransitionTime types.NullInt64 `db:"sleep_transition_time" json:"sleep_transition_time"`
HealthDataIntegrationStatus bool `db:"healthdata_integration_status" json:"healthdata_integration_status"`
FirmwareVersion string `db:"firmware_version" json:"firmware_version"` // ファームウェアバージョン
}
notification.proto
**ファイルに、ファームウェア更新の利用可能通知を追加
**ユーザーに新しいファームウェアが利用可能であることを知らせるための通知メッセージを定義し、この新しいメッセージタイプを使うRPCメソッドを定義する。
// notification.proto
syntax = "proto3";
package protos;
option go_package = "github.com/EarEEG-dev/clocky_be/pb";
import "shadow.proto";
// 既存の定義...
message StreamRequest {
int32 userId = 1; // user id
}
message FirmwareUpdateAvailableResponse {
int32 userId = 1;
string message = 2;
string new_firmware_version = 3; // 利用可能な新しいファームウェアのバージョン
}
service NotificationService {
rpc Listen(StreamRequest) returns (stream StreamResponse);
// ファームウェア更新通知用の新しいメソッド
rpc ListenFirmwareUpdates(StreamRequest) returns (stream FirmwareUpdateAvailableResponse);
}
**.proto
ファイルのメッセージ定義でサーバーのレスポンス側にstream
**キーワードを使用することで、サーバーストリーミングRPCを実装できる。
これにより、クライアントが一度リクエストを送信した後、サーバー側で変更があるたびにクライアントにデータを"プッシュ"する形で連続的に情報を送信することが可能になる。サーバー側で新しいファームウェアアップデートが利用可能になった際に、即座にその情報をクライアントにプッシュで送るようにするため、サーバーストリーミングRPCとする。
サーバーストリーミングRPCの詳細に関してはこちら。
メッセージとrpcメソッドを.protoファイルに記述終えたら、**protoc
コマンドを使って、.proto
**ファイルからGoのソースコードを生成する。
.protoファイルを作成し、コンパイルしてGo言語で使用するまでに関する記事はこちら。
gRPCのListenメソッドにFirmware Version比較ロジックを追加
.protoファイルで作成したrpcメソッドをコンパイルして作成されたListenFirmwareUpdates関数を用いて、新しいFirmwareバージョンの通知部分を実装する。
新しいFirmwareのバージョンを固定で持ち、**Listen
**メソッド内で、新しいFirmwareのバージョンとユーザーの現在のバージョンを比較して通知を送信するロジックを追加。
今回は、const newFirmwareVersion = "v1.0.1"と関数内に新しいファームウェアバージョンを直書きしたが、将来的には新しいファームウェア情報を格納するテーブルを用意してデータベースから呼ぶようにする。
Discussion