::class-exe

Tag: Code

LINEでベクターキャノンを準備してもらう

September 18, 2017

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

Wunderlistの完了タスクをグラフにした

July 31, 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

参考ページ

Node.jsを使ってnasneの録画本数を取得する

January 30, 2017

Node.jsを使ってネットワークレコーダーのnasneの録画本数を取得してみました。

こちらのpackageを利用しています。

upnp-device-client

実装とか

packageをインストールします。

$ npm install upnp-device-client

コードはこちらです。

var Client = require('upnp-device-client');
var fs = require('fs');
// nasneの名称とdevice description URLが記述されたJSONファイル
var obj = JSON.parse(fs.readFileSync('./nasne_list.json', 'utf8'));

obj.forEach(function(nasne) {
  var client = new Client(nasne.url);

  // "ビデオ/すべて"にぶら下がるオブジェクトを取得する。
  // 今回は録画本数として'TotalMatches'をそのまま利用している。
  client.callAction('ContentDirectory', 'Browse', { ObjectID: '0/video/all', BrowseFlag: 'BrowseDirectChildren', Filter: '', StartingIndex: 0, RequestedCount: 0, SortCriteria: '' }, function(err, result) {
    if(err) throw err;
    console.log(nasne.name + ": " + result.TotalMatches);
  });
});

コード中の'nasne_list.json'はこちらです。

[
  {
    "name": "nasne-1",
    "url": "http://192.168.1.11:58888"
  },
  {
    "name": "nasne-2",
    "url": "http://192.168.1.12:58888"
  }
]

結果

結果はこちらです。

$ node nasne.js
nasne-1: 873
nasne-2: 973

参考サイト

こちらを参考にしました。

Pythonでプロフィールの説明を更新する

July 1, 2015

Pythonでプロフィールの説明を更新してみました。

以下を参考にしました。

コードはこちらです。別ファイルのtwitter_oauth.pyにOAUTHに必要なトークン等が記載されています。

# -*- coding: utf-8 -*-
from twython import Twython
import twitter_oauth

def update_profile(text):

    twitter = Twython(
        twitter_oauth.CONSUMER_KEY,
        twitter_oauth.CONSUMER_SECRET,
        twitter_oauth.ACCESS_KEY,
        twitter_oauth.ACCESS_SECRET
        )

    twitter.update_profile(description=text)

def main():
    text = 'A long time ago, in a galaxy far, far away...'
    update_profile(text)

if __name__ == '__main__':
    main()

とりあえずこのコードを使って、1日おきにプロフィールの説明を更新するようにしています。

PebbleにTwitterのアイコンを表示する

December 29, 2014

PebbleにTwitterのアイコンを表示してみました。

以下を参考にしました。

CloudPeppleにあるサンプルを組み合わせて、Twitterのアイコンを出してみました。まずはテンプレートのExamples->Draw Bitmapを選びます。

Create Draw Bitmap

あとは適当に画像の位置を調整して、同じくテンプレートのSDK demos->HelloWorldも参考にしてテキスト表示させたコードが以下になります。

#include "pebble.h"

static GBitmap *image;
static TextLayer *text_layer;

void text_init(Window *window) {
    text_layer = text_layer_create( GRect(0, 128, 144, 32) );

    text_layer_set_text(text_layer, "@netaka");
    text_layer_set_font(text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD));
    text_layer_set_text_alignment(text_layer, GTextAlignmentCenter);

    layer_add_child(window_get_root_layer(window), text_layer_get_layer(text_layer));
}

static void layer_update_callback(Layer *me, GContext* ctx) {
    GRect bounds = image->bounds;
    graphics_draw_bitmap_in_rect(ctx, image, (GRect) { .origin = { 8, 0 }, .size = bounds.size });
}

int main(void) {
    Window *window = window_create();
    window_stack_push(window, true);

    Layer *window_layer = window_get_root_layer(window);
    layer_set_update_proc(window_layer, layer_update_callback);

    image = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_TWITTER);

    text_init(window);

    app_event_loop();

    text_layer_destroy(text_layer);
    gbitmap_destroy(image);
    window_destroy(window);
}

そして表示したい画像をメニューにあるRESOURCESからアップロードしましょう。最後にビルドしてPebbleにインストールすると写真のようになりました。

pebble_image

はじめ、Watch Faceにしたかったのに、どうしてもWatch Appでビルドされてしまうのでどうしてなのかと小一時間悩みましたが、メニューにあるSETTINGSから切り替えられました。

ChangeWatchface

ほんとはTwitterのAPIにアクセスしてアイコン取り寄せるとかそこまでしたいですね。それにしても簡単に画像が表示できるので、LINEのQRコードとかを表示したりすると友達追加の時に便利そうです。

PythonでTwitterのタイムラインを取得する

December 8, 2014

PythonでTwitterのタイムラインを取得してみました。

以下を参考にしました。

コードはこちらです。別ファイルのtwitter_oauth.pyにOAUTHに必要なトークン等が記載されています。

# -*- coding: utf-8 -*-
from twython import Twython
import twitter_oauth

def get_timeline(user, num):
    twitter = Twython(
        twitter_oauth.CONSUMER_KEY,
        twitter_oauth.CONSUMER_SECRET,
        twitter_oauth.ACCESS_KEY,
        twitter_oauth.ACCESS_SECRET
    )

    timeline = twitter.get_user_timeline(user_id=user, count=num)
    return timeline

def main():
    user = 'netaka'
    timeline = get_timeline(user, 10)
    for tweet in timeline:
        print tweet['text']

if __name__ == '__main__':
    main()

取得できるツイート件数のデフォルトは20件のようなのでご注意ください。

Pythonでツイートを投稿する

December 8, 2014

Pythonでツイートを投稿してみました。

以下を参考にしました。

コードはこちらです。別ファイルのtwitter_oauth.pyにOAUTHに必要なトークン等が記載されています。

# -*- coding: utf-8 -*-
from twython import Twython
import twitter_oauth

def post_tweet(text):
    twitter = Twython(
        twitter_oauth.CONSUMER_KEY,
        twitter_oauth.CONSUMER_SECRET,
        twitter_oauth.ACCESS_KEY,
        twitter_oauth.ACCESS_SECRET
    )

    twitter.update_status(status=text)

def main():
    text = "にゃんぱすー"
    post_tweet(text)

if __name__ == '__main__':
    main()

簡単にツイートできて便利ですね。

PythonでTwitterのリプライを取得する

December 2, 2014

PythonでTwitterのリプライを取得してみました。

以下を参考にしました。

コードはこちらです。別ファイルのtwitter_oauth.pyにOAUTHに必要なトークン等が記載されています。

# -*- coding: utf-8 -*-
from twython import Twython
import twitter_oauth

def get_mentions(status_id):

    twitter = Twython(
        twitter_oauth.CONSUMER_KEY,
        twitter_oauth.CONSUMER_SECRET,
        twitter_oauth.ACCESS_KEY,
        twitter_oauth.ACCESS_SECRET
    )

    mentions = twitter.get_mentions_timeline(count=200, since_id=status_id)

    return mentions

def get_reply(status_id):

    mentions = get_mentions(status_id)
    result = ""
    for mention in mentions:
        if mention['in_reply_to_status_id'] == status_id:
            result = mention['text']

    return result

def main():
    print get_reply(534338621193474048)

if __name__ == '__main__':
    main()

get_reply(status_id)は取得できる200件のmentionのうち、指定したステータスIDの一番古いリプライを返すはずです。実行結果は以下な感じです。

$ python reply_twitter.py
@netaka ねたか ずっと探してたのよ