WiFiモジュール(ESP8266)で作るワンコイントラッカー(2)

技術情報

WiFiモジュール(ESP8266)で作るワンコイントラッカー(1)に続いて、ここでは、ESP8266で取得したWiFiアクセスポイント情報を、Sigfoxネットワークで送信するところまでを試します。

用意するもの

品名数量参考
ESP-WROOM-02開発ボード(ESP8266を搭載した開発ボード) 1 ESPr® Developer
Sigfoxシールド(Sigfox通信モジュールを搭載したArduinoシールド) 1 UnaShield
ブレッドボード 1
ジャンパーケーブル 数本

すでに、ご予算的には、オーバーしていますが、ちゃんと基板をおこせる方は、ESP8266とSigfoxモジュールで作ってもらうと安価に作れます。

ESP-WROOM-02をArduino化する

前回は、ESP8266をPCからATコマンドを使って動作確認しましたが、今回は、ESP8266をArduinoとして動かし、WiFiアクセスポイント情報を取得したうえで、Sigfoxシールドに対してシリアルATコマンドを使ってデータ送信します。

Arduino IDEにESP8266ボードをインストール

ESP8266ボードのインストール

Arduino IDEを起動し、環境設定を開き、「追加のボードマネージャのURL」に下記URLを入力します。
http://arduino.esp8266.com/stable/package_esp8266com_index.json

tech-180804-1.png

この設定を入れておくと、ボードマネジャにesp8266が追加されますので、最新版をインストールします。

tech-180804-2.png

ESP8266ボードの設定

ESP-WROOM-02をPCと接続しておき、ボードの一覧から"Generic ESP8266 Module"を選択し、ボードの設定をします。

tech-180804-3.png

これで、スケッチをマイコンボードに書き込むことが可能になりました。

ESP8266とSigfoxシールドの接続

今回は、ESP8266をArduino化し、Sigfoxシールドと接続します。

tech-180804-4.png

Sigfoxシールド(UnaShield)は、Arduinoボードとの複数のPIN接続がありますが、内蔵Sigfoxモジュールを動かすためだけであれば、下図の通り、3V3*,5V,GND,RXD*(D5),TXD*(D4)の5つのPINだけでも動作可能です。

tech-180804-5.png

tech-180804-6.png

ESP8266 Sigfoxトラッカースケッチ

このサンプルスケッチでは、ESP8266で、WiFi.scanNetworksを行い、アクセスポイント一覧を取得し、String Atlas-WiFiのガイドラインに従い、上位2局のMACアドレスをSigfoxメッセージ送信コマンドAT$SF=[payload]で送信する例となっています。
EEPROMは、デザリング端末などのWiFiアクセスポイントを除外するために、そのSSID一覧を操作するために使用しています。RAMのサイズが十分にあるマイコンを使う場合は、EEPROMを使用する必要はありませんが、Arduino UnoはRAMが1024バイトしかないため、EEPROMを使用する必要があります。

#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>
#include <EEPROM.h>

int _wifiscan_ssidfilerlen = 12;

struct AP {
  String ssid = "";
  int rssi = -999;
  String mac = "";
};

SoftwareSerial SerialSig(14, 12, false, 256);

void setup() {
  Serial.begin(115200);

  writeIgnoreSSID();

  setupWifi();
  setupSigfox();
}

void setupWifi() {
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);

  Serial.println("[Wifi] Setup done.");
}

void setupSigfox() {
  SerialSig.begin(9600);

  SerialSig.write("AT");
  SerialSig.write(10);

  SerialSig.write("ATS410=0");
  SerialSig.write(10);

  SerialSig.write("AT$IF=923200000");
  SerialSig.write(10);  
}

void loop() {
  AP ap[2];   //RSSI上位2局のWiFi AP情報

  Serial.println("[WiFi] scan start");

  int n = WiFi.scanNetworks();
  Serial.println("[Wifi] scan done");
  if (n == 0) {
    Serial.println("no networks found");
  } else {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; i++) {
      // Print SSID and RSSI for each network found
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      String mac = WiFi.BSSIDstr(i);
      Serial.println(mac);
      mac.replace(":", "");

      filterAP(ap, WiFi.SSID(i), WiFi.RSSI(i), mac);
    }
  }
  Serial.println("");

  String msg = "AT$SF=" + ap[0].mac + ap[1].mac; //Sigfoxメッセージ
  Serial.println(msg);
  SerialSig.write(msg.c_str());
  SerialSig.write(10);

  delay(600000);
}

void filterAP(AP* ap, String ssid, int rssi, String mac) {
  if (filterMac(ssid, mac)) {
    if (ap[0].rssi < rssi) {
      ap[1] = ap[0];
      ap[0].ssid = ssid;
      ap[0].rssi = rssi;
      ap[0].mac = mac;
    } else if (ap[1].rssi < rssi) {
      ap[1].ssid = ssid;
      ap[1].rssi = rssi;
      ap[1].mac = mac;
    }
  }
}

bool filterMac(String ssid, String mac) {
  bool pass = true;
  pass = filterMacBySsid(ssid);
  if (pass) {
    pass = filterMacByMac(mac);
  }
  return pass;
}

bool filterMacBySsid(String ssid) {
  bool pass = true;
  for (int i = 0; i < _wifiscan_ssidfilerlen; i++) {
    String filteredSsid = read_data_from_rom(i);
    if (ssid.indexOf(filteredSsid) >= 0) {
      pass = false;
      break; 
    }
  }
  return pass;
}

bool filterMacByMac(String mac) {
  bool pass = true;
  if (mac.length() != 12) pass = false;
  //リザーブMACアドレスならフィルタリング
  if (pass) {
    if (mac.equalsIgnoreCase("000000000000") || mac.equalsIgnoreCase("FFFFFFFFFFFF")) {
      pass = false;
    }
  }
  //マルチキャストMACアドレスならフィルタリング
  if (pass) {
    long LSBbit_1stOct = strtol(mac.substring(0,2).c_str(), NULL, 16);
    if (LSBbit_1stOct % 2 == 1) {
      pass = false;
    }
  }
  return pass;
}

//EEPROMに文字列(6byte)を書き込む
//注意:EEPROMのサイズはEEPROM.beginで設定したサイズ
void write_data_to_rom(int address, String String_data) {
  const int MAX_LEN = 6;
  byte Byte_data[MAX_LEN+1];
  String_data.getBytes(Byte_data, MAX_LEN+1);
  int k;
  int start = address * (MAX_LEN+1);
  for (k = 0; k < MAX_LEN && Byte_data[k] != '\0'; k++) {
    EEPROM.write(start + k, Byte_data[k]);
  }
  EEPROM.write(start + k, '\0');
}

//EEPROMから文字列(6byte)を読み込む
String read_data_from_rom(int address) {
  const int MAX_LEN = 6;
  String data_from_rom;
  int start = address * (MAX_LEN+1);
  for (int i = 0; i < MAX_LEN && EEPROM.read(start + i) != '\0'; i++) {
    char c = EEPROM.read(start + i);
    data_from_rom = data_from_rom + String(c);
  }
  return data_from_rom;
}

void writeIgnoreSSID() {
  EEPROM.begin(512);

  write_data_to_rom(0, "android-");
  write_data_to_rom(1, "phone");
  write_data_to_rom(2, "samsung");
  write_data_to_rom(3, "huawei");
  write_data_to_rom(4, "iPad");
  write_data_to_rom(5, "iPhone");
  write_data_to_rom(6, "W01_");
  write_data_to_rom(7, "W03_");
  write_data_to_rom(8, "W04_");
  write_data_to_rom(9, "wx01-");
  write_data_to_rom(10, "wx02-");
  write_data_to_rom(11, "wx03-");

  EEPROM.commit();
}

お薦めサンプル

ESP8266やSigfoxモジュールの低消費電力化のためのDeep Sleepや、その他お作法をしっかりとやっているサンプルが、下記GitHubにあがっていますので、参考にしてください。
https://github.com/disk91/esp8266-sigfox-trackr

Sigfox Atlas-WiFiの利用にあたって

このスケッチを動かすと、定期的にWiFiスキャンしたデータをSigfoxクラウドに送信することができます。次は、Altas-WiFiサービスが必要となりますので、Sigfox Operator(日本は、京セラコミュニケーションシステム)にお問い合わせください