EPS32C3にBLE経由で受信したデータをWebサーバ送信

  • BLE経由で受信した温湿度と大気圧のデータをWebサーバにアップロードする方法を、備忘録として残しておきます

ソース

/*
  XIAO_ESP32C3_LED_Receive_Ant.ino

  Seeed XIAO BLE nRF52840から受信したBLEのアドバタイズデータを、WiFiでWebサーバーにPHPに送信する

  アンテナ付のハードでは、受信感度が高い
  OLED付のハードでは、受信感度が低いが、大気圧と温湿度を表示できる

  ボードマネージャ
   ESP32 by Espressif Syatem: Version 2.0.17

  ツール
   Patiton Scheme: Huge App(3MB On OTA/1MB SPIFFS)
   
*/

#include <Arduino.h>

// ------------WiFi------------------------------------
#include <WiFi.h>
#include "time.h"
#include "sntp.h"

#include <HTTPClient.h>
const String WEB_API_URL = "http://192.168.10.117/temp_humi_press.php";  // 送信先URL
// const String WEB_API_URL_IN = "http://192.168.10.117/temp_humi_press_in.php";  // 送信先URL



const char* ssid       = "aterm-afc0ef-g";
const char* password   = "3fe9c5cabc8c2";
const char* ntpServer1 = "ntp.nict.jp";
const char* ntpServer2 = "time.google.com";
const char* ntpServer3 = "ntp.jst.mfeed.ad.jp";
const long  gmtOffset_sec = 9 * 3600;
const int   daylightOffset_sec = 0;

// Callback function (get's called when time adjusts via NTP)
void timeavailable(struct timeval *t)
{
  Serial.print("Got time adjustment from NTP! ");
}

void printLocalTime()
{
  char str[256];
  unsigned long m;

  // timeとlocaltimeを使用して現在時刻取得
  time_t t;
  struct tm *tm;
  m = millis();
  t = time(NULL);
  tm = localtime(&t);
  sprintf(str, "\nday:%04d/%02d/%02d, time:%02d:%02d:%02d, ", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
  Serial.print(str);

}

// ------------U8g2------------------------------------
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
#define SDA_PIN 5
#define SCL_PIN 6
U8G2_SSD1306_72X40_ER_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);   // EastRising 0.42" OLED



//------------BLE関連------------------------------
#include <BLEDevice.h>
BLEScan* pBLEScan;

// 設定
const size_t RCV_CNT_MAX = 10;  // 同時に受信するデバイスの最大数
const int BLE_SCAN_TIME = 5;    // BLEのスキャンを行う時間(s)
const char XIAO[4] = { 0xFF, 0xFF, 0x12, 0x35 };   // XIAO nRF52840識別値(FFFFは固定)

// シーケンス番号の記憶
#include <map>
std::map<uint16_t, uint16_t> seqHist;

// その他定義
struct RcvData {
  uint16_t id;  // 子機ID
  uint8_t type; // 子機種別
  uint8_t ttl;  // TTL (time to live)
  uint16_t seq; // シーケンス番号
  float pres;   // 気圧データ
  float temp;   // 気温データ
  float humi;   // 湿度データ
  float vbat;   // 電圧データ
  int16_t rssi; // 電波強度 RSSI -50非常に強い -80弱い
};

// -----------デバッグに便利なマクロ定義 --------
#define sp(x) Serial.print(x)
#define spn(x) Serial.print(x)
#define spp(k,v) Serial.println(String(k)+"="+String(v))
#define spf(fmt, ...) Serial.printf(fmt, __VA_ARGS__)

// LED
int ledPin = 8;    // LED connected to digital pin 8


// 初期化
void setup() {
  // auto cfg = M5.config();
  // M5.begin(cfg); 
    Serial.begin(115200);
  delay(1000);
  spn(" System Start!  ");

  // ディスプレイの設定
  Wire.begin(SDA_PIN, SCL_PIN);
  delay(100);
  u8g2.begin();
  // u8g2.setFont(u8g2_font_helvB10_tr); // choose a suitable font
  u8g2.setFont(u8g2_font_lubB10_tr); // choose a suitable font
  u8g2.setContrast(190);     // set contrast to maximum 255
  u8g2.setBusClock(400000);  //400kHz I2C
  // u8g2.setDisplayRotation(U8G2_R2);
  delay(100);


  // // Wi-Fi接続
   //connect to WiFi
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  Serial.print(" CONNECTED  ");
  
  //init and get the time
  sntp_set_time_sync_notification_cb( timeavailable );
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2, ntpServer3);

  // // disconnect WiFi as it's no longer needed
  // WiFi.disconnect(true);
  // WiFi.mode(WIFI_OFF);

  // BLEの設定
  spn("init BLE device...");
  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan();
  pBLEScan->setActiveScan(false);   // パッシブスキャンにする

}

// メイン
  int BleTimer = 0;
void loop() {
  RcvData rcvdatas[RCV_CNT_MAX];
  int rcvcnt = 0;
  float pres,temp,humi;
  uint16_t rssi;

  // BLEのスキャンを行う
  // sp("\nscanning...");
  BLEScanResults foundDevices = pBLEScan->start(BLE_SCAN_TIME);
  int hit = foundDevices.getCount();
  // spf("found", hit);

  // 受信した一覧から対象デバイスを抽出する
  for (int i=0; i<hit; i++) {
    BLEAdvertisedDevice dev = foundDevices.getDevice(i);
    std::string data = dev.getManufacturerData();

    // debug
    // if (data[0] == XIAO[0] && data[1] == XIAO[1]) {
    //   String tmpinfo = "";
    //   spf("Scanned: Device_%03d (%02d): ", i, data.length());
    //   for (int j=0; j<data.length(); j++) spf("%02X ",data[j]);
    //   sp("");
    // }

    // XIAO nRF52840からのデータだったら値を格納する
    if (data.length() < 18 )continue;
    if (data[0] == XIAO[0] && data[1] == XIAO[1] && data[2] == XIAO[2] && data[3] == XIAO[3]) {
      rcvdatas[rcvcnt].id = data[5] << 8 | data[4];
      rcvdatas[rcvcnt].type = data[6];
      rcvdatas[rcvcnt].ttl = data[7];
      rcvdatas[rcvcnt].seq = data[9] << 8 | data[8];
      if (seqHist[rcvdatas[rcvcnt].id] == rcvdatas[rcvcnt].seq) continue;  // 同じデータは無視
      seqHist[rcvdatas[rcvcnt].id] = rcvdatas[rcvcnt].seq;
      if (rcvdatas[rcvcnt].type == 10) {  // 種別10: 実験用 volt(i2) temp(i2)
        rcvdatas[rcvcnt].pres = (float)(data[11] << 8 | data[10]) / 10.00 ;
        rcvdatas[rcvcnt].temp = (float)(data[13] << 8 | data[12]) / 10.00;
        rcvdatas[rcvcnt].humi = (float)(data[15] << 8 | data[14]) / 10.00;
        rcvdatas[rcvcnt].vbat = (float)(data[17] << 8 | data[16]) / 100;
        rcvdatas[rcvcnt].rssi = (uint16_t)dev.getRSSI() ;  // 電波強度

        rcvcnt ++;
      }
      if (rcvcnt >= RCV_CNT_MAX) break;
    }
  }

  // ディスプレイに表示
  if (rcvcnt > 0) {
    rcvcnt-- ;
    if ( BleTimer > 5 ){
      //シリアル出力
      printLocalTime();
      Serial.printf("Pres:%.1f,temp:%.1f,humi:%.1f,vbat:%.1f,rssi:%d",
        rcvdatas[rcvcnt].pres - 1000, rcvdatas[rcvcnt].temp, rcvdatas[rcvcnt].humi, rcvdatas[rcvcnt].vbat, abs( rcvdatas[rcvcnt].rssi ) );

      //液晶出力
      u8g2.clearBuffer();                 // clear the internal memory
      u8g2.setCursor(0,14);
      u8g2.printf("pres:%4d", int (rcvdatas[rcvcnt].pres) );
      u8g2.setCursor(0,27);
      u8g2.printf("temp:%4.1f", rcvdatas[rcvcnt].temp);
      u8g2.setCursor(0,40);
      u8g2.printf("hum: %4.1f", rcvdatas[rcvcnt].humi);

      u8g2.display();
      u8g2.sendBuffer();          // transfer internal memory to the display

      //WiFi出力
      postServer(rcvdatas, 1);
    }
    // Serial.printf("\nPres:%.1f,temp:%.1f,humi:%.1f,rssi:%d",
    //   rcvdatas[rcvcnt].pres, rcvdatas[rcvcnt].temp, rcvdatas[rcvcnt].humi,-1 * rcvdatas[rcvcnt].rssi );
    BleTimer = 0;

  } else {
    BleTimer++;

    if ( (BleTimer % 5 ) == 0 ){
      Serial.printf(" %d",BleTimer/5);
    }
  }

  delay(99);
}

// Webサーバーに送信
void postServer(struct RcvData* td, int cnt) {
  HTTPClient http;
  sp(" Send to Web Server ");

  // POSTデータ作成
  String jsonData = "{\"data\":[";
  char buff[64];
  for (int i=0; i<cnt; i++) {
    sprintf(buff, "{\"id\":%d,", td[i].id);
    jsonData += buff;
    sprintf(buff, "\"pres\":%.1f,", td[i].pres);
    jsonData += buff;
     sprintf(buff, "\"volt\":%.1f,", td[i].vbat);
    jsonData += buff;
    sprintf(buff, "\"temp\":%.1f,", td[i].temp);
    jsonData += buff;
    sprintf(buff, "\"humi\":%.1f,", td[i].humi);
    jsonData += buff;
    sprintf(buff, "\"rssi\":%d,", td[i].rssi);
    jsonData += buff;
    sprintf(buff, "\"seq\":%d}", td[i].seq);
    jsonData += buff;
    if (i < cnt-1) jsonData += ",";
  }
  jsonData += "],\"count\":"+String(cnt)+"}";
  sp(jsonData);

  // 送信
  // if(td[0].id == 101){
  //   http.begin(WEB_API_URL); //HTTP
  // }
  // else{
  //   http.begin(WEB_API_URL_IN); //HTTP
  // }
    http.begin(WEB_API_URL); //HTTP


  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  http.addHeader("Content-Length", String(jsonData.length()));
  http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
  int httpCode = http.POST(jsonData);
  printf("[HTTP] POST... code: %d ",httpCode);

  // 送信後の処理
  if (httpCode == HTTP_CODE_OK) {
    String payload = http.getString();
    printf(" OK %s ", payload);
  } else {
    printf("[HTTP] POST... failed, error: %s ",httpCode);
  }
  http.end();
}

コンパイルメモリ不足への対応

最後に

ここまでご覧いただき、ありがとうございました。もし誤りがあれば、ご指摘いただけますと幸いです

プライバシーポリシー |ページトップへ

`