🌸

LINE BOTとIFTTT(Fitbit)でなんちゃってピクミンブルームを作ってみた

2021/12/04に公開

この記事は、プロとアウトスタジオアドベントカレンダー2021の4日目です!

はじめに

前回の記事(https://qiita.com/tkyko13/items/bdfee3416792737fd48d)のようにLINE BOTとIFTTTを組み合わせて最新作のPikmin Bloomのようなものを作ってみました

IFTTTにfitbitがあったのでそれを利用し、一日の終わりにその日歩いた歩数と、それにあった苗を一つだけもらえて、引っこ抜けるサービスです

位置情報とかは関係なく、歩数です

Image from Gyazo

こんな感じに、一日の終わりにまず苗が通知され、引っこ抜くボタンを押すとその苗にあったピクミンを引っこ抜けます!

開発環境

  • Node.js v14.5.0
  • express v4.17.1
  • line/bot-sdk v7.4.0
  • localtunnel v2.0.2

使ったサービス

手順概要、目次

ほぼ前回と同じ

  1. LINE BOT作成
    1. LINE Developerに登録
    2. LINE BOTの設定
    3. ソースコードをコピペ
    4. アクセストークンとチャンネルシークレットを書き換え
    5. localtunnelインストール、実行
    6. localtunnelのURLをLINE BOTに設定、検証
    7. コンソールで出たログからsource内のuserIdをソースコード内に置き換え
  2. IFTTT作成
  3. Let's フィットネス

LINE BOTの作成

こちらの通りに作りました!

「1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest」
https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d

ソースコード

server.js
'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;

const config = {
  channelSecret: 'チャンネルシークレット',
  channelAccessToken:'アクセストークン',
};
const LINE_USERID = 'いったん普通のLINE BOTとして動作させ自分のIDを調べる';

// plant info
const pikminData = [
  {
    plantImg: 'https://app-story.net/wp-content/uploads/2021/11/akanonae-1.jpg',
    pikminImg: 'https://app-story.net/wp-content/uploads/2021/11/aka.jpg',
    type: '赤い苗'
  },
  {
    plantImg: 'https://app-story.net/wp-content/uploads/2021/11/kiiro.jpg',
    pikminImg: 'https://app-story.net/wp-content/uploads/2021/11/kiiro-1.jpg',
    type: '黄色い苗'
  },
  {
    plantImg: 'https://app-story.net/wp-content/uploads/2021/11/ao.jpg',
    pikminImg: 'https://app-story.net/wp-content/uploads/2021/11/ao-1.jpg',
    type: '青い苗'
  },
  {
    plantImg: 'https://app-story.net/wp-content/uploads/2021/11/murasaki-1.jpg',
    pikminImg: 'https://app-story.net/wp-content/uploads/2021/11/murasaki-2.jpg',
    type: '紫色の苗'
  },
  {
    plantImg: 'https://app-story.net/wp-content/uploads/2021/11/shiro.jpg',
    pikminImg: 'https://app-story.net/wp-content/uploads/2021/11/shiro-1.jpg',
    type: '白色の苗'
  },
  {
    plantImg: 'https://app-story.net/wp-content/uploads/2021/11/pinku.jpg',
    pikminImg: 'https://app-story.net/wp-content/uploads/2021/11/hane.jpg',
    type: 'ピンク色の苗'
  },
  {
    plantImg: 'https://app-story.net/wp-content/uploads/2021/11/gure.jpg',
    pikminImg: 'https://app-story.net/wp-content/uploads/2021/11/iwa.jpg',
    type: 'グレー色の苗'
  },
];

const app = express();
const client = new line.Client(config);

app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用(無くても問題ない)
app.post('/ifttt', async (req, res) => {
  const totalStep = parseInt(5000 + Math.random() * 10000); // test用
  // const totalStep = req.query.totalStep;
  console.log('totalStep = ' + totalStep);

  let index = 0;
  if (totalStep < 10000) {
    index = parseInt(Math.random() * 3);
  }
  else {
    index = parseInt(3 + Math.random() * 4);
  }
  console.log('index = ' + index);

  client.pushMessage(LINE_USERID, {
    'type': 'template',
    'altText': 'This is a buttons template',
    'template': {
      'type': 'buttons',
      'thumbnailImageUrl': pikminData[index].plantImg,
      'imageAspectRatio': 'square',
      'imageSize': 'cover',
      'imageBackgroundColor': '#FFFFFF',
      'title': 'おつかれさまです!',
      'text': '今日は' + totalStep + '歩あるきました。',
      'actions': [
        {
          'type': 'message',
          'label': '引っこ抜く',
          'text': pikminData[index].type
        }
      ]
    }
  });

  res.send('ifttt post');
});

// 以下replay message用 userIDも調べられる
app.post('/webhook', line.middleware(config), (req, res) => {
  console.log(req.body.events);

  if (req.body.events.length == 0) {
    res.send('Hello LINE BOT!(POST)');
    console.log('疎通確認用');
    return;
  }

  Promise.all(req.body.events.map(handleEvent)).then((result) =>
    res.json(result)
  );
});
async function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }
  console.log(event.source.userId);
  for (let i = 0; i < pikminData.length; i++) {
    if (pikminData[i].type == event.message.text) {
      return client.replyMessage(event.replyToken, {
        'type': 'image',
        'originalContentUrl': pikminData[i].pikminImg,
        'previewImageUrl': pikminData[i].pikminImg
      });
    }
  }

  // オウム返し
  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: event.message.text, //実際に返信の言葉を入れる箇所
  });
}

app.listen(PORT);
console.log(`Server running at ${PORT}`);

localtunnelで起動

ngrokがうまくいかなかったので、localtunnelを使ってみました

npm i -g localtunnel
lt --port 3000

Image from Gyazo

使い勝手はngrokと同じ感じですごくよい!

IFTTT作成

今回はfitbitと連携させるので、スマートフォンアプリをインストールします。

iOS: https://apps.apple.com/jp/app/ifttt/id660944635
Android: https://play.google.com/store/apps/details?id=com.ifttt.ifttt&hl=ja

あとfitbitもこちらから

iOS: https://apps.apple.com/jp/app/fitbit/id462638897
Android: https://play.google.com/store/apps/details?id=com.fitbit.FitbitMobile&hl=ja&gl=US

インストールしたら以下のようにアプレットを作ります。

【IFの方】

「fitbit」を検索し、

Image from Gyazo

「Daily activity summary」を選んでみました

Image from Gyazo

「Connect」していきましょう
この前にfitbitアプリもインストールしておき、アカウント作成もしておいています

Image from Gyazo

【Thenの方】

Webhookを検索し、以下のように設定します

Image from Gyazo

Image from Gyazo

アプレット全体はこんな感じに

Image from Gyazo

これで完成!と補足

例によって(?)アドベントカレンダー当日に書いております…
実際実はまだfitbitからの値でテストしてないですが、コード内にも書いてあるtest用のものでは確認できてるので多分できるんじゃないかと…

IFTTTの1日1回系のアクションは結構デバッグ大変なんじゃないだろうか
なんかテスト実行ほしいね(あったとしても有料かもな…)

終わりに

fitbitがIFTTTで使えるのはすごい楽しそう!

他にもたくさんあって、睡眠データとかも取れそうだし、こういったライフログが手軽に使えるのは面白い!!

永続化ですが、userIDを使う関係で簡単にはできないっすねぇでもやってみたい

Discussion