smartconfig+MQTT

ESP8266を便利な(笑)MQTTクライアントにするため、smartconfigと組み合わせてみます。センサーの情報をMQTTで一箇所に集めて、表示できるようにするのが目標です。

1.smartconfigの動作確認

まずベースは以前の記事のsmartconfigです。Androidのアプリ側はESP8266 smartconfigで動作することは確認しました。

2.ライブラリのインストール

ArduinoIDEで「ツール→ライブラリを管理」でライブラリマネージャーから「Adafruit MQTT Library」をインストールします。

3.ソースの結合

ソースを結合して以下の通りとしました。難しいところはありません。ついでに、NTPでの時刻合わせ、タイマ割り込みの処理も記述も追加しておきました。
トピックは /feed/sensor/番号 にすることにしました。
できればこの際、SSL化もしたかったのですが、mosquittoのブローカ側のSSL化すらうまく行っていないので今回は見送りです。どちらにせよ、プライベートIPアドレスの中での運用なのであまり気にする必要はないのですが。
※あちこちからの切り貼りです。

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include &quot;Adafruit_MQTT.h&quot;
#include &quot;Adafruit_MQTT_Client.h&quot;

/*****************************************************************************/
/* MQTT Client                                                               */

/************************* Adafruit.io Setup *********************************/
#define AIO_SERVER      &quot;10.89.105.1&quot;
#define AIO_SERVERPORT  1883                   // use 8883 for SSL
#define AIO_USERNAME    &quot;username&quot;  // 適当に変更(未使用)
#define AIO_KEY         &quot;password&quot;  // 適当に変更(未使用)
#define SERIALNO        &quot;0001&quot;

/************ Global State (you don't need to change this!) ******************/
// Create an ESP8266 WiFiClient class to connect to the MQTT server.
WiFiClient client;
// or... use WiFiFlientSecure for SSL
//WiFiClientSecure client;
 
// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

/****************************** Feeds ***************************************/
Adafruit_MQTT_Publish motion = Adafruit_MQTT_Publish(&mqtt, &quot;/feeds/sensor/&quot; SERIALNO);
Adafruit_MQTT_Subscribe command = Adafruit_MQTT_Subscribe(&mqtt, &quot;/feeds/command/&quot; SERIALNO);
char macstr[13];    // Station mode MAC address 

/*****************************************************************************/
/* NTP Client                                                                */
#include <time.h>
#define JST     3600*9

/*****************************************************************************/
/* Timer interrupt                                                           */
#define MS2CLK(ms)    (ms * 80000L)
uint32_t nxTim;

// 割り込みハンドラ
void timer0_ISR (void) {
  nxTim += MS2CLK(100); // 100msec 
  timer0_write( nxTim );
  
  // 割り込み処理
  digitalWrite(13, 1-digitalRead(13));   // Blink the LED
}

/*************************** Sketch Code ************************************/
 
void setup() {
  uint8_t cnt = 0;  

  // set for STA mode
  WiFi.mode(WIFI_STA);
  
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.flush();
  Serial.println(&quot;\r\n&quot;);
    
  // led status at pin4
  pinMode(12,OUTPUT);
  digitalWrite(12, HIGH);   // turn the LED on (HIGH is the voltage level)
  
  // led status at pin5
  pinMode(13,OUTPUT);
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  
  //configure pin0 
  pinMode(0, INPUT_PULLUP);

  // deplay for 2 sec for smartConfig
  Serial.println(&quot;2 sec before clear SmartConfig&quot;);
  delay(2000);
  
  // read pullup
  bool isSmartConfig = digitalRead(0);
  if (isSmartConfig == false) {
    // bink for clear config
    blinkClearConfig();
    Serial.println(&quot;clear config&quot;);
    // reset default config
    WiFi.disconnect();

  }

  // if wifi cannot connect start smartconfig
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(&quot;.&quot;);
    if(cnt++ >= 15){
       WiFi.beginSmartConfig();
       while(1){
           delay(500);
           if(WiFi.smartConfigDone()){
             Serial.println(&quot;SmartConfig Success&quot;);
             blinkSmartConfig();
             break;
           }
       }
    }
  }

  Serial.println(&quot;&quot;);

  WiFi.printDiag(Serial);

  // Print the IP address
  Serial.println(WiFi.localIP());

  // タイマ割り込みの設定
  noInterrupts();
  timer0_isr_init();
  timer0_attachInterrupt(timer0_ISR);
  nxTim = ESP.getCycleCount() + MS2CLK(100); // 100msec
  timer0_write( nxTim );
  interrupts();
  
  // time set with NTP
  configTime( JST, 0, &quot;ntp.nict.jp&quot;, &quot;ntp.jst.mfeed.ad.jp&quot;);

  // Setup MQTT subscription for command feed.
  mqtt.subscribe(&command);

  //  
  uint8_t mac0[6];
  WiFi.macAddress(mac0);
  sprintf(macstr,&quot;%02X%02X%02X%02X%02X%02X&quot;, mac0[0], mac0[1], mac0[2], mac0[3], mac0[4], mac0[5]);
}


void blinkSmartConfig() {
    digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(50);              // wait for a second 
    digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
    delay(50);
}

void blinkClearConfig() {
  int i=0;
  while(i<=3) { digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level) delay(100); // wait for a second digitalWrite(13, LOW); // turn the LED off by making the voltage LOW delay(100); i++; } } uint32_t x=0; void loop() { time_t t; struct tm *tm; char msg[64]=&quot;&quot;; bool isSW1 = digitalRead(0); if(isSW1 == false){ for(int i=5;i>0;i--){
      delay(1000);
      Serial.println(i);    
    }
    Serial.println(&quot;Power off&quot;);    
    delay(500);
    pinMode(15,OUTPUT);
    digitalWrite(15, HIGH);   // Power-off the board (HIGH is the voltage level)
    delay(5000);
  }
  digitalWrite(12, 1-digitalRead(12));   // Blink the LED

  /*******/
  /* NTP */
  t = time(NULL);
  tm = localtime(&t);
  sprintf(msg,&quot;%s %s %04d/%02d/%02d %02d:%02d:%02d %ld %d&quot;,
        SERIALNO,macstr,
        tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
        tm->tm_hour, tm->tm_min, tm->tm_sec,
        (long)t,x++);

  /********/
  /* MQTT */
  // Ensure the connection to the MQTT server is alive (this will make the first
  // connection and automatically reconnect when disconnected).  See the MQTT_connect
  // function definition further below.
  MQTT_connect();
 
  // this is our 'wait for incoming subscription packets' busy subloop
  // try to spend your time here
 
  Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(1000))) {
    if (subscription == &command) {
      Serial.print(F(&quot;Got: &quot;));
      Serial.println((char *)command.lastread);
    }
  }
 
  // Now we can publish stuff!
  Serial.print(F(&quot;\nSending message : &quot;));
  Serial.print(msg);
  Serial.print(&quot;...&quot;);
  if (! motion.publish(msg)) {
    Serial.println(F(&quot;Failed&quot;));
  } else {
    Serial.println(F(&quot;OK!&quot;));
  }
 
  // ping the server to keep the mqtt connection alive
  // NOT required if you are publishing once every KEEPALIVE seconds
  /*
  if(! mqtt.ping()) {
    mqtt.disconnect();
  }
  */
}

// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
  int8_t ret;
 
  // Stop if already connected.
  if (mqtt.connected()) {
    return;
  }
 
  Serial.print(&quot;Connecting to MQTT... &quot;);
 
  uint8_t retries = 3;
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
       Serial.println(mqtt.connectErrorString(ret));
       Serial.println(&quot;Retrying MQTT connection in 5 seconds...&quot;);
       mqtt.disconnect();
       delay(5000);  // wait 5 seconds
       retries--;
       if (retries == 0) {
         // basically die and wait for WDT to reset me
         while (1);
       }
  }
  Serial.println(&quot;MQTT Connected!&quot;);
}

ついでに、基板の回路図も再掲載です。

実装部品

ミニマム実装:
 半田面
    GS5 2-3
    GS6 2-3
    C6  0.1u
    C7  22u
    R1  470
    R2  4.7k
    R3  4.7k
    R4  100
    R7  20k
    R8  4.7k 
    R11 0Ω
    R19 22k
    R20 33k
    R21 470
    R22 470
    R23 470
    R24 470
 部品面
    U3  AZ1117-ADJ
    D1  LED
    D2  LED
    D3  LED
    SW1 タクトSW
    SW2 タクトSW
    C5  33u

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)