読者です 読者をやめる 読者になる 読者になる

39Si

プログラミング関連の勉強した内容を簡単にまとめておきます

CoffeeScript の勉強

腕をケガしてしまい、
特にやることなかったので、
前から気になってた CoffeeScript の基本的な内容を勉強した。

CoffeeScript

公式サイト

Version

CoffeeScript 1.10.0

Hello world

var や ; ,カッコは不要
コメントは # を使う

###
Hello world
###

# 変数
hello = 'Hello world'

# alert window で文章を表示
alert hello

変数

# 数値
num = 1

# bool true or false
flag = true

# 文字列
name = 'inner'

# 複数行
html = """
       <html>
           contents
       </html>
       """

式展開

score = 80
alert "score: #{score}"

配列 と オブジェクト

# Array
a = [1, 3, 5]     # a = [1, 3, 5]
b = [0..5]        # b = [0,1,2,3,4,5]
c = [0...5]       # c = [0,1,2,3,4]

# object
aaa = name: 'inner', age: 24

# 複雑に書く
bbb =
    name: 'inner'
    score:
        ccc: 10
        ddd: 20

制御文

条件分岐 if

flag が true の時に OK を表示する

flag = true

# 一行で if else
if flag then alert "OK" else alert "NG"

# 複数行で if else
if flag
    alert "OK"
else
    alert "NG"

# 後置の if
alert "OK" if flag

# そのまま代入
msg = if flag then "OK" else "NG"
alert msg

複雑な条件分岐

color = "green"

if color == "red"
    alert "color is red"
else if color == "green"
    alert "color is green"
else
    alert "color ?"

Switch

color = "green"

switch color
    when "red"
        alert "color is red"
    when "green" then alert "color is green"  # then を使って一行でも書ける
    else
        alert "color ?"

繰り返し for while

# for
sum = 0
for i in [0..9]
    sum += i
alert sum

# while
j = 0
sum = 0
while j < 10
    sum += j
    j++
alert sum

関数

# 引数がない場合
hello = -> 
    alert "hello"

# 引数と返り値
hello2 = (name) ->
    "I am #{name}."

# 関数の実行
hello()
result = hello2 "inner"
alert result

クラス

class User
    constructor: (name) ->
        # 最初に呼ばれるメソッド
        this.name = name
    do: () ->
        alert "I am #{@name}"

tom = new User "Tom"
alert tom.name
tom.do()

JavaScript の埋め込み

コードをバッククオートで囲む

参考

CoffeeScript言語リファレンス-sappari wiki ドットインストール

MeCab による形態素解析とPythonでマルコフ連鎖

Python マルコフ連鎖を利用して文章を生成する

  • 連鎖数は 3
  • 方法は下記のリンクのコードを参考にした。

MeCabとPythonでマルコフ連鎖を書いてみる(改) | Weboo! Returns.

環境

MeCab のインストール

過去に記事にしてるのでここでは省略

Python で Mecabを利用する【mac】 - プログラミングノート

内容

1. データベースの作成

SQLite3 でデータベースを作成する

$ python make_db.py

make_db.py

import sqlite3

# Connect database
conn = sqlite3.connect('markov.db')
c = conn.cursor()

# Create database table
c.execute("create table stocks(word1, word2, word3)")

conn.close()

2. 形態素解析で文章を単語に分ける

$ chmod u+x do_mecab.sh
$ python make_markov_chain.py

do_mecab.sh

#!/bin/sh
echo $*|/usr/local/bin/mecab -Owakati

make_markov_chain.py

import subprocess
import sqlite3

# split word
word_split = '''
'''

# Connect database
conn = sqlite3.connect('markov.db')
c = conn.cursor()


# make markov chain
def make_markov():
    # read sourcefile text.txt
    filename = 'text.txt'
    src = open(filename, 'r').read()

    src_list = src.split(word_split)

    # mecab による形態素解析
    for sentence in src_list:

        # run command
        result = subprocess.getoutput('./do_mecab.sh ' + sentence)
        # print(result)

        word_list = result.split(' ')
        word_list.remove('')  # 不要なデータの削除

        w1 = ''
        w2 = ''
        for word in word_list:
            if w1 and w2:
                c.execute("insert into stocks values(?, ?, ?)", (w1, w2, word))
                # print("insert data", w1, w2, word)
            w1, w2 = w2, word

    # save database
    conn.commit()


# create database table
def create_table():
    c.execute("create table stocks(word1, word2, word3")


# Main
if __name__ == "__main__":
    make_markov()
    conn.close()

3. 登録したデータを利用して文章を作成する。

$ python make_sentence.py

make_sentence.py

import sqlite3

# Connect database
conn = sqlite3.connect('markov.db')
c = conn.cursor()


# create sentence
def create_sentence():
    sentence = ""
    c.execute("select * from stocks order by random() limit 1")
    list1 = c.fetchall()
    w1 = list1[0][0]
    w2 = list1[0][1]
    sentence += w1 + w2

    for i in range(20):
        try:
            c.execute("select * from stocks where word1 = '" + w1 + "' and word2 = '" + w2 + "' order by random() limit 1")
            list2 = c.fetchall()
            w1, w2 = w2, list2[0][2]
            sentence += list2[0][2]
            # print(i, list2)

        except:
            # print("error")
            break
    return sentence


# Main
if __name__ == "__main__":
    # read_csv()
    result = create_sentence()
    print(result)
    conn.close()

参考

github

github.com

python でコマンドを実行する

環境

Python version

subprocess を利用してコマンドを実行

import subprocess

cmd = 'ls -l'
result = subprocess.getoutput(cmd)
print(result)  # 実行結果の表示

これだけ

参考ページ

python3 - subprocess

python3 で SQLite3 を使う

python version

SQLite3 version

  • 3.8.10.2

python code

import sqlite3

# Connect database
conn = sqlite3.connect('example.db')
c = conn.cursor()

# テーブルの作成
c.execute("create table stocks(word1, word2")

# データの挿入
w1 = "hello"
w2 = "world"
c.execute("insert into stocks values(?, ?)", (w1, w2))

# データの抽出
c.execute("select * from stocks")
list = c.fetchall()
print(list)

# Save
conn.save()

# Close
conn.close()

前回のまとめ

inner2.hatenablog.com

参考

python - sqlite3

SQLite 使い方

SQLite について

  • 軽量のデータベース
  • アプリケーションに組み込んで利用される

データベースの作成・接続

$ sqlite3 example.db

終了

sqlite> .exit

データベースの削除

'example.db' のファイルを削除

テーブル

テーブルの作成

sqlite> create table stocks(id, name);

型を指定してテーブルを作成

sqlite> create table stocks(id integer, name text);

型について - null : NULL - integer : 符号付整数 - real : 浮動小数点数 - text : テキスト - blob : binary large object 入力データをそのまま

テーブルのスキーマ情報の表示

sqlite> .schema
CREATE TABLE stocks(id, name);
  • schema(概要;枠組み;概略図)

テーブルの削除

sqlite> drop table stocks;

データの追加・更新・削除

データの追加

sqlite> insert into stocks values(1, 'inner');

データの更新

id = 1 の name カラム 'penpen' に変更

sqlite> update stocks set name = 'penpen' where id = 1;

データの削除

stocks テーブルの内容全て削除

sqlite> delete from stocks;

条件を指定して削除
stocks テーブル内の id = 1 のデータを削除

sqlite> delete from stocks where id = 1;

データの抽出 SELECT

テーブル内の全てのデータを取得

sqlite> select * from stocks;

name カラムのみを抽出

sqlite> select name from stocks;

Sort

昇順

sqlite> select * from stocks order by id asc;

降順

sqlite> select * from stocks order by id desc;

条件を設定

sqlite> select * from stocks where name = 'inner';

Limit

データを10個取得

sqlite> select * from stocks limit 10;

設定の確認

sqlite> .show

ヘルプ

sqlite> .help

参考

SQLite 入門

【Apple Watch と IoT】Apple Watch でエアコンを制御する【後編】

inner2.hatenablog.com

前編の続きです。

Raspberry PI で Twitter のつぶやきを読み取る

自宅に設置する Raspberry PI では主に2つのことを行います。 今回は、Python 3 系でプログラムを書くことにしました。

  1. Twitter でつぶやいたコマンドの読み取り
  2. Arduino への命令(Serial 通信)

Twitter の Timeline を取得

まず、Twitter のタイムラインの取得には以下の Module を使用しました。

また、Twitter の認証には OAuth 認証を使うため、あらかじめ設定をしておく必要があります。 私以外にたくさんの人が解説しているのでそちらを参考にしてください。 - OAuth 認証についての参考ページ

Arduino と Serial 通信

Serial で文字列を送信するのは大変そうだったので、 命令は文字1文字を送ることにし、 以下のようにした。

Twitter で heating とつぶやいた -> Arduino に "h" を送信
Twitter で cooling とつぶやいた -> Arduino に "c" を送信
Twitter で stop    とつぶやいた -> Arduino に "s" を送信

Code (Raspberry PI)

# import module pyserial twitter
from twitter import *
import serial
import time


# ------ Access key や 使用する Twitter アカウントの入力 --------
# Twitter Account
twitter_account = ""
# SETTING TWITTER ACCESS
token = ""
token_key = ""
con_secret = ""
con_secret_key = ""
# Arduino serial port
serial_port = '/dev/ttyACM0'  # mac /dev/tty.usbmodem1421
# ---------------------------------------------------------------

auth = OAuth(token, token_key, con_secret, con_secret_key)
t = Twitter(auth=OAuth(token, token_key, con_secret, con_secret_key))

# twitter read
def twitter_read():
    # init
    ser = serial.Serial(serial_port, 9600)
    mg = ser.read()
    print(mg)

    twitter_userstream = TwitterStream(auth=auth, domain='userstream.twitter.com')
    for msg in twitter_userstream.user():
        if 'user' in msg:
            # check user
            if msg['user']['screen_name'] == twitter_account:
                print(msg['text'])
                cmd = msg['text'].split('-')
                if cmd[0] == 'stop':
                    sends = "s".encode()
                    ser.write(sends)
                elif cmd[0] == 'heating':
                    sends = "h".encode()
                    ser.write(sends)
                elif cmd[0] == 'cooling':
                    sends = "c".encode()
                    ser.write(sends)


# Main
if __name__ == '__main__':
    time.sleep(10)
    try:
        twitter_read()
    except:
        print("error")

補足

  • Sleep 処理を入れているのはラズベリーパイのUSBポートが二つしかなく、キーボードと無線LANで埋まっており、Sleep 中にキーボードとArduinoを入れ替えるためです。

Arduino でエアコンを制御する

Arduino では、以下の三つのことをしました。

  1. あらかじめリモコンの信号の取得
  2. Serial 通信(Raspberry PI からの信号の読み取り)
  3. 赤外線LED から信号を送信

Arduino で赤外線LEDを利用する

Arduino の部分は下記のページを参考にしました。
リモコンの信号を取得する部分はそのまま利用しました。

Code (Arduino)

うまい具合に書けなかったので、かなりごり押しなコードになってます。

run.ino

// Arduino

// IR Signal Data
unsigned int airstop[] = {373,192,44,52,42,144,43,49,43,144,40,54,41,148,37,55,44,142,44,49,44,143,44,49,44,142,44,142,42,52,44,143,44,49,44,143,44,142,47,142,42,143,43,50,42,53,45,140,43,144,40,53,40,54,44,51,37,54,44,143,44,48,45,50,42,51,42,143,43,143,42,53,42,51,42,49,46,48,42,53,42,51,42,145,42,51,42,49,46,47,42,52,44,142,44,52,37,54,44,143,47,48,42,51,42,51,42,50,42,144,42,52,42,51,44,142,44,50,41,52,44,49,42,52,43,51,42,51,42,49,46,47,42,52,44,52,42,142,44,140,47,142,46,48,42,51,42,52,41,52,41,52,41,52,39,54,42,141,45,52,44,142,44,144,41,52,44,142,42,52,41,52,44,49,44,50,41,52,41,52,44,49,44,143,47,142,44,48,42,142,43,144,44,143,39,148,42,51,39,54,40,54,39,54,39,54,42,51,39,148,44};
unsigned int cool[] = {376,189,45,49,47,140,47,47,47,139,48,46,46,141,42,51,39,135,52,54,40,146,41,53,40,148,39,148,39,54,40,148,39,53,40,148,44,140,48,142,47,140,45,49,44,49,44,142,45,142,40,53,44,49,44,49,40,53,45,142,45,49,44,48,45,49,47,46,45,51,45,140,46,140,40,53,40,54,41,51,40,53,40,147,39,54,40,54,47,46,45,142,48,140,46,47,45,50,45,46,46,141,40,54,40,53,39,54,39,148,39,54,39,54,44,142,40,54,44,49,44,49,44,49,40,54,40,54,41,52,44,48,45,49,41,51,48,140,48,139,46,46,46,50,45,46,46,46,40,53,44,50,39,54,39,54,44,142,40,53,44,143,39,53,40,54,44,49,48,46,47,46,47,46,47,46,44,50,40,53,40,54,42,145,48,139,46,47,44,143,44,143,44,143,47,140,44,49,44,49,44,49,47,46,46,140,40,53,40,53,44};
unsigned int heat[] = {380,184,54,40,53,134,52,41,52,134,52,41,50,136,53,41,52,134,52,42,48,138,50,42,53,135,51,135,51,42,53,134,52,42,49,137,53,134,53,134,51,137,52,41,51,45,50,134,52,136,49,44,48,44,49,44,51,43,48,138,48,45,50,42,48,45,48,138,50,137,49,44,48,44,48,44,49,45,48,44,49,44,52,135,49,44,50,44,49,44,52,134,53,135,52,41,51,42,48,139,50,43,52,41,51,42,50,44,52,135,50,44,49,44,49,137,53,40,52,41,52,42,50,43,50,42,51,43,50,43,48,44,50,44,49,44,50,132,54,138,48,138,50,43,49,44,49,43,52,41,52,42,49,44,48,44,50,137,49,44,50,138,49,44,50,44,52,41,52,42,50,42,50,43,52,42,50,42,49,44,49,44,50,138,52,134,53,41,52,135,51,136,49,138,48,138,48,44,48,45,48,45,49,45,48,44,51,127,60,135,51};

int ir_out = 2;
char str='n';

// Init
void setup() {
  Serial.begin(9600);
  pinMode(ir_out, OUTPUT);
}

/* ---------- Send ir signal ---------- */

// 冷房
void cooling() {
  int dataSize = sizeof(cool) / sizeof(cool[0]);
  for (int cnt = 0; cnt < dataSize; cnt++) {
    unsigned long len = cool[cnt]*10;  // dataは10us単位でON/OFF時間を記録している
    unsigned long us = micros();
    do {
      digitalWrite(ir_out, 1 - (cnt&1)); // cntが偶数なら赤外線ON、奇数ならOFFのまま
      delayMicroseconds(8);  // キャリア周波数38kHzでON/OFFするよう時間調整
      digitalWrite(ir_out, 0);
      delayMicroseconds(7);
    } while (long(us + len - micros()) > 0); // 送信時間に達するまでループ
  }
}
// 暖房
void heating() {
  int dataSize = sizeof(heat) / sizeof(heat[0]);
  for (int cnt = 0; cnt < dataSize; cnt++) {
    unsigned long len = heat[cnt]*10;  // dataは10us単位でON/OFF時間を記録している
    unsigned long us = micros();
    do {
      digitalWrite(ir_out, 1 - (cnt&1)); // cntが偶数なら赤外線ON、奇数ならOFFのまま
      delayMicroseconds(8);  // キャリア周波数38kHzでON/OFFするよう時間調整
      digitalWrite(ir_out, 0);
      delayMicroseconds(7);
    } while (long(us + len - micros()) > 0); // 送信時間に達するまでループ
  }
}
// エアコンストップ
void air_stop() {
  int dataSize = sizeof(airstop) / sizeof(airstop[0]);
  for (int cnt = 0; cnt < dataSize; cnt++) {
    unsigned long len = airstop[cnt]*10;  // dataは10us単位でON/OFF時間を記録している
    unsigned long us = micros();
    do {
      digitalWrite(ir_out, 1 - (cnt&1)); // cntが偶数なら赤外線ON、奇数ならOFFのまま
      delayMicroseconds(8);  // キャリア周波数38kHzでON/OFFするよう時間調整
      digitalWrite(ir_out, 0);
      delayMicroseconds(7);
    } while (long(us + len - micros()) > 0); // 送信時間に達するまでループ
  }
}

/* ---------- Send ir signal ---------- */

void loop() {
  str='n';
  Serial.write(str);
  if(Serial.available()>0){
    str =Serial.read();
    Serial.write(str);
    if(str=='s'){
      air_stop();
      delay(3000);
    }else if(str=='c'){
      cooling();
      delay(3000);
    }else if(str=='h'){
      heating();
      delay(3000);
    }
  }
  delay(250);
}

PC から家電を制御する

MacWindows から直接家電制御したい場合は、PCから直接つぶやく
(Python Module を使うと簡単なのでコードは省略)

おわりに

ここまで、おつきあいいただきありがとうございます。長文になってしまい、すみませんでした。
普段しょうもない記事ばかり書いてますが、今回の内容は覚えることも多く大変でした。
Apple watch はもちろん iPhone アプリも初挑戦だったので、覚えることが多かったです。
特に、Apple watch は情報も少なかったので大変でした。

今回の内容で「Arduino いらないんじゃないか?」とか「Raspberry PI で LIRC 使ったら?」とか思っている人がいるかもしれませんが、
全くその通りで、昔使ったことがあるという理由だけで赤外線LEDの制御はArduino でやりました。
今後は、部屋の温度などの情報を取得できるようになどどんどん拡張していきたいです。

お世話になった本

iPhone アプリは初めてだったので、入門書のお世話になりました。
xcode の使い方と Label と Button ぐらいしかちゃんと見てないですが、
また今度しっかりと勉強したいです。

ほんきで学ぶSwift+iOSアプリ開発入門 Swift2,Xcode7,iOS9対応

ほんきで学ぶSwift+iOSアプリ開発入門 Swift2,Xcode7,iOS9対応

お世話になったページ 、Link

特に、Apple watch 関連は大変感謝してます。
ありがとうございます。

【Apple Watch と IoT】 Apple Watch でエアコンを制御する【前編】

前置き

昨年、Apple Watch が発売されましたが、実際に使ってみると時計以外の用途では天気予報の確認とメールやLINEなどの確認用といった用途でしか使ってませんでした。
そのため、バッテリーのことを考えると普通の腕時計でいいんじゃ・・・と感じてました。

そこで、Apple Watch のもっと役立つ使い方について考えたところ流行りの IoT との相性がもっともいいと思いました。
すでに、スマートフォンからエアコンなどの家電を制御している人はたくさんいますが、は常に身につけるものであるため、格段に便利になると思います。
今回は Apple Watch からエアコンを制御することにしました。

概要

f:id:inner2:20160110094620p:plain

Apple Watch でインターネットを通じて家電を制御するために、上の図のような形を考えました。
見ての通り、Apple Watch から iPhone を介して命令を Twitter でつぶやきます。
そして、自宅に設置した Raspberry PI で Twitter の Timeline を監視し、命令がきた時に Arduino に命令を Serial 通信で送ります。
Arduino では赤外線 LED でエアコンに信号を送ります。

Twitter を利用している部分は Django や Flask などのフレームワークを利用して WEB アプリを作りたかったのですが、 セキュリティの問題が不安だったため、Twitter を利用しました。
今回は、ソースコードがなるべくシンプルになるようにエアコンの「冷房・暖房・停止」だけでまとめますが、
照明をつけたりするのも少し変更するだけでできます。

環境

  • Raspberry PI1 Model B
    • OS: RASPBIAN JESSIE
    • Python version 3.4.3

【永久保証付き】Arduino Uno

【永久保証付き】Arduino Uno

Apple Watch から iPhone を介して Twitter でつぶやく

Apple Watch から直接 Twitter でつぶやくことはできないため、 Apple Watch から iPhone に命令を送り、iPhone のバックグラウンドでつぶやくようにします。
アプリの作成には主に下記のページを参考にしました。

Apple Watch アプリの画面
f:id:inner2:20160110094624p:plain

iPhone アプリの画面
f:id:inner2:20160110094621p:plain

作成手順

まずは、普通の iPhone アプリを作る。

  1. Xcode で新しいプロジェクトを作成。(template は iOS Application の Single View Application を選択)
  2. Main.storyboard を選択し、Button を追加する。

    • 今回はエアコンの「冷房(cooling)・暖房(heating)・停止(stop)」を制御するのでボタンは 3つ作成。
    • 同時にTitle で名前を変更した。

    f:id:inner2:20160110094622p:plain

  3. Button にクリックした時のイベントを追加する。

    f:id:inner2:20160110094623p:plain

  4. ViewController.swift を変更する。(code は長いので下に記載)

  5. ここからは、Apple Watch のアプリケーションを作成する。メニューバーの [Editor]-[Add Target...] を選択し、watchOS Application の WatchKit App を追加。
  6. interface.storyboard を選択し、Button を追加する。

    • 先ほどと同様に「冷房(cooling)・暖房(heating)・停止(stop)」の3つの Button 作成。

    f:id:inner2:20160110094625p:plain

  7. Button にクリックした時のイベントを追加する。

    f:id:inner2:20160110094626p:plain

  8. AppDelegate.swift と InterfaceController.swift を変更する。(code は下に記載)

ViewController.swift (code)

//
//  ViewController.swift
//  WatchApp
//
//  Created by inner on 2016/01/10.
//  Copyright © 2016年 inner. All rights reserved.
//

import UIKit
import Social
import Accounts

class ViewController: UIViewController {


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        getTwitterAccountsFromDevice()
        selectTwitterAccount()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // button click action iphone
    @IBAction func cooling_click(sender: AnyObject) {
        // tweet cooling
        postTweet("cooling")
    }
    @IBAction func heating_click(sender: AnyObject) {
        // tweet heating
        postTweet("heating")
    }
    @IBAction func stop_click(sender: AnyObject) {
        // tweet stop
        postTweet("stop")
    }

    // Twitter 関連
    // ------ Twitter Account -------
    let twitter_account: String = ""  // @ 以下のアカウント名を入力
    // ------------------------------


    var accountStore = ACAccountStore() //Twitter、Facebookなどの認証を行うクラス
    var twAccount: ACAccount? //Twitterのアカウントデータを格納する

    /* iPhoneに設定したTwitterアカウントの情報を取得する */
    func getTwitterAccountsFromDevice(){
        let accountType = accountStore.accountTypeWithAccountTypeIdentifier(ACAccountTypeIdentifierTwitter)
        accountStore.requestAccessToAccountsWithType(accountType, options: nil) { (granted:Bool, aError:NSError?) -> Void in

            // アカウント取得に失敗したとき
            if let error = aError {
                print("Error! - \(error)")
                return;
            }

            // アカウント情報へのアクセス権限がない時
            if !granted {
                print("Cannot access to account data")
                return;
            }
        }
    }
    // setting twitter account
    func selectTwitterAccount(){
        let accountType = accountStore.accountTypeWithAccountTypeIdentifier(ACAccountTypeIdentifierTwitter)
        let accounts = self.accountStore.accountsWithAccountType(accountType) as! [ACAccount]
        for account in accounts {
            if account.username == twitter_account{
                twAccount = account
            }
        }
    }
    // ツイートを投稿
    private func postTweet(cmd: String) {
        let URL = NSURL(string: "https://api.twitter.com/1.1/statuses/update.json")

        let now = NSDate()

        let formatter = NSDateFormatter()
        formatter.dateFormat = "yyyy/MM/dd HH:mm:ss"

        let date = formatter.stringFromDate(now)

        // ツイートしたい文章をセット
        let params = ["status" : cmd + "-" + date]

        // リクエストを生成
        let request = SLRequest(forServiceType: SLServiceTypeTwitter,
            requestMethod: .POST,
            URL: URL,
            parameters: params)

        // 取得したアカウントをセット
        request.account = twAccount

        // APIコールを実行
        request.performRequestWithHandler { (responseData, urlResponse, error) -> Void in

            if error != nil {
                print("error is \(error)")
            }
            else {
                // 結果の表示
                do {
                    let result = try NSJSONSerialization.JSONObjectWithData(responseData,
                        options: .AllowFragments) as! NSDictionary

                    print("result is \(result)")
                }
                catch {
                    return
                }
            }
        }
    }
}

AppDelegate.swift(code)

//
//  AppDelegate.swift
//  WatchApp
//
//  Created by inner on 2016/01/10.
//  Copyright © 2016年 inner. All rights reserved.
//

import UIKit
import WatchConnectivity

import Social
import Accounts

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {

    var window: UIWindow?
    let wcSession = WCSession.defaultSession()

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        if WCSession.isSupported() {
            wcSession.delegate = self
            wcSession.activateSession()
        }
        return true
    }

    // get message from watch
    func session(session: WCSession, didReceiveMessage message: [String: AnyObject], replyHandler: [String: AnyObject] -> Void) {

        // watchからのメッセージを受け取り
        if let watchMessage = message["toParent"] as? String {
            // twitter account の選択
            selectTwitterAccount()
            postTweet(watchMessage)
        }
        else{
            print("error: session receive")
        }
    }

    // Twitter関連
    // ------ Twitter Account -------
    let twitter_account: String = ""  // @ 以下のアカウント名を入力
    // ------------------------------
    var accountStore = ACAccountStore() //Twitter、Facebookなどの認証を行うクラス
    var twAccount: ACAccount? //Twitterのアカウントデータを格納する

    // setting twitter account
    func selectTwitterAccount(){
        let accountType = accountStore.accountTypeWithAccountTypeIdentifier(ACAccountTypeIdentifierTwitter)
        let accounts = self.accountStore.accountsWithAccountType(accountType) as! [ACAccount]
        for account in accounts {
            if account.username == twitter_account{
                twAccount = account
            }
        }
    }

    // ツイートを投稿
    private func postTweet(cmd: String) {
        let URL = NSURL(string: "https://api.twitter.com/1.1/statuses/update.json")

        let now = NSDate()

        let formatter = NSDateFormatter()
        formatter.dateFormat = "yyyy/MM/dd HH:mm:ss"

        let date = formatter.stringFromDate(now)

        // ツイートしたい文章をセット
        let params = ["status" : cmd + "-" + date]

        // リクエストを生成
        let request = SLRequest(forServiceType: SLServiceTypeTwitter,
            requestMethod: .POST,
            URL: URL,
            parameters: params)

        // 取得したアカウントをセット
        request.account = twAccount

        // APIコールを実行
        request.performRequestWithHandler { (responseData, urlResponse, error) -> Void in

            if error != nil {
                print("error is \(error)")
            }
            else {
                // 結果の表示
                do {
                    let result = try NSJSONSerialization.JSONObjectWithData(responseData,
                        options: .AllowFragments) as! NSDictionary

                    print("result is \(result)")
                }
                catch {
                    return
                }
            }
        }
    }


    func applicationWillResignActive(application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(application: UIApplication) {
        // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }


}

InterfaceController.swift

//
//  InterfaceController.swift
//  watch_iot Extension
//
//  Created by inner on 2016/01/10.
//  Copyright © 2016年 inner. All rights reserved.
//

import WatchKit
import Foundation
import WatchConnectivity

class InterfaceController: WKInterfaceController, WCSessionDelegate {

    let wcSession = WCSession.defaultSession()

    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)

        // Configure interface objects here.
        init_send()
    }

    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate()
    }

    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
        super.didDeactivate()
    }

    func init_send() {

        // Configure interface objects here.
        // WCSessionの開始
        if WCSession.isSupported() {
            wcSession.delegate = self
            wcSession.activateSession()
        }

        // reachableの確認
        if wcSession.reachable {
            print("reachable")
            // reachableであればメッセージを送る
            sendMessageToParent("init")
        }
        else{
            print("not reachable")
        }
    }

    // button click action
    @IBAction func cooling_click() {
        sendMessageToParent("cooling")
    }

    @IBAction func heating_click() {
        sendMessageToParent("heating")
    }

    @IBAction func stop_click() {
        sendMessageToParent("stop")
    }

    // send message
    func sendMessageToParent(msg:String){
        print("sendMessageToParent()")
        let message = [ "toParent" : msg ]
        wcSession.sendMessage(message, replyHandler: { replyDict in }, errorHandler: { error in })

    }

}

補足

  • iPhonetwitter を利用するときは[設定]-[Twitter]-[アカウントの使用を許可するAPP]で作成したプログラムにチェックが入っている必要があります。
  • Twitter は短時間に同じツイートをできないため、つぶやくときには現在の時間を入れています。

後編へ

長くなりすぎたため、前編と後編に分けました。
後編をどうぞ。

inner2.hatenablog.com