プログラム

ArduinoでHTTPリクエストをレンタルサーバに投げる方法

突然ですがArduinoの話題。

Arduinoにイーサシールドを接続してDHCPでIPを取得し、ホスト名で示したレンタルサーバへアクセスする際の接続例。
単純にPCからtelnetしてあげるのと同じですが、接続先が共有レンタルサーバ等の場合はHTTPのリクエストヘッダにHostヘッダが無いと当然ですが接続先でホスト名を利用して切り分けられないのでになるので接続できませんね。*1

*1:暫く悩んでしまった…情けない

2020年10月17日注記

WordPress移設に伴いサンプルソースコードが読みにくくなっていたためgistに転載しました。

開発環境で.envに定義された環境変数を取得(Padrinoの場合)

SqaleHerokuといったPaaSサービスを利用していると環境変数.envというファイルに定義しておくと、アプリケーション側でそのファイルの内容を環境変数として解釈してくれますが、rack-envというGemを利用すると開発環境でも.envで記載した内容を環境変数として解釈できる様になります。
以下、Padrinoで利用する場合。まず、Gemfileにrack-env追加。

# Gemfile
# Project requirements
gem 'rake'
gem 'rack-env', :group => "development"

で、app/app.rb に以下の1行を追加します。

module PadrinoSample
class App < Padrino::Application
use Rack::Env unless ENV['RACK_ENV'] == 'production' # 追加

これで本番環境と同様に開発環境上でも.envファイルを利用して環境変数を定義することができます。例えば、

HOGE=foo

と、.envファイルを定義しておけば、

get '/' do
ENV['HOGE'] #=> foo
end

これで、本番環境での動作を想定して開発環境で開発中からコード中で非公開にしたい情報をハードコーディングせずに済みます。

ccchartでグラフを描画する

ccchartというグラフ描画ライブラリがとても使いやすくて便利だったのでメモ。もし実際に利用する場合は、サンプルやドキュメントが充実しているのでそちらを参照した方が良いと思います。

最近、REMPで運営者用の管理画面を作っていることは以前書きましたがその中で利用状況等を示すグラフを作りたくなったので今回利用してみました。

使い方

使い方はとてもシンプルで、まずライブラリの読み込みとグラフを描画する領域をHTML上に定義します。

<html>
<head>
  <script src="http://ccchart.com/js/ccchart.js" charset="utf-8"></script>
</head>
<body>
<canvas id="graph-area"></canvas>
</body>
</html>

これで準備は完了。で、この領域(=canvasタグ内)に今回はREMP で利用しているMongoDBの情報を参照してグラフを描画させたかったので、グラフのみ非同期で描画させてAPI経由でグラフに必要な情報を参照して描画させてみました。
まずAPIの準備。ccchartは、JSONオブジェクトをパラメータとしてグラフを描画する仕様になっているので、API側で描画に必要なパラメータを全て作って渡す様にしました。Padrino側でAPIをこしらえてあげます。

# app/controllers/foo.rb
get :graphvalues do
timeScale = ['']
fooNum = ['foo']
minYRange = 0
maxYRange = 1000
Score.where(:created_at => 10.day.ago..1.day.ago).each do |oneScore|
timeScale << "#{oneScore.created_at.day}"
fooNum   << oneScore.foo
end
title = 'foo'
data = [timeScale, fooNum]
colorSet = ["red"]
# JSON
graphValues = {
config: {
titleFont: "100 18px 'Arial'",
title: title,
type: "line",
lineWidth: 4,
minY: minYRange,
maxY: maxYRange,
width: 480,
height: 400,
colorSet: colorSet,
bgGradient: {direction:"vertical",from:"#687478",to:"#222222"}
},
data: data
}
content_type :json
graphValues.to_json
end

なんかごにょごよしてますが、要はccchartで定められているグラフ定義用のJSONをサーバサイドで作っているだけです。
次にフロント側(JS)で、APIから取得したJSONを利用してグラフを実際に描画します。

<script>
$(document).ready(function(){
$.ajax({
type: "GET",
dataType:'json',
scriptCharset: 'utf-8',
url: "/foo/graphvalues",
success: function(res){
ccchart.init('graph-area', res);
}
});
});
</script>

そうすると以下の様なグラフが描画されます。

グラフの種類も多いですし、必要に応じて使ってみようと思います。

ActiveRecordで結果を単純な配列を得る(特定のカラムの)

特定のカラムを指定して検索した結果は素直にすると、

Visitlog.select([:normalize_count]).where(:group_id => 3, :visitor => '123')
=> [#<Visitlog normalize_count: 0.0833333>, #<Visitlog normalize_count: 0.0833333>,...]

となるのだけど、これを [0.08333, 0.0833, ...] といった具合の配列で得たい場合、ActiveRecordにpluckというメソッドがあるのでそれを利用すればよかったことをやっと知った...。

Visitlog.where(:group_id => 3, :visitor => '2457892').pluck(:normalize_count)
=> [0.0833333, 0.0833333, ...]

mapしたりする方法とか散見したのだけど、この方法がスマートですね。

Ruby gem 'parallel' で並列処理

ふたまわり位遅れてますが、gemライブラリのparallelを使うと並列処理が簡単に書けて便利。
例として、とあるグループ別に記録されている訪問ログに対して各訪問者別の処理をする場合、以下の様な具合でかける。

require 'parallel'
processor_count = Parallel.processor_count #CPUコア数取得
Group.select(:id).each do |group|
visitors = Visitlog.select(:visitor).uniq.where(:group_id => group.id)
Parallel.each(visitors, in_threads: processor_count) do |visitor|
visitor_process(group.id, visitor.id)
end
end

Parallel.each の箇所で引数の in_threads で与えられた数だけスレッドが作られて適宜実行される。この場合、各訪問者に対して行われる処理は独立なのでこの書き方で大丈夫ですね。

"Redis To Go"でRedisを使う

RedisをSqaleで動かしている自作サービスから利用したいと思ったのですが、今、手元にすぐ利用できるサーバが無いので"Redis To Go"というRedisのホスティングサービスを利用してみました。
無償のプラン(Nanoプラン)であれば、

  • 5MbyteまでのDBが作成可能
  • ホスティング側でバックアップは取られない
  • 同時10接続まで

といった条件はありますが、お試しレベルであれば手軽に利用できそうなので試してみました。

https://redistogo.com/signup からサインアップして、ログインすると下の様な画面になるので、画面右上の"New Instance"をクリック。

新規インスタンス

いくつかプランが選択されるので無償プランの"Nano"を選択。

プラン選択

インスタンスを作成すると接続に必要なURIの情報が表示されるのでここをコピーしておきます。(redis://〜:〜@〜.redistogo.com:9007/ といった形式の文字列)

接続情報

で、実際にRubyから作成したインスタンスに接続してみます。

$ gem install redis

先に控えた接続用のURI情報を使って以下の様に接続。

require 'URI'
require 'redis'
uri = URI.parse("redis://〜:〜@〜
.redistogo.com:9007/")
redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)

実際にKey-Valueをストアしてみると。

irb(main):008:0> redis.set "foo", "bar"
=> "OK"
irb(main):009:0> redis.get "foo"
=> "bar"

といった具合で利用できています。
インスタンス自体はAWSのUS-EASTリージョンで動いている様なので日本国内から利用すると多少レスポンスまでにラグがありますが、超お手軽にRedisの利用を試すことができます。

Mongoidで更新日時の範囲で絞込み

2回調べたので記録しておく。

Status.where(:updated_at => 25.minute.ago..15.minute.ago)

どう見てもそのまんまだろうという話なのだが、情けないかな頭にパッと出てこない。
普段から常にARとかMongoid使っていないと駄目なんだろうなぁ...。

ImpasというAPIサービスを作った

個人でささやかにWebサービスを運営されている方向けにImpasというAPIサービスを作りました。

このサービスは「twitter上でのツイート数、facebook上でのいいね数、はてなブックマークでのブックマーク数で簡単にランキングを生成する」ことができるAPIサービスです。
以下、概要図。

About of Impas

Webアプリケーション開発者はImpasのAPIを使ってImpasにランキング対象にしたい(各種ソーシャルパラメータを計測したいURL)を登録することで定期的にImpasがURLをクロールしてパラメータを取得して記録します。その記録を利用してImpasはランキングを生成するので、再びWebアプリケーション開発者はAPIを通じてランキングを取得することができます。
RubyクライアントをGem(impas-client)で用意していますので、以下の様な形で利用することができます。

URLの登録例

# クライアントの設定
require 'impas-client'
client = Impas::Client.new()
# URLを集計対象へ追加
IMPAS_GRP_KEY = ******
client.add_url(
IMPAS_GRP_KEY,
"http://www.youtube.com/watch?v=2HQkugdXyHY"
)
# ランキング取得
fbRank = client.ranking IMPAS_GRP_KEY, "fb"
twRank = client.ranking IMPAS_GRP_KEY, "twitter"
hatenaRank = client.ranking IMPAS_GRP_KEY, "hatena"

あるいは、以下の様に直接POSTやGETリクエストでURLの登録やランキング情報の取得もできます。以下ははてなブックマークのトップ10ランキングを取得する場合。

http://impas-hideack.sqale.jp/api/ranking/IMPAS_GRP_KEY/hatena/10

ランキングはJSONで取得されます。

{
"result": "ok",
"explain": "",
"description": {
"ranking": [
{
"callcount": 16,
"fb": 0,
"hatena": 809,
"tw": 17643,
"url": "http://www.youtube.com/watch?v=MGt25mv4-2Q"
},
{
"callcount": 12,
"fb": 0,
"hatena": 368,
"tw": 10591,
"url": "http://www.youtube.com/watch?v=cfpX8lkaSdk"
},

ドキュメント等々不足している感はありますが、もし興味がある方が居られたら是非ご利用くださいませ。

ロゴ

REMPチームでお馴染み(?)の@があっという間にロゴ画像を作ってくれましたが、何故か大王イカなのかは昨今の話題からお察しください。*1
あと、サービス名の"Impas"はドラゴンクエストの魔法のインパスから拝借しました。

Impas

*1:あっという間に作ってくれたのですが、それでこのクオリティというのがすごい…