🚽

GASでスマートオフィスを実現

2022/07/20に公開
2

私の職場は異なる三か所の空間で仕事をする人が1つのトイレを共用しています。
私が仕事をしているお部屋から、今現在トイレに人がいるかいないかわかりません。
階段を下ってやっとトイレに着いたのに、人が入っているということがあるので、入っている人にもなんか申し訳なく、またタイミングを見計らって(←どうやって・・)、再度トイレへ行くけどまた入っているかもしれないし・・と地味にストレスを感じていました。
これを解決するべく、GASでトイレの使用状況をわかるようにしてみました。

用意したもの

人がいるかいないか判断しないといけないのでセンサーが必要です。
色々ツールはありましたが、お手軽に試せそうなものが良かったので、Switch Botを使用することにしました。

・Switch Bot 人感センサー
・Switch Bot ハブミニ

https://www.switchbot.jp/products/switchbot-motion-sensor
https://www.switchbot.jp/products/switchbot-hub-mini

Amazonでセールしている時に買うのがおすすめです。

ネットで色々調べていると、ドアの開閉センサーを使っているようなのもありましたが、ドアがスライド式なので、トイレの中に人が入っているかわかる人感センサーを使用することにしました。

出来たもの

今回もGASでデプロイしてみんなに共有しました。


PC版画面


モバイル版画面

SwitchBot API

公式のドキュメントがGithubにありますので、そちらを確認して人感センサーで人の有無が確認できそうな箇所を探していきます。

https://github.com/OpenWonderLabs/SwitchBotAPI

ステータスが取得できるAPIを見つけたのでこれを使っています。

コード

index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
    <script type="text/javascript">
    //gsファイル内のgetVal関数を実行、結果に応じてクラスの値を変更する
      function update() {
        google.script.run.withSuccessHandler(
          function(resp){
            const empelm = document.getElementById('empty');
            const usingelm = document.getElementById('using');
            if(resp === "空き") {
              usingelm.classList.remove('chapter');
              empelm.classList.add('chapter');
            }else {
              empelm.classList.remove('chapter');
              usingelm.classList.add('chapter')
            }
          })
          .getVal();
      }
      //画面を表示時にupdate関数を実行する
      window.onload = function() {
        update();
      }
    </script>
  </head>
  <body>
    <div id="main">
      <h1 class="title">1階トイレの空き状況</h1>
        <div id="updatebutton" class="d-grid gap-2 col-6 mx-auto">
          <button type="button" class="btn btn-outline-primary btn-lg" value="更新" onclick="update()">空き情報更新</button>
        </div>
        <div class="item">
          <div class="rows" id="empty">空き</div>
          <div class="rows" id="using">使用中</div>
        </div>
  
    <div class="memo">使用中→空きへの検知は約30秒程タイムラグがあります。</div>
    </div>
    </div>
  </body>
  <style>
    #main {
      width: 80%;
      margin: 0 auto;
    }
    h1 {
      text-align: center;
      color: black;
      border-bottom: dashed 2px black;
      padding: 5px;
      margin-top: 10px;
    }
    button {
      margin-bottom: 5vw;
      margin-top : 3vw;;
    }
    .item {
      display: flex;
    }
    .rows{
      width: 35vw;
      height: 35vw;
      display: flex;
      justify-content: center;
      align-items: center;
      margin: 0 auto;
      color: #6091d3;
      background: #FFF;
      border: solid 1px #6091d3;
      border-radius: 5px;
      font-size: 2em;
    }
    .chapter {
      background : #6091d3;
      color: #FFF;
      font-size: 2.5em;
      border: solid 1px #FFF;
    }
    .memo {
      text-align: center;
      margin-top: 3vw;
    }
    </style>
</html>
コード.gs
//スプレッドシートのId
const sheetId = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
const sheet = SpreadsheetApp.openById(sheetId).getSheetByName('sheet');

//まず実行される関数
function doGet() {
  const file = HtmlService.createTemplateFromFile('index');
  return file.evaluate().addMetaTag('viewport','width=device-width,initial-scale=1');
}

//現在の状況をスプレッドシートから取得する関数
function getVal() {
  UpDate();
  return sheet.getRange("A1").getValue();
}

//switchbotAPIを叩く関数
function UpDate() {
 //SwitchBotアプリで発行
  const token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
  //ステータスAPI叩いて確認
  const deviceId = "XXXXXXXXXXXXX";
  const headers ={"Authorization": token};
  const options ={  
   "method" : 'GET', 
    "contentType" : 'application/json', 
    "headers" : headers, 
  } 
  const url = "https://api.switch-bot.com/v1.0/devices/" + deviceId + "/status"; 
  try {
    const resp = UrlFetchApp.fetch(url,options);
    const Jresp =  JSON.parse(resp.getContentText());
    if (Jresp["body"]["moveDetected"]){
      sheet.getRange("A1").setValue("使用中");
    }else {
      sheet.getRange("A1").setValue("空き");
    }
  }catch(e) {
    Logger.log(e);
  }
  return;
}

解説

今回もスプレッドシートをデータベース的に使用して、A1のセルに入っている値に応じて画面上の「使用中」もしくは「空き」の背景色を変更させるようにしています。

画面が表示された時と更新するボタンの押下時にコード.jsのgetVal関数を呼び出しています。

●更新ボタンを押した時

index.html
function update() {
	google.script.run.withSuccessHandler(
	  function(resp){
	    const empelm = document.getElementById('empty');
	    const usingelm = document.getElementById('using');
	    if(resp === "空き") {
	      usingelm.classList.remove('chapter');
	      empelm.classList.add('chapter');
	    }else {
	      empelm.classList.remove('chapter');
	      usingelm.classList.add('chapter')
	    }
	  })
	  .getVal();
  }

getVal関数はセルA1の値を返すので、コールバック関数の引数respで受け取り、その値に応じてクラスを変更することで背景色を変えるといった流れになっています。

コード.gsのUpdate関数ではリクエストに必要なパラメータを準備し、UrlFetchApp.fetchメソッドを使用してリクエストしています。

   const resp = UrlFetchApp.fetch(url,options);
   const Jresp =  JSON.parse(resp.getContentText());
   if (Jresp["body"]["moveDetected"]){
     sheet.getRange("A1").setValue("使用中");
   }else {
     sheet.getRange("A1").setValue("空き");
   }

レスポンスはJson文字列なのでjsonにパースします。
bodyの中の「moveDetected」がfalseかtrueかで人がいるいないの判断が出来ますので、そこの値に応じてセルに書き込む文字列を判別しています。

参考レスポンス例
{
   "statusCode":100,
    "body":{
   	"deviceId":"XXXXXXXX",
   	"deviceType":"MotionSensor",
   	"hubDeviceId":"XXXXXXXX",
   	"moveDetected":false,
   	"brightness":"bright"
    },
   "message":"success"
}

所感

SwitchBot楽しい!と思いました。
人感センサー以外にも色んなセンサー等があるので、操作なんかもしてみたいです。

職場のプチストレスをIoT技術で解消(大袈裟?)したので、私個人的には達成感があり、同じお部屋で働いている女子には結構好評です。
でも、男性や他のお部屋の方には知られていない&自分は使わないから・・といった具合で、今回はかなり限定的な人をちょっとだけ便利にするものだったので、あまり反響はありません。
次はもっと目立つところで何か出来そうなことはないか考えて作ってみたいと思います。

Discussion

szdpgasszdpgas

私が勤めている会社でもトイレ事情に悩んでいる社員がおり、相談を受けこちらの記事を発見しました。非常に参考になりました。ありがとうございます。人感センサー以外にもハブミニを使っている用途はなんなのでしょうか。API使用する際にハブミニも必要なのでしょうか。。。もし差し支えなければ教えていただけると嬉しいです🙇

akaneakane

返信が遅くなり申し訳ありません。
仰る通り、ハブミニはAPIを使うために必要になります。
人感センサーはあくまでセンサーでしかなく、他のツール(API、アレクサ、スマホ等)から操作しようと思ったら必要になるという認識です。
参考になりましたら幸いです。