atctl 開発メモ - Apple Silicon Mac から USB モデム Soracom Onyx へ AT コマンドを送ってみた

目次

Please check it.


この記事は 2026年 08 月時点 (以下、現在 / 現時点) の情報に基づいて記載しています。筆者は本記事を執筆した現時点において 株式会社ソラコム に所属していますが、本記事の内容は あくまでも筆者個人の見解に基づくものであり、所属する会社または組織とは一切関係ございません。


(参考)
「一般消費者が事業者の表示であることを判別することが困難である表示」の指定及び「『一般消費者が事業者の表示であることを判別することが困難である表示』の運用基準」の公表について

前提

atctl というツールを作ってみました。

この記事では、その開発メモと簡単な紹介を書いています。

実際に手元で AT コマンドを実行しながら気づいたことや、Apple Silicon Mac から USB モデムを扱う際の使い方を残した「技術メモ」に近い内容です。

自分用の備忘録的な位置づけではありますが、

  • Apple Silicon Mac から USB モデムを操作したい
  • macOS に /dev/cu.* のシリアルデバイスが表示されず困っている
  • AT コマンドを調べながら実行する負担を減らしたい
  • モデムの確認結果をログや診断証跡として残したい

といった方の参考になれば嬉しいです。

先日書いた SGP.32 対応 SORACOM Connectivity Hypervisor の記事でも、デバイス側の IMSI / ICCID や通信状態を確認するために開発途中の atctl を使っています。

uchimanajet7.hatenablog.com

atctl

実際に作成したものは以下になります。

github.com

atctl は、Apple Silicon Mac から USB セルラーモデムへ AT コマンドを送信・管理するための Rust 製 CLI / TUI です。

macOS が利用可能な /dev/cu.* シリアルデバイスを公開しない場合でも、libusb を使って USB インターフェースとエンドポイントへ直接アクセスします。

主な特徴は以下のとおりです。

  1. USB モデムへ直接アクセス

    • /dev/cu.* が利用できない場合でも、USB インターフェースと bulk IN / OUT エンドポイントを利用して AT コマンドを送信できます。
    • atctl devices と atctl inspect で、現在接続されているデバイスやUSBディスクリプターを確認できます。
  2. CLI と TUI の両方に対応

    • atctl send <COMMAND> で AT コマンドを直接実行できます。
    • atctl tui では、デバイス、コマンド、Sequence、応答、ログを一つの画面で確認できます。
  3. Preset と Sequence

    • Preset は、信号強度やSIM状態などを確認する一つの AT コマンドを名前から実行できます。
    • Sequence は、SMS送受信など複数の手順が必要な処理をまとめて実行できます。
  4. AT コマンド実行時の確認とログ

    • 状態変更や外部通信を伴う操作では、実行前に確認を表示します。
    • 機微な値は初期状態でマスクされます。
    • 通常の履歴とセッションログもマスク済みの状態で保存されます。
    • raw診断証跡は、出力先と確認語を明示した場合だけ作成されます。

利用方法や詳細な仕様については、GitHubリポジトリのREADMEとドキュメントを参照してください。

動作確認環境

現時点で実機確認している環境は以下です。

項目 確認環境
Mac Apple Silicon Mac
USBモデム SORACOM Onyx LTE USB Dongle
内蔵モデム Quectel EG25-G
USB ID 0x2c7c:0x0125
確認したファームウェア EG25GGBR07A08M2G

この環境では、USBデバイスの検出、ATコマンドの直接実行、Preset、Sequence、TUI、PTYブリッジ、SMS送受信、Quectel / SORACOMのping・TCP確認を実機で確認しています。

これは確認済み環境を示すもので、すべてのUSBモデムやOSで動作することを表明するものではありません。

なぜ作ってみたのか?

きっかけは、Apple Silicon Mac に SORACOM Onyx を接続した際に、USBデバイスとしては認識されていても、利用できる /dev/cu.* が表示されないケースがあったことです。

通常、AT コマンドを試す場合は、次のようにシリアルデバイスを探します。

ls /dev/cu.*

ここにモデム用のデバイスが表示されれば、screen や cu などを使って AT コマンドを送信できます。

しかし、macOS の USB ツリーではモデムが見えているのに、利用できるシリアルデバイスが作成されない場合があります。

USB側の状態は、次のようなコマンドで確認できます。

system_profiler SPUSBHostDataType

USBデバイスとして見えていても /dev/cu.* がないと、一般的なシリアルターミナルでは接続先を指定できません。

そこで、シリアルデバイスの公開を前提とせず、libusb を使ってUSBインターフェースへ直接アクセスするツールとして atctl を作りました。

また、AT コマンドは単純に文字列を送ればよいだけではありません。

例えば、

  • IMSI、IMEI、ICCIDなどの識別情報を読み取る
  • APNやネットワーク選択状態を変更する
  • モデムを再起動する
  • SMSを送信する
  • TCPソケットを開いてデータを送信する

といった操作があります。

確認用のコマンドと状態変更を伴うコマンドを同じ感覚で実行すると、意図せず通信状態を変更したり、機微な情報をログへ残したりする可能性があります。

そのため atctl では、USBアクセスだけではなく、

  • コマンドを探す
  • 内容を確認する
  • 必要な値を入力する
  • 影響のある操作を確認する
  • 応答を確認する
  • マスク済みログを残す
  • 必要な場合だけraw診断証跡を収集する

という一連の流れまでまとめています。

実際に使ってみる

今回は、以下の流れで試してみます。

  1. Homebrewでインストールする
  2. USBモデムを確認する
  3. ATコマンドを直接送信する
  4. TUIを起動する
  5. PresetとSequenceを確認する
  6. PTYブリッジを利用する

やっていること自体はシンプルです。

まずモデムが見えていることを確認し、基本的な AT コマンドを送信します。その後、TUIやPreset、Sequenceなどを確認してみます。

インストール

Homebrewを使ってインストールします。

brew install uchimanajet7/atctl/atctl

Homebrew Formulaからインストールした場合、実行時に必要な libusb も一緒にインストールされます。

インストールできたら、バージョンを確認します。

atctl --version

インストール、更新、削除、GitHub Releaseからの手動実行については、以下のドキュメントを参照してください。

github.com

USBモデムを確認する

最初に、現在接続されているAT操作対象を確認します。

atctl devices

atctl devices では、USBディスクリプターをもとに、AT操作対象として利用できる可能性があるデバイスが表示されます。

表示内容には、以下のような情報が含まれます。

  • Manufacturer
  • Product
  • VID / PID
  • USB bus
  • USB address
  • Device class

想定したモデムが表示されない場合は、libusb から見えるすべてのUSBデバイスを確認できます。

atctl devices --all-usb

ただし、USBデバイスとして見えることや、bulk IN / OUT エンドポイントが存在することだけでは、そのインターフェースがATコマンド用であるとは判断できません。

詳細を確認する場合は、次のコマンドを利用します。

atctl inspect

inspect では、Configuration、Interface、Alternate Setting、Endpointなどを確認できます。

ATコマンドを送信する

モデムが確認できたら、基本的な AT コマンドを送信します。

atctl send AT

モデムが正常に応答すれば、OK が返ります。

続いて、モデム情報を確認します。

atctl send ATI

一つのATコマンドを直接実行したい場合は、同じ形で指定できます。

atctl send AT+CSQ
atctl send AT+CEREG?
atctl send AT+CGACT?

複数のUSBモデムが接続されている場合は、atctl devices に表示された bus と address を指定します。

atctl send AT \
  --bus <BUS> \
  --address <ADDRESS>

出力は初期状態でマスクされます。

明示的にマスクを解除した画面出力が必要な場合は --no-mask を利用できますが、IMSI、IMEI、ICCID、電話番号、SMS本文、認証情報などが表示される可能性があるため、取り扱いには注意が必要です。

TUIを使ってみる

ATコマンドを対話的に操作する場合は、TUIを起動します。

atctl tui

TUIでは、以下の情報を一つの画面で確認できます。

  • Devices
  • Categories
  • Commands / Sequences
  • Status
  • Controls
  • Response
  • Logs

コマンドを名前やカテゴリーから探し、詳細を確認してから実行できます。

応答は Response に表示され、現在の実行状態は Status で確認できます。保存された履歴やセッションログもTUIから開けます。

なお、上のスクリーンショットでは確認用に Output masking: off となっていますが、通常はマスクが有効な状態で起動します。

ATコマンドに慣れていない場合や、目的のコマンド名を覚えていない場合は、まずTUIから試すのがわかりやすいと思います。

Presetを使ってみる

Presetは、一つのATコマンドを目的ごとの名前から実行するためのものです。

最初に一覧を確認します。

atctl preset list

例えば、信号強度を確認する signal-quality の内容は、次のコマンドで確認できます。

atctl preset show signal-quality

show はモデムへATコマンドを送信しません。

実際に実行する場合は、次のようにします。

atctl preset run signal-quality

製品に含まれるPresetには、以下のような確認があります。

  • モデム応答
  • メーカー、モデル、ファームウェア
  • SIM PIN状態
  • ネットワーク登録状態
  • オペレーター
  • 信号強度
  • PDPコンテキスト
  • SMS準備状態
  • エラー情報
  • モデム機能状態

状態変更を伴うPresetには、実行前の確認が表示されます。

Sequenceを使ってみる

Sequenceは、複数のATコマンド、プロンプト待ち、ペイロード送信、URC待ちなどをまとめた処理です。

一覧を確認します。

atctl sequence list

例えば、SMSを送信する sms-send-check の内容を確認します。

atctl sequence show sms-send-check

実行する場合は次のようにします。

atctl sequence run sms-send-check

対話実行では、送信先とSMS本文を入力し、実行内容と影響を確認してから送信します。

製品に含まれる標準Sequenceには、以下があります。

  • SMS送信
  • SMS受信・一覧
  • SMS読み取り
  • SMS返信

標準SMS操作を利用するために、利用者がSequence定義ファイルを作成する必要はありません。

GitHubリポジトリには、追加で読み込めるサンプルとして、Quectelのping・TCP確認や、SORACOM Ping Response Service・Unified Endpointを確認するSequenceも用意しています。

これらはQuectelやSORACOMに固有のサンプルとして明示的に読み込むもので、すべてのモデムで利用できる標準機能ではありません。

PresetとSequenceの詳細については、以下を参照してください。

github.com

自分自身でPresetやSequenceを作る場合には、GitHub リポジトリに参考として用意してある PresetとSequenceがありますので、それを参考にしてください。例えばAIに読み込ませるなどすれば利用できるかと思います

github.com

PTYブリッジを使ってみる

screen や cu などのターミナルツールを利用したい場合は、PTYブリッジを利用できます。

最初に、現在のUSB接続先を確認します。

atctl devices

表示された BUS と ADDRESS を指定してブリッジを起動します。

atctl bridge \
  --symlink /tmp/atctl \
  --bus <BUS> \
  --address <ADDRESS>

別のターミナルから screen で接続します。

screen /tmp/atctl 115200

ここで指定している 115200 は、シリアルターミナルツールとの互換性のための値です。USBモデムとの物理的な通信速度を指定しているわけではありません。

PTYブリッジでも、ATコマンドの確認、マスク、raw診断証跡に関する保護は適用されます。

ATコマンドを扱うための確認とログ

ATコマンドには、情報を読むだけのものと、モデムの状態を変更するものがあります。

例えば、信号強度を確認する AT+CSQ と、モデムを再起動する可能性がある AT+CFUN=1,1 では影響が異なります。

atctl では、実行前に次の内容を確認できるようにしています。

  • どのような影響があるか
  • 機微な入力や出力を扱うか
  • 操作を元に戻せるか
  • どのような結果が起こり得るか
  • 実行前の確認が必要か

既知の確認用コマンドはそのまま実行できますが、状態変更や外部通信を伴う操作では確認が表示されます。

通常の履歴とセッションログは、以下に保存されます。

~/.local/state/atctl/history.jsonl
~/.local/state/atctl/logs/<timestamp>.session.log

これらのログは初期状態でマスクされています。

一方、raw診断証跡には、マスクされていないUSB通信内容や機微な情報が含まれる可能性があります。そのため、自動的には作成されず、利用者が出力先を選択して raw-log の確認語を指定した場合だけ作成されます。

ATコマンドを初めて試す場合や、状態変更を伴う操作を行う場合は、安全ガイドも確認してください。

github.com

気づいたこと

/dev/cu.* がなくても、USB側から確認できる

macOSでシリアルデバイスが表示されないと、その時点でATコマンドの確認を諦めてしまいがちです。

ただし、USBデバイスとして認識され、利用可能なインターフェースとエンドポイントが確認できれば、libusb を経由して操作できる場合があります。

atctl devices と atctl inspect でUSB側の状態を確認できるようになったことで、単純に「見えない」で終わらず、次に何を確認するべきかがわかりやすくなりました。

TUIからコマンドを探せるのが便利

ATコマンドは種類が多く、メーカー固有コマンドもあります。

毎回マニュアルからコマンドを探して入力するよりも、目的やカテゴリーからPresetやSequenceを選び、詳細を確認してから実行できる方が楽です。

特に、

  • SIMが利用できる状態か
  • ネットワークに登録されているか
  • 電波状態はどうか
  • PDPコンテキストが有効か
  • SMSの送受信ができるか

といった確認を順番に行う場合は、TUIが使いやすいと感じています。

具体的なユースケースだと、例えば SORACOM のユーザーガイドでは 以下のように データを送受信できない場合の詳細な調査方法 が記載されています

users.soracom.io

実際に実行して、実行結果を記録するとなった場合手軽に使えることは 大きなアドバンテージになると感じます。

実行方法が変わっても確認方法は揃っている

send、preset run、sequence run、TUI、PTYブリッジは、それぞれ操作方法が異なります。

ただし、実行内容の確認、状態変更時の確認、出力マスク、ログ、raw診断証跡の考え方は共通です。

コマンドラインで実行する場合とTUIで実行する場合で、機微な情報の扱いや確認方法が大きく変わらないようにしています。

最後の診断証跡まで残せる

通常のトラブルシューティングでは、マスク済みのResponseやセッションログで十分なケースが多いと思います。

それでも原因がわからない場合には、利用者が出力先を選択したうえでraw診断証跡を収集できます。

普段からrawデータを保存するのではなく、通常の確認と最終的な診断証跡を分けられる点は、ATコマンドを扱うツールとして重要だと感じています。

まとめ

今回は、Apple Silicon Mac から USB セルラーモデムへATコマンドを送信・管理するための atctl を紹介しました。

atctl では、以下のことができます。

  • libusb を利用したUSBモデムの検出と直接アクセス
  • USBインターフェースとエンドポイントの確認
  • send によるATコマンドの直接実行
  • Presetによる一つの確認処理の実行
  • SequenceによるSMSなどの複数手順の実行
  • TUIによる対話操作
  • PTYブリッジによる screen や cu からの操作
  • 実行内容の確認と、影響のある操作に対する確認
  • 機微な情報のマスク
  • 履歴、セッションログ、Response export
  • 明示的に選択した場合だけ作成するraw診断証跡

現時点で実機確認しているのは、Apple Silicon MacとSORACOM Onyx LTE USB Dongleに内蔵されたQuectel EG25-Gの組み合わせです。

すべてのUSBモデムやOSでの動作を表明するものではありませんが、同じように、

「USBデバイスとしては見えているのに /dev/cu.* がない」

「ATコマンドを調べながら一つずつ確認するのが大変」

といった場面では、試してもらえればと思います。

github.com

日本語のREADMEも用意しています。

github.com

機会があれば、ぜひ試してみてください。

以上です。

Following is in English

medium.com

ローカル Markdown を Raycast からすぐコピーできる「MdClip」を作った

目次

Please check it.


この記事は 2026年 08 月時点 (以下、現在 / 現時点) の情報に基づいて記載しています。筆者は本記事を執筆した現時点において 株式会社ソラコム に所属していますが、本記事の内容は あくまでも筆者個人の見解に基づくものであり、所属する会社または組織とは一切関係ございません。


(参考)
「一般消費者が事業者の表示であることを判別することが困難である表示」の指定及び「『一般消費者が事業者の表示であることを判別することが困難である表示』の運用基準」の公表について

前提

MdClip という Raycast 拡張機能を作ってみました。

この記事では、MdClip を作った理由、実際の使い方、ローカルの Markdown ファイルをそのまま利用する設計にした理由、Raycast Store ではなく GitHub Releases で配布している経緯などを紹介します。

しっかりした比較検証記事というよりも、実際に作って使ってみた中で気づいたことを残した「開発メモ」に近い内容です。

Raycast を使っている方や、再利用する文章を Markdown ファイルで管理している方、ローカルファイルを中心にしたシンプルな仕組みに興味がある方の参考になれば嬉しいです。

MdClip

MdClip は、ローカルに保存している Markdown ファイルを Raycast から検索、プレビュー、コピーするための拡張機能です。

実際に作ったものは以下の GitHub リポジトリで公開しています。

github.com

MdClip の主な特徴は以下のとおりです。

  1. ローカルの Markdown ファイルを利用する

    • 専用のデータベースへ文章を移行する必要はありません。
    • 普段使っている .md ファイルとフォルダをそのまま利用します。
  2. Raycast から検索、プレビュー、コピーできる

    • ファイル名または Markdown Source からの相対パスで検索できます。
    • ファイルを選択すると、コピーする前に本文の冒頭をプレビューできます。
  3. 最大 3 つの Markdown Source を設定できる

    • 用途ごとに Markdown ファイルのフォルダを分けられます。
    • すべての Source をまとめて検索することもできます。
  4. コピー時に Dynamic Placeholders を展開できる

    • 日付、時刻、タイムゾーン、UUID、クリップボードの内容などを、コピーするタイミングで置換できます。
  5. Markdown ファイル自体は変更しない

    • MdClip はファイルの作成、編集、移動、名前変更、削除を行いません。

なぜ作ってみたのか?

繰り返し使う文章や手順を、Markdown ファイルとして管理することがあります。

たとえば、

  • プロンプト
  • チェックリスト
  • ブログ記事のアウトライン
  • レビュー時に使う文章
  • 作業手順
  • 定型的な返信
  • 小さなメモやテンプレート

といったものです。

Markdown ファイルで管理しておけば、普段使っているエディタで編集できますし、Git で履歴を管理したり、好きな方法で同期やバックアップを行ったりできます。

一方で、実際に文章を再利用するときは、

  1. エディタを開く
  2. 対象のフォルダへ移動する
  3. Markdown ファイルを探す
  4. ファイルを開く
  5. 本文を選択する
  6. クリップボードへコピーする

という操作が必要になります。

やっていること自体は単純ですが、最終的にやりたいことが「本文をコピーするだけ」であれば、少し手順が多いと感じます。

そこで、Markdown ファイルの管理方法は変えずに、Raycast を入口として検索、プレビュー、コピーだけを素早く行えるようにしたのが MdClip です。

スニペット管理ツールにしなかった理由

再利用する文章を扱うのであれば、スニペット管理ツールやノートアプリを使う方法もあります。

ただ、その場合は文章を専用のデータベースやアプリ内へ移行する必要があったり、そのアプリ独自の管理方法に合わせる必要があったりします。

今回やりたかったのは、新しい管理場所を増やすことではありませんでした。

Markdown ファイルはこれまでどおり自分のエディタで編集し、フォルダ構成や Git などもそのまま利用します。

MdClip が担当するのは、

  • 探す
  • プレビューする
  • コピーする

という部分だけです。

つまり、Markdown ファイルをそのままの形で維持しながら、クリップボードまでの経路だけを短くする、という考え方です。

実際に使ってみる

MdClip は、現時点では Raycast Store ではなく GitHub Releases から導入するローカル Raycast 拡張機能です。

利用には以下が必要です。

  • macOS
  • Raycast
  • ターミナル
  • 取得したリリースが対応する Node.js と npm

Git は必須ではありません。

MdClip を取得する

最新の GitHub Release から Source code (zip) をダウンロードします。

github.com

ダウンロードした ZIP ファイルを Finder で展開し、フォルダ名を mdclip に変更して、自分で管理しやすい場所へ配置します。

依存関係をインストールする

展開した mdclip フォルダでターミナルを開き、最初に Node.js と npm の条件を確認します。

node -p "require('./package.json').engines"
node -v
npm -v

現在利用している Node.js と npm が、表示された engines の範囲を満たしていることを確認します。

問題がなければ、依存関係をインストールします。

npm ci

Raycast へ読み込む

続けて以下を実行します。

npm run dev

ready - built extension successfully と表示されたら、Raycast から MdClip のコマンドを開ける状態になります。

最初に読み込んだ後は、ターミナルで Control + C を押して npm run dev を停止しても、MdClip は Raycast に残ります。

変更を反映したい場合や、開発モードのログを確認したい場合は、同じフォルダで再度 npm run dev を実行します。

正確な導入、更新、削除の手順は、日本語の Getting Started にまとめています。

github.com

Markdown Source を設定する

Raycast の Settings または Preferences から Extensions を開き、MdClip を選択します。

最初は Markdown Source 1 だけで利用できます。

Markdown Source Folder には、実際に .md ファイルを置いているフォルダを指定します。

MdClip は最大 3 つの Markdown Source を設定できますが、すべてを設定する必要はありません。

Markdown ファイルを探してコピーする

設定が終わったら、Raycast から Markdown Source 1 を開きます。

Markdown Source に設定したフォルダ内の .md ファイルが再帰的に読み込まれ、一覧に表示されます。

ファイルを選択すると、右側のプレビューペインで Markdown 本文の冒頭を確認できます。

既定のアクションは Copy Raw Content です。

そのため、対象のファイルを選択して Return を押すだけで、Markdown ファイルの本文全体がクリップボードへコピーされます。

また、Action Panel からは以下の操作もできます。

  • Copy Expanded Content
  • Show / Hide Preview
  • Open in Editor
  • Open
  • Open with...
  • Show in Finder

コピーするだけでなく、必要に応じてファイルを普段使っているエディタで開いたり、Finder で場所を確認したりできます。

Dynamic Placeholders を使う

Copy Expanded Content を使うと、Markdown ファイル内の対応するプレースホルダーを、コピーするタイミングで置換できます。

たとえば、以下のような Markdown ファイルを用意します。

作業日: {date}
現在時刻: {time}
タイムゾーン: {timezone}
識別子: {uuid}

クリップボードの内容:
{clipboard}

対応しているプレースホルダーは以下です。

{date}
{time}
{datetime}
{day}
{timezone}
{now}
{uuid}
{clipboard}

Copy Expanded Content を実行すると、現在の日付や時刻などへ置換された本文がクリップボードへコピーされます。

元の Markdown ファイルは変更されません。

Copy Raw Content と Copy Expanded Content を分けているのは、MdClip が勝手にプレースホルダーを置換しないようにするためです。

そのままコピーしたい場合は Raw、動的な値へ置換したい場合は Expanded と、利用者が明示的に選択できます。

すべての Markdown Source から探す

Markdown ファイルの保存場所が分かっている場合は、個別の Markdown Source コマンドを使えます。

一方で、どの Source に保存したか分からない場合は All Markdown Sources を使います。

All Markdown Sources では、有効化されている Markdown Source ごとにセクションを分けて Markdown ファイルを表示します。

ファイル名と相対パスに加えて、Markdown Source の表示名からも検索できます。

なお、MdClip は Markdown ファイルの本文を全文検索するツールではありません。

検索対象はファイル名、相対パス、All Markdown Sources の場合は Source の表示名です。

本文検索ではなく、再利用するファイルを素早く見つけることに機能を絞っています。

ローカルファイルとデータの扱い

MdClip は、利用者が有効化し、フォルダを設定した Markdown Source 内のファイルだけを読み取ります。

Markdown 本文がクリップボードへ送られるのは、利用者がコピーアクションを実行した場合だけです。

現在のクリップボードの内容を読み取るのも、{clipboard} を含む Markdown ファイルに対して Copy Expanded Content を実行した場合だけです。

通常利用中に MdClip 自体がネットワークリクエストを行うことはありません。

また、MdClip は Markdown ファイルに対して以下の操作を行いません。

  • 新規作成
  • 編集
  • 移動
  • 名前変更
  • 削除

普段使っている Markdown ファイルを正本として、その上に検索とコピーの入口だけを追加する形です。

なぜ Raycast Store ではなく GitHub Releases なのか?

MdClip の以前のバージョンは、最初に Prompt Launcher という名前で Raycast Store へ提出していました。

github.com

ただし、レビューでは、既存のプロンプト管理系の拡張機能と用途が近く、違いが分かりにくいという指摘がありました。

その後、名前と位置づけを Local Copy Blocks に変更し、README、メタデータ、スクリーンショットなども見直して再度提出しました。

github.com

それでも、既存のスニペット管理や再利用テキストのワークフローと重なるという点は解消できませんでした。

このあたりは、機能が動くかどうかとは別に、Raycast Store の中で既存の拡張機能とどう差別化するか、というプロダクトの位置づけに関する部分です。

このレビューを経て、改めて「何を作りたいのか」を整理しました。

結果として、汎用的なスニペット管理ツールを目指すのではなく、

  • 普通の Markdown ファイルを利用する
  • ローカルファイルを正本にする
  • 検索、プレビュー、コピーに集中する
  • ファイル自体は変更しない
  • コピー時だけ必要な値を展開する

という現在の MdClip の方向へ整理しています。

現時点では、Raycast Store への公開をアクティブな配布経路にはしていません。

代わりに、

  • GitHub でソースコードを公開する
  • GitHub Releases をリリース単位にする
  • Raycast のローカル拡張機能として利用する

という形で配布しています。

将来、改めて Raycast Store への提出を検討する可能性はありますが、現時点での正式な利用経路は GitHub Releases です。

実際に作って使ってみて気づいたこと

Markdown ファイルをそのまま使えるのが楽

一番大きいのは、再利用する文章の管理場所を増やさなくてよいことです。

MdClip 用のデータベースへ移行する必要はなく、これまで使っていた Markdown ファイルをそのまま利用できます。

エディタ、Git、同期、バックアップなどの仕組みも変更する必要がありません。

この「何も移行しなくてよい」という点は、地味ですが使い続けるうえで重要だと感じています。

Raw Copy が既定なのは安心できる

MdClip の既定アクションは Copy Raw Content です。

Return を押しただけではプレースホルダーを置換せず、ファイルに書かれている本文をそのままコピーします。

動的な置換が必要な場合だけ Copy Expanded Content を明示的に選びます。

便利さよりも予測しやすさを優先した部分ですが、個人的にはこの方が安心して使えています。

複数の Source を分けられるのが便利

Markdown Source を最大 3 つに分けられるため、たとえば、

  • 個人用
  • 開発用
  • ブログ用

のように用途を分けられます。

よく使う Source のコマンドには、Raycast 側で個別にホットキーを設定できます。

どの Source にあるか分からない場合は All Markdown Sources を使えばよいため、個別アクセスと横断検索の両方を使い分けられます。

導入のハードルは少しある

Raycast Store からワンクリックでインストールする形ではないため、初回導入ではターミナル、Node.js、npm が必要です。

更新についても、新しい GitHub Release を取得して手動でソースフォルダを入れ替えます。

そのため、一般的な Store 拡張機能より導入の手間はあります。

この点は現在の配布方法における明確な制約です。

利用時の注意点

MdClip には、いくつか意図的な制約があります。

  • Markdown ファイルの本文は検索しません
  • 本文は UTF-8 として有効である必要があります
  • .git、node_modules、隠しディレクトリは検索対象外です
  • シンボリックリンクは辿りません
  • Markdown ファイルを編集する機能はありません
  • クラウド同期機能はありません
  • 更新は GitHub Release から手動で行います

細かい仕様や設定については、日本語 README を参照してください。

github.com

まとめ

今回は、ローカルの Markdown ファイルを Raycast から検索、プレビュー、コピーする MdClip を作ってみました。

主なポイントは以下です。

  • 普段使っている Markdown ファイルをそのまま利用できます
  • 最大 3 つの Markdown Source を設定できます
  • 個別の Source またはすべての Source からファイルを探せます
  • 既定のアクションで Markdown 本文をそのままコピーできます
  • Dynamic Placeholders をコピー時に展開できます
  • 元の Markdown ファイルは変更しません
  • 通常利用中に MdClip 自体はネットワークリクエストを行いません
  • Raycast Store ではなく GitHub Releases から導入します
  • 導入には Raycast、Node.js、npm、ターミナルが必要です

新しいスニペット管理ツールを増やすのではなく、すでにある Markdown ファイルをそのまま使いながら、コピーまでの操作だけを短くするツールになっています。

少し地味なツールではありますが、Markdown ファイルで再利用する文章を管理している場合には、便利に使えるのではないかと思います。

興味があれば試してみてください。

github.com

github.com

github.com

以上です。

Following is in English

medium.com

SGP.32 対応の SORACOM Connectivity Hypervisor で SIM プロファイルを切り替えてデバイス側の確認をしてみた

目次

Please check it.


この記事は 2026年 07 月時点 (以下、現在 / 現時点) の情報に基づいて記載しています。筆者は本記事を執筆した現時点において 株式会社ソラコム に所属していますが、本記事の内容は あくまでも筆者個人の見解に基づくものであり、所属する会社または組織とは一切関係ございません。


(参考)
「一般消費者が事業者の表示であることを判別することが困難である表示」の指定及び「『一般消費者が事業者の表示であることを判別することが困難である表示』の運用基準」の公表について

前提

SORACOM Connectivity Hypervisor がリリースされました。

soracom.com

SORACOM Connectivity Hypervisor は、SGP.32 に対応した SORACOM IoT SIM において、SIM プロファイルの追加や切り替えを管理するための機能です。

ここで少しだけ前提を整理しておきます。

SORACOM には、もともと サブスクリプションコンテナ (追加サブスクリプション) という機能があります。これは、1 つの SORACOM IoT SIM に複数の追加サブスクリプションを保存できる機能です。たとえば plan01s に planX1 や planX2 などを追加し、物理 SIM を交換せずに、特定の国や地域でより適したサブスクリプションを利用できます。

つまり、「1 枚の SIM に複数の SORACOM のサブスクリプションを持たせる」こと自体は、これまでもできていました。

ただし、サブスクリプションコンテナは SORACOM が提供する追加サブスクリプションを SORACOM IoT SIM に配信して利用する仕組みです。そのため、SGP.32 対応 SIM のように、SORACOM 以外の通信事業者が提供するプロファイルも含めて追加・切り替えする、というものではありませんでした。

また、サブスクリプションコンテナでは、利用されるサブスクリプションはデバイスが存在する国や地域に応じて自動的に選択されます。公式ドキュメントにも「ユーザーコンソールで通信に利用するサブスクリプションを選択する機能はありません」と記載されています。つまり、ユーザーが任意のタイミングで「今からこのプロファイルを使う」と明示的に切り替えるというより、SIM 内のルールとデバイス・モデム側の挙動に任せる形でした。

一方で SORACOM Connectivity Hypervisor では、SGP.32 対応 SIM を前提に、SORACOM が提供するプロファイルだけでなく、他の通信事業者のプロファイルも含めて、リモートからプロファイルを追加・切り替えできることがポイントです。

なので、今回試して確認したかったのは「クラウド側でプロファイルを切り替えたとき、ローカルデバイス側ではどう見えるのか」です。

ということで今回は、

SORACOM Connectivity Hypervisor を使って SIM プロファイルを切り替えたときに、ローカルデバイス側ではどのように見えるのか

を確認してみました。

検証内容の注意事項

今回利用した SIM は、SORACOM Connectivity Hypervisor の確認用に用意した SGP.32 対応 SORACOM IoT SIM です。 このSIMを含めて、この記事で掲載している内容や画面については、開発中または検証用の内容が含まれます。

そのため、公開版とは異なる仕様や状態が含まれている可能性があります。 実際に利用する場合には、この記事の内容だけで判断せず、必ず利用者自身で確認と検証を行ってください

この記事は、あくまで個人である時点で試したメモとして楽しんでくださいw

そもそも SGP.32 とは?

SGP.32 は、GSMA が定めている eSIM / eUICC の仕様の 1 つで、ざっくり言うと IoT デバイス向けに SIM プロファイルをリモートで追加・切り替え・管理するための技術仕様 です。

GSMA の SGP.32 のページでは、SGP.32 は IoT 向け eSIM アーキテクチャで、ネットワーク制約やユーザーインターフェース制約のある IoT デバイスにおける eUICC のリモートプロビジョニングと管理、eUICC アーキテクチャ、インターフェース、セキュリティ機能を定義するもの、と説明されています。

www.gsma.com

SGP.32 のポイントは「スマートフォンの eSIM みたいにプロファイルを追加できる」だけではなく、画面や人の操作を前提にしにくい IoT デバイスでも、標準化された形でプロファイルを扱えるようにするところだと思っています。

これまでの SGP.xx との違い

eSIM / eUICC まわりの GSMA 仕様は、ざっくり以下のように整理できます。

仕様 主な対象 ざっくりした説明 IoT 観点での見え方
SGP.01 / SGP.02 M2M 組み込み機器や車載機器などを想定した、初期の eUICC / リモート SIM プロビジョニング仕様 事業者側・サーバー側主導の色が強く、導入・運用のハードルが高め
SGP.21 / SGP.22 Consumer スマートフォンやタブレットなど、ユーザーが画面操作できる端末向けの eSIM 仕様 LPA など、端末側の UI やユーザー操作を前提にしやすい
SGP.31 / SGP.32 IoT IoT デバイス向けの eSIM 仕様。SGP.31 がアーキテクチャ / 要件、SGP.32 が技術仕様 画面なし、低消費電力、断続的な通信など、IoT らしい制約を考慮しやすい

GSMA の仕様一覧を見ると、Consumer 向けには SGP.21 / SGP.22、IoT 向けには SGP.31 / SGP.32 が整理されています。また、SGP.31 は eSIM IoT Architecture and Requirements Specification、SGP.32 は eSIM IoT Technical Specification として掲載されています。

www.gsma.com

また、M2M 向けの SGP.02 については、GSMA の M2M 仕様ページに eSIM Technical Specification として掲載されており、Remote Provisioning Architecture for Embedded UICC の技術仕様として説明されています。

www.gsma.com

www.gsma.com

SORACOM の従来の eSIM プロファイルは GSMA SGP.22 に準拠したダウンロード式サブスクリプションとして提供されており、LPA が実装されているデバイスにインストールするものとして説明されています。

soracom.jp

つまり、同じ eSIM / eUICC と言っても、対象デバイスや運用モデルによって前提が違います。

  • M2M 向けの SGP.01 / SGP.02 は、車載機器や産業機器のような用途で、事業者側が管理する前提が強い
  • Consumer 向けの SGP.21 / SGP.22 は、スマートフォンのようにユーザーが画面を見て操作できる前提が強い
  • IoT 向けの SGP.31 / SGP.32 は、画面がない、電源や通信に制約がある、現地に人がいない、という IoT デバイス側の事情に寄せた仕様

という理解をしておくと、SORACOM Connectivity Hypervisor の位置づけがわかりやすくなると思います。

SORACOM Connectivity Hypervisor との関係

SORACOM Connectivity Hypervisor は、この SGP.32 に対応した SORACOM IoT SIM を前提に、SIM プロファイルの追加・切り替え・管理を行うための機能です。

リリースでは、SGP.32 に準拠しながら、SORACOM の eUICC 上のプロファイルを追加・切り替え・管理できるサービスとして紹介されています。

soracom.com

また、2025 年の発表時点では、SORACOM が提供するプロファイルに限らず、他の通信事業者が提供するプロファイルを含めて、リモートからプロファイルの追加・切り替えを可能にすることが紹介されていました。

soracom.com

この部分が、これまでのサブスクリプションコンテナとの大きな違いです。

「クラウド側で切り替えたら、デバイス側では IMSI や接続先の見え方が変わるのか」 「切り替え後もデータ通信はできるのか」 「どのくらいリアルタイムに切り替わるのか」

といった気になるところを、手元のデバイスでサクッと確認してみました。

実際にやってみた

今回確認した流れは以下です。

  1. SGP.32 対応の SIM で デフォルト有効化されている plan01s での状態をデバイスで確認する
  2. plan01s で SORACOM への ping 疎通を確認する
  3. SORACOM ユーザーコンソールの SORACOM Connectivity Hypervisor 画面で planX2 に切り替えてみる
  4. planX2 での状態をデバイスで確認する
  5. planX2 で SORACOM への ping 疎通を確認する

やっていること自体はシンプルです。

SIM プロファイルを切り替える前後で、デバイス側の AT コマンド結果と通信状態を確認します。 デバイス側ではAT コマンドのみで対応を行っています。

Soracom Onyx

今回利用したデバイスは、Soracom Onyx – LTE™ USB ドングル (SC-QGLC4-C1) です。

soracom.jp

Soracom Onyx は、LTE Cat.4 / 3G / GSM に対応した USB 型のデータ通信端末です。USB に挿すだけで利用できるので、SIM や回線まわりの動作確認をする時に便利です。

今回の確認では、Onyx の内蔵モデムに対して AT コマンドを送り、ネットワーク登録状態や IMSI、オペレーター情報などを確認しています。

1. デフォルトの plan01s での状態をデバイスで確認する

まずは、SIM を Soracom Onyx に挿して、デフォルトの状態を確認します。

今回の SIM では plan01s のプロファイルが有効な状態になっていました。

SORACOMユーザーコンソールを使ってSIMの状態と SORACOM Connectivity Hypervisor の操作や状態確認を行います デバイス側は、AT コマンドを使って状態を確認します

まずは、SORACOM ユーザーコンソールでオンライン表示になっている plan01s の ICCID / IMSI を確認します

plan01s は

  • ICCID: 末尾 163
  • IMSI: 末尾 630

続いて、ローカルデバイス側でAT コマンドを実行します

ICCID

AT+QCCID

+QCCID: ****************163F

OK

Completed: 2026-07-06T07:30:00Z

IMSI

AT+CIMI

************630

OK

Completed: 2026-07-06T07:31:09Z

これで、デバイス側から見ても SORACOMユーザーコンソールから見ても plan01s のプロファイルで接続している状態であることが確認できました。

ここで押さえておきたいポイントは、 このあと planX2 に切り替えた時に、 デバイス側で見える IMSI や ICCID がどのようなタイミングでどう切り替わるかです。

2. plan01s の状態で SORACOM への ping 疎通を確認する

次に、plan01s の通信疎通していることを確認します。

今回はAT コマンドだけで確認しているので シンプルに SORACOM に対して ping を実行しました。

Step 1/2 Ensure PDP context active

Command:
> AT+QIACT?

Modem response:
AT+QIACT?
OK

Command:
> AT+QIACT=1

Modem response:
AT+QIACT=1
OK

Analysis:
- AT+QIACT? checks Quectel TCP/IP PDP context state; AT+QIACT=<contextID> is only sent when the selected context is not active.
- Quectel PDP context 1 was not active in AT+QIACT? output; AT+QIACT=1 activated it.

Step 2/2 Ping SORACOM

Command:
> AT+QPING=1,"pong.soracom.io",4,4

Modem response:
AT+QPING=1,"pong.soracom.io",4,4
OK

+QPING: 0,"100.127.100.127",32,24,255

Analysis:
- AT+QPING checks IP reachability through the selected Quectel PDP context; received replies are not TCP or application receipt proof.
- Ping reply: host=100.127.100.127 bytes=32 time_ms=24 ttl=255

Notes:
- Received ping replies from pong.soracom.io are SORACOM network reachability evidence.
- Ping success is not TCP socket, Unified Endpoint, Beam, or destination application receipt proof.
- Use soracom-unified-endpoint-tcp-send-check when TCP payload delivery to Unified Endpoint must be checked.

Result: OK duration=6842ms

Completed: 2026-07-06T07:50:32Z

この結果で ping が正しく通っていることが確認できたので、 plan01s の状態で通信疎通ができていることが確認できました。

ここまでで、切り替え前の状態は確認できました。

3. SORACOM Connectivity Hypervisor を使って planX2 に切り替える

次に、SORACOM Connectivity Hypervisor を使って、クラウド側から利用するプロファイルを planX2 に切り替えます。

ユーザーコンソール上で、対象 SIM に対して planX2 のプロファイルを選択し、切り替え操作を実行します。

planX2 は

  • ICCID: 末尾 146
  • IMSI: 末尾 383

なので、プロファイル管理画面のプロファイル一覧にある有効ボタンを押して有効化を待ちます

切り替えの操作自体は、SORACOMユーザーコンソールで完結します。

ただし、ここで注意したいのは、クラウド側で切り替え操作を行ったからといって、デバイス側で即時に切り替わるとは限らないという点です。

SIM 側が切り替え情報を確認するタイミングに依存するため、反映までに時間がかかることがあります。

これは、SIM側から切り替えの内容をサーバ側に対して 一定時間でポーリングして取得しているからだと考えられます SORACOM Connectivity Hypervisor の画面にも、ポーリングでのアクセス履歴が表示されています

今回の確認では、しばらく待ってもデバイス側の状態が変わらないように見える場合がありました。 切り替えのイベントを見ると、リクエストした後にポーリングが行われていないということがわかります。

今回は検証目的なので、ポーリングを強制的に発生させるために モデムをリブートする、またはデバイス自体をリブートすると言った対応を実施して、 切り替え後の状態が確認できるようにしました。

AT+CFUN=1,1

OK

Completed: 2026-07-06T08:17:03Z

実際にモデムの再起動の後には、起動後に1回目のポーリング 2026-07-06 17:18:26 (UTC+09:00) があり そのタイミングで切り替えの依頼状態を把握して切り替え動作が発生し その後、プロファイル切り替え後にモデムが再起動を再び行い 2回目のポーリング 2026-07-06 17:20:40 (UTC+09:00) が記録されているという流れが想像できますね。

とはいえ、このあたりは、まだ私個人が手元ベースで確認した状況から想像しただけなので これから公式からドキュメントや紹介があると思うので楽しみに待ちましょう

4. planX2 での状態をデバイスで確認する

クラウド側で planX2 に切り替えた後、デバイス側でも状態を確認します。

planX2 は

  • ICCID: 末尾 146
  • IMSI: 末尾 383

ICCID

AT+QCCID

+QCCID: ****************146F

OK

Completed: 2026-07-06T08:34:07Z

IMSI

AT+CIMI

************383

OK

Completed: 2026-07-06T08:32:27Z

プロファイルの切り替え後は、デバイス側から見える IMSI や ICCIDが、切り替え前とは異なる値になっていることを確認できました。

つまり、SORACOM の SIM としては同じ物理 SIM を使っていますが、利用しているプロファイルが切り替わることで、デバイス側から見える IMSI や ICCID も変わります。

ここは、サブスクコンテナとは見え方が異なる点として注意が必要です。

サブスクコンテナでは、1 つの SIM に対してサブスクリプションを追加する形で扱うため、運用上は「同じ SIM にサブスクリプションを追加する」という感覚に近いです。

一方で、今回の SGP.32 対応 SIM のプロファイル切り替えでは、SORACOM の SIM としては別の IMSI に切り替わる見え方になります。

このため、IMSI や ICCID をキーにした管理をしている場合は、プロファイルの切り替え前後でどのように扱うかを考えておいた方が良さそうです。

5. planX2 の状態で SORACOM への ping 疎通を確認する

最後に、planX2 に切り替えた状態でも通信疎通していることを確認します。

Step 1/2 Ensure PDP context active

Command:
> AT+QIACT?

Modem response:
AT+QIACT?
OK

Command:
> AT+QIACT=1

Modem response:
AT+QIACT=1
OK

Analysis:
- AT+QIACT? checks Quectel TCP/IP PDP context state; AT+QIACT=<contextID> is only sent when the selected context is not active.
- Quectel PDP context 1 was not active in AT+QIACT? output; AT+QIACT=1 activated it.

Step 2/2 Ping SORACOM

Command:
> AT+QPING=1,"pong.soracom.io",4,4

Modem response:
AT+QPING=1,"pong.soracom.io",4,4
OK

+QPING: 0,"100.127.100.127",32,26,255

Analysis:
- AT+QPING checks IP reachability through the selected Quectel PDP context; received replies are not TCP or application receipt proof.
- Ping reply: host=100.127.100.127 bytes=32 time_ms=26 ttl=255

Notes:
- Received ping replies from pong.soracom.io are SORACOM network reachability evidence.
- Ping success is not TCP socket, Unified Endpoint, Beam, or destination application receipt proof.
- Use soracom-unified-endpoint-tcp-send-check when TCP payload delivery to Unified Endpoint must be checked.

Result: OK duration=6479ms

Completed: 2026-07-06T08:53:19Z

ping が通れば、planX2 に切り替えた後も通信疎通できていることが確認できます。

今回の確認では、plan01s の状態でも、planX2 に切り替えた後でも、SORACOM への ping 疎通を確認できました。

これで、

  • plan01s の状態でデバイス側から確認
  • plan01s の状態で通信確認
  • クラウド側で planX2 に切り替え
  • planX2 の状態でデバイス側から確認
  • planX2 の状態で通信確認

という一連の流れを確認でき SGP.32 という新しい規格のSIMを少しは体験することができました。

気づいたこと

今回、実際に手元で試してみて、いくつか気づいた点があります。

SIM プロファイルは正しく切り替わっている

まず、SORACOM Connectivity Hypervisor によるプロファイル切り替えは、デバイス側からも確認できました。

切り替え前後で AT コマンドの結果を比較すると、IMSI や ICCID などの情報が変わっていることが確認できます。

そのため、クラウド側の操作だけでなく、ローカルデバイス側から見ても、利用しているプロファイルが切り替わっていることが確認できました。

SORACOM の SIM としては別の IMSI になる

注意点として、切り替え後は SORACOM の SIM として別の IMSI に見えます。

これはサブスクコンテナとは違う点です。 サブスクコンテナの延長として考えてしまうと、IMSI や ICCID の取り扱いで違いが発生します すごい単純なところだと。SORACOMユーザーコンソール上のSIM管理では、別のSIMという扱いになります。 したがって、SIMグループの設定も別々に必要となるという形になります。 切り替える前のSIMがSIMグループに所属していたからといって、切り替え先も同じグループに所属しているということはなく、これまで通り自身で事前に正しいSIMグループへの設定が必要となります。

他にも 運用上で、IMSI や ICCID を識別子として扱っている場合は、この点に注意が必要です。

たとえば、

  • デバイス管理システムで IMSI / ICCID をキーにしている
  • ログや監視で IMSI / ICCID を見ている
  • キッティング結果を IMSI / ICCID ベースで記録している
  • 通信確認の結果を SIM 単位で突合している

といった場合には、切り替え前後の関係をどう管理するかを考えておく必要がありそうです。

切り替えはリアルタイムに起こるわけではない

もう 1 つの注意点は、切り替えが必ずしもリアルタイムに反映されるわけではないことです。

クラウド側で切り替え操作を実行しても、デバイス側がすぐに新しいプロファイルで接続し直すとは限りません。

SIM 側が切り替え情報を確認するタイミング、つまりポーリング間隔に依存します。

今回の確認では、モデムをリブートしたり、デバイス自体をリブートしたりすると、切り替え後の状態が確認されるようでした。

このようなリブートの操作自体がベストプラクティスであるかどうかという部分は 今後公式のドキュメントや実例が整備されていく過程で正しくわかってくると思うので このブログでの記載はあくまでも検証した時点での動作という部分に注意してください

初回有効化時は時間がかかることがある

また、新規のプロファイルを初めて有効化した場合 物理的に SIM を新規に挿した時と同様に時間がかかることがあるようです。

youtu.be

これは、初回のネットワーク登録やプロファイルの状態確認などが関係しているのかもしれません。

そのため、これまでの新規にSIMを差して起動する時と同様に この辺りは考慮して、切り替えや運用の設計をしておく必要があると感じました。

まとめ

今回は、SORACOM Connectivity Hypervisor を使って SIM プロファイルを plan01s から planX2 に切り替え、ローカルデバイス側の挙動を確認してみました。

確認した内容は以下です。

  • plan01s デフォルトの状態を AT コマンドで確認しました
  • plan01s の状態で SORACOM への ping 疎通を確認しました
  • SORACOM Connectivity Hypervisor を使って、クラウド側で planX2 に切り替えました
  • planX2 切り替え後の状態を AT コマンドで確認しました
  • planX2 の状態でも SORACOM への ping 疎通を確認しました

結果として、SIM プロファイルは正しく切り替わっており、切り替え後も通信疎通できることを確認できました。

一方で、いくつか注意点もあります。

  • SORACOM の SIM としては、切り替え前後で別の IMSI / ICCIDとして見える
  • サブスクコンテナとは考え方や見え方が異なる
  • 切り替えはリアルタイムに反映されるわけではない
  • 反映タイミングはポーリング間隔に依存する
  • モデムリブート、またはデバイスリブートにより切り替え後の状態を確認できる場合がある
  • 初回有効化時は、SIM を新規に挿した時と同様に時間がかかることがある

SGP.32 対応 SIM と SORACOM Connectivity Hypervisor によって、出荷後の IoT デバイスでも SIM プロファイルを柔軟に管理できるようになります。

ただし、実際の運用では、クラウド側の操作だけではなく、デバイス側での見え方や反映タイミングも含めて確認しておくことが大事そうです。

たとえば、キッティング作業の中に単純なプロファイルのダウンロードだけでなく、切り替えと通信疎通の確認を行うプロセスを入れるなどの工夫が必要になってきそうです。 SORACOMの仕組みでこの辺のキッティング周りまでカバーできるようなサービスやプロダクトが出てくることを期待したいですね。

以上にです。

ScanForge:WebUI でバーコード生成して AWS Lambda でスキャンする

目次

Please check it.


この記事は 2025年 12 月時点 (以下、現在 / 現時点) の情報に基づいて記載しています。筆者は本記事を執筆した現時点において 株式会社ソラコム に所属していますが、本記事の内容は あくまでも筆者個人の見解に基づくものであり、所属する会社または組織とは一切関係ございません。


(参考)
「一般消費者が事業者の表示であることを判別することが困難である表示」の指定及び「『一般消費者が事業者の表示であることを判別することが困難である表示』の運用基準」の公表について

SORACOM Advent Calendar 2025

この記事は SORACOM Advent Calendar 2025 の 21 日目の記事です。

qiita.com

今回は、SORACOM Flux で利用できるツールを作ってみました。 少しだけ機能を追加することで、SORACOM Flux がもう少し便利になるといいなぁと思って作ってみました。

以前に作成した AnnoForge と同様に、 ちょっとした お役立ちツールとして使ってもらえたら嬉しいです。

uchimanajet7.hatenablog.com

前提

ScanForge というツールを作ってみました。
この記事では、その 開発メモ と 簡単な紹介 を書いています。

実際に手を動かしながら気づいたことや、使ってみた感想を残した
いわゆる 「技術メモ」 に近いものです。

自分用の備忘録的な位置づけではありますが、
同じように開発している方や、生成AIを使ったコーディング支援ツールでの開発結果に興味がある方の
参考になれば嬉しいです。

開発には、以前作った AnnoForge と同じく、
生成AIによるコーディング支援ツール OpenAI Codex を使いました。

Codex は更新や修正のスピードがかなり早く、
この記事の内容は、読むタイミングによってはすでに古くなっている可能性があります。

実際、作成中にも
GPT-5.1 → GPT-5.1-codex → GPT-5.1-codex-max → GPT-5.2 → GPT-5.2-codex
とモデルが変化しています。

そのため、この記事がそのまま参考になるとは限りませんが、
それでも 開発の一例 として読んでもらえたらと思います。

openai.com

ScanForge

実際に作成したものは、以下になります。

scanforge は、WebUI でバーコードの作成とスキャンを行い、
さらに AWS Lambda 上の API でも、WebUI と同様にバーコードの作成とスキャンができるツールです。

主な特徴は以下のとおりです。

  1. GenAI のコーディング支援ツールだけで開発

    • 人が直接コードを書いたり編集したりすることはせず、関連ドキュメントを含め、すべて生成AIによって作成しました。
  2. WebUI + API のシンプルな連携

    • ブラウザ上でバーコードを作成し、作成したバーコードをそのまま API に送信。サーバ側でバーコードをスキャンし、値を返却するという一連の流れを実現できます。
  3. IaC で一括管理

    • Terraform を使って Lambda / Layer / alias prod / Function URL / IAM を一体で管理しています。また、bash スクリプトにより auth → setup → deploy → smoke test までを対話形式で実行できます。

作成は GenAI にすべて任せているため、
コードの細かい部分については、詳しく確認していません。

ただし、簡単な動作確認の範囲では問題なく動作しています。
利用方法やデプロイの詳細については、GitHub リポジトリを参照してください。

WebUI については、以下の GitHub Pages でも公開しており、
実際に動作を確認できます。

uchimanajet7.github.io

なぜ作ってみたのか?

バーコード、特に QR コードは、
デバイスのセットアップ時に利用されることが多くあります。

たとえば、初期パスワードやユーザー情報などが、
デバイス本体に QR コードとして印字されているケースがあります。

このような場合、従来は
スマホやタブレットのアプリで QR コードを読み取り、
人が内容を確認したうえで、
手動で入力したり記録したりする運用が一般的です。

しかし、扱う台数や規模がある程度大きくなってくると、
この対応は次第に難しくなり、
作業全体のボトルネックになっていきます。

その対策として、
スマホアプリ側にクラウド環境へのデータ送信や蓄積、
データ操作などの機能を持たせたものを自作する、
もしくは、そのようなサービスを探して利用する
といった選択肢が考えられます。

ただし、その場合は
初期投資が必要になったり、
ある程度の規模を前提とした構成になることが多く、
実際に「簡単に試してみる」ことが難しいという課題があります。

そこで、このツールと
既存のネットワークカメラや、画像を取得できるデバイスを組み合わせて利用することで、
QR コードを含むバーコードを手軽に取得し、
クラウド側で解析やデータ蓄積ができるようにすることを考えました。

もちろん、既存のバーコード読み取りツールで
必要十分なケースも多くあります。
そのため、このツールは
手軽にさくっと試せる構成としています。

また、WebUI については、
PC やスマホでカメラ利用を許可するだけで
バーコードの読み取りが可能です。

まずは WebUI だけで試し、
自動化やヘッドレスでの対応が必要になった場合に
API をデプロイして利用するなど、
段階的に使えるようになっています。

実際に使ってみる

せっかく AI で作った ScanForge なので、
実際に使ってみようと思います。

今回は、
WebUI で QR コードを作成し、
それをカメラで撮影、
撮影した QR コードの画像を API に渡して内容を読み取る、
という流れで試します。

試し方はいくつか考えられますが、
今回は SORACOM Advent Calendar 2025 の記事ということもあり、
ソラコムのサービスである ソラカメ と SORACOM Flux を使って
試してみることにします。

ScanForge

まずは、ScanForge のサーバーサイド、
つまり API 部分を AWS 環境にデプロイします。

この API は、
AWS Lambda 上で動作する設計になっています。

デプロイは Terraform で定義してあり、
必要なツールがセットアップ済みであれば、
GitHub リポジトリ内のデプロイスクリプトを実行するだけで完了します。

スクリプトを起動すると、
対話形式で必要事項を入力または選択していく流れになっており、
手順自体もシンプルです。

デプロイ方法や環境設定の詳細については、
以下の GitHub リポジトリの README.md を参照してください。

API のデプロイが完了すると、
AWS Lambda Function URLs によって
エントリポイントとなる URL が発行されます。

この URL を SORACOM Flux に設定することで、
Flux から ScanForge の API にアクセスできるようになります。

bash scripts/deploy/tf_outputs.sh
[tfout] ----- start: 2025/12/18 14:48:05.920 (JST) -----
[tfout] Terraform outputs
  function_url = https://5Xx4xx57xxxXxxxxxX40xxxxx.lambda-url.us-west-2.on.aws/
  function_arn = arn:aws:lambda:us-west-2:903921708000:function:scanforge-api
  alias_arn    = arn:aws:lambda:us-west-2:903921708000:function:scanforge-api:prod
  layer_arn    = arn:aws:lambda:us-west-2:903921708000:layer:scanforge-api-deps:10
[tfout] 呼び出し例は 'bash scripts/deploy/smoke.sh' の出力(run行)をご参照ください。
[tfout] 表示完了
[tfout] ----- end: 2025/12/18 14:48:09.502 (JST) (elapsed=3.565s) -----

WebUI 側については、
すでに GitHub Pages 上に公開しているため、そのまますぐに利用できます。 QRコードの作成は WebUI を使って行いました。

uchimanajet7.github.io

作成した QR コードは、
背景を透過しない設定とし、
内容としては、ソラコムのトップページの URL
https://soracom.jp/
をテキストとして設定しています。

次は、この作成した QR コードの画像を
スマホの画面に表示し、
そのスマホを ソラカメ で撮影して、
画像を取得してみようと思います。

ソラカメ

Info

ソラカメを使わない場合でも、画像ファイルを手動で SORACOM Harvest Files にアップロードすれば、同様に動作確認が可能です。

ソラカメを使わない場合は、このセクションは読み飛ばしても問題ありません。

ソラカメとは?

ソラカメはソラコムが提供している、クラウド型のカメラサービスです。 このブログでも過去に色々と試したことがあるので、よければそちらも確認してみてください

sora-cam.com

sora-cam.com

ソラカメを選んだ理由

今回ソラカメを選んだ理由は、
SORACOM Flux でカメラ画像を簡単に扱える ためです。

SORACOM Flux の設定だけで、
ソラカメから静止画を取得できるので、
「ちょっと試してみたい」といった場面でも非常に便利です。

soracom.com

また、追加で費用は発生しますが、
さらに手軽にソラカメを利用して AI による画像解析を行える
「ソラカメ AI」 も用意されています。

AI による画像解析が気になった方は、
こちらもあわせて確認してみてください。

soracom.com

ライセンスと料金について

今回は動作確認のみが目的だったため、
録画機能は利用せず、リアルタイムアクセスのライセンス を使用しました。

このライセンスを購入すると、
月額料金が発生します。
利用する前に、料金やサービス内容を必ず確認してください。

soracom.jp

users.soracom.io

また、「ソラカメを体験してみたい」という方に向けて、
無料トライアル も用意されています。

sora-cam.com

SORACOM Flux

SORACOM Flux は、
デバイスから送られてくるセンサーデータやカメラ画像にルールを適用し、
複数のデータソースや生成 AI を組み合わせて
分析や判断を行えるサービスです。

つまり、
IoT アプリケーションをローコードで構築できるプラットフォーム です。

SORACOM Flux の使い方や料金プランの詳細は、
以下のサイトを参照してください。
プランによっては費用が発生するため、利用前に必ず確認してください。

soracom.jp

users.soracom.io

ソラカメの静止画取得設定

まずは、ソラカメから静止画を取得する部分を設定します。
ソラカメを利用しない場合は、この設定はスキップしてください。

イベントソースの設定

イベントソースには
ソラカメ モーション検知 / サウンド検出イベントソース を利用します。

今回は、単純にソラカメの静止画を取得したいだけなので、
実際にはどのイベントソースを選択しても問題ありません。

なお、SORACOM Flux の仕様上、
イベントソースには必ずアクションを紐づける必要があります。

users.soracom.io

ソラカメ画像取得アクションの設定

イベントソースに
ソラカメ画像取得アクション を紐づけ、
静止画を取得したいカメラを指定します。

この設定では、次の 2 点に注意してください。

  1. 「SORACOM Harvest Files にエクスポートする」 を有効にする
  2. 「ライブ画像」 を選択する

SORACOM Harvest Files に出力するのは、
後続の処理で SORACOM Harvest Files イベントソース を利用するためです。

また、「ライブ画像」を選択するのは、
前のセクションで設定したソラカメが
リアルタイムアクセスライセンス を使用しているためです。

users.soracom.io

動作確認

設定が完了したら、
実際に静止画が取得できるか確認してみましょう。

ソラカメ モーション/サウンド検知 のテスト実行 を使って
イベントトリガーを発火させると、
ソラカメ画像取得アクションが実行され、
指定した SORACOM Harvest Files に
静止画が出力されているはずです。

画像が問題なく取得できていれば、
ソラカメの静止画取得設定は完了です。

ScanForge の WebUI でバーコードを作成する

ここまでで、
ソラカメを使って画像を読み取るための準備ができました。

次に、ScanForge の WebUI を利用して、
実際に読み取り対象となるバーコードを作成します。

uchimanajet7.github.io

今回利用したバーコードについて

今回の動作検証では、
利用頻度が高い QR コード を使って試してみました。

QR コードに埋め込むテキストとしては、
ソラコムのサービストップページである
https://soracom.jp/ を利用しています。

soracom.jp

WebUI では、以下の設定で QR コードを作成しました。

背景の透過を OFF にすると、
白背景に黒の QR コードが生成されるため、
読み取り時の精度を上げることができます。

ちなみに、SORACOM アイコンセット を利用して ロゴを設定したQRコードを作成すると以下のような形になります

users.soracom.io

次は、
SORACOM Flux から ScanForge の API を呼び出し、
実際に動的な QR コードの読み取り
を試してみます。

SORACOM Flux から ScanForge API を呼び出す

ここでは、
QR コード画像を SORACOM Harvest Files にアップロードし、
その画像を ScanForge API でスキャンして、
QR コードに含まれるテキストデータを読み取ってみます。

イベントソースの設定

今回の動作検証では、
SORACOM Harvest Files イベントソース を利用します。

このイベントソースを使うことで、
ソラカメを利用しない場合でも、
画像ファイルを手動で SORACOM Harvest Files にアップロードすることで
同様に動作確認が可能です。

users.soracom.io

ScanForge API の呼び出し設定

次に、
Webhook アクション を使って、
AWS 上にデプロイした ScanForge API を呼び出します。

users.soracom.io

以下は、
今回の検証で実際に設定した呼び出し例です。

{
  "barcodeUrl": "${event.payload.presignedUrls.get}"
}

この設定により、
SORACOM Harvest Files に画像がアップロードされるたびに、
Webhook アクションを通して
ScanForge API が自動的に呼び出されます。

API が呼び出されると、
今回の場合は QR コードの画像がスキャンされ、
QR コードの内容であるテキストが
戻り値として取得できます。

ソラカメ を利用する場合

ソラカメを利用している場合は、
あらかじめ設定した
ソラカメ モーション / サウンド検知のイベントソース の
テスト実行を行うことで、
ソラカメから画像を取得し、
SORACOM Harvest Files に保存することができます。

具体的には、
スマホの画面に作成した QR コード画像を表示し、
その画面をソラカメで撮影することで、
QR コードを読み取ることができます。

実際に、
私のスマホに QR コードを表示した状態を
ソラカメで撮影し、
QR コードをスキャンできています。

このように、
実際の環境でカメラさえ用意できれば、
QR コードをはじめとしたバーコードのスキャンが可能になります。

もちろん、逆に
テキストデータをバーコードに変換することもできるため、
たとえばデバイス側から送信されたデータを QR コードにして、
スマホで読み取るといった使い方も可能になります。

簡単な設定で、
現実の情報をバーコードに変換し、
相互にやり取りできる点は、
大きなメリットになるのではないでしょうか。

想定するユースケース

今回は SORACOM Harvest Files と SORACOM Flux を利用して、
Slack に結果を通知するところまでを試しましたが、
実際の現場を想像すると、さまざまなユースケースが考えられます。

たとえば、初期設定の情報やデバイス固有の ID 情報などが、
デバイス自体に QR コードとして印字されている場合があります。
また、SORACOM の SIM であれば、ICCID などの情報は
ユーザーコンソールからデジタルデータとして取得できますが、
SIM の台紙にバーコードが印字されているケースも、
現時点ではまだ多く見られます。

wiki.teltonika-networks.com

そういった中で、
固定したネットワークカメラと ScanForge の仕組みがあれば、
デバイスが設置されているエッジ側に
QR コードやバーコードの読み取り機能がなくても
対応できるようになります。

SORACOM Flux を利用する場合でも、
ソラカメに限らず、RTSP に対応した
ネットワークカメラであれば利用可能です。

soracom.com

大きな手間をかけずに対応できる点が、
もっとも大きなポイントになるかもしれません。

まとめ

  • ネットワークカメラで撮影したバーコードや、IoTデバイスから送信されたSVGデータのバーコードをスキャンできる仕組みを作りました
  • データからバーコードを作る仕組みも同様に作っており、少量かつ単純なテキストベースのデータであればバーコード化できるようになります
  • 双方向で変換が可能なため、現実のデータをデジタルにして他の端末でシンプルに読み取ることができます
  • たとえば、デバイスのキッティング時に必要な情報をQRコード化することや、デバイスに印字されている情報をデジタル化することも可能です
  • WebUIでバーコードを作成 → AWS Lambda上のScanForge APIでバーコードをスキャン → 読み出したテキストデータを返す、というシンプルな構成で動作します
  • TerraformによるIaC管理で、GitHubリポジトリにあるデプロイスクリプトを実行するだけでセットアップが完了するため、導入も簡単です
  • 今回の動作確認では、画像取得にソラカメ、画像保存に SORACOM Harvest Files、API呼び出しに SORACOM Flux を使用しました
  • ScanForge自体はWebUIとAPIの構成なので、他の環境でも同じように利用できます
  • WebUIはGitHub Pagesで公開されており、バーコードの作成やスキャンをすぐに試したいときに便利です
  • すぐに試せて、試行錯誤が簡単にできる点は大きな強みです
  • 機会があればぜひ試してみてください

以上です。

AnnoForge 開発メモ - WebUIで注釈設定 → AWS Lambdaで画像に注釈を追加してみた

目次

Please check it.


この記事は 2025年 10 月時点 (以下、現在 / 現時点) の情報に基づいて記載しています。筆者は本記事を執筆した現時点において 株式会社ソラコム に所属していますが、本記事の内容は あくまでも筆者個人の見解に基づくものであり、所属する会社または組織とは一切関係ございません。


(参考)
「一般消費者が事業者の表示であることを判別することが困難である表示」の指定及び「『一般消費者が事業者の表示であることを判別することが困難である表示』の運用基準」の公表について

前提

AnnoForge というツールを作ってみました。
この記事では、その開発メモと簡単な紹介を書いています。

内容としては、しっかりした比較検証記事というよりも、実際に手を動かしながら気づいたことや使ってみた感想を残した「技術メモ」に近いものです。

自分用の備忘録的な位置づけですが、同じように開発している方や、生成AIを使ったコーディング支援ツールに興味がある方の参考になれば嬉しいです。

開発には、以前作った openai-responses-mcp と同じく、生成AIによるコーディング支援ツール OpenAI Codex を使いました。
Codex は更新や修正のスピードがかなり早いので、この記事の内容が読むタイミングによってはもう古くなっているかもしれません。

それでも、開発の一例として読んでもらえたらと思います。

uchimanajet7.hatenablog.com

AnnoForge

実際にAIが作ったものは以下の GitHub にアップロードしてあります。

annoforge は、WebUIで定義したアノテーション(線・矩形・多角形・平行四辺形・円など)を、AWS Lambda 上の API で画像に描画し、S3 に保存して presigned URL を返すツールです。

主な特徴は以下のとおりです。

  1. GenAI のコーディング支援ツールだけで開発

    • 人が直接コードを書いたり編集したりせず、関連ドキュメントを含め、すべて生成AIによって作成しました。
  2. WebUI + API のシンプルな連携

    • ブラウザ上で注釈を描く → JSONをそのままAPIに送信 → サーバ側で同じ描画を再現してS3に保存 → 共有用URLを取得、という一連の流れがスムーズに完結します。
  3. IaCで一括管理

    • Terraform で Lambda / Layer / alias prod / Function URL / S3 / IAM を一体管理でき、bashスクリプトで auth → setup → deploy → smoke(POST → presigned → HEAD 200) までを対話形式で実行できます。

今回もコードの作成やドキュメントの作成も含めて GenAI にすべて任せているため、コードの細かい部分はまだ詳しく確認していませんが、簡単な動作確認の範囲では問題なく動作しています。利用方法やデプロイの詳細については、GitHub リポジトリを参照してください。

WebUI だけは以下の GitHub Pages でも公開しているので、実際に動作を確認できます。

uchimanajet7.github.io

なぜ作ってみたのか?

GenAI(LLM)に文章で指示を出すとき、入力に画像を使う場合があると思います。
ただその際、説明が難しかったり、目印になるものがなかったりして、文章だけではうまく意図を伝えられないことがあると思います。

たとえば、現実世界の現場では「侵入禁止エリア」を示す線や囲いが物理的に存在しないケースがあったとします。それでも、ルール上は「ここからここまでは侵入禁止」という領域が決まっていて、その範囲をカメラで監視したいとします。

GenAI に「この画像の中で侵入禁止エリアの状況を確認して」と伝える場合、どの範囲が侵入禁止なのかを文章だけで正確に説明するのは、かなり難易度が高くなります。

そこで 画像自体にAIが理解できる形で注釈(Annotation)を追加する AIに伝えやすくするという方法をとってみました。もし定点カメラのように、撮影画角や構図が固定されている画像であれば、画像の中に「ここが侵入禁止エリア」という赤枠などの注釈を付けておくことで、AIに「この赤枠の中の状況を確認して」と伝えるだけで済みます。

もちろん、既存の画像編集ツールを使って手動で注釈を付けたり、現実の環境に識別用の囲いを設置する方法もあります。

ただ、それだと毎回の作業が手間になったり現地での作業が必要となるので、「一度定義すれば、あとは自動で注釈を付けられる仕組みを作ってみよう」と思ったのが開発のきっかけです。

実際に使ってみる

せっかく AI が作ってくれた「AnnoForge」なので、実際に使ってみようと思います。やることは、WebUI でアノテーションを作成して、それを API に渡して描画してもらうという流れです。

ただ、これをそのまま試しても効果がいまいち分かりにくいので、ソラコムのサービスである ソラカメ と SORACOM Flux を使ってみることにしました。具体的には、画像にアノテーションがある場合とない場合で、GenAI がどんな結果を返すのかを比較してみようと思います。

AnnoForge

まずは AnnoForge のサーバーサイド、つまり API 部分を AWS 環境にデプロイします。 この API は AWS Lambda 上で動作する設計になっているためです。

デプロイは Terraform で定義してあり、必要なツールがセットアップ済みであれば、GitHub リポジトリ内のデプロイスクリプトを実行するだけで完了します。 スクリプトを起動すると対話形式で必要事項を入力または選択していく流れなので、手順もシンプルです。

デプロイ方法や環境設定の詳細については、以下の GitHub リポジトリの README.md を参照してください。

API のデプロイが完了すると、AWS Lambda Function URLs によってエントリポイントの function URL が発行されます。 この URL を SORACOM Flux に設定することで、Flux から AnnoForge の API にアクセスできるようになります。

bash scripts/deploy/tf_outputs.sh
[tfout] ----- start: 2025/10/14 13:13:26.960 (JST) -----
[tfout] Terraform outputs
  function_url = https://XoXnaqegx2oxjmiXXmtwp5al3m0mggid.lambda-url.us-west-2.on.aws/
  function_arn = arn:aws:lambda:us-west-2:XXXXXXXXXXXX:function:annoforge-api
  alias_arn    = arn:aws:lambda:us-west-2:XXXXXXXXXXXX:function:annoforge-api:prod
  layer_arn    = arn:aws:lambda:us-west-2:XXXXXXXXXXXX:layer:annoforge-api-pillow:11
[tfout] 呼び出し例は ‘bash scripts/deploy/smoke.sh’ の出力(run行)をご参照ください。
[tfout] 表示完了
[tfout] ----- end: 2025/10/14 13:13:28.971 (JST) (elapsed=1.999s) -----

WebUI 側はすでに GitHub Pages 上に公開してあるので、今回は以下の WebUI を使って動作確認を行います。

uchimanajet7.github.io

これで AnnoForge を利用する準備が整いました。 次は ソラカメ を使って、アノテーションを付ける対象の画像を取得してみようと思います。

ソラカメ

Info

ソラカメを使わない場合は、手動で画像ファイルをアップロードすれば同じように動作確認ができます。ソラカメを利用しない場合はこの部分を読み飛ばしても大丈夫です。

ソラカメとは?

ソラカメはソラコムが提供している、クラウド型のカメラサービスです。 このブログでも過去に色々と試したことがあるので、よければそちらも確認してみてください

sora-cam.com

uchimanajet7.hatenablog.com

ソラカメを選んだ理由

今回ソラカメを選んだのは、SORACOM Flux でカメラ画像を簡単に扱える からです。 SORACOM Flux の設定だけでソラカメから静止画を取得できるので、「ちょっと試してみたい」ときに非常に便利です。

soracom.com

ライセンスと料金について

今回は動作確認だけが目的だったので、録画機能は使わず リアルタイムアクセスのライセンス を利用しました。このライセンスを購入すると月額料金が発生します。利用前に必ず料金やサービス内容を確認してください。

soracom.jp

users.soracom.io

もし「ソラカメを体験してみたい」という方は、無料トライアル もあります。

sora-cam.com

ソラカメから画像を取得する

リアルタイムアクセスのライセンスを付与したソラカメでは、以下の手順で SORACOM API または SORACOM CLI を使って画像を取得できます。

users.soracom.io

ただし、この方法は API や CLI の操作が必要になるため、ちょっと面倒に感じる方もいるかもしれません。 そこで、次の SORACOM Flux の設定で、ソラカメからの画像取得も一緒に行う方法を設定してみようと思います。

SORACOM Flux

SORACOM Flux は、デバイスから送られてくるセンサーデータやカメラ画像にルールを適用して、複数のデータソースや生成 AI を組み合わせて分析・判断を行えるサービスです。 つまり、IoT アプリケーションを ローコードで構築できるプラットフォーム です。

SORACOM Flux の使い方や料金プランの詳細は、以下のサイトを参照してください。 プランによっては費用が発生する場合があるので、利用前に必ずご自身で確認してください。

soracom.jp

users.soracom.io

ソラカメの静止画取得設定

まずは、ソラカメから静止画を取得する部分を設定します。 ソラカメを利用しない場合は、この設定はスキップしてください。

イベントソースとして インターバルタイマー を利用します。 今回は単純にソラカメの静止画を取得したいだけなので、どのイベントソースを使っても構いません。 SORACOM Flux の仕様上、イベントソースには必ずアクションを紐づける必要があります。

users.soracom.io

イベントソースに ソラカメ画像取得アクション を紐づけ、取得したいカメラを指定します。 このときは次の 2 点に注意してください。

1.「SORACOM Harvest Files にエクスポートする」 を有効にする
2.「ライブ画像」 を選択する

SORACOM Harvest Files に出力する理由は、後のアノテーション処理で SORACOM Harvest Files イベントソースを使うためです。 また、ライブ画像を選ぶのは、前のセクションで設定したソラカメが リアルタイムアクセスライセンス を使っているためです。

users.soracom.io

設定ができたら、実際に画像が取得できるか確認してみましょう。

Timer Channel のテスト実行 を使ってイベントトリガーを発火させると、ソラカメ画像取得アクションが実行され、指定した SORACOM Harvest Files に静止画が出力されているはずです。

画像が無事に取得できたら、次はこの画像を使って AnnoForge の WebUI でアノテーションを追加してみます。

AnnoForge のWebUIでアノテーションを追加する

ここまででやっと画像の準備ができました。 次に AnnoForge の WebUI に画像をアップロードし、実際にアノテーションを追加してみます。

uchimanajet7.github.io

今回利用した画像について

今回の動作検証では、ソラコムのオフィスがあるビルの 9F から、ソラカメ で外の風景を撮影した画像を使用しました。 人の目で見ると、車道が丁字になっているのが分かりますが、これをテキストベースで GenAI に伝えるのは少し難しそうです。

そこで、車道の形をわかりやすくするために、以下のように車道に沿って枠線(アノテーション)を付与しました。 この枠線を付けることで、GenAI に対して「車道が存在する場所」と「その範囲」を明確に伝えることができます。

AnnoForge WebUI の出力

AnnoForge の WebUI では、設定したアノテーション情報を JSON 形式で出力します。 この JSON と「同じ画角・同じサイズ」で撮影された画像をセットで AnnoForge の API に入力することで、動的にアノテーション付きの画像を生成することができます。

この仕組みを使えば、定期的に撮影された新しい画像に対しても、あらかじめ設定したアノテーション領域を自動的に描画できます。 たとえば今回の画像で言うと、朝・昼・晩などのタイミングで画像を取得し、車道の渋滞状況を確認する といった活用も可能です。

AnnoForge の WebUI では、直線以外にもさまざまな図形を描画できます。 そのため、駐車スペースや駐輪スペースの領域指定、侵入禁止エリアの設定など、実際に現地で設置やメンテナンスを行うのが大変な場所でも、仮想的にエリアを定義できます。

このように、AnnoForge を使うことで、現実世界の空間情報を柔軟に可視化・管理することができます。

次は、SORACOM Flux から AnnoForge の API を呼び出して、実際に 動的なアノテーションの追加 を試してみます。

SORACOM Flux から AnnoForge API を呼び出す

ここでは、実際に画像を SORACOM Harvest Files にアップロードし、その画像にアノテーションを付与した状態で GenAI に簡単な問いかけをしてみます。

イベントソースの設定

今回の動作検証では、SORACOM Harvest Files イベントソース を利用します。 このイベントソースを使うことで、ソラカメを利用できない場合でも、画像ファイルを手動で SORACOM Harvest Files にアップロードすれば動作確認ができます。

users.soracom.io

AnnoForge API の呼び出し設定

次に、Webhook アクション を使って、AWS 上にデプロイした AnnoForge API を呼び出します。

users.soracom.io

以下は、今回の検証で実際に設定したアノテーションを付与するための呼び出し例です。

{
  "imageUrl": "${event.payload.presignedUrls.get}",
  "config":{
  "draw": [
    {
      "shape": "line",
      "x1": 744,
      "y1": 857,
      "x2": 1815,
      "y2": 786,
      "color": "FF0000",
      "thickness": 5
    },
    {
      "shape": "line",
      "x1": 732,
      "y1": 999,
      "x2": 976,
      "y2": 980,
      "color": "FF0000",
      "thickness": 5
    },
    {
      "shape": "line",
      "x1": 976,
      "y1": 980,
      "x2": 1014,
      "y2": 1076,
      "color": "FF0000",
      "thickness": 5
    },
    {
      "shape": "line",
      "x1": 1092,
      "y1": 961,
      "x2": 1165,
      "y2": 1077,
      "color": "FF0000",
      "thickness": 5
    },
    {
      "shape": "line",
      "x1": 1092,
      "y1": 961,
      "x2": 1825,
      "y2": 893,
      "color": "FF0000",
      "thickness": 5
    }
  ]
  }
}

この設定を行うことで、SORACOM Harvest Files に画像がアップロードされるたびに、Webhook アクションを通して AnnoForge API が呼び出されます。 API が呼ばれると、WebUI で設定したアノテーション が再現され、アノテーション付きの画像が生成されます。

また、ソラカメを利用している場合は、あらかじめ設定した インターバルタイマーのイベントソース のテスト実行を行うことで、ソラカメから画像を取得し、SORACOM Harvest Files に保存することができます。

このように、実際の環境で物理的に枠や柵を設置しなくても、 画像にアノテーションを付与するだけで、領域指定や AI に伝えるための目印を付けることが可能 になります。 簡単な設定で現実の空間情報をデジタル上に再現できるのが、画像アノテーションの大きなメリットです。

GenAI の確認結果の比較

最後に、実際に GenAI を使って結果の違いを確認してみました。 今回は SORACOM Flux 上で選択できる AI モデル Azure OpenAI(GPT-4.1) を利用し、アノテーションを付与した画像 と アノテーションなしの画像 の 2 パターンで、アノテーションの定義以外はまったく同じプロンプトを入力して比較しています。

アノテーションなしのプロンプト

画像はビルの9F  からの画像です。

車道に車が走っているのか?
走っていたら渋滞しているのか?

を確認して教えてください

確認結果の出力は以下のJSONフォーマットに沿って出力してください
JSONとして正しいフォーマットで出力してください

{
    "result": "画像を確認した結果を記載してください",
    "image": "${event.payload.presignedUrls.get}"
}

アノテーションありのプロンプト

画像はビルの9F  からの画像です。

赤線で囲われた部分は車道を表しています。

車道に車が走っているのか?
走っていたら渋滞しているのか?

を確認して教えてください


確認結果の出力は以下のJSONフォーマットに沿って出力してください
JSONとして正しいフォーマットで出力してください

{
    "result": "画像を確認した結果を記載してください",
    "image": "${payload.presignedUrl}"
}

プロンプト自体は非常に単純で、プロンプトの違いは、 たった一文

「赤線で囲われた部分は車道を表しています。」

を加えているかどうかだけです。

それぞれのプロンプトを GenAI に送信し、結果を Slack 通知 に出力するように設定しました。 実際に実行して得られた結果が以下になります。

アノテーションなし結果

# No annotations added
画像からは車道に車が走っていることが確認できますが、台数は少なく、渋滞している様子は見受けられません。

アノテーションあり結果

 # Annotations added
画像内の赤線で囲われた車道部分に複数台の車両が走行している様子が確認できます。ただし、車間距離は適切に確保されており、特に渋滞している様子はありません。通常の交通状況と思われます。

どちらの回答も、プロンプトの指示に沿って正しく回答しているように思えます。 ただし、アノテーションなしの方は、やや情報量が少ない傾向がありました。 これは必ずしも性能差ではなく、単純にその時の画像状況によるものと思われます。

一方で、アノテーションありの方は、明確に「赤線で囲われた範囲=車道」として認識されている様子が見られました。 このことから、アノテーションが意図した通りに機能し、AI にとって有効な補助情報になっている ことが確認できました。

同じ指示内容のプロンプトであっても、アノテーションを付与するだけで AI の理解精度が高まる というのは非常に興味深い結果です。 特に、テキストで説明しづらい領域を「簡単な指定で範囲を示せる」というのは、現場での応用を考えるうえでも大きなメリットだと感じました。

まとめ

  • テキストだけでは伝えにくい「画像内の注目領域」を、AnnoForge のアノテーションで明示し、GenAI に的確に伝えられるようにした
  • WebUI でアノテーションを作成 → AWS Lambda 上の AnnoForge API が画像に注釈を合成 → S3 に保存し presigned URL を返す、というシンプルな構成で動作
  • Terraform による IaC 管理で、GitHub リポジトリにあるデプロイスクリプトを実行するだけでセットアップが完了するため、導入も簡単
  • 今回の動作確認では、画像取得にソラカメ、画像保存に SORACOM Harvest Files、API 呼び出しに SORACOM Flux を使用。
  • AnnoForge 自体は、WebUI と API の構成なので、他の環境でも同じように利用できる
  • WebUI は GitHub Pages で公開されており、アノテーション付き画像をすぐに試したいときに便利
  • WebUI のアノテーションは JSON 形式で出力され、同じ画角の画像と組み合わせることで、動的に注釈付き画像を生成できる
  • 同じ画像を「アノテーションあり/なし」で Azure OpenAI(GPT-4.1) に投げて比較した結果、どちらも回答精度は低くなかった
  • ただ、アノテーションありの方は「赤線=車道」と明確に理解して応答していた
  • アノテーションを使うことで、AI に「どこを見てほしいか」を直感的に共有でき、テキスト説明だけのときよりブレが少なくなる
  • 渋滞判定、駐車・駐輪エリア管理、侵入禁止エリア監視など、現場に物理的な枠を設けずにデジタルで運用できるのが大きな利点
  • 領域を設定するだけで変更や削除も容易なため、現場での物理的な対応より圧倒的に効率的
  • すぐに試せて、試行錯誤が簡単にできるのは大きな強み
  • 機会があればぜひ試してみてください

以上です。

openai-responses-mcp 開発メモ - Codex と Claude Code を両方使って作ってみた

目次

Please check it.

この記事は 2025年 08 月時点 (以下、現在 / 現時点) の情報に基づいて記載しています。筆者は本記事を執筆した現時点において 株式会社ソラコム に所属していますが、本記事の内容は あくまでも筆者個人の見解に基づくものであり、所属する会社または組織とは一切関係ございません。


(参考)
「一般消費者が事業者の表示であることを判別することが困難である表示」の指定及び「『一般消費者が事業者の表示であることを判別することが困難である表示』の運用基準」の公表について

前提

openai-responses-mcp というものを作ってみました。
この記事は、その開発メモと簡単な紹介です。

主に自分用の備忘録という位置づけで書いているので、深掘りした比較検証記事というよりは、実務で手を動かす中での気づきや使い勝手を残した「技術メモ」に近い内容になっています。

開発の過程では、GenAI のコーディング支援ツールである OpenAI Codex と Claude Code を利用しました。ただ、あえて条件を整えて比較検証したわけではなく、日々の業務の中で適当に両方を使い分けながら、

  • どちらがどの局面で効いたか
  • 実際に使ってみての所感
  • 次に活かすための判断材料

といった内容をナラティブに記載したものです。 開発者の方や、生成AIによるコーディング支援ツールに興味がある方にとって、何かしらの参考になれば幸いです。

openai-responses-mcp

実際に作ったものは以下です。

openai-responses-mcpは OpenAI Responses API を利用して stdio(ローカル)接続で動作する MCP サーバーです。

特徴としては以下の通りです:

  1. GenAI のコーディング支援ツールのみで作成

    • 人がコードを直接書いたり変更したりせず、すべて生成 AI によって開発しました。
  2. MCP ツールは 3 種類

    • ただし、それらの呼び出しは MCP クライアント側に委ねています。クライアント側のLLMが良い感じに判断して使ってくれる想定です。
  3. モデル更新への柔軟な対応

    • gpt-5 以降の新しいモデルが公開されても、OpenAI Responses API が使える限り、設定変更だけで切り替え可能な想定で作っています。

GenAI に丸投げしてるので、コードの詳細は確認していないですが、簡単に動作確認した感じでは問題なく動作していると思います。gpt-5 モデルをMCP経由で呼び出しするという部分では活用できるものになってるのではないかと思います。

*設定やポリシーについての詳細は、GitHub リポジトリを参照してください

動作要件

  • Node.js v20 以上(推奨: v24)
  • npm(または npx が使える環境)
  • 環境変数 OPENAI_API_KEY に OpenAI API Key

Claude code への設定例

  • claude code cli :
claude mcp add -s user -t stdio openai-responses -e OPENAI_API_KEY=sk-xxxx -- npx openai-responses-mcp@latest --stdio

  • ~/.claude.json :
"openai-responses": {
    "type": "stdio",
    "command": "npx",
      "args": [
        "openai-responses-mcp@latest",
            "--stdio"
        ],
      "env": {
            "OPENAI_API_KEY": "sk-xxxx"
    }
}

Codex への設定例

  • ~/.codex/config.toml :
[mcp_servers.openai-responses]
command = "npx"
args = ["-y", "openai-responses-mcp@latest", "--stdio"]
env = { OPENAI_API_KEY = "sk-xxxx" }

CLAUDE.md や AGENTS.md への指示例

### 問題解決方針

開発中に問題や実装上の困難に遭遇した場合:

1. **必ず openai-responses MCP に相談すること**  
   - 相談は最優先かつ必須とする  
   - 独自判断での実装は絶対に行わない  

2. **質問は必ず英語で行うこと**  
   - openai-responses MCP への質問はすべて英語で記載する  

3. **代替手法や最新ベストプラクティスの調査**  
   - openai-responses MCP を活用して解決手段や最新のベストプラクティスを収集する  

4. **複数の解決アプローチを検討すること**  
   - 一つの方法に即決せず、複数の選択肢を比較検討した上で方針を決定する  

5. **解決策を文書化すること**  
   - 問題解決後は、再発時に迅速に対応できるよう手順や解決方法を記録しておく  

実際にはこの内容をLLMに渡して、「AIにとってわかりやすい、伝わりやすい英語に翻訳してくれ」 という指示で翻訳された内容を利用しています。

AIにわかりやすい文章はAIに作ってもらいましょうという感じです。

なぜ作ってみたのか?

GPT-5 のリリースをきっかけに、これまで自分用のローカルツールでちょこちょこ使っていた GenAI のコーディング支援ツールを、もう少し本格的に試してみたくなりました。

そして「どうせ使うなら、とことん楽をしたい」という単純な理由もあります。

もともとは Claude Code に、次の MCP ツールを追加して使っていました。

  • o3-search-mcp(OpenAI o3 モデルを呼び出せる) :

    github.com

この組み合わせはとても便利で、特に o3-search-mcp があることで、実行時エラーへの対処やライブラリ利用時の最新情報確認が格段に楽になっていました。

そこで、最近リリースされた最新モデル GPT-5。
コーディング性能が向上し、いわゆる リーズニングモデル という位置づけでもあったため、o3 モデルからの切り替えを試してみたいと考えました。

ChatGPT 5 に使い方を聞いてみる

そこでまず、ChatGPT 5 に「Claude Code を MCP クライアントとして利用して、gpt-5 モデルを呼び出す方法」を尋ねてみました。
やはり本人(gpt-5 モデル)が一番よく知っていそうですから。

すると、次の 3 つの方法が提示されました。

  1. MCP サーバーゲートウェイ的なプロダクトを利用する方法
  2. Codex の MCP サーバーモードを利用する方法
  3. 自分で軽量な MCP サーバーを作成する方法

このうち 1 と 2 は既存のプロダクトを利用する方法 で、3 は実装が必要な方法です。
とりあえず試してみるだけなら、既存のプロダクトを利用するのが早そうだと判断しました。

ただし、1 の汎用プロキシのようなプロダクトを利用する構成は、今回の用途には少しオーバースペック気味。
そこでまずは Codex をインストールして MCP サーバーとして利用してみることにしました。

OpenAI Codex CLI

OpenAI が公式に提供している Codex CLI を、GitHub の手順を参考に npm からインストールしました。
認証は OpenAI API Key を環境変数に設定して利用します。

インストールとAPI Keyの設定が終了すればこの状態で、Codex はそのままコーディング支援ツールとして利用可能です。
ただし、デフォルト設定ではファイルの読み書きやネットワークアクセスに制限が設けられています。

通常の「コーディング支援」としての利用であれば、行動の最終判断は人間が行うため大きな問題にはなりません。

しかし MCP サーバーとして利用する場合は、例えばネットワークアクセスが制限されていると許可が必要になったり、実際に Codex CLI を使うと 承認確認でユーザーの入力待ち状態になるケースがあります。

これらを自動承認や常時許可にしておかないと、MCP クライアント側では応答が止まったままになり、タイムアウトして利用できない、あるいはネットワークアクセスがずっと許可されないといった状態になってしまいました。

詳細な設定内容は公式 GitHub のドキュメントで確認できます。

私が実際に利用した設定は以下の通りです。

  • ~/.codex/config.toml :
model = "gpt-5"
approval_policy = "never"
sandbox_mode = "read-only"
network_access = true

なお、MCP サーバーでの動作は It is somewhat experimental と明記されているため、今後仕様や挙動が変わる可能性があります。 その点は注意が必要です。

Claude Code では以下の設定で動作を確認しました。

  • ~/.claude.json :
"codex": {
      "type": "stdio",
      "command": "codex",
      "args": [
        "--ask-for-approval",
        "never",
        "--sandbox",
        "read-only",
        "mcp"
      ],
      "env": {}
}

実際に Claude Code から Codex を呼び出してみると、例えばこんな感じで動作しました。

  • Claude Code での呼び出し例 :
> Codexを利用して今日の最新の東京都の気温を調べてく教えてください

⏺ Codexを使って今日の東京都の最新気温を調べます。

⏺ codex - codex (MCP)(prompt: "今日2025年8月20日の東京都(大手町)の最新気温を調べて教えてください。ウェブ検索を使って気象庁のデータから最新情報を取得
                     してください。")
  ⎿  以下が気象庁(AMeDAS「東京」:都心代表地点)の最新値です。

     - 最新気温: 32.4 ℃
     … +9 lines (ctrl+r to expand)

⏺ Codexを使って調べた結果、今日(2025年8月20日)の東京都の最新気温は以下の通りです:

  最新気温情報
  - 気温: 32.4°C
  - 観測時刻: 2025年8月20日 16:40 JST
  - 観測地点: 東京(AMeDAS局44132)

  補足情報
  - これは気象庁の公式AMeDASデータから取得した最新の観測値です
  - 観測地点は都心代表地点で、従来の大手町観測所は2014年12月2日に北の丸公園に移転しています
  - データ品質フラグは「0」(有効値)となっています

  現在32.4°Cと非常に暑い状況が続いています。

このように、MCP サーバーとして一応動作させることはできました。

ただし実際に使ってみると、

  • ネットワークアクセスの許可確認が何度も入る
  • そもそも「アクセスできない」という返答が返ってくることがある
  • 日本語での問い合わせ時には追加の確認ややり取りが発生しがち

といった点があり、安定性には少し難ありという印象でした。 サクッと試す程度なら問題ありませんが、実際にコードを書いていく場面では使いづらさを感じました。

というわけで軽量な MCP サーバーを自作する

Codex の MCP サーバーが o3-search-mcp の使い心地には遠く及ばず……という印象だったので、最後の 3 番目である 自作 を試すことにしました。

せっかく作るなら o3-search-mcp を参考にしつつ設定のバリエーションを少し増やす 方針に。
あわせて Codex をインストール したので、Codex を実際に使ってみる ことにしました。

とはいえ、普段は Claude Code を使っているため、最初のインプットやある程度のところまでは Claude Code で作成 しています。

さらに、Claude Code では spec.md に会話しながら仕様を AI に記述してもらう 形にしました。
こうしておくと、途中で コーディング支援ツールを切り替えたり、AIでの作業を中断して人が多少修正しても、AI へのインプットとして利用できる情報が 1 箇所に集約 されます。

Kiro や Tsumiki ほどかっちりしていなくても、メモ程度でもあった方が断然便利 なので、この方法を採用しています。

また、コーディング支援ツールへのインプットとして、Claude Code なら CLAUDE.md、Codex なら AGENTS.md を使って、ツールの動作指示を与えています。

ここはツール間で大きな違いはなく、最低限守ってほしいことややりとりのルールなど、私の好みを反映 したファイルになっています。

実際に作った openai-responses-mcp を Claude Code と Codex の両方に設定して使っていますが、いまのところ 便利で、o3-search-mcp と同じような体験 ができています。

精度や内容で気になる点は特になし。強いて言えば、MCP サーバーを呼び出してから結果が戻るまで、o3 モデルより gpt-5 モデルの方が少し時間がかかる かなーと感じるくらいです。

ツールの呼び分け についても、MCPクライアント側がいい感じにやってくれる ので、概ね 思った通りの動作 になっているように感じます。

以下が実際に Claude Code とCodex で明示的に指示して、openai-responses-mcp の動作を確認した結果です。

  • Codex での呼び出し例 :
user
openai mcp を使って今日の最新の東京の天気を教えてください。とても急いでいるので精度よりスピードを重視してください。クイックに回答してほしい

codex
MCPで「東京の今日の天気」を高速検索します。結果をすぐ要約して返します。

tool running...
openai-responses.answer_quick({"query":"Tokyo weather today"})

tool success, duration: 23.14s
openai-responses.answer_quick({"query":"Tokyo weather today"})

{"answer": "Tokyo weather today (2025-08-19 JST):\n- As of 13:57, it's mostly sunny around 34°C (93°F). \n- Forecast for the rest of today: partly sunny,
hot and humid. High 34°C (93°F), low 26°C (80°F). Stay hydrated if outdoors. \n\n- Key points:\n  - Date/time (Tokyo): 2025-08-19 13:57 JST. \n  - Current
conditions: Mostly sunny, ~34°C (93°F). \n  - Today's range: High 34°C/93°F, Low 26...

thinking
Interpreting weather data

I received a structured JSON that indicates the date is 2025-08-19 and that the weather is mostly sunny at 34°C—perfect, since it matches today. However,
there are no citations provided. The user's request prioritizes speed, so I can deliver this info in Japanese quickly. While I didn't perform a recency
check as per AGENTS.md guidelines, I can note the time as 13:57 JST. I'll structure my response in bullet points and keep it concise. No fabrications here,
just the tool's output!

Delivering quick weather update

I see that the user just wants a quick weather update, so I can ask a follow-up question about hourly breakdowns: "時間ごとの内訳が必要ですか?", but I
should keep it simple. The environment restricts some features, but the tool worked, so that's good. I'll avoid heavy formatting as per CLI guidelines and
use bullet points instead.

Here's a quick summary in Japanese:

- 今日の東京の天気(2025-08-19 JST)
- 現在: 晴れがち、約34°C
- 予報: 午後は所により晴れ、蒸し暑い。最高34°C、最低26°C
- 注意: こまめな水分補給
- 出典: 更新時刻: 13:57 JST


codex
- 今日の東京(2025-08-19 13:57 JST 時点)
- 現在: 晴れがち、約34°C
- 本日予報: 部分的に晴れ、暑く湿度高め
- 気温: 最高 34°C / 最低 26°C
- メモ: 炎天下の外出はこまめな水分補給を

時間別や雨アラートが必要ならお知らせください。

  • Claude Code での呼び出し例 :
> openai mcp を使って現時点のソラコムの株価を教えてください。回答時間よりも詳細さや内容を重視して確認してます

⏺ openai-responses - answer_detailed (MCP)(query: "ソラコム株価 現在 最新 SORACOM 6569")
  ⎿ {                                                                                                                                                  
      "answer": "結論\n- ソラコム(東証グロース: 147A)の最新終値は 1,312円です(2025-08-20 15:00 JST、当日高値 1,340円/安値 1,301円、前日比
    +3.06%)。([irbank.net](https://irbank.net/147A/p
    br?utm_source=chatgpt.com))\n- なお、証券コード「6569」はソラコムではなく日総工産のコードで、同銘柄はすでに上場廃止となっています。ソラコムの正しい
    証券コードは「147A」です。([blog.soracom.com](https://blog.soracom.
    … +26 lines (ctrl+r to expand)

⏺ ソラコム(東証グロース: 147A)の現在株価

  最新株価情報
  - 終値: 1,312円(2025-08-20 15:00時点)
  - 日中値動き: 高値 1,340円 / 安値 1,301円
  - 前日比: +3.06%(上昇)

  重要な注意点
  - ソラコムの正しい証券コードは「147A」です
  - よく間違われる「6569」は日総工産のコード(既に上場廃止)
  - 2024年3月26日に東証グロース市場に上場

  データの精度について
  - 取引所表示は通常15~20分のディレイあり
  - リアルタイム価格が必要な場合は証券会社アプリやPTS取引をご確認ください

  追加情報が必要でしたら
  - リアルタイム板情報
  - PTS(夜間取引)価格
  - 価格アラート設定
  - ドル換算価格

  なども調べることができます。

  • Claude Code での呼び出し例 :
  > openai mcp を使って素早く今日の東京の天気を調べてください。急いでます

⏺ openai-responses - answer_quick (MCP)(query: "今日の東京の天気")
  ⎿ {                                                                                                                                                  
      "answer": "今日(2025-08-19, Asia/Tokyo)の東京(東京都心)の天気:晴れ、非常に暑い。現在の気温は約34°C、午後は最高36°C前後、夜にかけて徐々に下が
    り29°C前後。午後は「晴れ〜曇り」で熱中症レベルの暑さに注意してください。\n\n- 要点:晴天・猛暑
    (最高約36°C)、午後も気温高め、夜はやや涼しくなる(約29–31°C)。\n-
    推奨:屋外の長時間作業や運動を避ける。こまめな水分補給・冷房利用を。\n\nSources:\n- tenki.jp — 東京都心(大手町)実況・予報ページ.
    https://tenki.jp/past/202
    … +6 lines (ctrl+r to expand)

⏺ 今日(8/19)の東京の天気

  - 晴れ、猛暑
  - 現在:34°C
  - 最高:36°C前後
  - 夜:29°C前後

  :warning: 熱中症レベルの暑さ - 水分補給と冷房利用必須

  • Claude Code での呼び出し例 :
> opneai MCP を使って今日の最新の東京の気温を調べて教えてください

  openai-responses - answer (MCP)(query: "今日の東京の気温 最新の天気情報")
  ⎿ {                                                                                                                                                  
      "answer": "東京の最新の気温・天気(2025-08-19 12:10 JST 時点)\n- 現在の気温: 34°C、晴れ。非常に蒸し暑く、屋外活動は熱中症に注意が必要です。 \n-
    今日の予想(2025-08-19 火): 最高 36°C / 最低 26°C、所により薄曇りで厳し
    い暑さが続きます。長時間の屋外は脱水・熱中症に注意。 \n- 明日の傾向(2025-08-20 水): 曇りがちで暑く、所により午後に雷雨の可能性。予想 36/26°C
    前後。 \n\nポイント\n- こまめな水分・塩分補給、日陰・冷房の活用、屋外ではこまめに休憩を。 \n\n必要なら、時間帯
    … +5 lines (ctrl+r to expand)

⏺ 今日(2025年8月19日)の東京の最新気温情報をお調べしました:

  現在の状況(12:10時点)
  - 気温:34°C(晴れ)
  - 非常に蒸し暑い状態

  今日の予想
  - 最高気温:36°C
  - 最低気温:26°C
  - 天候:所により薄曇り

  注意点
  - 厳しい暑さが続いているため、熱中症対策が必要
  - こまめな水分・塩分補給
  - 日陰や冷房の活用
  - 屋外での長時間活動は避ける

  非常に暑い一日になっているので、外出時は十分お気をつけください。

Claude Code での呼び出し例をよく見てもらえると、answer / answer_detailed / answer_quick の3つのツールを、指示の内容によってMCPクライアント側が判断して呼び出しているのが確認できるかと思います。

Claude Code と OpenAI Codex

正直なところ、どちらを使っても動くコードを作ること自体には大きな差はない、というのが個人的な感想です。

ただし 体験面 でいうと、圧倒的にストレスなく使えているのは Claude Code でした。
強く残念に感じた点としては、CLAUDE.md に書いてある内容をしばしばスルーして対応してしまうことが少なくなかった、という印象です。

話題になった Serena を導入すれば改善されるのかもしれませんが、そこまで困っていないためまだ試してはいません。

また、Claude Code は アップデート頻度が非常に高い 印象です。VSCode のプラグイン更新通知もよく目にしますし、開発が活発なので今後もどんどん改善されていきそうです。

一方で OpenAI Codex は、まだ開発途上という雰囲気があります。

最初に試したバージョンでは、CLI の出力が固定長で改行されてしまうため、ファイルパスが折り返されてコピー&ペーストで使いづらいといった問題がありました。地味な部分ですが日々コードを書いていると、こういう地味なところが案外ストレスになるという感じがします。

また、別の段落でも触れましたが、権限確認などの制御が多く、安全寄りに設計されている印象があります。良い面ではあるものの、体験としてはややまどろっこしく、Web 検索も積極的には行ってくれない感じを受けました。

両方にそれぞれ良い点・気になる点がありますが、まとめると個人的には以下のようになりそうです。

  • Claude Code

    • やりとりのテンポが良く、反復も速い
    • 気持ちよく「勢い」を保って個人開発を進められる
  • OpenaAI Codex

    • 手続きや規約を重視する方向
    • 確認やレビューを任せる用途に向いている感じを受ける

さらに、画像やクリップボード上のバイナリ(画像データ)の扱いにも違いがありました。
Claude Code はそのままテキストインプットエリアにコピペして確認の依頼が可能ですが、Codex はバイナリ貼り付け NG。ファイルについても、プロジェクト外のパスだと読み込みを渋る傾向があるようです。

ただし両方とも、playwright-mcp 経由でスクリーンショットを撮る という指示では問題なく動作して確認してくれました。

結局どっちがいいのか?

最終的な感想としては、好きな方を使えばいい、というところに落ち着きました。
参考にならないかもしれませんが、どちらを選んでもある程度の成果物は作れてしまうと思います。

これはめちゃくちゃスゴイことで、だいぶ適当に指示を出しても「動くもの」ができあがってしまうことになります。
もちろん品質や精度は別の話なので、そこにこだわろうとすると途端に大変になりそうですが、ちょっとした動作確認のハードルが圧倒的に下がっている感じがします。

選ぶポイント

  • 速度・反応・安定感を優先するなら
     → Claude Code

  • 権限や明示的な許可、指示書や規約に沿った動作を求めるなら
     → OpenAI Codex

という感じで、自分の重視する体験にあわせて選ぶのが良さそうです。

API Key 周りの使い勝手

どちらも API Key で利用できる のはありがたい点です。
ユーザー単位での設定は面倒になることが多いので、個人的にはとても良いユーザー体験でした。

特に Claude Code は Amazon Bedrock の API Key でも簡単にセットアップして利用できる のが好印象で、とても良い体験だと感じました。

まとめ

  • 結構雑にやっても 動くものはできた
  • Claude Code でも OpenAI Codex でも、どちらでもそれなりの成果物は作れる
  • 途中で仕様変更や追加をすると、既存コードやドキュメントへの反映漏れが多かった
  • 変更を反映するよりも、最初からゼロイチで作り直した方が整合性が取れやすいと感じた
  • ゼロから 1 にする作業の方が圧倒的に安定している印象
  • openai-responses-mcp を作ったのは結果的に良かった
    • Codex を使うきっかけにもなった
    • 「急いで」「素早く」「詳しく」などのキーワードを入れるだけで、MCP クライアント側がツールを切り替えてくれる
    • これは地味に便利
  • Codex にも openai-responses-mcp を設定して利用でき、インターネット経由での確認も楽になった
  • gpt-5 モデルの応答は少し時間がかかるので、o3 モデルより少し長めの待ちが必要
  • 今は Codex でも Claude Code でも、今回作った MCP を利用中
  • 問題や調査が必要な時に、コードエージェント側が勝手に調べてくれるので楽
  • 「急いで」「詳細に」といったキーワードにも反応して、検索ツールを自己判断で切り替えてくれるのも便利
  • 動作速度や反応は Codex より Claude Code の方が体感的に良い
  • いずれにしても、AI にコードを書かせてリポジトリ管理からリリースまで一通り回せたのは良い経験
  • 実際に試すことは大事だと実感
  • 削除したはずの仕様が残ったり、新旧の仕様が混ざったりして 整理は大変
  • 全体を俯瞰して編集するのはやや苦手そう
  • また、コードを動く方向に直すものの、仕様としてはどうなのか?と思う修正もあった

最後に

  • 選ぶポイントは色々あるけど、最終的には 自分の環境で試すのが一番の近道
  • 小さく試してから判断するのがおすすめ
  • 作ってみたのは結果的に良かったが、Codex の公式 MCP 対応が整ってきたらそちらに乗り換える方が良さそう
  • 良い開発体験を!

以上です。

Following is in English

medium.com

ちょっと便利かも? SORACOM Flux のちょい足し小技集

目次

Please check it.

この記事は 2024 年 12 月時点 (以下、現在 / 現時点) の情報に基づいて記載しています。現時点では 株式会社ソラコム に所属していますが、本記事の内容は あくまで個人の意見であり、所属する会社や組織とは一切関係ありません。


(参考)
「一般消費者が事業者の表示であることを判別することが困難である表示」の指定及び「『一般消費者が事業者の表示であることを判別することが困難である表示』の運用基準」の公表について

SORACOM Advent Calendar 2024

公開が遅れてしましましたが、この記事は SORACOM Advent Calendar 2024 の 21 日目の記事です。

qiita.com

今回は SORACOM Flux を使っていて「ここ、もうちょっとこうだったらいいのになぁ」と思う部分を、なんとか上手くできないか試してみました。 ちょっとしたお役立ちネタとしてまとめたので、SORACOM Flux を使うときに「これいいかも」と思ったら、ぜひ参考にしてもらえると嬉しいです。

SORACOM Flux

SORACOM Flux(以下、Flux)は、デバイスから送られてくるセンサーデータやカメラ画像にルールを適用し、複数のデータソースや生成AIを組み合わせて分析・判断を行える、IoT アプリケーションをローコードで構築できるサービスです。詳しくは、以下のリンクを参照してください。

soracom.jp

users.soracom.io

Flux を使うと、複数のサービスを連携させて、「やりたいこと」を手軽に実現できます。イメージとしては、IFTTT や Zapier のような iPaaS(Integration Platform as a Service)を思い浮かべてもらうとわかりやすいと思います。

現在は初期リリース段階で、Free プランのみが利用可能です。ただ、2025年3月4日から有償プランの提供開始 が予定されており、今後どのように進化していくか楽しみなサービスです。

soracom.jp

今回は現在の Flux でできる範囲でいろいろ試してみた内容をまとめました。

1. Flux から Slack に通知した画像がずっと表示されてたらいいのになぁ

例えば、以下のリンク先のようにSORACOM Harvest Files にアップロードした画像を 生成AI で判定して、その判定結果と一緒に画像を Slack に通知するケースを考えてみます。

users.soracom.io

この場合、Slack に通知されるのは SORACOM Harvest Files にアップロードした画像の URL です。ただ、この URL は Amazon S3 の署名付き URL(Pre-Signed URL) になっています。 署名付き URL についての詳細は、以下の公式サイトを参照してください。

docs.aws.amazon.com

ここで気になるのが、この署名付き URL には有効期限があるということ。有効期限が切れると、Slack 上でも画像のプレビューが表示されなくなりますし、URL をクリックしても画像を見ることができなくなってしまいます。

過去のハマりポイント

署名付き URL の有効期限については、すごい昔にハマったことがありますw 詳しくは昔書いたこちらの記事にまとめてあるので、興味があれば参考にしてください

uchimanajet7.hatenablog.com

署名付き URL の有効期限を確認する方法

Flux から通知された署名付き URL の有効期限を確認したい場合、以下のURL中パラメータをチェックすることで確認できます。

  1. X-Amz-Expires に URL の有効期間(秒数)が記載されています。
  2. X-Amz-Date に 署名が作成された時刻(UTC)が記載されています。
  3. 有効期限の計算方法 は X-Amz-Date に X-Amz-Expires の秒数を加算することで計算できます。

試しに手元で確認してみたところ、X-Amz-Expires=3600 が指定されていました。つまり、署名作成時刻から1時間が有効期限 ということになりますね。

Slack 通知を署名付き URL ではなくファイル添付にできないのか?

署名付き URL に有効期限があるなら、いっそのことファイルそのものを Slack の通知に添付してしまえば解決しそうですよね。

そこで、まずは Flux の Slack 通知アクションを再確認してみました

users.soracom.io

どうやら、Slack メッセージの送信には以下の公式サイトに記載があるリッチな表現が使えるようです

api.slack.com

ただ、これを活用しても通知できるのは結局 URL のみで、どうやらこれは Slack 側の仕様のようです。

ファイルを直接アップロードする方法を探してみた

「じゃあファイルそのものをアップロードする方法は?」と思い調べてみると、Slack にはファイルをアップロードするための API が別に用意されていることがわかりました。まず目に入ったのが以下の files.upload API です

api.slack.com

ところが、この API は 2025年3月11日に廃止予定 とのこと 詳細については、以下を参照してください

api.slack.com

新しいファイルアップロード方法

廃止後の移行先として、Slack では新しい方法が提供されています 詳細については、以下を参照してください

api.slack.com

簡単に手順を記載すると

  1. files.getUploadURLExternal APIでファイルアップロード用のURLを取得する

    api.slack.com

  2. 1 で取得したURLに対して実際にファイルを送信してアップロードする

  3. files.completeUploadExternal API でファイルアップロード処理を終了する
    • この処理で実際に指定したSlackチャンネルに画像を投稿できます

    api.slack.com

これらの手順を踏めば、ファイルを直接 Slack チャンネルに添付して投稿できるようになります。 ただし、Slack App に必要な権限を追加する必要がある点には注意してください。

users.soracom.io

Flux から Slack にファイルをアップロードしてみる

というわけで、実際に Flux を使ってファイルのアップロードを試してみます。

まず、SORACOM Harvest Files イベントソースを利用して、画像ファイルが SORACOM Harvest Files にアップロードされたらアクションが実行されるように設定します。

users.soracom.io

次に追加するアクションとして、SORACOM API アクションを利用して、SORACOM Harvest Files から実際に画像をダウンロードしてみることにしました。

users.soracom.io

画像をダウンロードする API

SORACOM Harvest Files からファイルをダウンロードするには、以下の getFile API を利用します

users.soracom.io

この API の URL には、画像ファイルが保存されている場所を指定する必要があります。そこで、イベントがキックされた際に受け取るペイロードから、必要な情報を渡して実行します。

具体的には次のような形で指定します /v1/files/private${event.payload.path}

送られてくる path の先頭にすでに / が付いているので上記のような指定の方法となってます。

Flux アプリを実行してみた結果

作成した Flux アプリをいざ実行してみると、以下のようなエラーが発生しました

FLX0306
エラー
Failed to send a http request. Response too large. Max size: 8192 bytes, Content length: 141136 bytes

このエラーメッセージを見る限り、どうやら Flux 側で受け取れるレスポンスのサイズに制限があるようです。今回は画像データが対象だったため、サイズが大きすぎて制限を大幅に超えてしまいました。

結果としては残念ながら、Flux 自体の制限によってこの方法では実行が難しいことがわかりました。 今後のアップデートでのサイズ制限まわりの改善に期待ですね。

画像ファイルのファイルサイズを小さくしてみたら?

Flux 側で受け取れるサイズに制限があるなら、ファイルサイズを小さくして制限内に収めればいいのでは?と思い、試してみました。 Flux はローコードをコンセプトにしているので、なるべくコードを書かずに実現できる方法を探してチャレンジしてみました。

色々と調べてみると、TinyPNG というサービスを使えば、画像の圧縮やフォーマット変更、リサイズなどが API 経由で実行できそうです。

tinypng.com

API を呼び出せるなら、Flux の Webhook アクション を使えば簡単に試せそうです

users.soracom.io

TinyPNG の詳細は公式サイトを参考にしてください 利用する場合には必ずご自身で詳細を確認し、不明点があれば TinyPNG に確認をお勧めします

tinypng.com

tinypng.com

Tinify API を使う手順

以下のAPIリファレンスを参照して TinyPNG の API (Tinify API) を試してみます

tinypng.com

簡単な手順を記載すると

  1. APIキーを取得する
    • 以下のページから登録して API キーを取得します

      tinypng.com

  2. API 認証について準備する
    • API との認証は HTTP Basic Auth を使います
    • ヘッダーに以下の形式で認証情報を付与します
  3. APIを使って画像ファイルをアップロードする
    • 画像ファイルをアップロードすると自動的に圧縮されます
    • 画像ファイルを直接アップロードする代わりに URL を指定する方法もあります
    • Flux から利用する際には、このURLにSORACOM Harvest Files の署名済みURLを指定します
    • アップロードが成功すると、圧縮済み画像のダウンロード URL が返ってきます
      • Location ヘッダー に URL文字列が記載されています
  4. APIを利用して圧縮後の画像をダウンロード
    • アップロード結果の Location ヘッダーで指定されたURLから画像がダウンロードできます
    • このダウンロードのために TinyPNG 側で画像は最大 48 時間保持 されます
    • そのため、指定されたURLにWebブラウザでアクセスすると画像が表示できます

という感じで、圧縮された画像を取得できることがわかります。 このほかにもAPIでは、アップロードされた画像に対して 画像のサイズ変更 や 画像フォーマットの変換を行ってから、ダウンロードを実行することもできます。

単純に自動圧縮の画像を利用した場合

まずは1番手軽に試せる、自動圧縮された画像のダウンロードを実行してみましたが

Failed to send a http request. Response too large. Max size: 8192 bytes

という結果で、これまでと同じくFlux側の制限を超えることはできませんでした。

画像フォーマットを変換した場合

次に、画像フォーマットの変換を試してみました。

TinyPNG では高圧縮率の AVIF フォーマットが利用可能でしたが、Slack 側が対応しておらず、AVIF をアップロードすると単なるバイナリファイル扱いとなり、プレビューが表示されませんでした。 そこで、JPEG を WebP フォーマットに変換してみましたが、結果は変わらずFlux側の制限を超えることはできませんでした。

画像のリサイズを行った場合

最後に、画像のリサイズを試してみました。

こちらは、画像サイズを可能な限り小さくしていけば、Flux側の制限に当たらないサイズにはできましたが、今度は画像が小さすぎて内容がほぼ見えなくなるという結果になりました。 この状態ではファイルを添付しても意味がないので、結果として目的は果たせないことになりました。

Slack API を使ったファイルアップロードを試してみる

とはいえ、せっかくなのでリサイズで小さくした画像を使って、Slack へのファイルをアップロード試してみることにしました。

事前に確認した手順に沿って、まずは files.getUploadURLExternal API を呼び出します

api.slack.com

Flux からこのAPIを呼び出す際には Content-Type を application/x-www-form-urlencoded と指定することと、合わせて POST Body に token=xoxb-xxxx&length=8192&filename=example.jpg のようなkey=value&key=value... の形式で必要な情報を記載することに注意すれば、問題なく Flux から呼び出しを行えました。

残念ながら

ここまでは、なんとかなったのですが、次に files.getUploadURLExternal API の戻り値で指定されたURLに、画像データをアップロードする部分がうまく行かずに失敗となりました。エラーとしてはこれまでと同じくFlux側の制限でエラーとなってしまったので、これ以上方法はなさそうでした。残念。

それ、Make ならできるよ!

他の iPaaS(Integration Platform as a Service)はどう対応しているのか気になったので、Make で試してみました。

Make とは?

Make は、以前は Integromat と呼ばれていた iPaaS です。同じようなサービスだと IFTTT や Zapier のほうが馴染みがあるかもしれませんね。

www.make.com

Make はノーコードで複数のサービスをつなげて、やりたいことを手軽に実現できるのが特徴です。 ただ、名前がシンプルすぎて Web 検索しづらいのが難点ですねw とはいえ、公式ドキュメントが充実していて、UI も直感的なので、利用には特に困らないと思います。

Make で Slack へのファイルアップロードを試してみる

まず、Flux 側では Webhook アクションを使い、署名済み URL を Make に送信する簡単な Flux アプリを作成します。

次に、Make 側で以下の手順を設定しました

  1. Webhook を受け取る
    • 署名済み URL を受け取るために Webhook を使用します

      www.make.com

  2. 画像をダウンロードする
    • 受け取った URL から画像を取得するために HTTP モジュールを使用します

      www.make.com

  3. Slack に画像をアップロードしてメッセージを送信
    • 画像を Slack の指定チャンネルにアップロードし、メッセージを投稿します。

      www.make.com

実際にやってみたら

これら 3 つのモジュールを組み合わせて、画像ファイルを Slack にアップロードするシナリオを作成しました。

特に複雑な設定は不要で、インプットされた値をそのまま利用するだけで問題なく動作しました。そして、Slack にアップロードされたファイルは Slack 側で保持されるため、署名済み URL の有効期限の問題から解放されました。

Make を使えば簡単に実現できたので、今後 Flux でも同様の対応できるようになる可能はゼロではなさそうです。もし「こういう機能があればいいな」と感じたら、ぜひソラコムにフィードバックしてみてください!

2. Flux のタイマーイベントを日時指定で設定できたらいいのになぁ

Flux で定期的に処理を実行したい場合、タイマーイベントを利用することになります。

users.soracom.io

ただし、現時点では一定間隔での間欠的な動作しか設定できません。 今後、有償の Standard プラン を利用することで、スケジュールタイマー(Cron 設定)が可能になる予定のようです

soracom.jp

現状の代替案

現時点で日時指定に近い動作を実現する方法として、以下のようなアプローチが考えられます

  1. タイマーイベントで間欠動作を起こす
  2. アクション側で「実行条件」を設定する

例えば、次のような実行時間帯を指定する条件を設定できます (getUTCHours(now())+ 9 >= 5) && (getUTCHours(now())+ 9 <= 18)

この方法を使えば、特定の時間帯にのみ処理を実行することが可能です。ただし、やはり直接日時を指定できるわけではないので少し手間がかかります。

今後、スケジュールタイマー機能が正式に対応されれば、Flux の利用がさらに便利になりそうですね。

Slack には日時指定で実行できる仕組みがある

Slack をいろいろ調べていたところ、reminder スラッシュコマンドや workflow のトリガーで日時指定ができる仕組みがあることを思い出しました。これを使って、Slack から Flux アプリを起動する仕組みを試してみることにしました。

Slack から Webhook を送信する方法

まず、Slack 側から Webhook を送信する必要があります。以前は Outgoing Webhooks を使えば簡単に実現できましたが、現在は非推奨 We do not recommend their use. となっており、将来的に利用停止となる可能性を考慮する必要があります。

api.slack.com

代わりに、Events API を使えば同じようなことが実現できるようなので、こちらを試してみることにしました

api.slack.com

Events API の設定

Slack App 側で必要な権限を設定し、Webhook の送信先 URL を Slack の管理画面で登録します。この際、以下の仕様に従って返信を行う必要があります

We’ll send HTTP POST requests to this URL when events occur. As soon as you enter a URL, we’ll send a request with a challenge parameter, and your endpoint must respond with the challenge value.

api.slack.com

試したみたものの

現在の Flux の Incoming Webhook では、受け取ったデータを任意の形で返信することができません。そのため、Slack からの送信先として Flux の Webhook URLを設定できませんでした。

一方で、以前の Outgoing Webhooks を使えばこの制限を超えられそうですが、非推奨機能であり今後利用停止の可能性があるため、今回は採用を見送りました。

とはいえ、現状 Flux 側の仕様で Webhook の返信ができないため、Slack をトリガーとして Flux を日時指定で動かす方法は見つかりませんでした。今後のアップデートや新機能に期待したいですね

それ、Make ならできるよ!

さて、また登場の Make です。やっぱり iPaaS として提供されているだけあって、細かいところまでしっかり作り込まれている印象を受けますね。

Flux で Slack からの Webhook を受け取れなかった原因は、challenge response を返せなかったからでしたが、Make にはこれに対応できる仕組みが用意されていました。

Webhook に応答できる Make の機能

Make では、受け取った Webhook に対して応答を返すことができるモジュールが用意されています

www.make.com

この機能を使うと、Webhook の内容に応じたレスポンスを返すことができます。 また、Slack の Event API を利用する場合は、通常の利用時にも HTTP 200 OK を返す必要があります

api.slack.com

Slack からの Webhook を Flux に送信する

Slack から受け取った Webhook を Flux に送信するには、Make の Make a request モジュールを使用します

www.make.com

今回は動作確認のため、固定の POST Body を送信しましたが、Slack からの Webhook には入力された文字列が含まれているので、この仕組みを使えば、Slack で指定した ID のソラカメから画像を取得する、といった処理も可能だと思いま

Slack の Workflow Builder でスケジュール実行する

ここまで準備できたら、あとは Slack 側で Workflow Builder を使ってスケジュール実行を設定します。Slack の UI で簡単に設定できるので手軽です。

スケジュール設定ではプルダウン形式で時間を選択するように見えますが、実は直接入力することで選択肢にない時間も設定可能です。細かい時間指定が必要な場合は試してみてください。

ちなみに、Slack のスラッシュコマンドで実行できる reminder コマンド を使う場合、Bot に対してメンションを行えないという制約があるため、reminder を使ったスケジュール設定はできませんでした。

Make を使ったスケジュール実行の利点

Make を挟むことで、UI を使ったスケジュール実行が可能になり、柔軟な運用ができるようになりました。 ただし、もし Flux 側が Slack の Event API による Webhook 利用に対応してくれれば、Slack から直接 Flux を呼び出せるようになるため、今後の対応に期待したいところです。

Flux で通知メッセージを動的に切り替えられたらいいのになぁ

Flux を使って IoT デバイスから送信されたデータに応じた通知やアクションを設定する場合、IoT デバイスイベントソースには SIM グループを紐付けることになります。 ですが、SIM グループに複数の SIM が紐付いていると、SIM 単位で個別のメッセージを送りたい場合に少し工夫が必要です。

users.soracom.io

考えられる手軽な対応方法

Flux だけに閉じて考えると、アクション実行条件を活用して、SIM ID で判別して個別の通知メッセージを割り当てる方法があります。しかし、この方法では SIM が増えるたびに設定を変更する必要があり、手間がかかります。

もっと単純な方法として、SORACOM 全体の仕組みを活用して、SIM、SIM グループ、イベントソースを 1 対 1 対 1 で紐付けることも考えられます。 しかし、この方法でも SIM の数が多くなると、Flux アプリ側で大量のイベントソースを設定する必要があり、現実的ではありません。

タグを使った解決案

そこで試してみたのが、SIM のタグを活用する方法です。タグに通知用のメッセージを格納し、SIM 単位で動的に通知内容を切り替えられるようにします。

実はこの方法、SORACOM の他の製品でも使われています。たとえば、SORACOM LTE-M Button for Enterprise では、グループのタグに必要な情報を保存し、それを参照してメールを送信する仕組みが採用されています。

users.soracom.io

users.soracom.io

タグ情報の制約

タグには保存できる情報量に上限があるため、保存する内容を工夫する必要があります。今回は単純な文字列をタグに入力して利用しました。

users.soracom.io

実際に試してみた

実際にタグ情報を使った解決案を以下の手順で試してみました。

  1. SORACOM ユーザーコンソールでタグ設定
    • SIM のタグ情報に通知用のメッセージを入力します

  2. Flux アプリで設定
    • IoT デバイスイベントソースを設定し、タグ情報を持つ SIM が所属する SIM グループをトリガーに指定します
  3. SORACOM API アクションでタグ情報を取得
    • 通知対象の SIM 情報を取得し、その中からタグ情報を抽出して通知に利用します

これで、SIMから情報が送信されるタイミングでFluxアプリが起動して、動的にタグから通知用の情報が取得され、通知の文面に使われます

Slack への通知の例

今回は例として、Slack にタグ情報の内容をそのまま通知しました。もちろん通知メッセージを編集することで、さまざまな用途に応用できます。

注意が必要なポイント

Flux にはレスポンスサイズの上限があるため、タグに格納する情報が大量になると、上限を超えて情報を取得できない場合があります。 また、タグ自体にも入力の上限値があるため、タグの制約と Flux のレスポンス上限値を合わせて考慮することが重要です。

Flux で SIM のタグを活用することで、動的に通知メッセージを切り替える仕組みを実現しました。ただし、制約があることを理解した上で、柔軟に対応できる運用を考えてみてください!

まとめ

SORACOM Flux を使う中で 「ここ、もうちょっとこうだったらいいのになぁ」 と思う部分をなんとかできないかを試してみました。

  • 画像の表示期限
    • Flux で画像を外部に通知するとき Amazon S3 の署名付き URL(Pre-Signed URL) が使われます
    • 署名付き URL には有効期限があるため、例えば Slack に通知すると一定時間で画像が表示できなくなります
    • これを解消するには、Slack に直接ファイルをアップロードする必要があり、Slack API の files.getUploadURLExternal と files.completeUploadExternal を使う必要があります
    • しかし、Flux の HTTP レスポンスサイズ制限により、大きなファイルのダウンロードやアップロードは現状では難しかったです
  • レスポンスサイズ制限
    • TinyPNG などの外部サービスを使い、画像を圧縮したりフォーマットを変換してファイルサイズを抑えてみましたが、残念ながら Flux 側の制限を超えることはできませんでした
  • スケジュール起動
    • タイマー起動ではなくスケジュール起動を利用したい場合に、Slack を活用してみました
    • ただし、Slack の Event API を利用する際には、Flux では Webhook に返答できないため、現状では直接利用するのは難しかったです
  • 外部サービスの Make を活用
    • Flux で解決できない部分は、外部のサービスである Make を利用して対応しました
    • Make の機能で Flux を補完することで、Flux の制限部分を解決しました
  • SIM タグの活用
    • SIM タグを活用して、デバイスごとに動的な通知メッセージを切り替える仕組みを試しました
    • Flux でタグを利用する際は、タグ情報のサイズ制限や Flux のレスポンス制限を考慮する必要があります
    • 制限を理解して利用するのであれば、手軽かつ便利に利用できると思います
  • 今後に期待
    • Flux はまだリリース初期段階と思われるので、こうした細かい部分の今後の進化に期待したい
    • 「ここ、もうちょっとこうだったらいいのになぁ」という部分があれば ぜひソラコムにフィードバック してみてください!

少しでもみなさんの参考になれば嬉しいです。楽しく SORACOM Flux を使って省力化できることが増えるといいですね。

以上です。