2010年
✖
h2o の status/json を mackerel に送る
mackerel にメトリクスとして送る
mackerel-plugin-h2o みたいなのは今のところないっぽい? ので、status/json からとれる内容をポストするプラグインを書いた。
https://github.com/cho45/mackerel-agent-plugins/tree/mackerel-plugin-h2o/mackerel-plugin-h2o
mackerel プラグインの書きかた
他のプラグインにならって go-mackerel-plugin-helper を使ってみた。FetchMetrics の返り値でちょっと悩んだけど、以下のようにすればよさそう。
- FetchMetrics ではとにかくとれる値をすべて map に詰めてかえす
- GraphDefinition でグラフと値の関連付けを行う
GraphDefinition に含まれないメトリクスは、FetchMetrics で map に詰めても送信されない。これが最初理解できてなかったので、FetchMetrics でややこしいことをやってしまったりした。
12本のNiMHを充電できる充電器を買った
いままでSANYO時代のエネループ充電器を使っていたが、必要性が増してきたのでこのようなものを買った。
単3と単4どちらも充電できる。一本ずつ充電管理されているのでバランスとかは考えなくて良い。
端子がちょっと固くて、しっかり押しこんでやらないと入らない。一応充電状態にはなってしまうので気をつける。写真のうちいくつかはちゃんと入ってない (撮ったときは気付かなかった) 9 と 10 はちゃんと入っている。1とか4はちゃんと入ってない。
音がちょっとうるさい
本体側で若干コイル鳴きしててうるさい。といってコイル鳴きなので、かなり静かな環境でなければ聞こえない。
待機電力
一本も電池を入れてない場合、液晶のバックライトが消えてスタンバイ状態になるようだ。このときの消費電力は 0.3Wぐらい。
全て充電完了になっている場合、液晶のバックライトがついて充電完了を知らせる表示になる。このときの消費電力は0.5Wぐらい。
その他
ACアダプタは12V 1.5A (18W) のものが付属していた。ポートあたり最大 500mA (1.2V) らしいので十分っぽい。
意識高いエントリ見るとサブイボでる
意識高い (意識高い系ではなく、真の) みると、ただただつらい。アドベントカレンダーで毎日意識高いエントリが目につく。精神が攻撃されている。もっと気楽に生きていきたい………
ミラクルニキが楽しい
ミラクルニキ-お着替えコーデRPG - Apps on Google Play これ。公式サイトはここ
元々中国のアプリ「奇迹暖暖」で、それをローカライズして販売してるっぽい。暖暖シリーズはいくつかあるっぽく、過去にも日本語版ローカライズ版はでてたりするっぽいがやったことはない。ありがちな日本語に不自然なところはあまりない(が、UIではときどきある)。日本の提供会社の情報があんまりなくて怪しい以外は気になるところはない。
とりあえず最高に楽しい。いろいろゲームやってみた結果、着せ替えができさえすれば楽しいってことには薄々気付きつつあったけど (ポケモン・サン/ムーンやったら着せ替えの衣装が足りなくてものたりなかった)、このゲームは完全に着せ替えオンリーを極めててよい。着せ替え対象のキャラクターは一人だけ(ニキ)だけど、衣装数が極めて多く、髪型も変えれるので気にならない。
キャラクターのデザイン自体も「可愛いが男媚びも女媚びもしてない」ぐらいのバランスだし、衣装も細かく描かれててめっちゃいい。ニキのキャラ設定自体も鼻につかない感じで余計な部分はない。あえていうなら付属してくる変なゆるキャラみたいのがウザいぐらい。
ミラクルニキ・プリンセス 4-12
h2o の duration stats
h2o の status ディレクティブのJSON出力を眺めていたら、duration-25 とか connect-time-50 とか 不思議なプロパティがいくつか含まれることに気がついた。しかしどうも全て0のようであるので、なんらかのコンパイルオプションなのだろうか?と思ってちょっと調べた。
結局これは global で duration-stats: ON すると有効になるみたいだった。そうすると以下のように数字が埋まりはじめる。
"duration-0": 0, "duration-25": 0, "duration-50": 0, "duration-75": 4731, "duration-99": 26829
おそらくμs単位のパーセンタイル値で、この場合たとえば duration-75 は 75% のリクエストが 4731μs 以内に納まるみたいなやつだと思う。
今のところドキュメントには書いてないっぽい、というかリリースされてないっぽいので HEAD が必要?なのかな。
メモ
- h2o_now は ms 単位
- durations は h2o.h の COMPUTE_DURATION で *delta_usec = h2o_timeval_subtract*1; となっていてμsになってるっぽい
- server-status はどこのホストに書いても同じのがかえってくる (あくまでサーバ共通のステータスがとれる)
CO2 センサの可視化
MH-Z19 という格安 CO2 センサを読んでみた | tech - 氾濫原 の続きです。
Raspberry Pi で喋らせる
Open jtalk で喋るようにしてあるので
- 1000ppm を超えたら換気をうながす (アラート)
- 600ppm 未満になったら告知する (アラート解除)
みたいにした。
alert = false
loop do
begin
ppm = get_latest.last
case
when ppm > 2000
system("jsay.sh", "CO2濃度が2000ppmを超えました。ただちに換気を行ってください")
alert = true
when ppm > 1000
system("jsay.sh", "CO2濃度が1000ppmを超えました。換気を行ってください")
alert = true
when alert && ppm < 600
alert = false
system("jsay.sh", "CO2濃度が600ppmまで下がりました")
end
rescue Exception => e
p e
end
sleep 5 * 60
end get_latest は GrowthForecast からデータをとってくるやつ。センサーからデータを読むプロセスは別にしてあるので、間接的にgfからとってきてる。
常に表示する
家で余っているスマフォに常時表示するようにした。これも GrowthForecast からデータをとる。具体的には
- ロード直後は http://gf.lab.lowreal.net/xport/home/sensor/co2?t=sh&width=60 で過去ログをとってくる
- その後は1秒ごとに http://gf.lab.lowreal.net/api/home/sensor/co2 を取得して number と updated_at を使う
グラフは vis.js を使ってみた。結構つかいやすい。example のうちの 404 Not Found を参考にしたらうまくできた。
今後
GrowthForecast にデータを投げてるので、gf の API をメインで使ってみたが、gf はそういう用途のためのものじゃないので、かなり無駄感がある。WebSockeet 経由でデータを転送するゲートウェイみたいなのをまず作ったほうがいいかもしれない。
✖
ハイターの種類と選びかた。最も汎用性が高いのは
花王の漂白剤シリーズに「ハイター」というのがあるが、種類がいっぱいあってよくわからない。というところだけど、実は公式のFAQに一覧があって、どのように成分が違うのかと用途が記載されている。
大きな違いは「界面活性剤」の有無になる。汎用性が高いのは含まれていないほうなので、とりあえず買うなら「ハイターE」「月星ブリーチC」あたり、「ハイターE」は一般向けだと「ハイター 衣料用漂白剤」になる。
なお基本的に「ハイター」には塩素系を期待すると思うが、酸素系の「ハイター」も存在しているので注意が必要。
消毒用途では基本的に10倍希薄して使うことになっている (商品は6%だが、塩素は揮発してしまうため 5% 扱いとする)。0.5%以上 (5000ppm) の濃度で使用しても消毒効果は上がらず、残ってしまう時間が長くなるだけなので、必ず守る。
なお次亜塩素酸ナトリウムが重宝される理由としては、蛋白質と接触すると食塩に変化するため残留リスクが低いことにある。
ref
✖
QAサイトで間違ったことが書いてあると、正解を書きたくなる心理を利用して、どんな回答にもまず間違った答えを機械が書くというのはどうか (あっててもいいけど)
✖
IPv6 対応にした
さくらのVPSのウェブサーバでIPv6の接続をうける | tech - 氾濫原 で、IPv6 アクセス環境がないと書いたが、スマフォで簡単に IPv6 接続できることを知った。
APN 設定
IIJ mio の場合、APN の設定で IPv4/IPv6を選ぶだけで優先的に v6 接続されるようになる。
全ホストの IPv6 対応
自力で確認できる環境が身近にあることがわかったので、このサーバでホストしているホストを IPv6 対応してみた (もとも IPv6 インターフェイスも listen してるので単に AAAA レコードをひけるようにしただけ)
ちゃんと接続されてるのか?
見た目が何も変わらないのが正しい状態なのだけど、IPv6 接続されてるのかよくわからないので、仕掛けをしてみた。
判定は単に REMOTE_ADDR を見て、IPv6 アドレスだったら IPv6 接続と判定する。: を含んでいたら IPv6 と判定するようにする。
このサイトの場合、ページ全体をキャッシュしているため、内容をIPv4/IPv6で出しわけると持つべきキャッシュが倍になってしまい現実的ではない。ということで、以下のようにした。
- CSS で適当なところに content: attr(data-ip-info); と書いておく
- JS で接続情報を取得するエンドポイントを叩き data-ip-info を埋める
ref
MH-Z19 という格安 CO2 センサを読んでみた
郑州炜盛电子科技 という会社の MH-Z19 という CO2 センサを買ってみました。Aliexpress で $22 ぐらいでした。
- 非分散形赤外線吸収式
- 電源は 3.6〜5V
- インターフェイスは UART または PWM 3.3V
- プリヒートは3分
- 温度補正あり。精度は±50ppm + 5%
5V の電源と 3.3V のインターフェイスが必要ですね。
とりあえず動かしてグラフ化
Ruby 用のライブラリを書いて読みだして、GrowthForecast に投げてみました。Raspberry Pi 上で動かしています。シリアルは USB 経由で、PWM では GPIO 経由で読んでいます。
結構おもしろくて、人がいるかいないかはグラフから一目でわかるレベルです。換気するとそくざに値に反映されるのもおもしろいです。
Ruby 用のライブラリ
Ruby で読み出し用のライブラリを書いてみました。
Serial 経由の読みこみとPWM (Linux のみ。sys/class/gpio 経由) どちらとも実装してあります。
PWM
Serial は仕様書通りに書いただけですが、PWM はちょっと工夫がいるのと、データシートそのままだとちゃんと値がでず試行錯誤したのでメモしておきます。
/sys/class/gpio でのエッジトリガ
PWM はエッジトリガをしかけて時間をそこそこ正確に計測する必要があります。Linux の GPIO でやる方法がわからなかったので、ちょっと調べて以下のようにしました。
- "/sys/class/gpio/gpio#{pin}/direction" を in に
- "/sys/class/gpio/gpio#{pin}/edge" を both に
- "/sys/class/gpio/gpio#{pin}/value" を開いて fd を取得
- select でエッジを待つ
- read で内容を読む
- seek で戻す
- select に戻る
select でブロックしてエッジが検出されると制御が戻ります。read したあと seek で戻さないと、次の select でブロックせずビジーループになってしまうようでした。
def self.trigger(pin, edge, timeout=nil, &block)
self.direction(pin, :in)
self.edge(pin, edge) #=> write "/sys/class/gpio/gpio#{pin}/edge"
File.open("/sys/class/gpio/gpio#{pin}/value", "r") do |f|
fds = [f]
buf = " "
while true
rs, ws, es = IO.select(nil, nil, fds, timeout)
if es
f.sysread(1, buf)
block.call(buf.to_i)
f.sysseek(0)
else
break
end
end
end
end 処理速度が不安でしたが、1ms 単位でとれれば十分なので Ruby + /sys/class/gpio でも十分でした。
PWM の場合の計算方法
データシートだと以下の計算式になっています。ここで th は PWM の high の時間、tl は low の時間、ppm は CO2 濃度です。
ppm = 2000 * (th - 2e-3) / ((th + tl) - 4e-3) が、どうみてもデータシート通りの値がでてきませんでした。どうやら型番が一緒で、検出レンジが 0〜2000ppm のものと、0〜5000ppm のものがあるようで、2000 の部分を 5000 にするとうまく計算できました。
キャリブレーション
シリアル経由だと、ゼロ補正とスパン補正というのがあります。仕様書にどうやってキャリブレーションするか書いてないのですが、おそらく以下の手順です
- CO2 がない環境 (窒素100%とか) でゼロキャリブレーション
- 既知のCO2濃度の環境でスパンキャリブレーション (スパンキャリブレーション時に既知の濃度を渡します)
↑ の手順おそらく間違いなので以下の正しいと思われる手順を書きます。MH-Z19B のデータシートの手順です。
- CO2 濃度が 400ppm の環境でゼロキャリブレーション
- CO2 濃度は 2000ppm の環境でスパンキャリブレーション (1000ppm 以上の既知の濃度を使うこと)
まぁキャリブレーションは難しいのですが、一定期間内の最低値を外気のCO2濃度 (約400ppm) とみなしてときどき自動で補正していく方法もあるようです。
気象庁の二酸化炭素濃度のグラフを見る限り、近年は 400ppm 程度のようです。季節変動もみられますが、センサーの精度よりも小さいので無視できます。
二酸化炭素濃度の基準
ビル衛生管理上では 1000ppm を目安に換気せよと書いてあります。これは二酸化炭素の影響だけではなくて、これを目安として他の有害物質の滞留を防ぐという意味合いもあるみたいです。
また CO2 単体でも 2000ppm以上になると自覚できる症状が現れることがあるようです。
ref.
✖
h2o の ssl-session-resumption のストア先を memcached に
internal がデフォルトで、特に問題もないしずっとこれにしていたが、h2o が再起動されるたびにキャッシュが消えるのではないか? どうせ memcached も起動してるのでそっちにストアすべきではないか? と思いはじめたので変えてみた。
まぁ弱小ウェブサイトだとそもそも resumption かかるようなことがぜんぜんないので意味ない。Google Bot も分散アクセスのせいか全く resumption しないし。
となりのトトロに星野源
最近子どもがとなりのトトロにハマってて毎日見てるんだけど、今朝は「お父さん」と「お母さん」が病院で会話しているシーンを見て、「星野源みたいねぇ」「ガッキーみたいねぇ」とか言いだして笑った。メガネかけてると星野源みたいねぇと言うのはしばしばあるんだけど、さらに「ガッキーみたいねぇ」は初めて聞いた。
最近は直接見てないはずなので (というか親が見ようとすると嫌がる)、結構前のを覚えているようだ。
✖
✖
↑ の写真 webp で Google Photos にアップロードしたんだけど、Chrome で見ても jpeg でしか配信されない。うーん…… いまいち webp 配信の条件がわからない。
Google Photos 上のサムネとかは webp になってるけど、大きめの画像は jpeg 固定なんだろうか
Lightroom で webp の一発書きだし
webp のインストール
homebrew で入れる。
$ brew install libtiff $ brew install --HEAD webp
-
- HEAD つけないとコンパイル済みの TIFF 非対応バイナリがインストールされるので注意
Export Actions にシェルスクリプトを置く
~/Library/Application Support/Adobe/Lightroom/Export Actions
にスクリプトを置くと、書き出しダイアログで選べるようになる。書き出したあとスクリプトの引数に現像済みファイル名が渡されるので、これを処理するようにすればよい。
以下のようなファイルを webp.rb という名前で Export Actions フォルダに保存して実行属性をつけておく。
#!/usr/bin/env ruby
require 'logger'
logger = Logger.new('/tmp/webplog')
logger.info ARGV.inspect
begin
ARGV.each do |f|
dir = File.dirname(f)
out = File.join(dir, File.basename(f, ".tif") + '.webp')
logger.info "%s => %s" % [f, out]
IO.popen([
'/usr/local/bin/cwebp',
'-metadata', 'all',
'-preset', 'photo',
'-q', '90',
'-o', out,
'--',
f
], :err=>[:child, :out]) do |io|
while l = io.gets
logger.info l.chomp
end
end
end
rescue Exception => e
logger.fatal e.inspect
end Lightroom の書き出し設定
ファイル設定
- TIFF
- 8 bit/チャンネル
として
「後処理」で「webp」を選ぶ
で書きだし。
問題点
EXIF が消える。cwebp が TIFF の EXIF デコードに非対応のため
h2o の proxy.reverse.url で localhost を指定していたら確率的に connection failure
リバースプロキシとして使っている h2o で
proxy.reverse.url: http://localhost:5001/
みたいに書いていたら確率的に connection failure がでて悩んだ。結局
proxy.reverse.url: http://127.0.0.1:5001/
で解決
なぜこうなったか
/etc/hosts に ::1 localhost のエントリ(IPv6)があり、h2o は解決したアドレスのうちからランダムに1つ選択するため。プロキシ先のバックエンドサーバは IPv6 を bind しておらず、::1 が選択された場合に接続に失敗していた。
メモ
- h2o がホストを選択するところ (rand している)
- nginx でも同様の設定をしていたが、nginx はランダムにしないみたい
h2o で listen するポートを増やしたときは master プロセスの再起動が必要
start_server が listen してないポートは以下のようなエラーになる。
cp socket:(null):80 is not being bound to the server
h2o は SIGHUP で graceful restart が可能だが、listen するポートが変わった場合は実際にlistenしている親プロセス (start_server プロセス) の再起動が必要になる。
nginx をアンインストール
これまで HTTPS (443) だけ h2o で処理していたが、nginx に使ってるぶんのメモリ量がMOTTAINAIのでh2oだけでやるようにした。さようなら nginx。
複雑なことをしているホストは全くなかったので普通に書きかえていっただけ















