class.exe

blog.netaka.net

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

9/18/2017

この記事を書いてから4年が経っています。内容が古いかもしれません。

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

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

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

LINE Business Center

bot_account
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
line_ada_bot

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

7/31/2017

この記事を書いてから4年が経っています。内容が古いかもしれません。

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
wunder_graph

参考ページ

Footnotes

  1. Wunderlist | To-do リスト、リマインダー、タスク管理 - App of the Year!

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

1/30/2017

この記事を書いてから4年が経っています。内容が古いかもしれません。

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でプロフィールの説明を更新する

7/1/2015

この記事を書いてから6年が経っています。内容が古いかもしれません。

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のアイコンを表示する

12/29/2014

この記事を書いてから7年が経っています。内容が古いかもしれません。

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

以下を参考にしました。

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

Create 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
pebble_image

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

ChangeWatchface
ChangeWatchface

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

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

12/8/2014

この記事を書いてから7年が経っています。内容が古いかもしれません。

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でツイートを投稿する

12/8/2014

この記事を書いてから7年が経っています。内容が古いかもしれません。

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のリプライを取得する

12/2/2014

この記事を書いてから7年が経っています。内容が古いかもしれません。

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 ねたか ずっと探してたのよ

Pythonでプロフィール画像を更新する

11/27/2014

この記事を書いてから7年が経っています。内容が古いかもしれません。

Pythonでプロフィール画像を更新してみました。

以下を参考にしました。

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

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

def update_profile_image(filename):
    file = open(filename, 'rt').read()
    enc_image = base64.b64encode(file)

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

    twitter.update_profile_image(image=enc_image)

def main():
    filename = './kuro.png'
    update_profile_image(filename)

if __name__ == '__main__':
    main()

base64エンコード、めっちゃ楽ですね。とりあえずこのコードを使って、3時間おきにプロフィール画像を更新するようにしています。

Pythonで埋め込みツイートを取得する

11/25/2014

この記事を書いてから7年が経っています。内容が古いかもしれません。

Pythonで指定したステータスIDから埋め込みツイートを取得してみました。

以下を参考に取得しています。

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

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

def get_embed_tweet(embed_id):
    twitter = Twython(
        twitter_oauth.CONSUMER_KEY,
        twitter_oauth.CONSUMER_SECRET,
        twitter_oauth.ACCESS_KEY,
        twitter_oauth.ACCESS_SECRET
    )

    embed = twitter.get_oembed_tweet(id=embed_id)

    if embed.has_key('html'):
        return embed['html']

    return ""

def main():
    id = 536174907856404481
    print get_embed_tweet(id)

if __name__ == '__main__':
    main()

取得した埋め込みツイートはこちらです。

PythonでTwitterにツイート

8/7/2013

この記事を書いてから8年が経っています。内容が古いかもしれません。

python-twitterでTwitterにツイートしていましたが、動かなくなっていました。

python-twitterではなく、twythonならツイート出来ました。 Python-twitterをつかったTwitter API 1.1のツイート取得と投稿 - VivoWiki こちらも試しましたがうまくいかず。環境はさくらVPSです。

Flex 4 SDKをつかって、Adobe AIRでHello World!

8/7/2011

この記事を書いてから10年が経っています。内容が古いかもしれません。

アプリケーションのインストール
アプリケーションのインストール

Adobe AIRでHello World!するための備忘録です。流れとしては、こちらが参考になります。

ではSDKのインストールから、Hello World!の作成までは以下から。

準備しましょう

まずは、Adobe AIRとFlex 4 SDKをインストールしましょう。

SDKは解凍して、/Developer/SDKsにおきました。中のbinディレクトリをパスに通しましょう。

SWFファイルをつくろう

今度はHello World!のプログラムを保存しましょう。

package
{
    import flash.display.*;
    import flash.text.*;
    public class main extends Sprite
    {
        public function main()
        {
            var textField:TextField = new TextField();
            textField.text = "Hello World!";
            addChild( textField );
        }
    }
}

保存したファイルを、main.asとします。amxmlcでコンパイルしましょう。

$ amxmlc main.as

main.swfができました。ブラウザに渡せば表示されるはずです。

AIRアプリケーションをつくろう

AIRのファイルを作るには、XMLファイルが必要になります。SDKを解凍した中にある、flex_sdk_4.5.1/templates/air/descriptor-template.xmlがテンプレートになります。必要なのはこれぐらいになります。

<application xmlns="http://ns.adobe.com/air/application/2.6">
 <id>class-exe.helloworld.</id>
 <filename>HelloWorld</filename>
 <versionNumber>1.0.0</versionNumber>
 <initialWindow>
 <content>main.swf</content>
 <title>HelloWorld</title>
 <visible>true</visible>
 </initialWindow>
</application>

はまったのが、どこかのXMLファイルをコピペしたら、xmlnsの末尾の数字が適切ではなくて、うまくいかないことでした。

あとは最初に紹介したサイトを参考にして、adtコマンドを使用して、署名ファイルを生成して、パッケージ化すると

$ adt -certificate -cn SelfSigned 1024-RSA main.p12 password
$ adt -package -storetype pkcs12 -keystore main.p12 -storepass password main.air main.xml main.swf

airファイルができるはずです。

airファイルをクリックすれば、

アプリケーションのインストール
アプリケーションのインストール

インストールが表示されます。実行すれば、

Adobe AIRでHello World!
Adobe AIRでHello World!

デスクトップのアプリケーションとして表示されました。

OpenCVでスクリーンショット(Windows)

1/8/2011

この記事を書いてから11年が経っています。内容が古いかもしれません。

スクリーンショット(Windows)
スクリーンショット(Windows)

OpenCVでデスクトップの画像を扱う方法です。前回のWindows版です。OpenCVのバージョンは前回と同じく2.2です。適切なライブラリを指定してください。

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

うまくいけば、画像のようになるはずです。ソースコードは以下から。

#include <opencv2/opencv.hpp>

int main (int argc, char * const argv[])
{
    /* デスクトップのサイズ */
    HWND desktop = GetDesktopWindow();
    RECT rect;
    GetWindowRect(desktop, &rect);
    int width = rect.right;
    int height = rect.bottom;

    /* RGB用と反転用とリサイズ用のIplImageの作成 */
    IplImage *iplimage = cvCreateImageHeader(cvSize(width, height), IPL_DEPTH_8U, 3);
    IplImage *flipimage = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
    IplImage *resizeimage = cvCreateImage(cvSize(width/2, height/2), IPL_DEPTH_8U, 3);

    /* DIBの情報を設定する */
    BITMAPINFO bmpInfo;
    bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmpInfo.bmiHeader.biWidth = width;
    bmpInfo.bmiHeader.biHeight = height;
    bmpInfo.bmiHeader.biPlanes = 1;
    bmpInfo.bmiHeader.biBitCount = 24;
    bmpInfo.bmiHeader.biCompression = BI_RGB;

    /* DIBSection作成 */
    LPDWORD lpPixel;
    HDC hDC = GetDC(desktop);
    HBITMAP hBitmap = CreateDIBSection(hDC, &bmpInfo, DIB_RGB_COLORS, (void**)&lpPixel, NULL, 0);
    HDC hMemDC = CreateCompatibleDC(hDC);
    SelectObject(hMemDC, hBitmap);

    /* IplImageヘッダにデータをセット */
    iplimage->imageData = (char *)lpPixel;

    /* ウィンドウ */
    cv::namedWindow("Screenshot", CV_WINDOW_AUTOSIZE);

    while (true)
    {
        /* デスクトップから取得 */
        BitBlt(hMemDC, 0, 0, width, height, hDC, 0, 0, SRCCOPY);

        /* 上下反転して,リサイズ */
        cvFlip(iplimage, flipimage);
        cvResize(flipimage, resizeimage);

        /* ウィンドウへ表示 */
        cv::imshow("Screenshot", resizeimage);
        if(cv::waitKey(30) >= 0) break;
    }

    /* 解放 */
    cvReleaseImageHeader(&iplimage);
    cvReleaseImage(&flipimage);
    cvReleaseImage(&resizeimage);
    ReleaseDC(desktop, hDC);
    DeleteDC(hMemDC);
    DeleteObject(hBitmap);

    return 0;
}

OpenCVでスクリーンショット(Mac OS X)

1/1/2011

この記事を書いてから11年が経っています。内容が古いかもしれません。

スクリーンショット(Mac OSX)
スクリーンショット(Mac OSX)

OpenCVでデスクトップの画像を処理する方法です。直接、スクリーンショットを取得します。OpenCVのバージョンは2.2を使用しています。Xcodeで「ApplicationServices.framework」を追加しておいてください。

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

うまくいけば、画像のようになるはずです。ソースコードは以下から。

#include
#include

int main (int argc, char * const argv[])
{
    /* ディスプレイのサイズ */
    size_t width = CGDisplayPixelsWide(CGMainDisplayID());
    size_t height = CGDisplayPixelsHigh(CGMainDisplayID());

    /* RGBA用とBGR用のIplImageの作成 */
    IplImage *iplimage = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 4);
    IplImage *bgrimage = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
    IplImage *resizeimage = cvCreateImage(cvSize(width/2, height/2), IPL_DEPTH_8U, 3);

    /* グラフィックコンテキストの作成 */
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef contextRef = CGBitmapContextCreate(
        iplimage->imageData, width, height,
        iplimage->depth, iplimage->widthStep,
        colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrderDefault);

    /* ウィンドウ */
    cv::namedWindow("Screenshot", CV_WINDOW_AUTOSIZE);

    while (true)
    {
        /* メインディスプレイからCGImageRefを取得 */
        CGImageRef imageRef = CGDisplayCreateImage(CGMainDisplayID());
            CGContextDrawImage(contextRef,
            CGRectMake(0, 0, width, height),
            imageRef);

        /* RGBAからBGRに変換して,リサイズ */
        cvCvtColor(iplimage, bgrimage, CV_RGBA2BGR);
        cvResize(bgrimage, resizeimage);
        /* ウィンドウへ表示 */
        cv::imshow("Screenshot", resizeimage);

        CGImageRelease(imageRef);
        if(cv::waitKey(30) >= 0) break;
    }

    /* 解放 */
    cvReleaseImage(&iplimage);
    cvReleaseImage(&bgrimage);
    cvReleaseImage(&resizeimage);
    CGContextRelease(contextRef);
    CGColorSpaceRelease(colorSpace);

    return 0;
}

MATLABのGUIで複数のグラフを選ぶ方法

11/16/2010

この記事を書いてから11年が経っています。内容が古いかもしれません。

MATLABのGUI
MATLABのGUI

こんな感じにGUIの中にグラフが複数ある場合、plot(x, y) するには、

plot(handles.axes1, x, y)

という風に指定できる。handles.axes1はGUIDEに表示されていて、タグというのがaxes1に該当します。

ここを参考にしました。複数の座標軸をもつ GUI :: GUIDE GUI の例 (MATLAB®)