LINEのMessaging APIで、ボットにセリフを喋ってもらいます。

ボット用アカウントをつくる

LINE Business Centerでボット用アカウントを作ります。詳しくは割愛しますが、個人用だったのでDeveloper Trialで作っています。

LINE Business Center

bot_account

HTTPSが使えるサーバを準備する

Webhook使ってメッセージを受け取るので、HTTPSで受け取れるようなサーバを準備してください。

ボット用のSDKを手に入れて、実装する

便利なSDKがあるのでinstallしましょう。

line/line-bot-sdk-python: SDK of the LINE Messaging API for Python.

Usage:にサンプルがあるので利用します。セリフを喋るためにちょっと手を加えたのがこちらです。

from flask import Flask, request, abort
from dotenv import load_dotenv, find_dotenv
import time
import os

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)

app = Flask(__name__)
load_dotenv(find_dotenv())

line_bot_api = LineBotApi(os.environ.get('CHANNEL_ACCESS_TOKEN'))
handler = WebhookHandler(os.environ.get('CHANNEL_SECRET'))


@app.route("/ada", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)
    print(body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)

    return 'OK'


@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    to = ''
    if event.source.type == 'group':
        to = event.source.group_id
    if event.source.type == 'user':
        to = event.source.user_id
    if event.message.text == "ベクターキャノン":
        line_bot_api.push_message(to, TextSendMessage(text='ベクターキャノンモードへ移行'))
        time.sleep(3)
        line_bot_api.push_message(to, TextSendMessage(text='エネルギーライン全段直結'))
        time.sleep(2)
        line_bot_api.push_message(to, TextSendMessage(text='ランディングギア、アイゼン、ロック'))
        time.sleep(3)
        line_bot_api.push_message(to, TextSendMessage(text='チャンバー内、正常加圧中'))
        time.sleep(2)
        line_bot_api.push_message(to, TextSendMessage(text='ライフリング回転開始'))
        time.sleep(7)
        line_bot_api.push_message(to, TextSendMessage(text='撃てます'))


if __name__ == "__main__":
    app.run()

できました

こちらが「ベクターキャノン」と言うと、ボットは某ゲームのセリフを喋ります。

line_ada_bot

September 18, 2017 作成

退社したらお疲れさまと言ってもらいます。IFTTTでやってみます。

トリガー

Locationサービスで会社の建物を設定します。

trigger

アクション

LINEサービスで通知メッセージを設定します。

action

レシピ

できあがったレシピはこんなのです。

recipe

LINE Notifyから、お疲れさま、って言ってもらえました。

line-notify

September 4, 2017 作成

このブログの読み込みがなぜか重かったので、さくらのVPSのコンパネを確認したら、ストレージのリソースが制限されていました。

restriction

かくにん

リソースの制限についてはこちら。

リソース制限表示について – さくらのサポート情報

月曜日からDISK I/Oの負荷が増え始めて、水曜日に制限され始めたようです。同じサーバではこのブログ以外に自分専用にMastodon1も動かしています。どちらかと言えばMastodonのほうが高負荷そうです。

disk_io

ためす

負荷が高そうと予想されるMastodonをとりあえず止めてみます2。バージョンはv1.4.7でした。

$ docker-compose stop
Stopping mastodon_sidekiq_1 ... done
Stopping mastodon_streaming_1 ... done
Stopping mastodon_web_1 ... done
Stopping mastodon_db_1 ... done
Stopping mastodon_redis_1 ... done

さいかくにん

土曜日12時頃に止めたところDISK I/Oの負荷が減りました。その一時間後にはリソース制限も解除されました。

disk_io_2

といっても、Mastodonを止め続けておくわけにはいかないので、DISK I/Oへの高負荷の原因をあとで調べないといけないです。


  1. tootsuite/mastodon: A GNU Social-compatible microblogging server 
  2. 止める前にsidekiqのログとか見ておけばよかったですね。 

August 12, 2017 作成

ToDoリストアプリのWunderlist1から完了タスクを取得してグラフにしてみました。Pythonをつかって、直近7日間の完了タスク数をグラフにしています。

環境は以下の通りです。

$ python -V
Python 2.7.10
$ pip freeze
matplotlib==2.0.0
python-dateutil==2.6.0
pytz==2016.10
requests-oauthlib==0.8.0

手順

  1. アプリを登録して、APIに必要なアクセストークン等を取得する(詳細は割愛)
  2. 全リストのIDを取得
  3. IDから完了タスクを取得
  4. 日付ごとに完了タスクをカウント
  5. matplotlibでグラフ化

コード

# coding:utf-8

import json
from requests_oauthlib import OAuth2Session
from dateutil import parser
from datetime import timedelta, datetime
import matplotlib.pyplot as plt
from pytz import timezone


class Wunderlist:
    def __init__(self):
        self.api = OAuth2Session()
        self.api.headers['X-Client-ID'] = 'your_client_id'
        self.api.headers['X-Access-Token'] = 'your_access_token'

    def fetch_list_id(self):
        req = self.api.get('https://a.wunderlist.com/api/v1/lists',
                           params={})

        if req.status_code != 200:
            print ('Error: %d' % req.status_code)
            return []

        lists = json.loads(req.text)
        id = [l['id'] for l in lists]
        return id

    def fetch_completed_at(self, id):
        req = self.api.get('https://a.wunderlist.com/api/v1/tasks',
                           params={'completed': 'true', 'list_id': id})

        if req.status_code != 200:
            print ("Error: %d" % req.status_code)
            return []

        tasks = json.loads(req.text)
        completed_at = [t['completed_at'] for t in tasks]
        return completed_at

    def fetch_completed_at_all(self):
        list_id = self.fetch_list_id()
        completed_at = []
        for id in list_id:
            completed_at.extend(self.fetch_completed_at(id))
        return completed_at


def make_complete_counts(completed_at, start_date, x):
    dates = [parser.parse(date).astimezone(timezone('Asia/Tokyo')).date() for date in completed_at]
    dates = [date for date in dates if date >= start_date]

    diff_dates = [(date - start_date).days for date in dates]

    result = [diff_dates.count(days) for days in x]
    return result


def make_date_ticks(start_date, x):
    dates = [(start_date + timedelta(days=var)).strftime('%m/%d') for var in x]
    return dates


def main():
    today = datetime.now(timezone('Asia/Tokyo')).date()
    start_date = today - timedelta(days=6)

    wunderlist = Wunderlist()
    completed_at = wunderlist.fetch_completed_at_all()

    x = range(7)
    y = make_complete_counts(completed_at, start_date, x)
    x_ticks = make_date_ticks(start_date, x)

    plt.xkcd()
    plt.bar(x, y)
    plt.xticks(x, x_ticks)
    plt.savefig('wunder_graph.png')


if __name__ == '__main__':
    main()

できました

wunder_graph

参考ページ

July 31, 2017 作成

素でMarkdownが使えるWikiのCrowi1を自宅のNUCにインストールしてみました。正確にはCrowiではなくcrowi-plus2ですが。環境は次の通り。

  • Ubuntu Server 16.04 LTS
  • Intel NUC Kit D54250WYK

Dockerのインストール

Dockerを使ってインストールしてみます。

$ sudo apt install docker
$ sudo apt install docker-compose
$ docker -v
Docker version 1.12.6, build 78d1802

crowi-plusのインストール

READMEどおりに、インストールしてみます。

$ git clone https://github.com/weseek/crowi-plus-docker-compose.git crowi-plus
$ cd crowi-plus
$ docker-compose up

すると、エラーが出ます。

ERROR: Version in "./docker-compose.yml" is unsupported. You might be seeing this error because you're using the wrong Compose file version. Either specify a version of "2" (or "2.0") and place your service definitions under the `services` key, or omit the `version` key and place your service definitions at the root of the file to use version 1.
For more on the Compose file format versions, see https://docs.docker.com/compose/compose-file/

やりなおし

古かったようです。ということで、Dockerの公式マニュアルにそってやりなおします。

Get Docker CE for Ubuntu | Docker Documentation

$ sudo apt remove docker-compose
$ sudo apt remove docker
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
$ sudo apt update

準備できたので、インストールしなおします。

$ sudo apt install docker-ce
$ sudo -i
# curl -L https://github.com/docker/compose/releases/download/1.14.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
# exit

今度こそ大丈夫そうです。

$ docker -v
Docker version 17.06.0-ce, build 02c1d87

だめです

大丈夫じゃなかったです。

$ docker-compose up -d
ERROR: Couldn't connect to Docker daemon at http+docker://localunixsocket - is it running?

こちらを参考にdockerグループにユーザーを追加します。

Dockerコマンドをsudoなしで実行する方法 - Qiita

つながらないです

localhostからだけだったので、docker-compose.ymlのポートのマッピングを変更しました。

$ git diff
diff --git a/docker-compose.yml b/docker-compose.yml
index dae65d3..d176205 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -6,7 +6,7 @@ services:
       context: .
       dockerfile: ./Dockerfile
     ports:
-      - 127.0.0.1:3000:3000
+      - 3000:3000
     links:
       - mongo:mongo
       - redis:redis
$ docker-compose ps
          Name                         Command               State           Ports          
-------------------------------------------------------------------------------------------
crowiplus_app_1             dockerize -wait tcp://mong ...   Up      0.0.0.0:3000->3000/tcp 
crowiplus_elasticsearch_1   /docker-entrypoint.sh sh - ...   Up      9200/tcp, 9300/tcp     
crowiplus_mongo_1           docker-entrypoint.sh mongod      Up      27017/tcp              
crowiplus_redis_1           docker-entrypoint.sh redis ...   Up      6379/tcp
$ sudo lsof -i:3000
COMMAND     PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
docker-pr 25053 root    4u  IPv6  93412      0t0  TCP *:3000 (LISTEN)

できました

install

July 27, 2017 作成

Ubuntu Server 16.04 LTSをインストールしたNUCでWi-Fi接続してみました。環境、バージョン等は以下の通り。

iwconfigを利用可能にする

iwconfigはwireless-toolsパッケージに入っているようです。

$ iwconfig
The program 'iwconfig' is currently not installed. You can install it by typing:
sudo apt install wireless-tools
$ sudo apt install wireless-tools

iwconfigでWi-Fiモジュールを確認する

iwconfigでWi-Fiモジュールが確認できました。wlp2s0というインタフェースのようです。

$ iwconfig
lo        no wireless extensions.

eno1      no wireless extensions.

wlp2s0    IEEE 802.11abgn  ESSID:off/any  
          Mode:Managed  Access Point: Not-Associated   Tx-Power=0 dBm   
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Power Management:on

wpa_passphrase, wpa_supplicantを利用可能にする

wpasupplicantパッケージをインストールします。

$ sudo apt install wpasupplicant

設定情報を作成する

wpa_passphraseでパスフレーズを暗号化して、設定情報をwpa_supplicant.confというファイルで保存します。

$ wpa_passphrase "ESSID" "passphrase"
network={
    ssid="ESSID"
    #psk="passphrase"
    psk=d5b7ea2dda330fb59753d126e0b98bc968644423abb76bb52374a027718219c6
}
$ wpa_passphrase "ESSID" "passphrase" > wpa_supplicant.conf

お家のアクセスポイントはSSIDがステレスなので、scan_ssid=1を追記しています。

wpa_supplicantコマンドで接続する

wpa_supplicantコマンドでアクセスポイントに接続します。

$ sudo wpa_supplicant -i wlp2s0 -c wpa_supplicant.conf -B

そして、DHCPクライアントでIPアドレスを取得します。

$ sudo dhclient wlp2s0

起動時に接続するようにする

こちらを参考に、systemdサービス用に、wpa_supplicant@wlp2s0.serviceを作成します。参考ページの記載とほぼ同じですが、wpa_supplicantのパスを/sbin/wpa_supplicantにしているのと、ExecStartPostdhclientを追記しています。

$ sudo mv wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant-wlp2s0.conf
$ sudo vim /etc/systemd/system/wpa_supplicant@wlp2s0.service
[Unit]
Description=WPA supplicant daemon (interface-specific version)
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device

[Service]
Type=simple
ExecStart=/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
ExecStartPost=/sbin/dhclient %i

[Install]
Alias=multi-user.target.wants/wpa_supplicant@%i.service

無線インタフェースだけで運用する

有線を繋げていないと起動時にStarting Raise network interfaces...で待たされてしまうので、networking.serviceを止めてしまう。

$ sudo systemctl disable networking.service

追記

こっちのほうが適当そう。eno1をコメントアウトする。

/etc/network/interfaces
# The primary network interface
# auto eno1
# iface eno1 inet dhcp

参考ページ

July 24, 2017 作成

Intel NUC Kit D54250WYKのBIOSが古かったのでアップデートしてみました。

Ubuntu Server 16.04 LTSをD54250WYKにインストールしたところ、ブートがうまくいかなかったので、試しにBIOSをアップデートしてみました。1

bioファイルをダウンロード

ダウンロードページからWY0045.bioをダウンロードします。ダウンロードしたら適当なメディア(USBメモリ等)に保存します。
ダウンロード BIOS アップデート [WYLPT10H.86A]

bioファイルを選択

BIOSスクリーン上にBIOS Versionが記載されているので、右端のUpdate >を選択して、保存したbioファイルを選択する。2

visual_bios

BIOSをアップデート

選択後、BIOSスクリーンを出てからアップデートが始まります。

参考ページ

D54250WYKにUbuntuを入れてみたが、シャットダウンできない... - tuttitanの日記


  1. 結局、ブートできるようになったけどBIOSをアップデートしたおかげなのかは不明。 
  2. スクリーンショットはバージョン 0045にアップデートした後のもの。 

July 24, 2017 作成

QNAP NASにDokuWikiをインストールしたときのメモです。

バージョン

使用しているNASは以下の通り。

  • Model: TS-219P II
  • QTS: 4.2.3

アプリ

QTSからDokuWiki - Beta1というアプリが用意されているのでインストールします。

下記ディレクトリにあります。

home/Qhttpd/Web/dokuwiki/

アップグレード

DokuWikiのバージョンが古かったのでアップグレードします。

アップグレードはプラグインを使用しました。

plugin:upgrade [DokuWiki]

以下はアップグレード時のエラーについて。

書き込み権限で失敗する

ほとんどの更新ファイルが権限がなく書き込みができないので、httpdusrの権限を変更しました。

ダウンロードしてきたファイルが展開できない

プラグインは下記から更新用アーカイブを手に入れますが、展開に失敗するのか更新ファイルがあるディレクトリが空っぽ2になってしまいます。そのため、なんのファイルも更新できずに、アップグレードが終了します。

https://github.com/splitbrain/dokuwiki/archive/stable.tar.gz

対応として、自前で展開させたら、とりあえずうまくいきました。

# cd /home/Qhttpd/Web/dokuwiki/data/tmp
# tar -xzf dokuwiki-upgrade.tgz
# mv dokuwiki-stable/ dokuwiki-upgrade

  1. https://www.qnap.com/en-in/app_releasenotes/list.php?app_choose=DokuWiki 
  2. ディレクトリが空っぽの理由は不明。 

May 15, 2017 作成