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の隙間
ありがとうございます