net関数を使うと、Luaプラグインは、obniz Cloudを経由せず、お客様自身のサーバーと直接やり取りできます。端末が現在つながっているネットワーク回線を通じてデータを送受信し、HTTP(net.http)、生のTCP(net.tcp)、UDP(net.udp)の3種類のプロトコルに対応します。
既存のAPIやプライベートなエンドポイント、obniz Cloudが扱わないサービスへ端末から接続したいときに、お使いください。
共通の挙動と制約
いずれのnet関数も、使う前にこの節をお読みください。
- 現在のネットワーク回線に従います。 HTTPとTCPは、そのとき接続している回線(Wi-Fi、Ethernet、LTEのいずれか)を通じて動作します。UDPは、Wi-FiまたはEthernetでのみ動作し、LTEでは使えません。
- 完了するまで処理をとめます。 各関数は同期的に動作し、操作が完了するか、失敗するか、タイムアウトするまで返りません。待機中は通信ウォッチドッグに餌を与えるため、長い転送でも端末はリセットされません。ただし、その間、関数を呼んだハンドラはとまったままです。すぐに返ることを期待される
on_online_loop()やon_offline_loop()の中では、長い転送を避けてください。 - 平文のHTTPのみに対応し、TLSは使えません。 通信は暗号化されません。URLは
http://をお使いください。https://は動作しません。機密情報を送るときは、信頼できるネットワークでのみお使いください。 - ソケットは1本ずつお使いください。 接続を1本だけ開き、使い終えてから閉じ、その後に次の接続を開いてください。2本目以降が開けるかどうかは、空きメモリや使っているネットワーク回線の状況によります。複数を同時に開いたままにすることは、あてにしないでください。不要になったソケットは、必ず閉じてください。
- エラーは送出されず、返り値で示されます。 失敗したとき、関数は
nilと短いエラー文字列を返します。結果を使う前に、1つ目の返り値を確認してください。
net.http
net.http.get(url)
HTTPのGETリクエストを実行し、応答をすべて受け取るまで待ちます。
| 引数 | 型 | 説明 |
|---|---|---|
url |
string | 対象のURLです。http://で始めます。https://には対応していません。 |
成功すると3つの値を、失敗するとnilとエラー文字列を返します。
| 返り値 | 型 | 説明 |
|---|---|---|
status |
number | 200などのHTTPステータスコードです。 |
body |
string | 応答の本文です。 |
headers |
string | 応答ヘッダの生データです。 |
net.http.post(url, body, contentType)
指定した本文で、HTTPのPOSTリクエストを実行します。
| 引数 | 型 | 説明 |
|---|---|---|
url |
string | 対象のURLです。 |
body |
string | 送信するリクエスト本文です。 |
contentType |
string | 任意。Content-Typeヘッダです。既定値はapplication/octet-streamです。 |
返り値はnet.http.get()と同じです。
net.http.request(options)
メソッド、ヘッダ、本文、タイムアウトを細かく指定して、リクエストを実行します。optionsはテーブルです。
| フィールド | 型 | 説明 |
|---|---|---|
url |
string | 必須。対象のURLです。 |
method |
string | 任意。HTTPメソッドです。既定値はGETです。 |
headers |
table | 任意。リクエストヘッダです。{ ["Key"] = "Value" }または{ "Key: Value" }の形式で指定します。 |
body |
string | 任意。リクエスト本文です。 |
timeout |
number | 任意。待つ時間(ミリ秒)です。既定値は30000です。 |
返り値はnet.http.get()と同じです。
HTTPの制約
HTTPクライアントは、意図的に小さく作ってあります。次の制限に注意してください。
Connection: closeを送り、サーバーが接続を閉じるまで読み続けます。キープアライブは使いません。- リダイレクトを追いません。
3xxの応答は、そのまま返します。 - チャンク転送エンコーディングのデコードや、
gzipの解凍を行いません。本文は受信したそのままを返すため、できるだけ、圧縮もチャンクもしない応答を要求してください。 - ホスト名は、128文字未満にしてください。
net.tcp
net.tcp.connect(host, port)
平文のTCP接続を開き、ソケットのidを返します。TLSには対応していません。
| 引数 | 型 | 説明 |
|---|---|---|
host |
string | ホスト名またはIPアドレスです。 |
port |
number | ポート番号です。 |
成功するとソケットのidを、失敗するとnilとエラー文字列を返します。このidを、ほかのnet.tcp関数に渡してください。
net.tcp.write(id, data)
接続を通じてデータを送ります。すべてのデータを送り終えると返り、30秒でタイムアウトします。
| 引数 | 型 | 説明 |
|---|---|---|
id |
number | net.tcp.connect()が返したソケットのidです。 |
data |
string | 送信するデータです。 |
書き込んだバイト数を返します。失敗するとnilとエラー文字列を返します。
net.tcp.read(id, maxlen)
すでに届いているデータを読み取ります。新しいデータを待ちません。
| 引数 | 型 | 説明 |
|---|---|---|
id |
number | ソケットのidです。 |
maxlen |
number | 任意。読み取る最大バイト数です。既定値は1024で、上限は4096未満です。 |
| 返り値 | 型 | 説明 |
|---|---|---|
data |
string | nil | 受信したデータです。空文字列("")は、まだデータが届いていないことを表します。nilは、接続が閉じたか、エラーが起きたことを表します。 |
readはすぐに返るため、1回の呼び出しでメッセージ全体を受け取ろうとせず、ループのたびに繰り返し読み取ってください。
net.tcp.close(id)
接続を閉じ、ソケットを解放します。
net.udp
UDPは、Wi-FiまたはEthernetでのみ動作します。LTEでは使えません。セルラー接続では、net.udp.open()がudp not supported on cellularで失敗します。
net.udp.open(localPort)
UDPソケットを開き、そのidを返します。
| 引数 | 型 | 説明 |
|---|---|---|
localPort |
number | 任意。バインドするローカルポートです。省略すると、システムが割り当てます。 |
成功するとソケットのidを、失敗するとnilとエラー文字列を返します。
net.udp.sendTo(id, host, port, data)
指定した宛先へ、データグラムを送ります。
| 引数 | 型 | 説明 |
|---|---|---|
id |
number | ソケットのidです。 |
host |
string | 宛先のホスト名またはIPアドレスです。 |
port |
number | 宛先のポートです。 |
data |
string | データグラムのペイロードです。 |
送ったバイト数を返します。失敗するとnilとエラー文字列を返します。
net.udp.receive(id, maxlen)
データグラムを1つ受け取ります。待たずに返り、届いていなければnilを返します。
| 引数 | 型 | 説明 |
|---|---|---|
id |
number | ソケットのidです。 |
maxlen |
number | 任意。読み取る最大バイト数です。既定値は1024で、上限は4096未満です。 |
| 返り値 | 型 | 説明 |
|---|---|---|
data |
string | nil | 受信したペイロードです。何も届いていなければnilです。 |
ip |
string | 送信元のIPアドレスです。 |
port |
number | 送信元のポートです。 |
net.udp.close(id)
ソケットを閉じます。
Example: 1分ごとにアナログ値を送信する
以下のプラグインは、1分に一度、IO0の電圧を読み取り、JSONとして平文のHTTPでお客様自身のサーバーへ直接送信します。すべて端末上で動作し、obniz Cloudを経由しません。
last = 0;
function on_online_loop()
-- 60秒に一度だけ実行する
if os.getTick() - last < 60 * 1000 then
return;
end
last = os.getTick();
-- IO0のアナログ電圧を読み取る
local voltage = ad.get(0);
local body = '{"voltage":' .. tostring(voltage) .. '}';
-- お客様自身のサーバーへPOSTする
local status, resp = net.http.post("http://example.com/api/measurements", body, "application/json");
if status == nil then
-- 失敗したときは、2つ目の値にエラー文字列が入る
os.log("post failed: " .. tostring(resp));
return;
end
os.log("posted, status: " .. tostring(status));
end