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);
コメントをかく