2021年12月22日水曜日

memo アプリの紹介

memo アプリの紹介

適当に作ったアプリがいい感じになったので紹介します

URL

現在は Heroku にデプロイしています
個人のサーバやローカルマシンにデプロイして使うこともできます

使い方

好きなテキストや手書きの画像を保存できます
アカウントを作成しなくても利用できます
他の人に見られたくないメモはアカウントを作成しログインしてから保存します

テキストは Home (/) で使えます
チェックボックスをオンにすると複数行のテキストも入力できます

Board (/image) に移動すると手書きのボードが出てきます
マウスでペイントのように使えます
画像も好きなように保存できます
書いた画像を保存しないでダウンロードするだけもできます

機能一覧

  • 好きなテキスト保存/取得
  • 好きな手書き画像の保存/取得
  • アカウント作成/削除
  • アカウントログイン/ログアウト
  • レスポンシブデザイン対応

構成

  • 言語・・・go
  • フレームワーク・・・beego v2
  • データストア・・・Redis

TODO

  • アカウント作成時のセキュリティの考慮
    • パスワードのポリシールールを設ける
    • 2auth など
    • メジャーサービスの OAuth2 対応
  • API 化
    • 現在は WebUI のみ提供
  • 独自ドメインでの運用
    • Heroku or VPS
  • beego v2 の脆弱性対応

2021年12月16日木曜日

2021 できたこと・できなかったこと

2021 できたこと・できなかったこと

去年に引き続き今年もやりました

できたこと

時系列

2月に何もしてないがそれ以外は何かしらアウトプットができたのがよかった
既存アプリのバグフィックスやエンハンスはプラットフォーム側の更新に合わせて継続的にやっていきたいがかなり面倒

資格はこれで 11 個になった

新しい技術への挑戦はあったがやや少ない印象
また技術以外への新しいことや趣味への挑戦がなかったのが残念

その他

  • ブログ執筆数: 269 (12/16 時点)
  • Podcast エピソード数: 12
  • 断捨離

これらは去年から引き続きがんばれたかなと思う
Podcast は一ヶ月に一回ペースを守れた

今年はいろいろなものを断捨離できたのがすごいよかった
身軽になることでいろいろな管理や運用から開放される感じが良い

できなかったこと

  • Youtube Live (去年に引き続き)
  • 新規アプリ開発

Youtube Live は永遠の課題なのかもしれない
アプリはアイデアがない

来年の豊富

  • 新規アプリ開発
  • モチベーションを維持する
  • 引き続き断捨離 and アウトプット

今年はよくアウトプットできたと思う
記事、動画、Podcast をうまく使い分けてアウトプットできた

Unity or Unreal で 3D ゲームを作りたいがこれ以上管理するアプリやサービスが増えると破綻するので悩み中

資格は来年も取得予定

2021年10月1日金曜日

IoT Gateway for BLE meets ESP32

IoT Gateway for BLE meets ESP32

Video

Environments

  • ESP32 devkitc v4
  • IoT Gateway for BLE v1.17
  • CloudMQTT
  • Chrome

Sketch

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint32_t value = 255;

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

void onButton() {
  // sedning integer 255 via notify
  pCharacteristic->setValue((uint8_t*)&value, 4);
  pCharacteristic->notify();
}

void setup() {
  Serial.begin(115200);
  pinMode(0, INPUT_PULLUP);

  // Create the BLE Device
  BLEDevice::init("ESP32");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ   |
                      BLECharacteristic::PROPERTY_WRITE  |
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_INDICATE
                    );
  pCharacteristic->addDescriptor(new BLE2902());

  // Start the service
  pService->start();

  // Start advertising
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(0x0);  // set value to 0x00 to not advertise this parameter
  BLEDevice::startAdvertising();
  Serial.println("Waiting a client connection to notify...");
}

void loop() {
  // notify value no button pushed
  if (deviceConnected) {
    static uint8_t lastPinState = 1;
    uint8_t pinState = digitalRead(0);
    if (!pinState && lastPinState) {
      onButton();
    }
    lastPinState = pinState;
  }
  // disconnecting
  if (!deviceConnected && oldDeviceConnected) {
    delay(500); // give the bluetooth stack the chance to get things ready
    pServer->startAdvertising(); // restart advertising
    Serial.println("start advertising");
    oldDeviceConnected = deviceConnected;
  }
  // connecting
  if (deviceConnected && !oldDeviceConnected) {
    // do stuff here on connecting
    oldDeviceConnected = deviceConnected;
  }
}

Websocket

<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
  <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript"></script>
  <script type="text/javascript">
    var wsbroker = "m11.cloudmqtt.com";
    var wsport = 30707
    var username = "xxxxxxx"
    var password = "xxxxxxx"

    var client = new Paho.MQTT.Client(wsbroker, wsport, "myclientid_" + parseInt(Math.random() * 100, 10));
    client.onConnectionLost = function (responseObject) {
      console.log("connection lost: " + responseObject.errorMessage);
    };
    client.onMessageArrived = function (message) {
      console.log(message.destinationName, ' -- ', message.payloadString);
      var counter = $("#counter");
      var num = parseInt(counter.text());
      num++;
      counter.text(num);
    };
    var options = {
      useSSL: true,
      timeout: 3,
      onSuccess: function () {
        console.log("MQTT connected");
        client.subscribe('#', {qos: 1});
      },
      onFailure: function (message) {
        console.log("MQTT disconnected: " + message.errorMessage);
      }
    };
    options.userName = username;
    options.password = password;
    function init() {
      client.connect(options);
    }
    </script>
    <style type="text/css">
      #counter {
        color: #40e0d0
      }
      .container {
        width: 100%;
        margin: 0 auto;
      }
      h1 {
        text-align: center;
      }
    </style>
  </head>
  <body onload="init();">
    <div class="container">
      <header>
        <h1 id="msg">Pushed button count: <span id="counter">0</span></h1>
      </header>
    </div>
  </body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/FitText.js/1.2.0/jquery.fittext.min.js" integrity="sha512-e2WVdoOGqKU97DHH6tYamn+eAwLDpyHKqPy4uSv0aGlwDXZKGwyS27sfiIUT8gpZ88/Lr4UZpbRt93QkGRgpug==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <script>
    $("#msg").fitText(1.2);
  </script>
</html>

2021年9月23日木曜日

BluetoothLE デバイスを作る

BluetoothLE デバイスを作る

自分のアプリ用の BLE デバイスが無いということに気がついたので作りました
BLE モジュールは手元にあった BLESerial2 を使いました

環境

  • macOS 11.6
  • arduino IDE 1.8.16
  • Arduino Pro mini
  • BLESerial2

コンセプト

BLE デバイスと接続だけできてもダメなので Notify でデータを飛ばせるようにします

データを飛ばすには Serial.write するだけなのでタクトスイッチを押したらシリアル通信するような構成にします

送信するデータは何でも OK ですが今回はテストなので「0」を飛ばします

あとは通電や動作確認用に LED を設置します

とりあえずプロトタイプを作成する

ブレッドボード上にそれっぽく配置していきます

写真の上で BLESerial2 の制御をしています
Arduino の TX ピント BLESerial2 の TX ピンをつないでいます

写真の下でタクトスイッチと LED の制御をしています
適当なピンを使って digitalRead と digitalWrite をしているだけです

スケッチ

Arduino Pro mini に書き込むスケッチは以下の通りです
PULLUP なのでタクトスイッチが押された場合にはピンの情報は「0」になります
「0」になったら LED を光らせるために degitalWrite しています
また Serial.write もし BLESerial2 に信号を送信しています

連打できないように delay を 1.5 秒入れています

const int SWITCH_PIN = 7;
const int LED_PIN = 4;

void setup(){
  pinMode(SWITCH_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(9600);
}

void loop(){
  int value;
  value = digitalRead(SWITCH_PIN);
  if (value == 0) {
    digitalWrite(LED_PIN, HIGH);
    Serial.write(0);
    delay(1000);
  }
  digitalWrite(LED_PIN, LOW);
  delay(500);
}

ユニバーサル基板上に実装する

ブレッドボードだとかっこ悪いのでユニバーサル基板にはんだして回路を実装していきます

かなり適当な回路なので保護回路などはありません
みなさんはマイコンやモジュールを破壊しないようにちゃんと保護回路を組んであげてください

で、できたのが以下です



さすがに Arduino と BLESerial2 は他でも使う可能性があるのでピンヘッダをつけて取り外せるようにしています

Arduino Pro mini の部分は面倒だったのでそのまま使っているので電源の供給は FTDI のシリアル変換器を使って 5V をコンセントなどから取ります

たぶんこの部分もシリアルピンがあるマイコンで代用できるので ATTiny などを使えばさらに小型化できると思います

モジュールの配置とジャンパ線の配線がキレイにできるようになると上級者な気がします
自分は下手くそなので妥協して絶縁テープでまかればジャンパ線を使ってずるしています

動作確認

自分の Bluetooth アプリ「IoT Gateway for BLE」をスマホにインストールしてためします

チャンネルは CloudMQTT を使っています
BLE デバイスを登録してチャンネルと紐付けて Gateway を作成しスタートすれば OK です

今回は写真だけです
SensorTag を使ったデモ動画を過去にあげているので実際に動いている様子はそちらを御覧ください

費用

たぶん 3,500 円くらいです
だいぶ昔に購入したのであまり記憶にないです

  • BLESerial2・・・2,000円
  • Arduino Pro mini・・・1,000円
  • その他 (抵抗やジャンパ、基盤など)・・・500円

最近だとラズパイ4や ESP32 などすでに開発ボードに BLE モジュールが搭載されているケースがあるのでそれを購入したほうが回路も作成する必要もないし安く済むと思うのでそちらを購入したほうがいいかなと思います

作成時間

プロトタイプからユニバーサル基板上への実装までで 4 時間くらいかかりました
ブレッドボードで 1時間30分でユニバーサル基板上への実装で 2時間30分くらいの内訳です

久しぶりに電子工作した割にはスムーズにできたかなと思います

最後に

はんだしているときは無心になれるのでオススメです

メモ

  • BLESerial2 は 3.3v 動作なのだがなぜか分圧した 3.3v だと動作しなかったので Arduion の VCC (5V) から取っている
    • もしかするとそのうち BLESerial2 が壊れるかもしれない

2021年8月16日月曜日

ワクチン注射打ったらぶっ倒れて救急車で運ばれた話

ワクチン注射打ったらぶっ倒れて救急車で運ばれた話

再発防止として残しておきます
油断はよくないということを学びました
そして無事です
そしてお世話になったお医者様、看護師の皆様本当にありがとうございます

結論

結論としてはワクチンの副作用で倒れたわけではなく「迷走神経反射」で倒れました

おそらくコロナワクチンで倒れたということもあり念の為しっかり診察や処置をしていただいたんだと思います

時系列

ざっくり以下のような感じです
4 箇所注射してます

  • 11:45 ワクチン接種
  • 11:50 倒れる (一時意識不明、大げさに書いていますが一瞬意識を失ったようです)
  • 12:00 緊急処置?(点滴とか血圧上げる注射とか、ここからずっとベット)
  • 12:30 救急隊到着
  • 12:35 救急車で大きな病院に運ばれる
  • 13:00 大きい病院到着
  • 13:10 診察と治療開始 (採血、心電図、脳CT)
  • 14:00 診察結果を聞く
  • 14:05 ひたすら休む (血圧は 10 分起きくらいに測りました)
  • 15:30 トイレ
  • 16:00 復活、精算、帰宅

背景

もともと注射が嫌いで過去にも採血で倒れたことがありました
注射するときは横になってしてもらうのですが今回は調子に乗って座ったまま注射したのが最大の原因かなと思います(これが今回の教訓でもあり今後はちゃんと横になるようにしたいと思います)

迷走神経反射で救急車で運ばれるのか?と思う方もいるかなと思いますが今回は「コロナワクチン」だったのでアナフィラキシーの可能性もあり、もしワクチン後に倒れた場合は救急で大きな病院で詳細に診察してもらうのが決まりのようです
というのもあり今回は少し大きな話になってしまいました

教訓

先にも述べましたがまずは横になって注射するのを肝に銘じたいと思います

本当にいろいろな方に迷惑を掛けたのでそうしないためにも万全の状態で注射します

掛かったお金

結構お高くつきましたが生きていることと教訓を学べと考えれば安いもんかなと思います

  • ワクチン接種・・・0円
  • クリニックの治療代・・・2,330円
  • 病院での治療代・・・10,750円
  • その他 (タクシー代など)・・・4,000円

最後に

本当は 2 回目も接種する予定だったのですがお医者様から「今回はやめておいたほうがいいかも」と言われたので今回の2回目の接種やめておこうかなと思います

そして明日以降副反応で更に辛くなるのかと思うと泣けます

追記: 副反応について

翌日以降の副反応についてメモしておきます

  • 1日目・・・倦怠感ほぼなし、熱:36.5、関節の痛みなし、注射した肩の部分が痛む
  • 2日目・・・倦怠感なし、熱:36.1、関節の痛みなし、注射した肩の部分の痛みなし
  • 3日目・・・全開

2021年8月4日水曜日

氷をすくうスコップの作り方

氷をすくうスコップの作り方

モデリングからプリント方法まで動画に撮ってみました
自分はだいたいいつもこんな感じで 3D プリンタを使っています
ポイントなど詳しく紹介します

環境

  • macOS 11.5
  • blender 2.93.1
  • QIDI-Print 5.3.2
  • X-Smart

モデリング

3D プリンタでプリントするためには 3Dモデルデータが必要になります
拡張子でいうと「.stl」や「.obj」ファイルになります

blender はフリーのモデリングツールでゲームなどでも使えるレベルのモデリングが可能です
自分は blender でモデリングしますがモデリング自体が面倒な場合は Thingverse などで好きな stl ファイルを探すのもありです

スコップをモデリングした流れは以下のような感じです

  • 四角のオブジェクトを追加
  • 大きさをスコップの大体の大きさに合わせる
  • 全面を Extrude や Subdivide などを使って作成
    • このとき Vertex や Face が被らないように調整する
  • 位置の調整をして形を整える
  • Inset と Extrude で取っ手の部分を作成
  • 最後に全体を Bevel して角をなくす

という感じです
最終的には以下のようなモデルを作成しました
.stl ファイルでエクスポートすれば完了です

3Dプリンタで出力する場合はこれで OK ですがゲームなどのデータとして使う場合はこれでは不十分で Animation や Texture の設定が更に必要になります

スライシング

スライシングは作成した 3Dモデリングデータをプリンタでプリントできる形式に変換する作業のことを言います

スライスツールにはいろいろあり今回しようした QIDI-Print は QIDI-Tech というプリンタを販売しているメーカが無料で公開しているスライスツールになります
基本的にはプリンタのメーカがプリンタとスライスツールをセットで提供してくれていることが多いです

どんなスライスツールを使っても問題ないですがプリンタによっては使えないオプションなどがあるので注意しましょう (例えばサポートの細かい設定やノズルの速度など)

実は 3Dプリンタでプリントする際にはモデリングよりもこのスライシングの作業のほうが重要かもしれません

うまくサポートを設定できなかったり大きさの調整をミスると思ったとおりにプリントすることができなくなります
個人的に特に大事だと思うのは「ノズルの速度」と「サポートの調整」になります
ノズルの速度は一番下のレイヤーがうまくプリントボードに接着できるかに影響します
ノズル速度が早すぎるとうまくプリントボードに接着せず出来上がった際に反り返りが発生します
サポートの調整はオーバハングに影響します
自分は 75 - 80 度くらいのオーバハングまではサポートを使わないようにしています
なるべくサポートを使わないほうがプリントのミスを防ぐことができますがサポートがないとオーバハングには対応できないので 90 度の部分などは必須になります
特に端の部分のサポートがうまく設定できていないと印刷ミスになったりします
このあたりが 3Dプリンタ職人の腕の見せどころになるかなと思います

問題なければ出力します
最終的には「.gcode」というファイル形式を出力できれば OK です

プリント

あとは出力します
素材は PLA を使っています
だいたい 6 時間くらいかかっています

プリントが始まったら後は失敗しないように願うしかありません
一層目がうまくプリントできていれば基本的には大丈夫なはずです

あとはノズルのつまりやフィラメント切れの可能性がありますがほぼ起きることはないと思います

PLA はノズルから排出されてから冷えることで固まるので風を当てたりカバーを外して通気を良くすることでよりキレイにプリントできるかなと思います

プリントボードから剥がす

X-Smart 付属のプリントボードは曲がるので簡単に剥がすことができます
曲がらない場合や手でうまく剥がせない場合にはヘラなどを使って剥がしましょう

サポートも今回は手で取れました
これくらい大きなサポートであれば簡単に外せますが細かい部分のサポートは本体と密着することがあり外すのが難しくなります
そういう場合はペンチやニッパを使って外しましょう

試す

動画を見てください
それなりに使えていると思います

感想

そんなに難しいモデリングではなかったのですぐにできました
買おうと思えば買えるけどせっかく 3Dプリンタがあったので作ってみました
モデリングの勉強にもなったので良かったかなと思います

取っ手のオーバハングしている部分はあとでトリミングしてある程度キレイにしましたがもう少し丁寧にサポートを設定してもよかったかなと思います
オーバハング問題は FDM 形式の 3Dプリンタでは正直どうしようもないかなと思います

取っ手の部分に穴を開けてフックで掛けられるようにしたのは Good ポイントかなと思います
こんな感じで好きな形にできるのは自作の良いところかもしれません

2021年7月6日火曜日

飲酒量をロギングしてみた

飲酒量をロギングしてみた

1 年間ほどアルコールの飲酒量をロギングしてみたので紹介します
思った以上に飲んでいることがわかりました

サマリ

まずはデータのサマリを紹介します

  • 記録日数: 405日
  • 飲酒した日数: 234日
  • 飲酒しなかった日数: 171日
  • 一日の最大飲料: 2800ml
  • 一日の平均飲料: 563ml

平均すると毎日 500ml 缶を 1 本飲んでいるという結果になりました

作ったもの

一応可視化できるようにしました

@kakakikikeke - 飲酒量のロギング
https://kakakikikeke.com/alcohol

仕組みは後述しますが縦軸が飲酒量 (ml) で横軸が日にちになります
なので一日あたりどらくらい飲酒したのかのグラフになります

ちょっと仕組み紹介

実はデータは GoogleSpreadSheet で全部管理していました

ここでグラフにしてもよかったのですがせっかくなので Web で見れるようにしてみました

使用しているツールは Charts.js になります
v3 になってかなりいろいろなグラフが描画できるのとアニメーションも豊富だったのでこれにしました
あとは jQuery などで DOM 操作しています

SpreadSheet にあるデータは Google Apps Script を使って JavaScript で使えるデータに変換しています
なので定期的に手動でデータを取り込む必要があります
データベースに移行してそっちに貯めるようにしてもいいのですがさすがに面倒なのでやっていません

感想

平日は飲まないようにしているつもりでしたが結構飲んでいるなという印象です
というかグラフにするとほぼ飲んでいるようなグラフになっています

また平日飲まなくても週末に飲みすぎているせいで一日平均すると結構な量になっていました
連休があるところは特に飲んでいた印象です

「コロナのせい」なのかは不明ですが個人的に飲んでる量が増えた感はないです

現状体調の変化や体型の変化はないのですがこのまま続けるといずれガタが来るかなと思っているので健康には気をつけようと思います

今後

せっかくなのでもう少し記録してみようと思います
Web で見れるグラフはリアルタイムではないですがデータが溜まったら定期的にアップデートしていこうと思います