iwathiiのアイコン画像
iwathii 2021年05月14日作成 (2021年05月15日更新)
製作品 製作品 閲覧数 918
iwathii 2021年05月14日作成 (2021年05月15日更新) 製作品 製作品 閲覧数 918

obnizを使った習慣化定着のための物理ボタン(リマインダー機能付き)

obnizを使った習慣化定着のための物理ボタン(リマインダー機能付き)

イントロダクション

習慣化したいことがある、けど、長く続けられたためしがない。
新年度が始まったから新しいことをスタートしたけど3日坊主になってしまった。
そんな人結構多いのではないでしょうか。

なにか新しいことを習慣にするまでには何かしらのトリガーが必要だとおもいます。
そんなトリガーとなってくれるアイデアとして物理ボタンを使うことを提案します。

何かを習慣化した自信をつけるために

「1日に1回ボタンを押す」

という習慣をつけることからはじめてみましょう。

デモ

ここに動画が表示されます

構成図

キャプションを入力できます

使った部品

名前 数量
obniz Board 1Y 1
3LEDプッシュライトミニ(ダイソー) 1
ジャンパー線 4
銅線 5
ピン 4

※プッシュライトは電池を入れて押すと光るライト
※トリビアの泉のへーボタンに形が似ている

回路図

obniz Board 1Y

完成した回路図が上のようになっています。
10,11ピンのトグルスイッチの部分が実際にはプッシュボタンのスイッチになっています。

キャプションを入力できます

もとのダイソープッシュライトを回路図で表すと下のようになっていて
スイッチとLED部分の配線を変えてobnizと接続しています。

ダイソープッシュライト

ダイソープッシュライトの改造

本来は、電池ボックスの3つの爪のような部分を通してスイッチとLEDが接続されていて
電池を入れてスイッチを入れることでLEDが光るようになっています。

配線の変更

ただ、今回はobnizでスイッチとLEDを個別で使うために中の配線を変えています。
下の写真で黒い台座のようになっている部分が電池ボックスです。

今回は電池ボックスには電池をいれないで使用するので、
電池ボックスの爪の部分で銅線との接続点としてはんだ付けをしています。

キャプションを入力できます

写真では分かりづらいですが、左下の爪の部分で接続している赤い銅線が外部へ繋がっており、
左側のスイッチの奥から出ている白い銅線も同様に外と繋がっています。

接続点

また、写真のようにダイソープッシュライトには3つのLEDとスイッチが入っています。
LEDのカソード・アノードに当たる2配線の部分をプッシュライトの外側へ出してジャンパ線で接続できるようにします。
下の写真の下2つのピンがLED部分の接続点です。

キャプションを入力できます

またスイッチに関しても2配線の部分を外側に出してジャンパ線が差し込めるようにしています。
写真の上2つのピンがスイッチの部分です。
もともとは穴やピンはついていないので今回はハンダゴテで穴を開けてピンを設置しました。

これにより合計4つの接続点を外部へ出し、それを用いてobnizとつなげています。
それにより、LEDとスイッチを別々にobniz側からコントロールできるように加工をしました。

改造が完了したらobnizと接続をします。

プログラム

obniz 側

<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
    />
    <link rel="stylesheet" href="/css/starter-sample.css" />
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script
      src="https://unpkg.com/obniz@3.14.0/obniz.js"
      crossorigin="anonymous"
    ></script>
  </head>
  <body>
    <div id="obniz-debug"></div>
    <div class="wrap">
      <div
        class="w-75 h-75 mx-auto mt-5"
        style="position:relative; max-width:500px; max-height:500px; "
      >
        <p>最終実施時刻</p>
        <p id="lastTime">最終実施時刻</p>
        <p>経過時間</p>
        <p id="pastTime"></p>
        <p>次回実施までの残り時間</p>
        <p id="remainTime"></p>
        <p>本日の残り時間</p>
        <p id="diffTime"></p>
        <p>現在時刻</p>
        <p id="RealtimeClockArea">※ここに時計が表示されます。</p>
      </div>
    </div>
    <script>
     var led;
     let now = new Date();
     let dbTime = new Date();
     let pollingCounter = 0;
     let nextDayStartTime = new Date();
     let afterOneDay = new Date();
     let isBlinkStatus = 0;
     let isPrevBlinkStatus = 0;
     nextDayStartTime.setDate(nextDayStartTime.getDate() + 1);
     nextDayStartTime.setHours(0);
     nextDayStartTime.setMinutes(0);
     nextDayStartTime.setSeconds(0);
     var text =
       nextDayStartTime.getMonth() +
       1 +
       "/" +
       nextDayStartTime.getDate() +
       " " +
       nextDayStartTime.getHours() +
       ":" +
       nextDayStartTime.getMinutes();
     //document.getElementById("nextDayStartTime").innerHTML = text;

     window.onload = function () {
       getDbTime();
     };

     function getDbTime() {
       const URL =
         "GASのURL";
       let render_text = "確認できません";
       fetch(URL)
         .then((response) => {
           return response.json();
         })
         .then((data) => {
           // GETでdataの取得が成功したときの処理
           console.log(data.message);
           dbTime = new Date(data.message);

           afterOneDay = dbTime;
           afterOneDay.setDate(dbTime.getDate() + 1);
           render_text =
             dbTime.getMonth() +
             1 +
             "/" +
             dbTime.getDate() +
             " " +
             dbTime.getHours() +
             ":" +
             dbTime.getMinutes();
           document.getElementById("lastTime").innerHTML = render_text;
         })
         .catch((error) => {
           console.log(error);
         });
     }

     function set2fig(num) {
       // 桁数が1桁だったら先頭に0を加えて2桁に調整する
       var ret;
       if (num < 10) {
         ret = "0" + num;
       } else {
         ret = num;
       }
       return ret;
     }

     function diffClock() {
       let nowTime = new Date();
       let diff = (nextDayStartTime.getTime() - nowTime.getTime()) / 1000;

       let hoursLeft = Math.floor(diff / (60 * 60)) % 24;
       var minitesLeft = Math.floor(diff / 60) % 60;
       var secondsLeft = Math.floor(diff) % 60;
       // 二桁表示
       minitesLeft = ("0" + minitesLeft).slice(-2);
       secondsLeft = ("0" + secondsLeft).slice(-2);
       // 出力
       document.getElementById("diffTime").innerHTML =
         hoursLeft + "時間" + minitesLeft + "分" + secondsLeft + "秒です";
     }

     function remainClock() {
       var nowTime = new Date();
       let diff = (afterOneDay.getTime() - nowTime.getTime()) / 1000;

       var hoursLeft = Math.floor(diff / (60 * 60)) % 24;
       var minitesLeft = Math.floor(diff / 60) % 60;
       var secondsLeft = Math.floor(diff) % 60;
       // 二桁表示
       minitesLeft = ("0" + minitesLeft).slice(-2);
       secondsLeft = ("0" + secondsLeft).slice(-2);
       // 出力
       document.getElementById("remainTime").innerHTML =
         hoursLeft + "時間" + minitesLeft + "分" + secondsLeft + "秒です";
       console.log(diff);

       let remainSeconds = Math.round(diff);
       console.log(remainSeconds);
       if (remainSeconds >= 10800) {
         isBlinkStatus = 0;
       } else if (remainSeconds >= 7200 && remainSeconds < 10800) {
         isBlinkStatus = 5000;
       } else if (remainSeconds >= 3600 && remainSeconds < 7200) {
         isBlinkStatus = 3000;
       } else if (remainSeconds >= 1800 && remainSeconds < 3600) {
         isBlinkStatus = 1000;
       } else if (remainSeconds >= 900 && remainSeconds < 1800) {
         isBlinkStatus = 500;
       } else if (remainSeconds >= 450 && remainSeconds < 900) {
         isBlinkStatus = 250;
       } else if (remainSeconds < 450) {
         isBlinkStatus = 120;
       }

       console.log(isBlinkStatus);
       if (isBlinkStatus == 0) {
         led.off();
       } else {
         if (isPrevBlinkStatus != isBlinkStatus) {
           led.blink(isBlinkStatus);
           isPrevBlinkStatus = isBlinkStatus;
         }
       }
     }

     function showClock2() {
       var nowTime = new Date();
       var nowHour = set2fig(nowTime.getHours());
       var nowMin = set2fig(nowTime.getMinutes());
       var nowSec = set2fig(nowTime.getSeconds());
       var msg = "現在時刻は、" + nowHour + ":" + nowMin + ":" + nowSec + " です。";
       document.getElementById("RealtimeClockArea").innerHTML = msg;
       pollingCounter++;

       diffClock();
       remainClock();
     }
     setInterval("showClock2()", 1000);

     var switchStatus = false;
     var pressedPrevStatus = false;
     var firstTime = true;
     var obniz = new Obniz("OBNIZ-ID");
     obniz.onconnect = async function () {
       led = obniz.wired("LED", { anode: 6, cathode: 7 });
       obniz.display.clear();
       obniz.display.print("1日1善!");

       var button = obniz.wired("Button", { signal: 10, gnd: 11 });

       pressedPrevStatus = await button.isPressedWait();

       button.onchange = function (pressed) {
         if (pressed != pressedPrevStatus) {
           switchStatus = true;
           pressedPrevStatus = pressed;
         } else {
           switchStatus = false;
         }

         if (switchStatus) {
           led.off();
           dbTime = new Date();
           afterOneDay = dbTime;
           afterOneDay.setDate(dbTime.getDate() + 1);
           render_text =
             dbTime.getMonth() +
             1 +
             "/" +
             dbTime.getDate() +
             " " +
             dbTime.getHours() +
             ":" +
             dbTime.getMinutes();
           document.getElementById("lastTime").innerHTML = render_text;
           const URL =
             "GASのURL";

           let SendDATA = {
             action: "obniz_action",
           };
           let postparam = {
             method: "POST",
             mode: "no-cors",
             "Content-Type": "application/x-www-form-urlencoded",
             body: JSON.stringify(SendDATA),
           };
           fetch(URL, postparam);
           //           obniz.display.print("ON");
         }
       };
     };
</script>
  </body>
</html>

GAS 側

function obj2txtout(obj){
  let output = ContentService.createTextOutput();
  output.setMimeType(ContentService.MimeType.JSON);
  output.setContent(JSON.stringify(obj));
  return output;
}

function doPost(e){
  const SHEET_ID = 'SHEET_ID';
  const SpreadSheet = SpreadsheetApp.openById(SHEET_ID);
  let Sheet = SpreadSheet.getSheetByName('データベース');
  // ポストされたデータをJSONにパースする
  let JsonDATA = JSON.parse(e.postData.getDataAsString());
  Sheet.appendRow([Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss'),JsonDATA.action]);
  return obj2txtout({ message: "success!", });
}

function doGet(){
  const This_month = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM');
  const SHEET_ID = 'SHEET_ID';
  const SpreadSheet = SpreadsheetApp.openById(SHEET_ID);
  let Sheet = SpreadSheet.getSheetByName('データベース');
  let Data = Sheet.getDataRange().getValues();
  let lastRow = Sheet.getLastRow() - 1;

  return obj2txtout({ message: Data[lastRow][0], });
}

GASへのデータ格納に関してはこちらの投稿を参考にさせていただきました。
obnizを使ったスマート貯金箱『Moneygement』

最後に

100均一の電子機器をobniz Boardを使ってカスタムしたり、便利なものに変えていくのは楽しいので
また何かあれば引き続きやっていきたいです。

1
ログインしてコメントを投稿する