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

とあるエンジニア系ライダーの日常

Webエンジニアの話、バイクの話

ReactでStateとPropsをちゃんと使ってみる

前回の記事でReactが使える環境は作ったので、

まずはStateとPropsをちゃんと使ってリストを作ってみる。

ListBaseにStateを持たせて、

ListにPropsとして渡して、

ListRecordを描写してみようかなと。

StateとPropsについて

State
  • そのコンポーネントが持っている状態
  • mutable data (可変のデータ)
  • maintained by component (コンポーネントによって保持)
  • should be considered private (プライベートであるべき)

this.setState({state1: "value1",state2: "value2"});

のようにコンポーネント作成後任意のタイミングで入れられる。

初期値は

this.state = {state1: "value1",state2: "value2"}

こんな感じで入れてもいい。

Props
  • コンポーネントから渡されたプロパティ
  • immutable data (不変のデータ)
  • passed in from parent (親から渡される)
  • can be defaulted & validated (デフォルト値の設定と検証が可能)

<Component props1="value1" props2="value2">

のようにコンポーネント作成時に入れられる。

作ってみた

構成は前回と同じ。

 "dependencies": {
    "react": "^15.4.2",
    "react-dom": "^15.4.2"
  },
  "devDependencies": {
    "babel-core": "^6.24.0",
    "babel-loader": "^6.4.1",
    "babel-preset-es2015": "^6.24.0",
    "babel-preset-react": "^6.23.0",
    "webpack": "^2.2.1"
  }

 こんな感じ。

最初の呼び出し元としてapp.jsxを作る。

前回はindex.html内でrenderを呼んでいたが、

app.jsx自体にやらせることにした。

app.jsx

import React from 'react';
import ReactDom from 'react-dom';
import ListBase from './listbase.jsx';

ReactDom.render(
  <ListBase/>,
  document.getElementById('listbase'));

なので、webpack.config.jsは、app.jsxをベースとしてapp.jsを作る様に

webpack.config.js

const path = require('path');

module.exports = {
    entry: {
        app: './src/app.jsx'
    },
    output: {
        path: './public',
        filename: '[name].js' // 上記entryのキーに対応したテンプレート
    },
    module: {
        loaders: [
            {
                loader: 'babel-loader',
                exclude: /node_modules/,
                test: /\.js[x]?$/,
                query: {
                    cacheDirectory: true,
                    presets: ['react', 'es2015']
                }
            }
        ]
    }
};

なので、index.htmlはapp.jsを呼び出すだけ。

index.html

<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div id="listbase"></div>
    <script src="public/app.js"></script>
</body>
</html>

 ここからはさくっと。

呼び出されるListBaseコンポーネントはStateデータをコンストラクターで持ち、

<List data={this.state.data}/>

として子コンポーネントに渡すだけ。

listbase.jsx

import React, {Component} from 'react'
import List from './list.jsx';

export default class ListBase extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: [
        {
          id: 1,
          name: 'tanaka'
        }, {
          id: 2,
          name: 'yoshida'
        }
      ]
    };
  }
  render() {
    return (<List data={this.state.data}/>);
  }
}

渡されたdataを、

Listコンポーネント内でループしてListRecordコンポーネントをdataの数だけ生成する。

listrecord.js

import React, {Component} from 'react'
import ListRecord from './listrecord.jsx';

export default class List extends Component {
  render() {
    var rows = this.props.data.map(function(row) {
      return (<ListRecord data={row} key={row.id}/>);
    });

    return (
      <ul>
        {rows}
      </ul>
    );
  }
}

で、最終的にListRecordがPropsを描写する。

listrecord.jsx

import React, {Component} from 'react'

export default class ListRecord extends Component {
  render() {
    return (
      <li>
        {this.props.data.id}:{this.props.data.name}
      </li>
    );
  }
}

npm run webpack -pして、

index.htmlを表示してみる!

1:tanaka

2:yoshida

おお!表示された。

PropsはImmutableなので、値を変える時はListBase自体で

setStateし直すということか。

それで、

<ListRecord data={row} key={row.id}/>

keyを比較して変更のあったものを再描写してる感じかな。

(最初keyがなくて怒られた苦笑)

うん、なんとなくだけどわかってきた。

ES6で書くとfunction(){}とかなくてJSっぽくなくていい!

DebugしにくいからReactDevTool入れてちゃんとサーバー上で動かした方がいいな。

あとコンポーネントとして、

こうやってマイクロな感じで作ったコンポーネントを組み合わせて呼び出して、

全部JSじゃなくて必要なところだけコンポーネントを埋め込んでリッチにする方が、

DOM全部管理するより開発しやすいんじゃないかなーと思った。

 

ここまでやって、次はFluxとかでのデータフロー管理なわけかな。

ちょっとずつ進んでる感。

React+Babel+WebpackでHTMLにリストを書いてみた。

作ってみるもの

WebでReactの動的サイトを作るのを目標にとりあえず今回は、

React、Babel、Webpackを使って

普通のリストを作ることにしようかと。

もろもろのバージョンは下記

node:7.6.0

npm :4.4.4

React:15.4.2

Babel:6系

Webpack:2.2.1

Reactとは

Facebookが作っているJSのView部分だけのライブラリ

facebook.github.io

詳しくは本家を。

現在バージョンは15で、初期と大分変わっているので、記事を参考にする際はお気をつけください。

Babelとは

「BabelはブラウザにまだサポートされていないようなJavaScriptの次世代の標準機能を、現在のブラウザでも使えるようにするNode.js製のトランスパイラ。」

要はJSのコンパイラと考えていただければ。

ECMAScriptJavaScript の標準試用)準拠なのがいいところ。

Webpackとは

設定ファイルを書けば、依存関係を解消し、

ビルドしてくれるツール(つまりコンパイラ)です。

さっそく作ってみよう!

とりあえず今回は、

React、Babel、Webpackを使って

特に動かないリストを作ることにしようかと。

とりあえず動くものはFluxとか使ってからで。

まずは作業用ディレクトリでnpmで初期化して必要なものをインストール 

※Babel6になりパッケージの分離が行われ、

必要なもののみインストールする必要あります。

npm init
npm install --save react react-dom npm install --save-dev webpack babel-core babel-loader babel-preset-es2015 babel-preset-react

このままじゃ使いづらいので

package.jsにwebpackコマンドを登録

"main": "index.js",
"scripts": {
"webpack": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},

これでnpm run webpackでwebpackが使えるようになります。

とはいえwebpackが何をするかの設定ファイルが必要なので、

下記を用意します。

※これもBabel6の影響でloaderがbabel-loaderになっています。

webpack.config.js

const path = require('path');

module.exports = {
    entry: {
        app: './src/app.js'
    },
    output: {
        path: './public',
        filename: '[name].js' // 上記entryのキーに対応したテンプレート
    },
    module: {
        loaders: [
            {
                loader: 'babel-loader',
                exclude: /node_modules/,
                test: /\.js[x]?$/,
                query: {
                    cacheDirectory: true,
                    presets: ['react', 'es2015']
                }
            }
        ]
    }
};

./publicに、entryでキーに指定した名前の[name].jsが書き出されます。

こうしておけば複数も可能です。

JSは今回はメインの呼び出しとリスト自体の2つ

app.js

import React from 'react';
import ReactDom from 'react-dom';
import List from './list.js';

window.ListApp = {
    render:  () => {
        ReactDom.render(
            <List />,
            document.getElementById('listapp')
        );
    }
};

list.js

こっちは今回は適当。

import React, {Component} from 'react'

export default class List extends Component {
    constructor() {
        super();
    }

    render() {
      var list = [];

      var data = [
        { text: "1" },
        { text: "2" }
      ];

      for(var i in data){
        list.push(<li key={i}>{data[i].text}</li>);
      }

      return(
        <ul>
          {list}
        </ul>
      );
    }
}

で、肝心のHTMLですが。 

index.html

<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>List書いてみよ</title>
</head>
<body>
    <div id="listapp"></div>
    <script src="public/app.js"></script>
    <script>ListApp.render();</script>
</body>
</html>

これだけ。

最後に

npm run webpack -p

すると、publicディレクトリにapp.jsが出来ているので、

ブラウザからhtmlを開いてみると普通にリストが表示されます。

(ただのリストなので画像は貼りませんが苦笑)

まとめ

とりあえず入門したかなと。

ここから、FluxかRedux使ってデータ持たせたり、

ちゃんとコンポーネント設計したり、

axiosとか使ってAPI呼んでデータ取ってきたり。

お砂場はできれども道は遠き。

SpringのUTにDBSetupを使ってみたら良かった

はじまり

DBのテスト、できればきれいに書きたい。

ということで

  • insert文とかベタ書き : なんか嫌だ
  • DBUnit : 使ったことはあるけど、ファイル参照嫌だ
  • オレオレUtil : 再利用性がない!

ということで、DBSetupというのを見つけた。

データは「流れるようなインタフェース(Fluent Interface)」で作成する。

この一文に惚れたからだ。

自分の環境

  • spring-boot
  • JPARepository
  • JUnit4

これに合うようにやってみた。

テストされる側

単にデータを全部返すだけのメソッド

@Service
@Transactional
public class MyDataService {

@Autowired
MyDataRepository myDataRepository;

public List<MyData> findAll() {
return myDataRepository.findAll(new Sort(Sort.Direction.ASC, "id"));
}
}

使ってみた

とりあえずversion2.0をimport

pom.xml

<!-- https://mvnrepository.com/artifact/com.ninja-squad/DbSetup -->
<dependency>
<groupId>com.ninja-squad</groupId>
<artifactId>DbSetup</artifactId>
<version>2.0.0</version>
</dependency>

SpringBootはテスト時はtest/resources/application.propertiesがあったらそちらを読み込むので作成。

spring.datasource.url=jdbc:mysql://192.168.33.10/mytestdatabase
spring.datasource.username=testuser
spring.datasource.password=password
spring.datasource.driverClassName=com.mysql.jdbc.Driver

spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

これで通常環境は汚染されない。

DataSourceどうやってとってくるかで迷ったけど、普通に@Autowire

DataSouce取ればテスト用のDataSouceが入ってた。

@RunWith(SpringRunner.class)
@SpringBootTest

この辺のDIのおかげかな。

あとは、データの定義、これがカッコイイ!!!

クラス内にデータがどうなっているか収まるのでDBUnitよりも読みやすい!!!

public static final Operation DELETE_ALL =
Operations.deleteAllFrom("mydata");

public static final Operation INSERT =
Operations.insertInto("mydata")
.columns("id", "name")
.values("1","Tanaka")
.values("2","Yoshida")
.values("3","Suzuki")
.build();

で、Beforeでデータをセットしてやると。

@Before
public void before(){
Destination dest = new DataSourceDestination(dataSource);
Operation ops = Operations.sequenceOf(DELETE_ALL, INSERT);
DbSetup dbSetup = new DbSetup(dest, ops);
dbSetup.launch();
}

sequenceOfで生成したOperationを繋げられるので楽!

あとは普通にテストすれば

@Autowired
MyDataService myDataService;

@Test
public void canFindAll() throws Exception {
List<MyData> myData = myDataService.findAll();
assertThat(myData.get(0).getId(),is(1));
assertThat(myData.get(0).getName(),is("Tanaka"));
}

オールグリーン!!!

まぁ、使ってみたかっただけのテストなんで、テスト自体は雑ですが。

なんて素敵なんだろう。この流れるようなインターフェース。

もうDBUnitのことなんて忘れよう!

DBのテストをこれで切り出して、

その部分がテストされていればあとはMockitoとかでMockすればいいし。

うん、なんか結局惚れた!

 

SpringBoot,Thymeleaf,JpaRepositoryで基本構成を作ってみた

あけましておめでとうございます!

SpringBoot、前から気になるなぁと思っていたので、

年末にちょこっと触ってみた。

SpringBootとはとかはハショリます。

今年は週1ぐらいでブログ書きたいなぁと。勉強するために!

 

とりあえずmavenで必要なものを突っ込んでみる

STS(簡単にSpringBootを開発するツール)もあるけど、

おもしろくないのでInteliJでmavenプロジェクトを作成して

必要なものだけ全部突っ込んでみる。

必要な物 

  • spring-boot-starter-parent: SpringBootのベース
  • spring-boot-starter-web
  • spring-boot-starter-thymeleaf: Thymeleafが使いたかった!
  • spring-boot-starter-data-jpa: 結局裏ではhibernate使ってるけど
  • mysql-connector-java: MySQLは適当にVagrantで建てた
  • lombok: あるとJpaRepository使いやすかった
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

 

 

まずは起動用ファイル

SpringBootはサーバーを内包していて、mainから走らせれば起動するので、

これだけ書けばとりあえずサーバーが起動する。

なんとなく名前はBootにしてみた。起動しそうだからb

@SpringBootApplication
public class Boot {
public static void main(String[] args) {
SpringApplication.run(Boot.class, args);
}
}

 

 

Thymeleafを組み合わせてみる

resources/templatesにhtmlファイルを設置

index.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>top page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
test
<p th:text="${msg}" />
</body>
</html>

コントローラーがその名前を返せばいいだけ。

今回はindex.htmlとしたのでこんな感じ。

@Controller
@RequestMapping("/")
public class IndexController {
public String index(Model model) {
model.addAttribute("msg","Hello Spring Boot");
return "index";
}
}

簡単すぎる!

これでBootを走らせるともうlocalhost:8080で見れる!

早すぎる!

 

 

Jpa Repositoryを使ってみる

まずは必要なデータベース!!!

データベース名:mydatabase

テーブル名:mytable

として作って適当にデータを突っ込んでみる。

次に

resources/application.properties

を作ってアクセスできる様に下記を記載する

今回はVM上でmysqlがあるのでこんな感じ。

spring.datasource.url=jdbc:mysql://192.168.33.10/mydatabase
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driverClassName=com.mysql.jdbc.Driver

spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect

がないと、

org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set

で悩まされた。。。

 

あとは簡単!

Entityを用意する

@Entity
@Data
@Table(name = "mydata")
public class MyData {

@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
private String name;

}

JpaRepositoryのinterfaceを用意する。

だいたいのメソッドがデフォルトで用意されている。

@Repository
public interface MyDataRepository extends JpaRepository<MyData, Integer> {
}

Repositoryの実装としてServiceを作る。

AutowiredとかはSpring DIの基本なので説明飛ばします!

@Service
@Transactional
public class MyDataService {

@Autowired
MyDataRepository myDataRepository;

public List<MyData> findAll() {
return myDataRepository.findAll(new Sort(Sort.Direction.ASC, "id"));
}
}

最後にThymeleafに送っていたデータをDBからServiceを使って取得。

MyDataにtoStringが実装されてるから取得した値をそのまま出してみる。(雑)

@Controller
@RequestMapping("/")
public class IndexController {

@Autowired
MyDataService myDataService;

@RequestMapping(method = RequestMethod.GET)
public String index(Model model) {
List<MyData> myDataList = myDataService.findAll();
model.addAttribute("msg", myDataList.get(0));
return "index";
}
}

そして走らせる。

 

 

無事成功!

f:id:kensanty:20170101190003p:plain

ほとんど引っかかるところはなく簡単にできたのがすごい!

環境構築もいらないし。

でも、楽だけど、中身をちゃんと知らないといけないなぁと思った。

まぁ、とりあえずベース環境として使って、

勉強しながら気分次第でmavenのimport方法変えていけばいいかなと。

YAGNIということで。

これをベースに何作るかは全然考えてない。。。

デブサミ関西2016に行ってきた

Developers Summit 2016 KANSAI #devsumi

デブサミ関西に行ってきたので感想をまとめ。

なぜか基調講演が1番おもしろかったのでとりあえずそれだけ紹介。

基調講演

鈴木雄介さん

グロースエクスパートナーズ執行役員

日本Javaユーザーグループ会長

クラウドって仮想サーバーのことだけじゃないよね

1.インフラの仮想化 IaaS

仮想インフラによってインフラを所有から利用へ。

2.ミドルウェアの仮想化 PaaS

AWS RDSみたいにミドルウェアもその部分だけを利用できる。
データベースサーバーを借りるのではなくデータベースサービスを借りる。
バックアップとかクラスタかも考えなくていいはず。
その為に積極的にプラットフォームの制約は受け入れる!
フレームワークのように、あと何年かするとそれが当たり前になると。

3.システム構成のコード化

ChefとかAnsibleみたいなの。

 

それら3つが揃って本当にクラウドだよねって話だった。
IaaSだけではクラウドと言えのるか?というのがおもしろかった。
企画→開発→運用 がクラウドの方が早い!


クラウドの進化の紹介

2001年アジャイルソフトウェア開発宣言

「企画→開発」の効率化

2006年クラウド
2009年:DevOps

「開発→運用」の効率化

データセンターの移行にスクラムを導入したところから。

変更と安定稼働は相反する

DevOpsというよりOpsをなくすって考えっていう話がおもしろいw

2010年:多様なリリース方法

ブルーグリーンデプロイメント

本番環境を2つ用意して切り替えるやり方。

カナリアリリース

一部のユーザーだけに特定のバージョンを提供する。

って、やってたけどそんな呼び方するって知らなかった。

2012年:カオスモンキー

NetFlixが使っている。

本番環境をランダムにダウンさせる製品。

インフラの自動化のテストをするため、

自動復旧を観測する。

まじか!データセンターまるごと落とすとかもするらしい。

2014年:マイクロサービスアーキテクチャ

大事だよなぁ。影響範囲を減らすの。

システム全体を単一の構成で作ると技術の切れ目でチームを構成しがち。

コンウェイの法則)

それに対して、システムをサービス同士の連携で実現する。

サービスレベルでチームを構成する。

 

APIさえ変わらなければいい。

だからアジャイルがやりやすい。

 

あと、MSAに再構築は愚か!今から始められる。

少しずつ取り入れるのを始めるべきってのには共感した。

確かにちょっとずつ切り出していくのが1番良さそう。

 

そして、ここでドメインモデルが出てくる。

業務領域で分ける。正解はない。。。難しいよねDDD。

 

全てはアジャイルからはじまった。

「この年表のどの時点にみなさんはいますか?」

って言うのがカッコ良かった。

クラウド時代のデベロッパ

アプリとインフラは不可分に。両方コード化している。

何をコーディングして何をコーディングしないのか。

システム開発からサービス運営へ

企画→開発→運用の全てでエンジニア!!!

スペシャリスト:特定領域の専門家

ジェネラリスト:専門家を繋いで価値に繋げる

どちらを目指すか、戦略を考えて先へ進んで行かないといけない。

ビジネスの中心にエンジニアがある。

エンジニアにもコミュニケーション、プレゼン、チームビルディング能力が必要。

特にジェネラリストに必要。

個人でシステムをつくり上げるのは不可能に近い。

 

スキルを縦か横に拡げるという話だった。

この話にはすごい悩まされた。

自分のスキルはどっちかというといつも横に広がっていっているな。

どっちかというとジェネラリスト向きなんだろうなと思った。

しゃべるのも好きだし。その方向だとそういう方向にどう拡げるか

考えないとなー。

 

この講演の内容はクラウドファーストアーキテクチャ設計ガイドで読めるらしいです!笑

phpとslim3で汎用掲示板を作ってみた

ふとしたきっかけからphpslim3を使って汎用掲示板を作ってみました。

ライセンス表記とか全然してないけどオープンソースなので、

プルリクもらえると嬉しいですw

github.com

Slim3について

phpのマイクロフレームワーク

Slim Framework - Slim Framework

ORマッパーとか機能は全然ついてなく、

後からComposerでvendorに追加していく感じ。

CakePHPみたいに規則も厳しくなく、設定ファイルも簡単なので、

いろいろ組み合わせて作っていくと案外いいかなと。

ただ、リクエストをさばくのがroutes.phpだけなので、

機能が増えるとこれがかさばって可読性下がりそう。

routes.phpから完全にそれぞれのページのパラメーター関係のロジックを

抜き出して、そこに全部渡せばすっきりするかな?

今回の構成について

こんな感じで、バリデーションとCSRFはComposerでありものを突っ込んだ。

やっぱり車輪の再開発はしたくない。

で、routes.phpではそういったパラメーターの処理だけさせて、

あとはapp/src/usecaseの中のロジックでDBとかの処理をしている感じ。

これだけでローカル試せます

実はscotch-box(LAMPvagrant box)を入れているので、

vagrantとvirtual boxがインストールしてあれば、

cloneしてvagrant up、

MySQLddl.sqlのユーザー作成とテーブル作成をして、

Document Rootを/public(index.php)があるにすれば動くはず。

PHPで開発するならローカルのエディター使いながら随時確認できる

scotch-boxおすすめ!

Scotch Box ♥ A Vagrant LAMP Stack That Just Works

TODO:やりたい、やりたかったこと

- ほんとはDDDで作りたかったので、

時間があったらusecaseからmodelとrepositoryを切り出して、

もっと柔軟性を持たせたいかな。

- DIとnamespaceを適当にやってしまった所をちゃんと定義

したいかなと。

- エラーハンドリングとかトランザクションが適当なので、

もっとしっかりしたいなと。usecase内でトランザクションがはれる様なイメージ。

まとめ

Slim3自体は簡単かつすっきりとした小規模システムをつくりたい、

リクエストのハンドリングとテンプレートエンジンとかだけ使えれば十分。

あと、そういった作りにしておいてロジックを分離することで、

今後フレームワーク間の載せ替えや

バージョンアップも簡単になるんじゃないかなと。

 

IRKitが届いたので遊んでみた

IRKitが届いたので遊んでみた

  • IRKitについて
  • やりたいこと
  • 手始め
  • 初めてのiOSApp
  • 実際の開発
  • 完成 

IRKitについて

引用:公式サイト http://getirkit.com/

IRKitは、 公式iOSアプリ IRKitシンプルリモコン 公式Androidアプリ IRKitシンプルリモコン から操作できるほか、
IRKit iOS-SDK を使えば、 任意のタイミングで赤外線信号を送ることのできるiOSアプリを簡単につくることができます。
また、JavaScriptを使ってブラウザから赤外線信号を送ったり
curlを使って黒い画面(Terminal)から赤外線信号を送ることもできます。
IRKitデバイス自体にHTTPサーバがあり、
JSON形式の赤外線情報を HTTP POSTリクエストにのせて送ることで、赤外線信号を送ることができるのです。
また、IRKitと同じWiFiにいなくても、外出先から赤外線信号を送るための、インターネット上にあるサーバのAPIも公開しています。
IRKitデバイスは、Arduino Derivative(派生)のプロダクトです。
未使用のピンは引き出してあるので、温度センサや明るさセンサなどを追加し、ArduinoIDEを使ってプログラムを書き込めば、
よりスマートなリモコンをつくることもできます。

やりたいこと

「帰ったよ」って言うと電気、エアコン、テレビをつける。
「いってきます」って言うと電気、エアコン、テレビを全部消す。

手始め

まずはcurlでエアコンをつけてみようかと

  1. IRKitをWifiに接続
  2. エアコンからIRKitに赤外線を送る
  3. MacからcurlでIRKitに送信された赤外線をJson形式で取得する
  4. MacからcurlでIRKitに赤外線を送信してエアコンをつける

1.IRKitをWifiに接続
まずはiPhoneを使って、IRKitに家のWifiの情報を送ってSetUp。
赤いランプの点滅が青くなったら接続完了!
RouterにつないでみるとIRKitが接続されていることがわかるので、
ホスト名を( ..)φメモメモ

2.エアコンからIRKitに赤外線を送る
とりあえずcurlがつながるか確認

curl -i "http://IRKitHoge.local/messages" -H "X-Requested-With: curl"

HTTP/1.0 200 OK
Access-Control-Allow-Origin: *
Server: IRKit/2.1.3.13.gbe33d36
Content-Type: text/plain

 

つながった!

次、青いランプが点灯している状態で、エアコンのONボタンをIRKitに向かって押した後GET
curl -i "http://IRKitHoge.local/messages" -H "X-Requested-With: curl"

HTTP/1.0 200 OK
Access-Control-Allow-Origin: *
Server: IRKit/2.1.3.13.gbe33d36
Content-Type: text/plain

{"format":"raw","freq":38,"data":
[18031,8755,1190,1190,1190,3341,1190,3341,1190,3341,1190,1190,1190,3341,
1190,3341,1190,3341,1190,3341,1190,3341,1190,3341,1190,1190,1190,1190,1190
,1190,1190,1190,1190,3341,1190,3341,1190,1190,1190,3341,1190,1190,1190,1190
,1190,1190,1190,1190,1190,1190,1190,1190,1190,1190,1190,1190,1190,3341,1190
,3341,1190,3341,1190,3341,1190,3341,1190,65535,0,9379,18031,4400,1190]}

f:id:kensanty:20150824173808p:plain

赤外線信号って、、、複雑。。。

ということでこれをそのまま送信してみましょう。

curl -i "http://10.0.1.2/messages" -H "X-Requested-With: curl" -d
'{"format":"raw","freq":38,"data":
[18031,8755,1190,1190,1190,3341,1190,3341,1190,3341,1190,1190,1190,3341,
1190,3341,1190,3341,1190,3341,1190,3341,1190,3341,1190,1190,1190,1190,1190
,1190,1190,1190,1190,3341,1190,3341,1190,1190,1190,3341,1190,1190,1190,1190
,1190,1190,1190,1190,1190,1190,1190,1190,1190,1190,1190,1190,1190,3341,1190
,3341,1190,3341,1190,3341,1190,3341,1190,65535,0,9379,18031,4400,1190]}'

HTTP/1.0 200 OK
Access-Control-Allow-Origin: *
Server: IRKit/2.1.3.13.gbe33d36
Content-Type: text/plain

エアコンついたーー!!!

ちなみにそれぞれのJsonの意味はこんなんらしい
Key Description
format "raw"のみ
freq 赤外線信号のサブキャリア周波数を表します。38 または 40 のみ。単位 [kHz]
data 赤外線信号は、サブキャリア周波数のオン・オフからなります。IRKitデバイスはオン→オフ間の時間、オフ→オン間の時間を 2MHz のカウンタで数えます。dataには、カウンタで数えた数をオン・オフの回数分ならびます。
よくわからん。

初めてのiOSApp

さて、Siriに話しかけてリモコンを操作したかったものの、

実はiOSAppを作ったことがありませんでした!!!

というかXCodeを触ったこともありませんでした!!!

というかSwift書いたことない!!!

ので、実機確認が無料でできるXCode7をダウンロード。

XCode6まではDeveloperProgramに登録(有料)しないと実機確認

できないので注意。

Swiftは、まぁノリで書けるだろうと。

とりあえずこれだけ覚えた

func メソッド名(引数:型) -> 戻り値の型 {
        return 戻り値
}

型の定義とかがJavaと逆なのかー。

でも、なんか書きやすい!

ってか言語仕様わかりやすいから以外とスラスラ書ける。

Swiftおもしろい、iOSAppおもしろい!

実際の開発

最初

irkit/ios-sdk · GitHub

本家のSDKを使おうと思ったんですが、、、

Objective-C ! そっちは書きたくない。

BridgeでImportできるらしいけど、

そんな面倒なこともあんまりしたくないなーということで、

UIViewのLoad後の処理にHTTPリクエストを書きましたw

func sendMessage(message: String) {
   let urlString = "http://IRKithoge.local/message/"
   var request = NSMutableURLRequest(URL: NSURL(string: urlString)!)
   request.HTTPMethod = "GET"
request.HTTPBody = message.dataUsingEncoding(NSUTF8StringEncoding)
var task = session.dataTaskWithRequest(req, completionHandler: {
(data, resp, err) in
println(resp.URL!)
println(NSString(data: data, encoding: NSUTF8StringEncoding))
})
task.resume() }
}

普通にHTTPのBodyに赤外線情報のJSONを突っ込んで送りました。

で、このアプリ名を「帰ったよ」にして

iPhoneにデプロイ。

すると、Siriに「帰ったよ」と言うと、

アプリが起動して自動で赤外線が送られるという簡単な仕組み。

Siriがアプリ内のコマンド実行できたらもっといいのになー。。。

完成

「HeySiri 帰ったよ」でエアコンON、電気全灯

「HeySiri いってくる」でエアコンOFF、電気消灯

はい、なぜテレビはできなかったか。。。

テレビはONとOFFの信号が同じなので、

どっちかわからないのです!

まぁ、帰ったらちょっと便利になったのでいいや。

 

item.rakuten.co.jp

 

公式サイト

IRKit - Open Source WiFi Connected Infrared Remote Controller