2016年12月現在、APIがアップロードと自己JOB実行・取得しかできないFlashAir IoT Hubにて、
Uploadに関しては、純正スクリプトの機能と等価です。そのため、credentialが必要です。
それ以外の操作については、ブザウザと同様に振る舞うため、IoT Hubに登録してあるメールアドレスとパスワードが必要です。
カードID情報は、Uploadはcredentialと対でなければなりませんが、それ以外は任意のカードのIDが使用できます。
*動作確認は十分に行っていません
※一応利用規約上、抵触する事項はなさそうですが、自己責任でご利用ください。
- CSV/JSONのダウンロード(他カードに対しても可能)
- JOBの発行(他カードに対しても可能、というかそうでないと意味がない)*
- PIOの操作(同上)*
- JOB一覧の取得(同上)
- グラフのラベルの読み出し(ユーザーおよび他カードからの文字情報の取得として利用可能)
- グラフのラベルの書き換え(ユーザーおよび他カードへの文字情報の送出として利用可能)
- カード名の書き換え
- カード情報の取得
- JOBの指定削除
- JOBの全削除
- 最終アクセス日時の取得
Uploadに関しては、純正スクリプトの機能と等価です。そのため、credentialが必要です。
それ以外の操作については、ブザウザと同様に振る舞うため、IoT Hubに登録してあるメールアドレスとパスワードが必要です。
カードID情報は、Uploadはcredentialと対でなければなりませんが、それ以外は任意のカードのIDが使用できます。
*動作確認は十分に行っていません
※一応利用規約上、抵触する事項はなさそうですが、自己責任でご利用ください。
※すべてを読み込むと極僅かな記述でメモリ不足になるため、必要な機能だけを切り出して使用してください。
ORIGIN = "https://iot-hub.flashair-developers.com"
REFERER = 'https://iot-hub.flashair-developers.com/'
API_URI = "https://iot-hub-api.flashair-developers.com/_/"
TYPE_JSON = 'application/json'
CLOSE = 'Close'
function upload(card_id,card_credential,values)
local body = cjson.encode({values=values})
b, c, h = fa.request {
url='https://iot-hub-api.flashair-developers.com/v1/devices/' .. card_id .. '/measurements/flashair',
method='POST',
headers={
['Authorization']='Basic ' .. card_credential,
['Content-Length']=tostring(string.len(body)),
['Content-Type']=TYPE_JSON,
},
body=body,
}
collectgarbage("collect")
return c;
end
function login(mail,pass)
collectgarbage("collect")
local code = enc(mail..":"..pass)
local body = '{"long_session": false, "frontend": 2}'
b, c, h = fa.request {
url=API_URI..'login',
method='POST',
headers={
['Authorization']='Basic ' .. code,
['Content-Length']=tostring(string.len(body)),
['Content-Type']=TYPE_JSON,
['Origin']=ORIGIN,
['Referer']=REFERER,
['Connection']=CLOSE,
['User-Agent']=UserAgent,
['x-requested-with']='me', --"error":"csrf_protection"対策。
},
body=body,
}
collectgarbage("collect")
if(c == 200)then
local login_cookie = string.match (h, "Set%-Cookie%: (%g+)") --Cookie切り出し
return login_cookie
end
return c; --401 = AuthErr
end
function logout(login_cookie)
collectgarbage("collect")
local body = ''
b, c, h = fa.request {
url=API_URI..'logout',
method='POST',
headers={
['Cookie']=login_cookie,
['Content-Length']=tostring(string.len(body)),
['Content-Type']=TYPE_JSON,
['Origin']=ORIGIN,
['Referer']=REFERER,
['Connection']=CLOSE,
['User-Agent']=UserAgent,
['x-requested-with']='me', --"error":"csrf_protection"対策。
},
body=body,
}
collectgarbage("collect")
if(c == 200)then
local login_cookie = string.match (h, "Set%-Cookie%: (%g+)") --Cookie切り出し
return login_cookie
end
return c; --401 = AuthErr
end
function download(login_cookie, card_id)
b, c, h = fa.request {
url=API_URI..'devices/'.. card_id ..'/measurements/flashair?format=json', --csvでCSV形式になる
--取得範囲(開始・終了時刻)の指定もできるようだ。
--https://iot-hub-api.flashair-developers.com/_/devices/0000000000000000/measurements/flashair?start=2016-12-03T16:50:19.983Z&end=2016-12-03T17:20:19.983Z&interval=30s&func=first
method='GET',
headers={
['Referer']=REFERER,
['Connection']=CLOSE,
['Cookie']=login_cookie,
['User-Agent']=UserAgent,
}
}
collectgarbage("collect")
return b
end
function labelGet(login_cookie, card_id)
b, c, h = fa.request {
url=API_URI..'flashairs/'.. card_id ..'/labels' ,
method='GET',
headers={
['Referer']=REFERER,
['Connection']=CLOSE,
['Cookie']=login_cookie,
['User-Agent']=UserAgent,
}
}
collectgarbage("collect")
return cjson.decode(b);
end
function labelSet(login_cookie, card_id, label1,label2,label3,label4,label5)
local body = '{"labels":["'..label1..'","'..label2..'","'..label3..'","'..label4..'","'..label5..'"]}'
b, c, h = fa.request {
url=API_URI..'flashairs/'.. card_id ..'/labels',
method='PUT',
headers={
['Content-Length']=tostring(string.len(body)),
['Content-Type']=TYPE_JSON,
['Origin']=ORIGIN,
['Referer']=REFERER,
['Connection']=CLOSE,
['Cookie']=login_cookie,
['User-Agent']=UserAgent,
},
body=body,
}
collectgarbage("collect")
return c
end
function jobList(login_cookie, card_id, detail)
local detail_str = "true"
if(detail == false)then
detail_str = "false"
end
b, c, h = fa.request {
url=API_URI..'devices/'.. card_id ..'/jobs?with_details='..detail_str,
method='GET',
headers={
['Referer']=REFERER,
['Connection']=CLOSE,
['Cookie']=login_cookie,
['User-Agent']=UserAgent,
}
}
collectgarbage("collect")
return b
end
function jobDelete(login_cookie, card_id, jobid)
--PRE-FLIGHT
b, c, h = fa.request {
url=API_URI..'devices/'.. card_id ..'/jobs/'..jobid,
method='GET',
headers={
['Referer']=REFERER,
['Connection']=CLOSE,
['Cookie']=login_cookie,
['User-Agent']=UserAgent,
}
}
collectgarbage("collect")
if(c ~= 200)then
return c
end
local etag = string.match (h, "Etag%: (%g+)") --エンティティタグ切り出し
--DELETE
b, c, h = fa.request {
url=API_URI..'devices/'.. card_id ..'/jobs/'..jobid,
method='DELETE',
headers={
['Referer']=REFERER,
['Connection']=CLOSE,
['Cookie']=login_cookie,
['User-Agent']=UserAgent,
['If-Match']=''..etag..'',
}
}
collectgarbage("collect")
return c
end
function jobPio(login_cookie, card_id,data,ctrl)
local body = '{"request": {"type": "pio", "data": '..data..', "ctrl": '..ctrl..'}}'
b, c, h = fa.request {
url=API_URI..'devices/'.. card_id ..'/jobs',
method='POST',
headers={
['Content-Length']=tostring(string.len(body)),
['Content-Type']=TYPE_JSON,
['Origin']=ORIGIN,
['Referer']=REFERER,
['Connection']=CLOSE,
['Cookie']=login_cookie,
['User-Agent']=UserAgent,
},
body=body,
}
collectgarbage("collect")
if(c == 201)then -- Created
local jobid = string.match (b, '%{%"id%"%:%"(%g+)%"%,%"status%"') --ID切り出し
return jobid
end
return c
end
function jobRequest(login_cookie, card_id, path , arg_json)
local body = '{"request": {"type": "script", "path": "'..path..'", "arguments": "'..arg_json..'"}}'
b, c, h = fa.request {
url=API_URI..'devices/'.. card_id ..'/jobs',
method='POST',
headers={
['Content-Length']=tostring(string.len(body)),
['Content-Type']=TYPE_JSON,
['Origin']=ORIGIN,
['Referer']=REFERER,
['Connection']=CLOSE,
['Cookie']=login_cookie,
['User-Agent']=UserAgent,
},
body=body,
}
collectgarbage("collect")
if(c == 201)then -- Created
local jobid = string.match (b, '%{%"id%"%:%"(%g+)%"%,%"status%"') --ID切り出し
return jobid
end
return c
end
function pioGet(login_cookie, card_id)
b, c, h = fa.request {
url=API_URI..'devices/'.. card_id ..'/measurements/pio/diff' ,
method='GET',
headers={
['Referer']=REFERER,
['Connection']=CLOSE,
['Cookie']=login_cookie,
['User-Agent']=UserAgent,
}
}
collectgarbage("collect")
return b
end
function jobDeleteAll(login_cookie, card_id)
local cnt = 0;
while true do
local dat = jobList(login_cookie,card_id,false)
collectgarbage("collect")
local tb = cjson.decode(dat);
collectgarbage("collect")
for key, val in pairs(tb["jobs"]) do
c = jobDelete(login_cookie,card_id,val["id"])
cnt = cnt+1
collectgarbage("collect")
end
if(tb["hasNext"]~=true)then
break;
end
end
return cnt;
end
function LastAccessGet(login_cookie, card_id)
b, c, h = fa.request {
url=API_URI..'devices/'.. card_id ..'/last_access' ,
method='GET',
headers={
['Referer']=REFERER,
['Connection']=CLOSE,
['Cookie']=login_cookie,
['User-Agent']=UserAgent,
}
}
collectgarbage("collect")
return b
end
function DevicesGet(login_cookie)
b, c, h = fa.request {
url=API_URI..'devices' ,
method='GET',
headers={
['Referer']=REFERER,
['Connection']=CLOSE,
['Cookie']=login_cookie,
['User-Agent']=UserAgent,
}
}
collectgarbage("collect")
return b
end
function DeviceNameSet(login_cookie, card_id, name)
local body = '{"name": "'..name..'"}'
b, c, h = fa.request {
url=API_URI..'devices/'.. card_id,
method='PATCH',
headers={
['Content-Length']=tostring(string.len(body)),
['Content-Type']=TYPE_JSON,
['Origin']=ORIGIN,
['Referer']=REFERER,
['Connection']=CLOSE,
['Cookie']=login_cookie,
['User-Agent']=UserAgent,
},
body=body,
}
collectgarbage("collect")
return c
end
-- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
-- licensed under the terms of the LGPL2
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
function enc(data)
return ((data:gsub('.', function(x)
local r,b='',x:byte()
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
return r;
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
if (#x < 6) then return '' end
local c=0
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
return b:sub(c+1,c+1)
end)..({ '', '==', '=' })[#data%3+1])
end
--end of base64
--main--
UserAgent = 'IoT Hub Scraper on FlashAir Alpha 0.2';
id = "0000000000000000000"; --Upload & Download & Call
cred = "AaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAa"; --Upload only
user = "mailadr@mailadr.com"; -- Download & Call
pass = "password"; -- Download & Call
id2="0000000000000000000"
stat = upload(id,cred,{0,1,2,3,4})
print(stat);
cok = login(user,pass)
print(cok);
lab = labelGet(cok, id)
print(lab);
dat = download(cok, id)
print(dat);
--dat = jobDelete(cok,id2,"dng4akdel8g0")
--print(dat)
dat = jobPio(cok,id2,0x0E,0x0E);
print(dat);
--[[
for i = 1, 3 do
dat = jobPio(cok, id2,bit32.band(i,0x0E),0x0E);
print(dat);
end
]]
dat = DevicesGet(cok);
print(dat);
dat = LastAccessGet(cok,id2)
print(dat);
dat = DeviceNameSet(cok,id,"Lua (supported by "..UserAgent..")");
print(dat);
dat = jobRequest(cok, id,"/HelloWorld.lua","World")
print(dat);
dat = jobList(cok,id2,false)
print(dat);
dat = labelSet(cok,id,"Hello! This is " .. UserAgent ,lab.labels[2],lab.labels[3],lab.labels[4],lab.labels[5])
print(dat);
dat = pioGet(cok, id2);
print(dat);
dat = jobDeleteAll(cok,id2)
print(dat);
cok = logout(cok)
print(cok);

コメントをかく