obnizとGyazoAPIを使って自分史上最高の体を撮影できる装置を作りたい。


## トレーニングを通して変わったこと
初めまして！あべれんと申します。筋トレ歴2年程度の新米トレーニーです。
「みんなの筋肉体操」をきっかけに筋トレにハマりました。コロナ禍で武田真治と何度一緒に腕立て伏せをしたかわかりません。

https://www.youtube.com/watch?v=JDc-xApip7k

そんな経験を通して少しずつ体が変わり、筋トレの沼にハマっていきました。
筋トレにハマって一番変わったのは朝のルーティーンです。人間の体はだいたい朝が一番絞れてます(見栄えがいい状態)。毎朝起きたら洗面台の前で上裸になり、鏡に映る体の状態を見て、一人少しニヤニヤしています。
え、ちょっとキモイって？**きっとみなさんも筋トレにハマったらこうなります。**

## 毎朝のルーティーンで感じたこと
ルーティーンを通して鏡を見て幸せな気分にはなれますが、より一層自分が「頑張ったなぁ」と思えるように写真を撮って記録をしてみようと思いました。
ですが、思ったより道のりは大変でした。自分で写真を撮ってみて以下のようなことを感じました。

::: note
- スマホで撮影をすると片手はカメラを向けないといけないので、筋肉が盛れるポーズが取りにくい。
- 筋トレインスタグラマーみたいな自撮りはうまくできない。
- 鏡を使って背中をきれいに撮影するのが難しい。
- 撮影のために三脚とデジカメを洗面台に置いておくのが一番いいが、設営が面倒だしスペースが邪魔。
:::

これらのちょっとした不満を解消するために、毎朝、両手が空いた状態でもポーズを取ると勝手に盛れた写真を撮影し、管理してくれる装置が作れないかなと思いました。

## 実装のイメージ
簡単に図にすると以下のように考えました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775528/4c341766-7f95-0654-5f54-de0cb9b9938e.png)
obnizでカメラを使用することができると聞いたことがあったので、カメラの部分はobnizとjpegSerialCamを使用することにしました。
またいいポーズの状態で写真を撮りたいのでTeachablemachineを使用してポーズの判定をしてみようかなと思います。
撮影した画像はAPIを使用して簡単に実装ができそうだったのでGyazoに保存することにしました。

## 実装ができた部分の紹介
記事を執筆している時点で➂と④の部分の実装をすることができました。
➁のTeachablemachineの部分はNode‐REDを使って手軽に連携したかったのですが、自分が書いたコードとNode‐REDをどうつなぐといいのか理解が及ばず時間切れになりました…

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">obnizで撮った自分の写真をgyazoに送る仕組みで自分の朝の一番絞れてる写真を残したいなと思ってます。<br>三脚いらず、両手塞がらずに自由なポーズで撮れるのが楽しい。<br>僕の体の仕上がりはさておき面白がってくれる人がいたらコメントください！<a href="https://twitter.com/hashtag/%E7%AD%8B%E3%83%88%E3%83%AC?src=hash&amp;ref_src=twsrc%5Etfw">#筋トレ</a> <a href="https://twitter.com/hashtag/IoT?src=hash&amp;ref_src=twsrc%5Etfw">#IoT</a> <a href="https://twitter.com/hashtag/obniz?src=hash&amp;ref_src=twsrc%5Etfw">#obniz</a> <a href="https://twitter.com/hashtag/%E3%83%88%E3%83%AC%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0?src=hash&amp;ref_src=twsrc%5Etfw">#トレーニング</a> <a href="https://t.co/HuDePWz4Xi">pic.twitter.com/HuDePWz4Xi</a></p>&mdash; あべれん (@rencoln1229) <a href="https://twitter.com/rencoln1229/status/1600329021224808448?ref_src=twsrc%5Etfw">December 7, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

※Twitterに顔を出すのはちょっと怖かったので加工がしたく、スクショになっています。
gyazoにはTwitterにアップした以外の写真も複数枚保管されています。

<details><summary>お見苦しいところもあるので隠しておきます。</summary>

![13.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775528/8f1fb3c4-39fd-0436-2346-add2bd2d229d.jpeg)

</details>

## 環境・コード

制作を行った環境は以下の通りです。

::: note
環境
- [obniz Board 1Y](https://obniz.com/ja/products/obnizboard#areapdctSpec)
- [JpegSerialCam](https://obniz.com/ja/sdk/parts/JpegSerialCam/README.md)
- node.js v18.7.0
- Visual Studio Code v1.73.1
- gyazo api v0.3.1 
- obniz v3.24.0
:::

<details><summary>ソースコード全量はこちらになります。</summary>

```javascript:masclephoto.js
const Obniz = require('obniz');
const obniz = new Obniz('obnizID'); // Obniz_IDに自分のIDを入れます。
const Gyazo = require('gyazo-api');
const client = new Gyazo('GyazoAcsessToken');//gyazoのアクセストークンを入れます。
const fs = require("fs");

obniz.onconnect = async function () {

    obniz.display.clear(); // 画面を消去
    obniz.display.print('Hello obniz!');

    obniz.io6.output(true);
    obniz.io9.output(false);
    var cam = obniz.wired("JpegSerialCam", { cam_tx: 1, cam_rx: 2 });
    await cam.startWait({ baud: 115200 });
    const jpegData = await cam.takeWait();
    fs.writeFileSync("output.jpg", Buffer.from(cam.arrayToBase64(jpegData), "base64"), (err) => {
        if (err) console.log(err);
    });

    client.upload('./output.jpg', {
        title: "my picture",
        desc: "upload from nodejs"
    })
        .then((res) => {
            console.log(res.data.image_id);
            console.log(res.data.permalink_url);
        })
        .catch((err) => {
            console.error(err);
        });
}
```

</details>

## 使ってみての感想と企画への反応
ここまで進めてみて、手軽に撮影ができて嬉しかったのですが、自分が使ってても改善点が多くあったので備忘として記録します。

::: note
- **カメラの品質をもっと上げたい…**
- 撮影されるタイミングがわからず、**ポーズを固定している時間が結構長く感じる。**
- obnizをずっと起動させていると多少熱が溜まるので起動させっぱなしだと火事にならないか心配。
- **Gyazoでちゃんと見れるのは10枚までだった**ので別の管理手段を考えたほうが良さそう。
- 現状はPCが近くにないと起動できないので、**ボタンで起動する形にしたい。**
- アップロードが終わったらすぐに見れるようにLINEなどで通知が欲しい。
:::

また、自分と同年代で同じタイミングで筋トレを始めた友人に企画の内容と撮影できた写真を見せたところ、以下のようなフィードバックをいただきました。
友人本人はInstagramで自撮りは載せないけどトレーニングをしたらストーリーを毎回投稿しており、使ってくれそうなユーザー候補になるかもと思って、相談してみました。

::: note
フィードバックの内容
- ジムで自撮りはしないけど記録を残したい人はいそう。
- めっちゃ画像が荒いのでこれで記録になるかというと微妙。
- 「写ルンです」みたいに、撮った日付と時間帯もスクショの中に入ってたら見返しやすい。
:::

一定ニーズはあるかもしれない、と感じましたが画像の荒さは初めて見る人だと違和感が強いとのことだったので、限界はありますが他のカメラを試してみるのいいかもしれません。引き続き改善をしてみて、実際に使ってもらいながらまた改善点を見つけたいと思います。

ここまでお読みくださり、ありがとうございました！
よかったら**LGMT(いいね)とコメントいただけると嬉しいです！**

## おまけ：起こったエラーなど
**➀ローカルコネクト**
obnizを実際に使っていると、以下のメッセージが出ました。
```
Cannot use local_connect because the connection was timeouted
local websocket error. Error: WebSocket was closed before the connection was established at WebSocket.close
```
こちらはローカルコネクト、というobnizに搭載されている機能でobnizとデバイスが同じWifi環境下にいる場合、クラウドを通さずに接続がされるもののことで、通常だったら問題ないのですが、私の使用していたWifiがたまたま相性が悪かったみたいです。

https://obniz.com/ja/doc/reference/common/connection/localconnect

回避策としてはobnizとデバイスのWifiを別々にしてあげると、ローカルコネクトは発生しないので想定通りに動かすことができました。

**➁fs.writeFileとfs.writeFileSync**
もともとコードを作成した中でobnizの公式ドキュメントにあった```fs.writeFile```
をそのまま使っていたのですが、そのまま動かしてみると以下のようなメッセージが表示されました。
```
Failed to parse form data.
```
```fs.writeFile```はファイルを書き出す指示なのですが、非同期(その後の処理を止めない)で進みますが、```fs.writeFileSync```の場合は同期(その後のコードを止める)ことができるので同期・非同期を理解しておいた方が良さそうです！