皆さんは毎日の薬って飲んでいますか? 今は飲んでいなくても、年取ってくると生きてるだけで何だか色々なところが調子悪くなって薬が必要になってきたりもします。私は尿酸値が高く、もうかれこれ15年ほど朝に薬を飲んでいます。で、この薬なのですが、ホント飲み忘れる。また、飲んだにも関わらず、びっくりするほど飲んだかどうかを覚えていません(私だけ??)。
今回は この飲み忘れを防止する機械をArduinoで作った話です。かれこれ1年近く使用していますが、これにしてから殆ど飲み忘れがありません。
薬の飲み忘れ防止の選択
服薬管理アプリ(スマートフォンアプリ)
まず直ぐに思いつくのが投薬管理のスマートフォンアプリ。無料のものも多く、私も最初はこれを使用しました。薬の残り個数管理や、リマインダー、スヌーズなど色々な機能があるのですが、
- スマホを探す→スマホの電源を入れる→ロック解除→飲んだボタンを押すのが面倒
- スマホが手元にあっても、朝食中など、まだ薬を飲まない時に微妙な操作性
- 飲んだかどうかが自分しか分からない&アプリを起動しないと分からない。
- (無料のものは)広告などの通知などが邪魔。個人情報もできれば取られたくない。
- クラウド連携等、多機能なのは正直設定などが面倒
→1週間程度で使わなくなりました。
スマートスピーカ
- Google Home、IFTTT、Googleスプレッドシートを使って独自音声コマンドでログをとる@Qiita
https://qiita.com/miso_develop/items/be562d8a823ad2639d94
上記の記事を読み「スマホを探さなくて済む!」と参考にしながら同じようなシステムを作りました。googleスプレッドシートに記録がない場合は定期的にSlackとgoogle homeの音声で通知を繰り返し、「飲んだよ」って言うと通知が止まる的なもの。ただこれの問題点は…
- 通知が来た瞬間には飲めないが、もうちょっと後で…と思ってると忘れる
- 飲んだ時に「ok google 薬飲んだよ」って言わなければならない→面倒
- 飲んだかどうかパッと確認できない(確認にgoogle homeに聞く or スマホを見なければならない)
→結構飲みやすれが多い状態で2ヶ月ほど続けた。
という事で…
- 視覚的に飲んだ / 飲んでいないが直ぐにわかる
- 飲んだ場合、飲んだ記録を直ぐに、簡単に付けられる
- できれば、見た目にも少し気を使いたい…
そんな商品は無かったので、作ってみました。
できたのがこれ
- 指定の時刻になると光る
- 頭をポチッと押すと光が消える
- 6時間、頭のボタンを押されなければ自動的に消える
- ちょっとかわいい
仕組みはすごく単純で、ハード系の一番最初に試す”Lチカ”とほぼ同じです。
でもこれ作ってからはホント飲み忘れなし! レガシーな物理スイッチの威力を感じます。
作り方
材料
Arduinoがおうちに転がっているような方であれば、既に持っているものばかりだと思われます。
- Arduino Nano
- リアルタイムクロック(DS3231)
- LED×2
- 抵抗 150Ωくらい×2
- プッシュスイッチ
適当なものを。今回は http://akizukidenshi.com/catalog/g/gP-04586/ を使用。 - USB ACアダプタ(スマホに付いてきた、適当に余っているものを)
筐体のデータ
3Dプリンタのデータを置いておきます。
https://www.tinkercad.com/things/dQp2mWPZLOf-kusuribox
接続方法
スイッチはINPUT_PULLUPを使うのでプルアップ抵抗は使いません。Arduinoの外部割り込み機能を使うので2番ピンに接続して下さい。電源は、余ってたスマホ用の5V USB充電器をArduinoのUSBポートに刺して使います。
プログラム(スケッチ)
このプログラムではLEDを付ける時刻がハードコードしてありますが、もう一つスイッチを作って、それを押したら設定できるようにしたり、電源コネクタをつなげた時の時刻などにすると汎用性が上がるのかなぁとも思いました。また、Arduinoのsleep機能を使えば電池でも動くのかなとも思いますが、面倒なのでやっていません。スイッチを外部割り込みを使って検出するので、ボタンは2番ピンに入れて下さい。
初回のみRTC.set(compileTime())とprintDateTime()の//を取り、RTCにPCの時刻を書き込み、シリアルモニタで問題なく現在時刻になっているかを確認します(使用前に再度コメント状態に戻して書き込みます)。
#include <DS3232RTC.h> #include <MsTimer2.h> #include <Streaming.h> #define BUTTON_PIN 2 #define LED_PIN1 5 #define LED_PIN2 6 DS3232RTC myRTC; void setup() { Serial.begin(115200); // ボタンを入力に pinMode(BUTTON_PIN, INPUT_PULLUP); // ボタンを外部割り込みにする attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), stopLED, FALLING); // 割り込み(LED点滅用) MsTimer2::set(500, flashLED); myRTC.begin(); //アラーム自動開始。分,時,曜日(関係ない) myRTC.setAlarm(DS3232RTC::ALM1_MATCH_HOURS, 30, 4, 0); myRTC.alarm(DS3232RTC::ALARM_1); myRTC.alarmInterrupt(DS3232RTC::ALARM_1, false); //アラーム自動停止。分,時,曜日(関係ない) myRTC.setAlarm(DS3232RTC::ALM2_MATCH_HOURS, 0, 13, 0); myRTC.alarm(DS3232RTC::ALARM_2); myRTC.alarmInterrupt(DS3232RTC::ALARM_2, false); // PCから時刻を持って来て、RTCに設定(初回のみ使用。2度めはコメントアウトして書き込む) // myRTC.set(compileTime()); } void loop() { //アラーム開始 if ( myRTC.alarm(DS3232RTC::ALARM_1) ) { Serial.print("アラーム開始"); MsTimer2::start(); } //アラーム自動停止 if ( myRTC.alarm(DS3232RTC::ALARM_2) ) { stopLED(); } //デバッグ用(現在の時刻を表示) // printDateTime(myRTC.get()); delay(100); } // LEDを点滅させる void flashLED() { static boolean output = true; output = !output; if (output){ analogWrite(LED_PIN1, 5); analogWrite(LED_PIN2, 0); }else{ analogWrite(LED_PIN1, 0); analogWrite(LED_PIN2, 5); } } // LEDを停止 void stopLED() { Serial.print("アラーム停止"); //LED停止 MsTimer2::stop(); analogWrite(LED_PIN1, 0); analogWrite(LED_PIN2, 0); } // 時刻表示 void printDateTime(time_t t) { Serial << ((day(t)<10) ? "0" : "") << _DEC(day(t)); Serial << monthShortStr(month(t)) << _DEC(year(t)) << ' '; Serial << ((hour(t)<10) ? "0" : "") << _DEC(hour(t)) << ':'; Serial << ((minute(t)<10) ? "0" : "") << _DEC(minute(t)) << ':'; Serial << ((second(t)<10) ? "0" : "") << _DEC(second(t)); Serial.println(""); } // コンパイルしたPCの時刻を返す // https://github.com/JChristensen/DS3232RTC/blob/master/examples/alarm_ex1/alarm_ex1.ino time_t compileTime() { const time_t FUDGE(10); //fudge factor to allow for upload time, etc. (seconds, YMMV) const char *compDate = __DATE__, *compTime = __TIME__, *months = "JanFebMarAprMayJunJulAugSepOctNovDec"; char compMon[4], *m; strncpy(compMon, compDate, 3); compMon[3] = '\0'; m = strstr(months, compMon); tmElements_t tm; tm.Month = ((m - months) / 3 + 1); tm.Day = atoi(compDate + 4); tm.Year = atoi(compDate + 7) - 1970; tm.Hour = atoi(compTime); tm.Minute = atoi(compTime + 3); tm.Second = atoi(compTime + 6); time_t t = makeTime(tm); return t + FUDGE; //add fudge factor to allow for compile time }
最後に
薬が1種類×1日1回なので これでちょうど良いのですが、増えてきたら 結局昔からある↓が一番一番有効なのかもしれません。シンプル、一覧性、保存場所など悔しいけどかなりわかりやすいです。ただ、もう少しシュッとした見た目のがあればいいのになぁ。
薬飲まないのが一番ですが、飲むことになったら思い出してもらえればと思います。あとは、作ってご両親にプレゼントとかでも楽しいかも。
ナカバヤシ お薬カレンダー 1週間分 壁掛タイプ グレー IF-3010GY【送料無料】 |
コメント
はじめまして
検索してこちらにたどり着きました
早速 薬飲み忘れ装置作ってみました
なぜかLEDが点滅しません
単体では5ピン、6ピン共に正常に動作します
以下のプログラムが怪しいと思うのですが
自分が勘違いしているのか
おっさん初心にお時間がありましら ご教授お願いします
// LEDを点滅させる
void flashLED()
{
static boolean output = true;
output = !output;
if (output){
analogWrite(LED_PIN1, 5);
analogWrite(LED_PIN2, 0);
} else {
analogWrite(LED_PIN1, 0);
analogWrite(LED_PIN2, 5);
}
}
作ったのが結構前なのではっきりと覚えていないのですが、LEDが明るすぎたので暗くしたのだと思います。
とりあえず、
if (output){
analogWrite(LED_PIN1, 255);
analogWrite(LED_PIN2, 0);
} else {
analogWrite(LED_PIN1, 0);
analogWrite(LED_PIN2, 255);
}
とかでどうでしょうか?
今朝も使いましたが毎朝ちゃんと動いてくれてます。
お忙しい所、早速のご教授ありがとうございました
もう一度 挑戦してみます
プログラムは、初体験なので おっさんの固い頭には
簡単なことでも難しいです
本当に ありがとうございました。
また 何かありましたら コメントします
失礼しました
もう一度 挑戦してみました所
うまく動作することができました事に感謝します
時刻設定の勘違いでした
3Dプリンタは持っていませんので
100均で適当な箱を探して 親にプレゼントしたいと思います
本当にありがとうございました