玄関をSuicaで開ける
玄関をSuicaで開ける
この記事は おうちハック Advent Calendar 2015 の23日目の記事です。
動機
私は普段、家の鍵を他の鍵と一緒にでまとめてをオシリポケットに入れているのですが、座ると鍵が当たって痛いので PASMO や Suica で開けられるようにしたいと思います
私は iPhone なので FeliCa を搭載していないため iPhone と iPhoneケースの間に PASMO と 磁気干渉防止シートを挟んで使っています
では、作っていきましょう!
この記事を見れば作れるようにしたいので少しくどくなるかもしれませんが、ご了承ください
セキュリティはあまり考えていません。試す際は自分で対策してください
(でも多分、空き巣は NFC をハックするより窓を割って入ってくる方が簡単)
構成
今回、時間をかけず簡単に作るために機能を最低限の「NFC をかざしたら鍵を開ける(そして自動で閉める)」という機能に絞ることにします
NFC リーダ はこの手の工作では定番の RC-S380 を使います
サーボモータは鍵のサムターン(つまみ)を回すことを考えてトルクの大きなものを秋月電子で購入しました
NFC からidmを取得する
Raspberry Pi の公式から Raspbian jessie を落としてSDカードにセットし IPアドレスの固定等の設定を行ったら(今回はRaspberry Pi Bを使います)
いよいよ PASMO から idm を取得します
idm とは PASMO/Suica 等の製造番号のことです
nfcpy
NFC を使うためのツールであるnfcpyを使います
これは公式サイトの Getting started の通りやるとインストールできました
bzrというバージョン管理システムをinstallして、nfcpyをinstallしたい場所に移動、bzrでnfcpyをinstallします
sudo apt-get install bzr cd <hoge> bzr branch lp:nfcpy trunk
続いて Python で USB を使うたに python-usb をinstallします
sudo apt-get install python-usb
できたらサンプルコードを動かしてみましょう
sudo python examples/tagtool.py
PASMO等をタッチして、こんな感じにIDが表示されたら成功です
今回はこのサンプルコードをそのまま使わせてもらいます
サーボを動かす
ServoBlaster
サーボを動かすにはServoBlasterというCで書かれたツールを使います
git で公開されているのでgit clone してきて、Cのコードをmakeでコンパイルしinstallします
git clone git://github.com/richardghirst/PiBits.git cd PiBits/ServoBlaster/user make sudo make install
サーボを動かしてみる
ServoBlasterは/dev/servoblaster
に文字列[Servo_number]=[0-100]%
を書き込むことでサーボを動かしてくれます
echo 4=100% > /dev/servoblaster
ServoBlasterで指定するServo_numberはgpioのピン番号とは違うので注意が必要です
ここではパーセンテージで指定するのでサーボを見ながら鍵を開けるのに良い角度を探ります
私のサーボの場合は91と40でした
このServoBlasterのいいところは使っていない時サーボに電圧をかけないところです
このため普通の鍵でも手で開閉錠できます
サーボが動いたら NFC をかざした時サーボを回してみましょう
サーボについて追加情報があります *1
登録したidmの時サーボを回す
Ruby から nfcpy と ServoBlaster を使うコードを書きます
ただコマンドを実行するだけなので簡単です
(ServoBlasterは Ruby の File.write ではダメな模様)
#ここは先ほど表示させた自分のidmに書き変える USERS = {"Bob_Marley" => "xxxxxxxxxxxxxxxx", "Alice_Cartelet" => "xxxxxxxxxxxxxxxx"} #ここも自分のサーボにあったものに書き換える #s03t-2bbmg servo UNLOCK_ANGLE = "91" LOCK_ANGLE = "40" AUTO_LOCK = 40 def nfc() #ここも自分の環境にあったものを指定 `sudo python ~/Documents/nfc/trunk/examples/tagtool.py` end def idm(text) m = text.match(/ID=(.*?)\s/) idm =m[1] print("IDm = #{idm}\n") return idm end def unlock() print("Unlocking\n") `echo 4=#{UNLOCK_ANGLE}% > /dev/servoblaster` end def lock() print("Locking\n") `echo 4=#{LOCK_ANGLE}% > /dev/servoblaster` end loop do idm = idm(nfc) unlock_user = USERS.key(idm) unless unlock_user == nil print("Welcome back #{unlock_user}!\n") unlock print("Wait #{AUTO_LOCK}sec...") sleep(AUTO_LOCK) print("\n") lock else print("Illegal user\n") end print("Please wait reader restart...\n") end
実行するとこんな感じに動くと思います 動画には写っていませんが40秒後に閉まります
ハードウェア
鍵のサムターン(つまみ)にサーボを取り付けるための木材をノコギリとドリルで作成します
30mm*30mmの角材を30mmで切ってサイコロ状のものを作成、サムターンに合う穴を開けます
続いてサーボを固定するためにダンボールでマウントを作成します
ダンボールを10枚積層、木工ボンドで合わせて完成です
ダンボールだととても簡単でよかったです(1時間ほどアニメ見ながら切りました)
レーザ加工機が使う余裕があればアクリルで作ってもいいかもしれません
ただダンボールでも木工ボンドで補強するとかなり頑丈になります
ちなみに今回は溜まりに溜まったamazonの箱を使いました
取り付けて完成です
動かすとこんな感じ(このNFCリーダは表からも裏からも使えました)
— Coro (@Coro365) December 23, 2015
— Coro (@Coro365) December 23, 2015
今後
- 開閉錠ボタンと状況表示用のLEDを付けたい
- 鍵が開いているか閉まっているかの状態を確認したい
- リードスイッチ(磁気を感知するスイッチ)でドアの開閉を検知してオートロックの挙動に生かしたい
- Sinatraとかでブラウザ上で開閉とログの確認をしたい
- Supervosorを使ってRaspberry Piのデーモンにする
雑感
- ServoBlasterとnfcpyが優秀ですぐにできてしまった
- 一番時間がかかったのはマウントを作成するところ(ダンボールで作る前にアクリルをノコギリとドリルで加工して半日無駄にしている)
- PASOM決済だけで生活できればiPhoneだけ持ち歩く生活にできるかも
- 個人が少しのお金で、いろんなことが可能な環境は素晴らしいなと思いました(この方向で人間、進化してもらいたい)
- 今後も隙を見ておうちを便利にしていきたいです
初めて Advent Calendar に参加しましたがイベントドリブンな感じで作ることができたので参加してよかったです(参加しなかったら作らなかったかも)
そんな おうちハック Advent Calendar 2015 の明日の記事は @YarmUIさん の スマートメータを自作した話 です
良いお年を!
購入したもの
Raspberry piは部屋に転がっていたものを使ったので出費は 4000円ほど
- Amazon.co.jp: Raspberry Pi Type B 512MB: パソコン・周辺機器
- Amazon.co.jp: SONY 非接触ICカードリーダー/ライター PaSoRi(パソリ) USB対応 RC-S380: パソコン・周辺機器
- GWSサーボ S03T/2BBMG/F(フタバ): サーボ 秋月電子通商 電子部品 ネット通販
ドアセンサ、開閉スイッチなどをつける時は必要です
- タクトスイッチ 12mm TVGP01-G73BB(黒): パーツ一般 秋月電子通商 電子部品 ネット通販
- ピンヘッダ 1×40 (40P): パーツ一般 秋月電子通商 電子部品 ネット通販
- ケース入りリードスイッチ(磁石付セット)MC-14AG: センサ一般 秋月電子通商 電子部品 ネット通販
参考ページ
- Raspberry PiにRaspbianをインストールする for Mac OSX
- Raspberry Pi 2 (Raspbian: jessie) でIPアドレスを固定する
- PWMでRaspberry PiのLEDの明るさ調整する
- FeliCa(フェリカ)IDmとは?|ステルス・ネットワークス
- Python module for near field communication — nfcpy trunk documentation
- Raspberry-PiにおけるGPIO関係ツールのインストール方法 | Раздан-3
- GPIO: Raspberry Pi Models A and B - Raspberry Pi Documentation
- nfcpyでお手軽NFC開発[1/2]
ありがとうございます
追記1 2017/08/09
サーボモータを回転させた際RasPiが再起動してしまう時は、別に電源を用意してください。
私の場合は、以下のように別電源にしました。(この方法が最適解かどうかはわかりません)
- USBケーブルを用意し皮膜をはがした後、プラスとマイナスの線をより分けます。
- プラスの線はサーボのプラスにつなぎ、マイナスの線 はサーボ と RasPi のGroundに繋ぎます。
- USBケーブル自体はApple USB 充電器 に繋ぎます
追記2 2017/08/09
多くの方にこの記事を読んで頂き大変嬉しく思っております。
また、この記事を見て同じものを作ろうとしている方の何人に連絡をいただきとても嬉しいです、記事にした甲斐がありました。
記事公開から1年以上経ち、その間にも iPhone が Suica 対応したり、電子マネー対応の店が増えてきたり、スマフォでATMからお金を引き出せたり、iPhone 1つで生活できる世の中に近づいている気がしてワクワクしています。
さて、この記事で作った物にLED,ドア開閉センサ,ボタンを追加した物がGithubに上がっているので、こちらもどうぞ。
github.com
追記おわり
*1:追記1 2017/08/09 をご覧ください
AppleScriptでiTunesのテレビ番組を連続再生する
iTunes のテレビ番組を連続再生するには再生したいテレビ番組をプレイリストに登録してリピート再生するという方法がある。
しかし、毎度毎度プレイリストを作るのは大変なので AppleScript を使って自動で次のエピソードに移動するようにしてみる
仕組み
- Scriptを起動したら TV Show が再生されていないか20秒毎にチェックする
- 再生されていたらそのEpisode の合計時間と現在の再生位置から残りの再生時間を3分ごとに調べる
- 残りの再生時間が3分以下になったら1分ごとにチェック、1分以下になったら1秒ごとにチェック
- 残りの再生時間が1秒以下になったら次のEpisode に移動する
- 2にもどる
今回使った命令いろいろ
次のEpisode に移動
- これは他の種類のメディア(音楽とか)にも使えてキーボードについている送りキー[▶︎▶︎]と同じ機能を持つ
tell application "iTunes" next track end tell
再生中のトラックの合計時間を調べる
- 1:20:30(h:m:s) のように出力される
tell application "iTunes" set timeSize to time of current track as text end tell
再生中のトラックの再生済みの時間を調べる
- 秒で出力される
- 再生されていない時は
missing value
となる
tell application "iTunes" set nowPositionSec to player position end tell
コードは Gist にある
This applescript will automatically play the episode of the next iTunes TV show. · GitHub
- 右にある
Download ZIP
からダウンロードする - Script Editor で開いて
.app
形式で保存する - Spotlight から起動したり、iTunes Scriptフォルダに入れて iTunes からも起動できる
- iTunes Scriptフォルダは
~/Library/iTunes/Scripts
参考ページ
- 鳶嶋工房 / AppleScript / Tips / スクリプトの中断
- スクリプトの中断
- iTunes for Mac まとめ - AppleScript
- iTunes関連の命令について
- life log: AppleScript 最速基本文法マスター
- AppleScriptについて
- iTunes Scripts の使い方
- iTunes Scriptフォルダの場所
ありがとうございます
Raspberry Pi で家電を操作する1
目次
今回は長くなるので複数回に分ける
- Raspberry Pi で家電を操作する1 (MacにWebサーバを設置して照明を操作する)
- Raspberry Pi で家電を操作する2 (Raspberry PiにWebサーバを設置して照明を操作する)[未投稿]
やりたいこと
- 今回はブラウザから部屋の照明のスイッチをサーボモータで動かしon/offさせたい
- 最初は Mac で作ってからRaspberry Pi に移す
構成と環境
Raspberry Pi とArduino の通信はシリアル通信を使用した
Raspberry Pi から直接サーボを操れるようだが、慣れているので Arduino を使用した。そのうち変更するかもしれない
作業の軌跡
- Arduino でシリアルを受信してサーボを動かす
- Sinatra からシリアル信号を送る
- 時間差をつけてシリアル信号を送る
- Sinatra にタイマー機能をつける
- Raspberry Pi に移す
- IPを固定する
- ホスト名でリモート接続できるようにする
- 作成したSinatraアプリケーションをデーモンにする
Arduino でシリアルを受信してサーボを動かす
シリアル信号に応じてサーボを右もしくは左に少し回して照明などのスイッチをon/offする
スケッチは以下のような感じになった
- loop で常時シリアル信号を監視する
- 信号は数字になっていてそれぞれに対応したアクションを探す
- アクションが決定したら実行する
- サーボをデフォルトの位置に戻す
codeはgistにある
Arduino のコード
Sinatra からシリアル信号を送る
Sinatra でブラウザにon/offボタンを表示させ押せれたらシリアル信号を送るとようにしたい
Sinatra とは Ruby on Rails のような Ruby で Webサーバを立てるためのドメイン特化言語(DSL)です
Sinatra でシリアル通信を扱うためにはgemのserialportが必要なのでinstallする
gem install serialport
コードは以下のようになった
- 初期動作
- textで保存したシリアルポートの名前(環境によって異なる)を読み込む
- シリアルのインスタンスを作成
/
がリクエストされたらon/offボタンのあるhtmlを送る- スタンドライトのonのボタン
/standOn
が押されたらシリアルを送信し/
にリダイレクトする
嵌ったところ1 逆引きDNS
localhost:4567
でアクセルするとロードが100ms程度で終わるのに対しIPアドレスを直接指定すると1分以上かかってしまった
どうやらSinatra側がアクセスしてきたクライアントのIPアドレスをホスト名に変換するときに hosts が設定されていないとタイムアウトするまで時間がかかってしまうらしい (この解釈であってるかわからない)
DNS逆引きを止めるコードがネット上にあったので使わせてもらうことにした
sinatraでDNS逆引きを止める | TechRacho
嵌ったところ2 inline-block の隙間
今回 inline-block を使ったがリストタグ<ul>
内に改行があると改行が半角スペースとなって表示されるらしい
その影響で各ボタンの間に隙間ができてしまって結果的にレイアウトが崩れてしまった
CSS で inline-block の文字間を 0em にして inline-block中 のul
の文字間を xx-large とすることで解決した
一部を抜粋
ul{ list-style:none; font-size: 0em; /* inline-block 隙間対応*/ } li p, .on, .off, .timer{ padding: 30px 0px; margin: 0px; display: inline-block; font-size: xx-large; /* inline-block 隙間対応*/ color: #FFFFFF; }
rerun
余談だが今回始めてrerun
を使ってみた
rerun は関連するコードが更新されるとsinatraを再起動してくれる
sinatra-contrib
だとイマイチ動こかないことがあったが rerun はいい感じに再起動してくれる
gem install rerun
してrerun 'ruby app.rb'
する
Sinatra: Frequently Asked Questions
タイマー機能を作る
今回は簡単に指定時間 sleep させたあと任意のアクションのアドレス(例えばlocalhost:4567/standOn
)にアクセスするようにする
コードはこんな感じになった
require "open-uri" Hour = 3600 #Create mode print("Select Mode\n1. Stand Light On\n2. Stand Light Off\n3. Room Light On\n4. Room Light Off\n--> ") mode = gets.to_i case mode when 1 then mode = "standOn" when 2 then mode = "standOff" when 3 then mode = "roomOn" when 4 then mode = "roomOff" else print("Mode error\n") return 0 end print("Select #{mode}\n\n") #Create timelimit print("Select Time(hour)\n--> ") limit = gets.to_i print("Select #{limit}hour\n\n") #Wait print("Waiting #{limit}hour...") sleep(Hour * limit) print("\n\n") #Acsess open("http://localhost:4567/#{mode}").read print("Done\n")
Sinatra にタイマー機能をつける
上記のタイマだとターミナルからしか使えないのですこし面倒 しかもターミナルウインドウを閉じてしまうとプロセスも閉じてしまうので困ってしまう なので Sinatra と同じプロセスで動かして尚且つブラウザからも操作できるようにしてみる
コードはこんな感じになった
- '/'でタイマのボタン
T
(/timer/standOn)を押す - 2つめのパスに記したアクション(例えばstandOn)を引数に
/timer
が開く /timer/standOn
で時間を入力して時間とアクションをpostで送るapp.rb
がpostを受けて別スレッドでsleepさせておき本スレッドではすぐに/
にリダイレクトする- 別スレッドが時間になったら任意のアクションのアドレス(例えば
localhost:4567/standOn
) にアクセスする
このように直接時刻(6:30)を指定する方法と数時間後(4時間30分後)を指定する方法を用意した
雑感
- タイマの時間指定をするフォームで
input type="tell"
にするとiPhone等で数字入力するときにテンキーキーボードが出てくるのでカッコイイ - 将来的にはタイマボタン
T
で/timer/standOn
に画面遷移するのではなくon/offボタンの長押しで画面遷移したい - iosのブラウザで
input type="time"
を表示するとinputの親要素ごと上下に数ピクセルずれてしまったのでなんとかしたい - Mac や iPhone でアクセスできるとお布団から出なくても部屋の明かりをon,offできて寝る時に便利
- 照明のタイマー機能でやすやす起きれると思っていたら、布団に頭まで潜っているので意味がなかった(特に冬は)
コードはGithubとgistにある
- Sinatra のコード Coro365/home-control
- Arduino のコード It receives the serial signals to control the switches.
次回予告
次回は今回のコードを Raspberry Pi に移します
Raspberry Pi で家電を操作する2 (Raspberry PiにWebサーバを設置して照明を操作する)[未投稿]です
参考ページ
- Sinatraについての質問です Sinatraのサーバにlocalhost:4567で… - 人力検索はてな
- ありがとうございました
- sinatraでDNS逆引きを止める | TechRacho
- DNS逆引きキャンセル
- Ruby - rerunでSinatraのファイル変更時にリロード - Qiita
- rerunについて
- inline-blockを並べた場合に発生する「隙間」を消去するCSS » INSPIRE TECH
- inline-blockの隙間
ありがとうございます
Ruby で Pushbullet を使う
Pushbullet の API を使って各デバイスに通知を送ってみる
Pushbullet
Pushbullet はブラウザ又は Mac/Windows/iOS/Android のアプリからアクセスできて特定のデバイスにテキストや地図、ファイル等を送信できる。送信を受けたデバイスには通知センターに表示できる
今回はこれを使って Mac から任意のタイミングで iPhone にpush通知 を送るようにしたい
Gem インストール
Ruby で扱うための gem が公開されていたのでこれをインストール
gem install washbullet
自分のアクセストークンを Pushbullet の Setting から入手
32桁の文字列がアクセストークンになっている
アクセストークンを使って API から自分のid とデバイスのid を調べる
ターミナルで以下のコマンドを実行する
自分のid
curl -u Your_Token: https://api.pushbullet.com/v2/users/me
デバイスのid
curl -u Your_Token: https://api.pushbullet.com/v2/devices
JSON が帰ってる。 "iden":に続く文字列がidになる
取得したidで通知を送る
require 'washbullet' client = Washbullet::Client.new('Your_Token') client.push_note('Your_Device_Id', 'title', 'messege')
これを実行するとで送信された
id を Ruby から調べる
手動でidを読むのは面倒なのでアクセストークンを入力すると自動で自分のid と Pushbullet に登録されたデバイスのid を返すようにしてみた
require "json" def getUserId (token) api_response = `curl -s -u #{token}: https://api.pushbullet.com/v2/users/me` userId = JSON.parse(api_response) return userId["iden"] end def getDeviceId (token) api_response = `curl -s -u #{token}: https://api.pushbullet.com/v2/devices` deviceInfo = JSON.parse(api_response) deviceIds = Array.new deviceInfo["devices"].size.times do |i| deviceId = deviceInfo["devices"][i]["iden"] deviceName = deviceInfo["devices"][i]["nickname"] deviceModel = deviceInfo["devices"][i]["model"] deviceIds.push([deviceId, deviceName, deviceModel]) end return deviceIds end token = "Your_Token" p getUserId (token) p getDeviceId (token)
実行すると自分のidとデバイスid,デバイスのニックネーム,デバイスモデルが表示される
参考ページ
- Pushbullet API Documentation
- 公式ドキュメント
- hrysd/washbullet
- 今回使ったgem、お世話になります
- Ruby 1.9 以降で JSON を扱う - 見上げれば、空
- jsonの扱い方
ありがとうございます。