自宅開発環境をUbuntuにしました

hatappi.hateblo.jp

前書いたように最近自宅の開発環境をAWSに移行するとともに開発環境をDockerに移行した
これ自体はよくて何か問題があればコンテナを立て直せばよいし、必要なものはMItamaeでいれてDocker Imageつくるだけでwebアプリケーションとバッチで使用される

ただ1つ問題がありそれが自分のMacでローカルで開発をする時

ホストのMacRailsディレクトリをmountしてDocker上ではrails serverを動かして開発しているのですが遅い!!
rake db:migrateとかrails consoleしてもすぐにはレスポンスかえってこない…..

このMacでファイルマウントしたファイルのアクセス遅い問題は昔から存在していて下記のissueで長いことやりとりがされている

github.com

これの解決方法はいくつかあり

docker-sync

docker-sync by EugenMayer

1つ目の方法ですが、マウントではなくrsyncやunisonを使用してファイルを転送しようというアプローチです
使ってみたところたしかに早くなるのですが、docker-sync用の設定ファイルが必要になり管理する対象が1つ増え個人的にはスマートではないなという感じです

mount時のcachedをつける

docs.docker.com

Docker 17.04からマウント時のconsistencyが新しく導入されマウント時に -v /hoge:/app:cached のように指定します
ただこれはつけない時よりかは早くなるだけで、快適とはいえないです

ではどうしたのか??

Mac捨てました ※ 物理的にではないです

MacをすててUbuntuにしました
昔自宅でサーバーを運営していた時に使用していたマシンがあったのでそれを掃除したりグリスぬったりして使えるようにしてUbuntuいれました
今回はUbuntu 17.04をいれてその後にGNOMEをいれました
余談ですがUbuntu 18.04 LTSからのデフォルトデスクトップ環境はGNOMEになるらしいですね !! 記事はこちら

CPUはIntel® Core™ i5-4440 CPU @ 3.10GHz
メモリは8G
HDDで500G
モニタは家のテレビ
です
たぶん使いだすとメモリが足りないとかSSDが良いとは出てくると思いますが、それがお金の余裕が出てきてからで!!

とりあえずDockerをいれて開発をはじめてみたのですが快適!快適!
開発するのが楽しくて仕方ない

Ubuntu 17.04でコピーをmacでいう ⌘ + c でする

最近Ubuntu Desktopを触りはじめた
今までUbuntuだとDocker ImageとかのCLIの環境でしか使ってこなかったからGUIがあるの新鮮

今回はそんな初めてのUbuntu Desktopをセットアップする時にいつものようにコピペをしようと思ったらなぜか出来ない
どうやらコピーはCtrl + Cとなっている ではMacでいうキーは何になっているかというと、Superキーになっているらしい(WindowsでいうWindowsキー)

原因はわかったけど困るのでキーの割当を変更する
ネットで調べて見ると/usr/share/X11/xkb配下のファイルを追加したり変更したりするのがあったり色々あるけど下のやつが一番シンプルだった

SuperキーにCtrlを割り当てる

今回の動作環境はUbuntu Gnome 17.04を使用しました

# キーボード設定とかフォントの変更とか色々できるやつ
$ sudo apt-get install gnome-tweak-tool
# 起動する
$ gnome-tweak-tool &

これでウィンドウが立ち上がる
後は設定項目からタイピングを選択しAlt/Winキーの動作をおしてCtrl is mapped to Win keys (and the usual Ctrl keys)にチェックをつける

これだけ!! これでいつものように+cでコピーが出来るようになった

任意の場所に自宅の温度、湿度をPOSTしたい

前回はこんな記事書きました

hatappi.hateblo.jp

ただこれの欠点としてはUDPなので届いてるかも分からないですし、学習リモコンの電源が抜けてるとかで送信出来ないかもしれない
といった問題が考えられます

根本的な解決にはなりませんが、温度をとれるようにすることでエアコンが効いて温度がさがっているか把握できるのではないかと思ってやることにしました

どう実現するのか

おそらくみなさん家にRaspberry Piが転がってると思うのですが、今回はそれを使用しました
僕の場合はRaspberry Pi A+が転がってました

温度の取得はRHT03(or DHT22)を使用しました
このRHT03は温度だけでなく湿度とかもとれます
使用範囲としては湿度が0-100%RH、温度が-40~80℃と家庭で使用するには申し分なさそうです

Raspberry Piの設定

Raspberry Piのセットアップなどに関してはネットで検索すると出てくるので省略します

今回使用したRaspberry Pi A+にはwifibluetoothなどは内蔵していないので、USBタイプのLANアダプタを使用してネット環境に接続しました

RHT03をつないだ後はこんな感じです

f:id:hatappi1225:20170719085248j:plain

任意のサーバーにPOSTリクエストをする

今回はPython2.7.10を使用しました
まず温度と湿度に関してですが、すでに取得できるようなスクリプトがあるので使用させていただきます

github.com

セットアップなどはREADME.mdに書いても書いてありますが、下記で行えます

$ sudo apt-get update
$ sudo apt-get install build-essential python-dev
$ sudo python setup.py install

これをするとPythonスクリプトで下記のようにすることで温度と湿度がとれます

import Adafruit_DHT
humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.DHT22, 4)
print "temperature is %f" % temperature
print "humidity is %f" % humidity

簡単ですね
Adafruit_DHT.read_retryに引数を渡すのですが、第一引数で使用しているセンサーを指定します
他にはAdafruit_DHT.DHT11Adafruit_DHT.AM2302があります
第2引数でGPIOの番号をわたします 番号はこちらを参考にしました

後はこれを任意の場所にPOSTできるようにするだけです
今回のPOST先は自宅サービスなのですが、自宅サービスは深夜の時間帯は費用削減のために落としているのでリクエストすることが出来ません
そこで今回はリクエストに成功しなかった場合は送るはずだった温度と湿度をファイルに書き出して、次に実行される時に一緒にリクエストをするようにしました
そのスクリプトが下記です

# -*- coding: utf-8 -*-
import requests
import json
import os
from logging import getLogger, FileHandler
from pytz import timezone
from datetime import datetime
import Adafruit_DHT

logger = getLogger(__name__)
logger.addHandler(FileHandler('hoge.log', 'a+'))

humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.DHT22, 4)

temperature_humidity_arr = [{
    "temperature": temperature,
    "humidity": humidity,
    "recorded_at": datetime.now(timezone('Asia/Tokyo')).strftime("%Y-%m-%d %H:%M:%S")
}]

temp_json_path = "data.json"

if os.path.isfile(temp_json_path):
    with open(temp_json_path, 'r') as f:
        temperature_humidity_arr = json.load(f) + temperature_humidity_arr

try:
    response = requests.post(
        'https://example.com',
        data=json.dumps({"temperature_humidity": temperature_humidity_arr}),
        headers={'Content-Type': 'application/json'},
        timeout=30
    )
    # 4xx, 5xxなどの場合に例外を出す 
    response.raise_for_status()
    if os.path.isfile(temp_json_path):
        os.remove(temp_json_path)
except Exception as e:
    logger.error('ERROR: %s' % e.message)
    with open(temp_json_path, 'w') as f:
        json.dump(temperature_humidity_arr, f)

これで無事自宅サービスに温度や湿度が送れるようになりました
もちろんPythonで温度や湿度がハンドリングできるので、Mackerelに送ってメトリクス監視しても良いですし自由自在です

自宅サービスUPDATE: エアコンが外から操作できるようになった

hatappi.hateblo.jp

上記で自宅サービスをDockerで動かせるようにしたので、ついでに今回は機能開発もした

hatappi.hateblo.jp

今回追加した機能は前回の記事でも触れたエアコンを外から付けたり消したりするものを実際に運用できる形にしたもの
LINEから操作できるようにもしようと思ったのですが、Rails + Reactでつくったwebの方も使ってもらいたかったので今回のゴールはwebから操作できるようにした

Wiresharkから取得した16進数のデータはbinarylogic/settingslogicにもたせておいて
それらは下記のようなクラスを通じてUDPプロトコルで通信をさせる

require 'socket'

class UdpConnector
  attr_reader :socket

  def initialize
    @socket = UDPSocket.new
  end

  def send_packet(data)
    hex_array = data.scan(/.{2}/).map {|e| "0x#{e}".hex}
    socket.send(hex_array.pack('C*'), 0, ENV['HOST'], ENV['PORT'])
  end
end

UDPなので実際についたかまでは分からないですが、とりあえず通信が完了したらLINEで電源操作がされた旨を通知している

f:id:hatappi1225:20170715160235g:plain

f:id:hatappi1225:20170715160354p:plain

これでこの夏は凌げる気がする