プラグイン / Lua

Plug-in class リファレンス

OS7以降

プラグインを利用することで、端末上で直接プログラムを動かすことができます。

これによりobnizの端末のみでオフライン時の動作や通信データの圧縮など高度な最適化が可能となります。

書き込みと実行

Luaはネットワーク接続と関係なく、OSの起動時からOSにより即座に実行が開始されます。

シリアルコンソールではなくobniz.jsからLuaを書き込むには以下のように文字列を送信し保存します。

obniz.storage.savePluginLua()を利用することで内部のフラッシュを上書きします。こちらは上書きするだけで実際の実行は再起動後となります。即座に適用するにはobniz.plugin.reloadLua()を呼び出します。

// Javascript Example

obniz.storage.savePluginLua(`
 os.log("Hello World")
`);
obniz.plugin.reloadLua();

二重書き込みの阻止

接続ごとにPluginを書き換えると内部のフラッシュメモリの寿命に影響が出ます。
そこで、期待するLuaが入っていたら書き込まないような処理が必要です。obnizOSは起動したときに読み出したLuaの名称を送信するため、これを比較することで防ぐことができます。obniz.plugin_nameには起動時に利用されたpluginの名前が入ります。pluginの名前はLuaの中でplugin_name()関数の返り値として指定できます。

// Javascript Example

  if (obniz.plugin_name !== 'my_plugin') {
    console.log("Must Load Plugin");
    obniz.storage.savePluginLua(`
function plugin_name()
  return "my_plugin"  -- max 30 chars
end
`);
    obniz.plugin!.reloadLua();
    obniz.reboot(); // Not necessary on every case.
  } else {
    console.log("No Need to Load Plugin");
  }

随時実行

Luaスクリプトは本体に保存せずともSDK経由で随時実行することが可能です。

// Javascript Example
  obniz.plugin!.execLua(`
      x=1;
      x=x+2;
      os.log(x.."\\n")
  `); // will print "3" on obnizOS console(need console enabled)

  obniz.plugin!.execLua(`os.log(os.getTick().."\\n")`);
  obniz.plugin!.execLua(`os.log(os.getTick().."\\n")`);

この機能を利用することで、端末を再起動することなく必要な関数・変数を随時更新することができます。

これによりダウンタイムを発生させることなく高速に端末の挙動を最適化し、通信量を最大限圧縮することが可能となります。

通信頻度を値によってクラウドから変更する例

// Javascript Example
  if (temperature > 26) {
    obniz.plugin!.execLua(`
      interval = 1;
    `);
  } else {
    obniz.plugin!.execLua(`
      interval = 60;
    `);
  }

送信されるデータの種類をモードによって切り替える例

  if (mode == 'temperature') {
    obniz.plugin!.execLua(`
      function filter(data)
        if data.temperature == nil then
          return nil
        end
        return data
      end
    `);
  } else {
    obniz.plugin!.execLua(`
      function filter(data)
        return data
      end
    `);
  }

対応している全Lua向けのobniz関数


-- System Event Handler
function on_event(event)
  if event == "power_on" then
  elseif event == "setting_mode" then
  elseif event == "connecting_to_network" then
  elseif event == "connecting_to_cloud" then
  elseif event == "online" then
  end
end

-- func(int), module(int), data(string(uint8 array))
function on_upstream(func, module, data)
  if necessary then
    return 1;
  elseif rightnow then
    return 2;
  elseif mustDrop then
    cloud.upstreamEnqueue(1, 2, str); -- change to differenct command
    cloud.upstreamFlush(); -- optional
    return 0;
  end
end

-- received from obnis.js
function on_command(command)
  cloud.pluginSend("123");
end

-- called while online every around 1msec
function on_online_loop()
  -- os.log(\"online_loop\");
end

-- called while offline every around 1msec
-- You should care about communication because this function will be called
-- different thread.
function on_offline_loop()
  -- os.log(\"offline_loop\");
end

function on_self_check()
  os.log(" - self check ok");
end

function plugin_name()  -- will be get by obniz.plugin_name
  return "my_plugin"
end

-- Available Functions

-- OS
os.getTick(); -- system tick in msec 
os.getUnixTime(); -- get seconds from 1970/1/1. you must adjust time by calling pingWait();
os.log("hello world");
os.wait(1000); -- 1,000msec wait
os.reboot();
os.resetOnDisconnect(false); -- It will never reset after disconnection. And queued data never lost when offline.
os.sleep(5 * 1000, 0); -- deep sleep + external module sleep.
os.sleep(5 * 1000, 1); -- deep sleep + without external module sleep.
os.sleep(5 * 1000, 2); -- light sleep + external module sleep.
os.sleep(5 * 1000, 3); -- light sleep + without external module
os.getVersion();
os.getHW();

-- storage file
storage.fileOpen("text.txt")
storage.fileWrite("ABC");
storage.fileAppend("abcdefg");
length = storage.fileGetSize();
data = storage.fileRead(0, length);
storage.fileClose();

-- storage kvs
error = storage.kvsSave({ name = "Yuki", attr = { engineer = true } })
data = storage.kvsLoad();

-- Cloud
cloud.connect();
cloud.disconnect();
cloud.upstreamEnqueue(0, 1, data) -- module func data
cloud.pluginSend(data);
cloud.pluginSendFrameStart(frame_id, length); -- framing 
cloud.pluginSendFrameEnd(); -- framing 
cloud.enqueueTimestampByTick(os.getTick()-1000); -- it will enqueue unix timestamp

-- io
io.retain(1, true);
io.output(1, true);
local val = io.input(1);

-- ad
local val = ad.get(1); -- 0.0v~3.3v

-- uart
uart.start(1, 2, 9600)  -- tx:io1 rx:io2 baud:9600
uart.send("hello");
local data = uart.recv() -- uart.recv(1) limit to 1byte max
if #data > 1 then
  os.log(data); -- received
end

-- spi
local err = spi.start(20, 21, 19, 8, 100 * 1000); -- MOSI, MISO, CLK, CS(could be null for non shared SPI), baudrate
if err > 0 then
  os.log("SPI Error: " .. err);
  return
end
let result = spi.write(string.char(0x40, 0x00, 0xC0)); -- result must be 3bytes if success.

-- wifi
wifi.on();
wifi.off();
wifi.sniffStart(callback);
wifi.sniffSetChannel(2);
wifi.sniffStop();

-- ble
ble.on();
ble.off();
ble.scanStart(onFind, { -- default option values
  active=true,
  interval=16,
  window=16,
  phy1m=true,
  phyCoded=true,
  duplicate=true
});

Articles