honeylab's blog

各種ハードウェアの改造、主にファミコンミニなどをやってます(ました)

SwitchBot Indoor CameraのOSS/GPLソースコードがなかなか届かないけど

honeylab.hatenablog.jp

 

こちらの記事にあるように、このカメラ、いわゆる中華カメラOEM製品で、
ReaktekのSDKを使用してカメラのアプリを、クラウドサーバとしては"TUYA"というプラットフォームを利用しているようです。
そのため、u-boot(GPLv2)、Linux Kernel(GPLv2)、busybox(GPLv2)などが例によってOSSのコードを利用しています。

※例によっての例※

honeylab.hatenablog.jp

 

本来は製品の公開と同時、もしくは製品などに添付する形でOSSの使用許諾宣言を添付したり、著作権者の表示が必要で、また製品・バイナリの入手者からの請求に応じてソースコードを提供する必要があります。これは任意、サービスではなく、そもそも製品の提供時に満たされていなければいけない条件ですので、現時点でこの製品は

GPL Violated」である、という状態です。

 一応、開発担当者には伝えている、とされていますが、それからそろそろ2週間ぐらいたつので、早めにソースコードが欲しいのですが…

 

なんだよおまえGPL警察かようぜーなとお思いかもしれませんが、ぶっちゃけその辺は私はどうでもよくて、この製品のGPLコードを手に入れてさっさと解析して、この機械を自由に改造できるようにしたいのです。

 

 

GPLは、プログラム(日本国著作権法ではプログラムの著作物)の複製物を所持している者に対し、概ね以下のことを許諾するライセンスである。

  1. プログラムの実行[注釈 2]
  2. プログラムの動作を調べ、それを改変すること(ソースコードへのアクセスは、その前提になる)
  3. 複製物の再頒布
  4. プログラムを改良し、改良を公衆にリリースする権利(ソースコードへのアクセスは、その前提になる)

 

 と、Wikipediaにはこのように書かれています。

特に、おそらくu-bootのソースコードにはmicroSDからのファームウェア更新ルーチンが含まれているため、それを使用してファイルシステムの書き換えを行いたいのです。

 

(Ghidraで解析してみてるんですが、なんかうまくいかないの…)

さて、ソースコードが手に入らないので似た製品のソースコードがないかを調べていたところ、割とメジャーな TP-Link C100が同じSoCであるRTS3903を使用し、コードを公開しているようでした。

 

ダウンロードしてみると、大変親切なことに、Reaktek RTS3903 SDKに含まれるソースコードの多く、さらにビルド用のGCCまで一緒に公開してくれていました。
大変親切ですので、展開して中身をあれこれ調べているところです。

www.tp-link.com

このgccでビルドしたコードはおそらくそのままSwitchbot Indoor Cameraで動かすことができると思います。

ところで大変興味深いのですが、このアーカイブに含まれる環境はOpenWrtのファームウェア作成環境のようで make 一発で書き込み用のファームウェアまで作成することができる完全なものでした。すごいすごい。

 というわけで、ある程度はRTS3903の素性もわかり、buildrootを使用してIndoor Cam上で動く実行バイナリを作成するところまではやってきました。

RTS3903はMIPSなんですが、ATOM Camとかに使われてるMIPS32より圧倒的に古い、MIPS Iというレベルのコードしかサポートしていないようで、buildrootの2013年版のリリースまで戻る必要がありました。

 

f:id:honeylab:20210724143415p:plain

シリアルログインだと、カメラアプリからのデバッグメッセージが延々と表示されて醜いのですが、telnetdを動かすことができるとそれに邪魔されずにシステムを調べることができます。

さて、もはや全然普通の使い方してないんですが、これからどういじっていこうかなぁ

ATOMCam2でIFTTTやLINEで通知を送る(webhookを利用する)

これもコミュニティで何度も話題となりつつスルーされている外部連係機能ですが、例によって無理やり実装してみます。

Cam1の時にも実装した、通知用のmp4ファイルが作成され、AWSにアップロードされた後に削除しようとする動作をフックしてファイルを横取りする、という部分

honeylab.hatenablog.jp

を改造し、ここでWebhookを行うことで各種通知サービスを利用することとします。

 

まず、rm.shというスクリプトを作成しておき、そこから呼び出される alarmhook.sh を作成します。

さらに、起動時スクリプトで、/bin/rm が呼び出される際に、代わりにrm.shが呼び出されるようにシンボリックリンクを書き換えます。

それらの内容はこんな感じ。

gist.github.com

 

この方法で、webhookを利用する連携サービスを使って検知画像を飛ばしたり、自動で何かを行うようなことが可能となります。
rm.shを書き換える方法だと、ATOMAWS に画像を転送してから実行するのでちょっとタイムラグが発生してしまうことは留意する必要があります。
もうちょっと工夫すれば、その前に引っ掛けることはできると思いますが、まあいいでしょ。

 

では、実際に動かしてみた感じを貼っておきます。

IFTTTからTwitter投稿を行ってみました。

f:id:honeylab:20210719232358p:plain

 このように、いきなりTweetすることができます。

…が、スクリプトを見るとわかるように、どうもIFTTT経由で画像をTweetしたり、gmailで添付させようとすると、いったんHTTPアクセス可能な外部サーバーに画像を保存する方法でしかできないように見えます…

もしもほかの方法でできることを知っている方がいれば教えてください。

IFTTTだとそこから先の連係機能がかなり強いので、IoTホームを作るにはなかなかいいと思います。

 

そのほか、LINE Notify APIを使ってみました。

Image

上の画像のように、直接LINEのトーク画面に送られてきます。

 

参考にしたのは公式のこちらのブログです。

engineering.linecorp.com

LINE Notifyだと、画像の添付に外部サーバを必要とせず、直接curlで投げ込むことができて便利です。

まあ、Lineに通知を放り込む場面がまだいまいち思いつきませんが…
家族・会社グループチャットに投げ込む、とかはできて便利だとは思います。

 

また、slackの投稿APIもどうやら画像を直接投げ込めるようです。

まだ試していませんが、たぶんできると思いますw

 

そのほか、何か外部連係周りでできたらいいなと思うもの、あったら教えてください。

SwitchBot Indoor Cameraを解析する(u-boot編)

honeylab.hatenablog.jp

 

さて、カメラの画質とか、そういうのは普通の人にやってもらうことにして、
私はシステムに入ってあれこれできないかを確かめてみます。

 

まず、UART端子が見つかったので、これを使ってu-bootコンソールかLinuxのシェルに残ることを試みます。

u-bootの起動時にいろいろなキーを押していると、ESCを押したときに、パスワードの入力を促されることに気づきました。

 

どうやら、ここで正しいパスワードを入力すれば操作が可能になるようです。

とりあえず、適当に入れてみましたが駄目です。
これは、ここで使われているu-bootのソースコードにパスワードの保存箇所が記録されているはずです。
では、ソースコードを… まだ公開されてないようですね。
とりあえず、メーカに問い合わせて、ソースコードを送ってもらうことに…

 

まぁ、一般のメーカのサポート窓口なんてこんなものです。とはいえ、もうちょっと丁寧に書いてもいい気がしたので改めて返信しておきました。

 

で、u-bootのソースコードが無いのでパスワードのヒントがありません。

取り合えず、同じSoCであるRTS3903を使用している TP-Link C100のu-bootソースを見ていくことにしました。

www.tp-link.com

いろいろ調べてみると、ここでは、CONFIG_ENV領域にある特定の環境変数を取得・比較しているようでした。

f:id:honeylab:20210711010014p:plain

このENV領域がFlash上にあれば、参照できるはずです。

というわけで、Flashを引っぺがしてダンプします。

 


しかし、目grep程度では見つけられませんでした。
では、改めてu-bootのソースを見ていくと…

getenvでは

f:id:honeylab:20210711010152p:plain

CONFIG_ENV_ADDRというアドレスが環境変数の格納されている場所です。

定義を探していくと…

f:id:honeylab:20210711010424p:plain

#define CONFIG_ENV_ADDR 0xB0030000

…はて?どこのアドレスだこれ…?

…CPUのレジスタ空間に近いな

…ああああああ… これたぶんCPU内蔵Flashのアドレスじゃないかな…
(データシートが無いのでほんとかどうかはわからないが、おそらくそう)

ってことはFlashダンプには入ってないわ…

 

残念!!!!!

 

ということで、まずはu-boot shellへの進入に失敗!

 

あとは、本物のu-bootのソースが手に入ったら最終確認してみよう。
もしかしたら、起動したLinuxから無理やりregister読めるかもしれんし…

 

 

 

SwitchBot Indoor Cameraが届いた

ので、早速分解しました。

 実際、このコネクタがUARTでした。

起動ログはこんな感じです。

Switchbot indoor cam bootlog · GitHub

 

SoCはRealTekのRTS3903、MIPSらしいです。

FlashはGigaDeviceのGD25Q64、RAMは64MBです

 

とりあえずFlashを引っぺがして、ROMの解析を始めました。

今のところ、そんなに面白いことはわかっていません。

また、パッと見た感じ、RTSPでストリームを取れたり、HTTPで何かができたりは一切無いようです。

むしろ、どうもセキュアのほうに振ってるらしく、microSDカードに保存された映像、クラウドに保存された映像いずれも、専用アプリからしか見えないとのことです。

support.switch-bot.com

 

へーーーー。

続々・ATOMCam2が(中略)RTSPサーバ機能を追加した(パッケージ更新)

サーバパッケージを更新しました。

drive.google.com

どうしてもメモリが足りない状態が多いので、やむなくSDカード上にswapファイルを作成しました。
SDカード上へのswapはちょっと思うところがないわけではないですが、まぁSDカードにはずっと録画データを書いているわけなのと、そこまで頻繁にswapしているというわけでもなさそうなのでしばらくこれで様子見てみます。

念のため、高耐久性で、でも壊れてもいいSDカードを使用してください。

 ーーーーーーーーーー

refererからfacebook辺りから人が来てるっぽいんですが、どこで紹介されてるかわからないので、もしよければコメントから教えてください

(ニッチな用途なので、ある程度ユーザを把握したいです)

ーーーーーーーーーーー

 

honeylab.hatenablog.jp

 

honeylab.hatenablog.jp

 

上の2記事からの続きです。

あれやこれや調べた結果、かなり力技ですが、タイトル通りRTSPサーバ機能を追加し、
ローカルLAN内でVLCなどのRTSPビューアで表示ができるようになりました。

 

もちろん、ルータの設定などを行えば外からも見ることが可能です。
実行ファイル群はATOM CamのOEM元の系統であるWyzeCamのオープンファームウェア「OpenMiko」からの拝借です。

github.com


(手元でT31用のSDKを使ってパッチ・再コンパイルしています)
「OpenMiko」の本来の使い方では完全にファームウェアを入れ替えてしまうため、これと同じように作るともともとの便利なATOMCamのどこからでも見れる機能が使えなくなってしまいます。
それはそれで不便なため、元の機能をうまいこと残し、追加機能を共存させることに成功しました。

ATOM Cam2で使うためには、microSDカードにここにあるアーカイブ内の「Test.tar」と各種フォルダを置いて、カメラを起動するだけでこの機能が使えるようになります。

 

f:id:honeylab:20210705121130p:plain



本体上のストレージには何の影響も与えませんので、microSDカードを抜いて再起動すれば、完全に元の状態で動くようになります。

一応おいておくので試してみてもいいですが、
動かなかったら、あぁ動かなかったな、忘れよう。と思っておいてください。

また、動体検知等の機能はOFFのほうがよさそうです。メモリが足りないです。


尚、この実行ファイルはmicroSDカードに置かれるので、アプリから「microSDカードのフォーマット」をすると、たぶん動作がおかしくなりますので、これだけはやらないように注意する必要があります。
(もちろん、microSDカードを抜いて再起動すれば元通りになりますし、改めてファイルを書き戻せばハック状態にできます。)

 配信されているIPアドレスは、ATOMCamの公式アプリを起動して、デバイス情報の中にある「IPアドレス」になります。

VLCで開くアドレスは rtsp://[IPアドレス]:8554/unicast になります。

f:id:honeylab:20210705121537p:plain

 なお、現時点ではストリームできるのは画像のみです。

 

さて、この実装に関して肝となるのはOpenMikoにも入っている「v4l2loopback」というカーネルモジュールです。

github.com

 

このモジュールを使うと、システム内に任意の /dev/video[x] デバイスを作成することができ、このデバイスに画像データを流し込むことで、通常のLinuxで使用される、/dev/videox をキャプチャデバイスとして扱うようなプログラムに画像を渡す、いわゆる「バーチャルカメラ」や「仮想キャプチャデバイス」などと呼ばれるもの相当が実現可能になります。

あとは、ATOM Camのプログラムの起動時に仕掛けをして、カメラから画像データが到着するたびに、この仮想キャプチャデバイスにデータを渡し、バックグラウンドで一般的に使われているRTSPサーバ「v4l2rtspserver」

github.com

を動かせばいいだけです。

(↓参考リンク)

dev.classmethod.jp

カメラ内のプログラムに仕掛けをしているコードはこんな感じです。

gist.github.com

 

ここで少し課題があります。

今のところ割り込んで画像を取得しているのは、カメラからの直データではなく、その次に接続されたH264エンコーダの出力になっています。

そのため、おそらく今のところ「mjpg_streamer」(生画像データかJPEGデータが必要)はまだ動かせません。/dev/videoから出てくるデータは生データとは限らないのです。


その代わり、H264エンコードはハードウェアで行われていますので、追加の負荷がほとんど発生しない状態でRTSP配信ができています。

f:id:honeylab:20210705112310p:plain

 

理論上は、カメラ直後のYUVストリーム、うまくいけばハードウェアJPEGエンコード後のストリームも取れるはずなので、それは別デバイスに流してmjpg_streamerに食わすかcgiで吐き出せば、普通のブラウザでJPEG画像としてみることも可能になるはずです。追々挑戦してみたいと思います。

 

 あと、おまけ機能としてtelnetdを上げてあります。
上にあるIPアドレスに、telnetで、ユーザ root パスワード atomcam2でログインできます。

追記:とりあえずJPEG画像を取得する

エンコードされたフレームから再生成するので直接よりは画質が落ちますが、スクリプトなどで実行して送ったりするためにはffmpegを使うといいです。

ffmpeg -i rtsp://192.168.0.18:8554/unicast -f image2 -frames:v 1 test.jpg -y

などとやると、test.jpgが保存されます。 

続・ATOM Cam2がいつまでたってもONVIFに対応しないのでハックで殴る

honeylab.hatenablog.jp

 

上の記事でも紹介しましたが、ATOMCamシリーズ、そのまま使うには玄人にはちょっと不便な部分をハックするにあたって、T31のSDKを使って直接新しいアプリケーションを書き、画像を取得することにすでに成功しています。

しかし、今はまだアトムテックのサーバーは生きていますし、同じような機能を実装するのは大変です。
そのため、上の記事ではあきらめていた、既存のアプリに手を入れて、欲しいストリームを横取りすることができないかを調べてみました。

まずは、ダンプから抽出した実行ファイルを眺めてみます。

/sysetem/bin 以下がこんな感じ

f:id:honeylab:20210630140049p:plain

そして、/system/libがこんなかんじ

f:id:honeylab:20210630140133p:plain

 

この中からアプリ「iCamera_app」と、そのライブラリ、「localsdk.so」を、定番の「Ghidra」で解析、逆コンパイルして、映像の初期化あたりから辿っていきます。

f:id:honeylab:20210630101259p:plain

どうやらこの辺がビデオストリームを生成しているところのようです。

f:id:honeylab:20210630101352p:plain

local_sdk_video_createなどの関数が見えてきます。

f:id:honeylab:20210630101559p:plain

local_sdk_video_set_encode_frame_callbackという関数があります。
おやおや、もしかすると、これはフレームの到着のたびに呼ばれる仕組みがあるのでは???という期待が出てきました。

localsdk.soを見ていきます。

f:id:honeylab:20210630101808p:plain

この関数を調べていくと、get_venc_sb_pstという関数で取得した関数テーブルに外部関数を登録していることがわかりました。

そして、実際にビデオストリームが開始すると、

f:id:honeylab:20210630102009p:plain

登録した関数にフレームバッファを渡して呼び出してくれそうなことがわかりました。

(わかりました、って書いてるけど、全然簡単じゃなくて何時間もかかってるのよw)

では、このコールバック登録を横取りして自作の関数を呼び出させてしまえばいいじゃん、ということになります。

しかし、そんなことできるのでしょうか。

Linuxには LD_PRELOAD という呼び出し方法で、実行ファイルから呼び出される外部ライブラリの対象に自作の関数を割り込ませる方法があります。

qiita.com

この方法を使って、コールバック登録関数を上書きして動作を変更します。
本来、コールバック登録関数に渡されるのはATOM Camの中の関数ですが、
その登録作業を横取りし、自作の関数を呼び出させます。そして、そのあと、本来のATOM Camの関数が呼び出されるようにすれば、ATOM Cam側では何も気づかず今までと同じ動作を続けます。

このために、以下のような関数を定義します。

gist.github.com

このファイルをコンパイルして、.soファイルを作成します。

mips-linux-uclibc-gnu-gcc -fPIC -shared -o libcallback.so snooper.c -ldl 

 そして、本来のアプリが呼び出される部分を変更し、

LD_PRELOAD=./libcallback.so.bin /system/bin/iCamera_app &

として呼び出すと、アプリでliblocalsdk内の”local_sdk_video_set_encode_frame_callback”を読んだつもりが、新しく私の書いた関数が呼び出されてしまうのです。

新しく書いたコールバック関数内では、渡されたフレームバッファを単純にファイルに書き出してみました。

 

うまくいけば、これでカメラから出力され、H264エンコードされたストリームが取得できるはずです。

出力されたストリームを、ffplayに渡してみると

 

Image

やった!!!!画像が出てきました。

どうやらうまくいったようです。

この方法だと、前の記事に書いたように一から新しいアプリを書く必要もなく、もともとのサーバ中継システムを生かしたまま、新たにRTSP配信など、直接データを取り出すことが可能になります。

ここで取り出されたストリームは H264 NAL ストリームなどと呼ばれているようです
ffplayに渡して再生できるので、たぶんffmpegなどに渡してトランスコードするだけで配信サービスができる気がするんですが…ffmpegコンパイルがちょっとめんどくさそうですね…

 

とはいえ、前回の記事よりは圧倒的に進歩しました。
せっかくここまではできたので、このままローカルでストリームが取得できるところまでどうにか作ってみたいと思います。

 

ATOM Cam2がいつまでたってもONVIFに対応しないのでハックで殴る

ONVIF対応について | ATOM Tech(アトムテック)

 

知ってる人は知ってると思いますが、使い始めるまではクッソ簡単なATOMCam2ですが、ちょっと凝ったことをしようとすると、例えばブラウザからjpgが見てみたい、とかVLCでストリームを見たい、とかローカル内でマルチカメラを自分で見たい、とか言った目的のために、いわゆるONVIF対応が待ち望まれていて、さらにそれは開発中だと言い続けて早数か月、ユーザからは悲観的なコメントがあふれ、不満のコメントがぶつけられ続けています。

community.atomtech.co.jp

community.atomtech.co.jp

改めて言うけど、ちょっと使うにはすごいいいです。

個人的にたくさん並べてますし、交差点カメラとしての動作もばっちりです。

f:id:honeylab:20210628150320p:plain

f:id:honeylab:20210628150338p:plain

 

しかし、これをプログラムから自動化しようとすると、途端に何もできないのです。

ATOM Cam2の基板にははIngenic T31というSoCとイメージセンサが搭載されていますが、例えばラズパイにUSBビデオキャプチャをつなげた時のように、/dev/video0にアクセスすれば画像ができる、といった仕組みにはなっていません。

この組み合わせのための専用のSDKが準備されています。
しかし、そのSDK自体はその辺には転がっていません。
ネットの海をあれこれして、怪しげなサイト(別に怪しくはないのですが)にクレジットカード番号を入力したところ、T31用のSDKを入手し、サンプルコードを実行させることができました。

 

f:id:honeylab:20210628141201p:plain

 

f:id:honeylab:20210628145446p:plain

 

 

f:id:honeylab:20210628141238p:plain

 

 


サンプルコードは非常に簡潔で、どうやらWyzeやATOMCamのアプリを制作している会社がラップしている"localsdk"は、このSDKに一枚皮をかぶせ、SDKの"sample"などの文字列が残ったままで作られている程度のもののようです。

また、元のSDK自体にもLinuxソースコードやビルド済みカーネル、rootfsなどが添付され、割と簡単にカスタムファームウェアを作れるレベルの内容であることがわかりました。また、WyzeCamではv2までのカスタムファームウェアが実際にリリースされていますので、まともなエンジニアがちょっと本気を出せば、ONVIF機能などあっという間に完成するもののはずです。

 

このサンプルコードを改変し、boa(httpサーバ)を使い、ATOMCam2の画像をローカルLAN経由で取得することに成功しました。

f:id:honeylab:20210628141558p:plain

 


これを拡張していく、例えばmjpg-streamerやffmpegなどに画像を渡すことで、ONVIFやRTSPへの対応ができるものと考えられます。

では、ATOMTechは何でできないのか。

エンジニア逃げたのかなw

 

いや、もともと内部にはエンジニアはいなくて、下請けに何らかの理由で追加開発を拒否されているんでしょうか。

 

さて、ここで一つ問題があります。
出荷されたATOMCamでは、iCamera_appというアプリがカメラの制御をすべて使用していて、あとから機能追加などをすることができません。
(試してないんですが、たぶん。)
つまり、いまのATOM アプリを使用しつつ、自作の画像取得アプリを動かす、というのは、iCamera_appからのソースコードレベルでの改変を行わないとおそらくできないものと考えられます。

(いや、すごい頑張ればできるんだけど…逆アセンブルから大体のプログラムの構造はわかってて、それに対して適当にinjectionすればできそうではあるんだけど…)


まぁ、これらを踏まえると、ATOMTechが倒産した暁には、iCamera_appを完全に無効化し、何らかの画像中継サーバなどを利用するか、ローカルでどうにかするためのアプリをリリースする環境は十分に整っていると考えられます。

(私がやるとは言ってない…)

 

なので、皆さん、安心して ATOM Cam2を買うんだ!
市販レベルでは結構最高品質のカラーナイトビジョンとWiFi搭載マイコンボードがついてなんと3000円!!安い!!!!買うなら↓のリンクから(アフィ)

 

こんなアフィ記事ねーよ。