mrubyでsqlite3
スマートメーターのデータなどをcsvで保存してjsonに変換してchart.jsでグラフにしているが、snmpなどのデータも取り始めて、sqlite3に変更してみた。
ずっとcsvでも良いかと思っていたのですが、sqlite3を調べてみたところ、ライブラリを22万行のファイル1本で書かれていて、依存もなくちょっとやってみようという気がおきました。
ZRouterのports-modokiに入れてピルドできるようにしました。
mrbgemsはこれを使いました。
csvで処理していた時には、cronから起動させるバッチで定期的にjsonを作っていましたが、sqlite3を使えばcgiで動的に作ることが可能になります。
とりあえずこんな感じでデータを保存しあります。1カラム目が日付で2カラム目が時間です。これらはdefault CURRENT_DATE,CURRENT_TIMEで設定してあります。
sqlite> select * from sm;
2020-04-05|23:50:47|6279.7
2020-04-06|00:00:01|6279.7
2020-04-06|00:10:01|6279.8
2020-04-06|00:20:01|6279.8
2020-04-06|00:30:02|6279.8
2020-04-06|00:40:02|6279.9
2020-04-06|00:50:01|6279.9
2020-04-06|01:00:01|6279.9
2020-04-06|01:10:02|6280.0
2020-04-06|01:20:01|6280.0
2020-04-06|01:30:02|6280.0
2020-04-06|01:40:01|6280.1
2020-04-06|01:50:01|6280.1
2020-04-06|02:00:02|6280.1
cvsの時はJSTで保存していたのですが、sqlite3はデフォルトUTCになるようです。
JSTとUTCの関係はこんな感じです。
JSTの今日はUTCの昨日の15時から今日の15時になります。
結構無理やりですが、今日のメーター値の抜き出しを、こんなコードにしてみました。
#!/usr/local/bin/mruby
db = SQLite3::Database.new('/tmp/ouchi.db')
time = Array.new
val = Array.new
yday = (Time.now - 60*60*24).to_s[0, 10]
tday = Time.now.to_s[0, 10]
i = 0
# select by JST
sel = 'select time, power from sm'
whe = ' where (time>="15:00:00" and date=?) or (time<"15:10:00" and date=?)'
db.execute(sel + whe, yday, tday) do |row, fields|
time[i] = row[0]
val[i] = row[1]
i = i + 1
end
print "Content-type: text/json\n\n"
j = 0
tmo = 0
print '{"date":"' + tday + '","type":"sm.log","data":['
while j < i do
if j != 0
print ","
end
print "["
# convert to JST from UTC
h = time[j][0, 2].to_i
if tmo == 0 && h >= 15
h = h - 15
hs = "0" + h.to_s
elsif h == 0
hs = "09"
tmo = 1
else
h = h + 9
hs = h.to_s
end
print "\"" + hs + time[j][2, 6] + "\"," + val[j].round(1).to_s
print "]"
j = j + 1
end
print ']}'
一日の集計は丸一日分のデータと次の日の一つ目のデータが必要なので24時台のデータを入れるようにしてあります。
jsonはバッチで作っていた時と同じフォーマットにして、こんな感じで吐かれます。
{"date":"2020-04-06","type":"sm.log","data":[["08:50:47",6279.7],["09:00:01",6279.7],["09:10:01",6279.8],["09:20:01",6279.8],["09:30:02",6279.8],["09:40:02",6279.9],["09:50:01",6279.9],["10:00:01",6279.9],["10:10:02",6280],["10:20:01",6280],["10:30:02",6280],["10:40:01",6280.1],["10:50:01",6280.1],["11:00:02",6280.1],["11:10:01",6280.2],["11:20:02",6280.2],["11:30:01",6280.2],["11:40:02",6280.3],["11:50:01",6280.3],["12:00:02",6280.3],["12:10:01",6280.4],["12:20:01",6280.4],["12:30:01",6280.4],["12:40:01",6280.4],["12:50:01",6280.5],["13:00:01",6280.5],["13:10:01",6280.5],["13:20:02",6280.6],["13:30:02",6280.6],["13:40:01",6280.6],["13:50:01",6280.7]]}
chart.jsでこんなグラフにしてます。
JSTのcsvファイルをUTCのcsvファイルに変換するプログラムを作って見ました。
def jst2utc d, t
y = d[0, 4].to_i
m = d[6, 2].to_i
d = d[8, 2].to_i
h = t[0, 2].to_i
mi = t[3, 2].to_i
s = t[6, 2].to_i
u = Time.local(y, m, d, h, mi, s).utc
[u.to_s[0, 10], u.to_s[11, 8]]
end
fd = File.open("sm.log")
while line = fd.gets do
arr = line.chop.split(",")
d, t = jst2utc arr[0], arr[1]
print d + "," + t + "," + arr[2] + "\n"
end
データファイルサイズはcsvが240530バイトに対してsqlite3が323584になっていました。
日ごと使用量を調べるために日が変わった最初のデータを拾って引き算しています。
select date, power from sm where time>"15:00:00" and time<"15:00:10" order by date
これはあまりよくなくて、15:00:00のデータ取得に失敗していた場合には、数字がおかしくなります。
select date, power from sm as A where A.time in (select B.time from sm as B where B.date=A.date and time > "15:00:00" limit 1)
すると日が変わって最初のデータを拾えるようなので、問題起きないのですが、結構重いです。
以下のようにするとJSTに変換されるようです。
select datetime(date, time, 'localtime'), power from sm;
rubyもsqlも素人なので、もっと良い方法があると思うので、ご指摘ください。
Author And Source
この問題について(mrubyでsqlite3), 我々は、より多くの情報をここで見つけました https://qiita.com/yamori813/items/13276a7900339492c798著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .