esp_mqttを使ってみる

Scripting機能


esp-mqttにはScripting機能が有ります。
Scriptingについては、こ ちらにスクリプト言語のドキュメントが有り、scriptsフォルダーにサンプルが有ります。
特定のイベントに応じてesp_mqtt側のGPIOをLチカしたり、esp_mqttのUARTにデータを送信したり、メッセージを Publishしたりできます。
MQTT client/bridging機能と組み合わせると、インターネット上の他のマシンからPublishすることで、esp_mqttを操作する ことがで きます。

今回は作者の方から直接送っていただいた、定時実行のスクリプトを紹介します。
以下の様に毎時10分毎と毎正時に特定のトピックを送信するスクリプトです。
なお、スクリプトをesp_mqtt側にアップロードする際に、netcatが必要になります。
Windows環境で動くnetcatはこちらに 有りますが、今一つ使い方が分からなかったので、RaspberryPiを使いました。


まず、esp_mqttにtelnetかシリアルで接続しuplink AP(インターネットにつながるAP)とNTPサーバーの設定を行います。
シリアルで接続するとリセット後の動作を確認することができます。
CMD>set ssid aterm-e625c0-g →  uplinkルーターの SSID
SSID set (auto_connect = 1)

CMD>set password xxxxxxxxxxxxx → uplinkルーターのパスワー ド
Password set

CMD>set ntp_server ntp.nict.jp
NTP server set to ntp.nict.jp
CMD>Got NTP server: 133.243.238.243

CMD>set ntp_timezone 9
NTP timezone set to 9 h

CMD>time
Wed 21:56:01

CMD>save
Config saved

CMD>reset


これでesp_mqttのNTPが有効になります。
次に、Raspberry側に以下のスクリプト(script.cron)を用意します。
% Example for some regular timers

% Config params, overwrite any previous settings from the commandline
config ntp_server      ntp.nict.jp
config ntp_timezone    9

% Now the initialization, this is done once after booting
on init
do
    setvar $t_prefix = "$SYS/broker/time"
    setvar $tt1 = $t_prefix | "1"
    setvar $tt2 = $t_prefix | "2"
    setvar $tt3 = $t_prefix | "3"
    setvar $tt4 = $t_prefix | "4"

    % Starts, when time is synced
    subscribe local $t_prefix

% Now the events, checked whenever something happens

on topic local $t_prefix
do
    % Wait for sync
    unsubscribe local $t_prefix
    settimer 1 1000
    setalarm 1 "12:00:00"
    setalarm 2 "00:00:00"

on timer 1
do
    % Check for full 10 minutes
    if (substr($timestamp,4,4) = "0:00") then
        publish local $tt1 $timestamp
            % Check for full hour
            if (csvstr($timestamp,1,":") = "00") then
            publish local $tt2 $timestamp
            endif
    endif
    settimer 1 1000

on alarm 1
do
    publish local $tt3 "12:00:00"

on alarm 2
do
    publish local $tt4 "00:00:00"

再びesp_mqttにtelnetかシリアルで接続し、スクリプトをesp_mqtt側にアップロードします。
esp_mqttは2000番のポート番号でスクリプトを待ち受けます。
CMD>script 2000
Waiting for script upload on port 2000

Raspberry側に戻ってesp_mqttのアクセスポイントに接続後、netcatでスクリプトを送信します。
$ sudo nmcli d wifi connect MyAP
$ netcat 192.168.4.1 2000 < script.cron

netcatは転送が終わっても自動的に終了しないので、適当なタイミングでコントール+cで抜けます。
esp_mqtt側にアップロードの完了が表示され、「show script」コマンドで、アップロードされたスクリプトを確認することができます。
「set script_logging 1」でスクリプトの動作を表示します。
Script upload completed (1069 Bytes)
Syntax okay
CMD>show script
   1: % Example for some regular timers
   2:
   3: % Config params, overwrite any previous settings from the commandline
   4: config ntp_server ntp.nict.jp
   5: config ntp_timezone       9
   6:
   7: % Now the initialization, this is done once after booting
   8: on init
   9: do
  10:     setvar $t_prefix = "$SYS/broker/time"
  11:     setvar $tt1 = $t_prefix | "1"
  12:     setvar $tt2 = $t_prefix | "2"
  13:     setvar $tt3 = $t_prefix | "3"
  14:     setvar $tt4 = $t_prefix | "4"
  15:
  16:     % Starts, when time is synced
  17:     subscribe local $t_prefix
  18:
  19: % Now the events, checked whenever something happens
  20:
  21: on topic local $t_prefix
  22: do
  23:     % Wait for sync
  24:     unsubscribe local $t_prefix
  25:     settimer 1 1000
  26:   setalarm 1 "12:00:00"
  27:   setalarm 2 "00:00:00"
  28:
  29: on timer 1
  30: do
  31:     % Check for full 10 minutes
  32:     if (substr($timestamp,4,4) = "0:00") then
  33:       p...

CMD>show script 40
  40:
  41: on alarm 1
  42: do
  43:   publish local $tt3 "12:00:00"
  44:
  45: on alarm 2
  46: do
  47:   publish local $tt4 "00:00:00"

CMD>reset

CMD>set script_logging 1
Script logging set


これ以降、esp_mqtt側から以下のトピックが通知されます。
$SYS/broker/time1 毎時00/10/20/30/40/40/50分
$SYS/broker/time2 毎時00分
$SYS/broker/time3 12:00:00
$SYS/broker/time4 00:00:00

ファームを書き込んだESP8266以外に、もう1台のESP8266を用意し、以下のスケッチを書き込みます。
/*
 * subscribe from esp_mqtt server
 * https://github.com/martin-ger/esp_mqtt
 */

#include <ESP8266WiFi.h>
#include <PubSubClient.h> // https://github.com/knolleary/pubsubclient

#define MQTT_SERVER     "192.168.4.1"  // esp_mqtt server
//#define MQTT_SERVER     "esp_mqtt"    // esp_mqtt server
#define MQTT_PORT       1883
#define MQTT_SUB_TOPIC  "nopnop2002/#" // You can change
#define MQTT_SYS_TIME1  "$SYS/broker/time1" // Every 10minute
#define MQTT_SYS_TIME2  "$SYS/broker/time2" // Every hour on the hour

const char* SSID = "MyAP";
const char* PASSWORD = "";

WiFiClient espClient;
PubSubClient client(espClient);

void errorDisplay(char* buff) {
  Serial.print("Error:");
  Serial.println(buff);
  while(1) {
    delay(200);
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

void setup() {
  delay(1000);Serial.begin(9600);
  Serial.print("Wait for WiFi...");
  WiFi.begin(SSID, PASSWORD);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.print("subnetMask: ");
  Serial.println(WiFi.subnetMask());
  Serial.print("gatewayIP: ");
  Serial.println(WiFi.gatewayIP());

  Serial.print("Connect to ");
  Serial.println(MQTT_SERVER);
  client.setServer(MQTT_SERVER, MQTT_PORT);

  char clientid[20];
  sprintf(clientid,"ESP8266-%06x",ESP.getChipId());
  Serial.print("clientid=");
  Serial.println(clientid);
  Serial.print("Attempting MQTT connection...");
  // Attempt to connect
  if (!client.connect(clientid)) {
    errorDisplay("connect Fail");
  }
  Serial.println("connected as subscriber");
  client.setCallback(callback);
  client.subscribe(MQTT_SUB_TOPIC);
  client.subscribe(MQTT_SYS_TIME1);
  client.subscribe(MQTT_SYS_TIME2);
 
}

void loop() {
  client.loop(); // Receive MQTT Event
}