ラズベリーパイとESP32で温度管理システムの制作(2) 送信デバイス制作

ラズベリーパイに温湿度データを送信するデバイスの作成です。
###全体のレイアウト
ユニバーサル基板に部品をはんだ付けしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361605/f75ad89b-1c8f-c6a6-a00c-f0c40068b683.png)

##回路
SHT31とssd1306を並列でi2c接続します。
とはいっても4つの線を並列に繋ぐだけ。簡単簡単。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361605/d1ffeff2-0f7e-8f3b-e97c-785e28f4f0f2.png)


####i2cアドレスの確認
配線が決まったらブレッドボードでアドレスの確認をします。
コードは[このページ](https://leico.github.io/TechnicalNote/Arduino/esp32-i2cscan)を参照しました。

コードを走らせて、出てきたアドレスをメモします。
この場合は、SHT31が0x45、ssd1306が0x3Cでした。

####ESP32に書き込む
```c++
/*
 * =========WiFi Config==========
*/
#include "WiFi.h"
#include "AsyncUDP.h"
#include <stdio.h>

const char * ssid = "ssid";
const char * password = "ssidのパスワード";

//IPアドレスは複数のESP32全て同一にします。
AsyncUDP udp;
IPAddress ESP32_ip(192,168,x,x);
IPAddress server_ip(192,168,x,x);
IPAddress gateway(192,168, x, x);
IPAddress subnet(255, 255, 255, 0);
IPAddress DNS(192, 168, x, x);

//ESP32に固有番号を振る
int deviceNo = 1;

#define ssd1306_Address 0x3C  //ssd1306のi2cアドレス
#define SHT31_Address  0x45  // SHT31のI2Cアドレス

WiFiServer server(80);

const int LEDPIN = 2;
const int PORTNO = 1234;
/*
 * =========SHT31 Config==========
*/
#include <SPI.h>
#include <Arduino.h>
#include <Wire.h>
#include "AE_SHT31.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define NUMFLAKES     10 // Number of snowflakes in the animation example



// SHT31のアドレスを設定
AE_SHT31 SHT31 = AE_SHT31(SHT31_Address);

float temp,humi;


/*
 * =========SeepSleep Config==========
*/

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  9     /* Time ESP32 will go to sleep (in seconds) */

RTC_DATA_ATTR int bootCount = 0;

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}






void setup() {
  // シリアル通信を9600bpsに設定
  Serial.begin(9600);
  
  // シリアルに文字を出力
  // SHT31をソフトリセット
  SHT31.SoftReset();
  // 内蔵ヒーター 0:OFF 1:ON
  SHT31.Heater(0);

  if(!display.begin(SSD1306_SWITCHCAPVCC,ssd1306_Address )) { 
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  display.clearDisplay();
  
  //ssd1306の表示設定
  display.drawPixel(10, 10, WHITE);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  
   temp = SHT31_TEMP();
   humi = SHT31_HUMI();
   
/*
 * =========ディスプレイ表示==========
*/
   
   display.clearDisplay();
   display.setCursor(0,0);
   display.print(" "); 
   display.print(temp); 
   display.println(" 'C");
   
   display.print(" "); 
   display.print(humi); 
   display.println(" %"); 
     
   display.display();
/*
 * =========WiFi Setup==========
*/

   pinMode(LEDPIN,OUTPUT);
    
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);

    WiFi.config(ESP32_ip, gateway, subnet, DNS); 
    
    if (WiFi.waitForConnectResult() != WL_CONNECTED) {
        Serial.println("WiFi Failed");
        while(1) {
            delay(1000);
        }
    }
    
    if(udp.connect(server_ip, PORTNO)) {
        Serial.println("UDP connected");
        udp.onPacket([](AsyncUDPPacket packet) {
            Serial.print("UDP Packet Type: ");
            Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast");
            Serial.print(", From: ");
            Serial.print(packet.remoteIP());
            Serial.print(":");
            Serial.print(packet.remotePort());
            Serial.print(", To: ");
            Serial.print(packet.localIP());
            Serial.print(":");
            Serial.print(packet.localPort());
            Serial.print(", Length: ");
            Serial.print(packet.length());
            Serial.print(", Data: ");
            Serial.write(packet.data(), packet.length());
            Serial.println();
            //reply to the client
            packet.printf("Got %u bytes of data", packet.length());
        });


    }

}



void loop()
{

   temp = SHT31_TEMP();
   humi = SHT31_HUMI();
   
/*
 * =========ディスプレイ表示==========
*/
   
   display.clearDisplay();
   display.setCursor(0,0);
   display.print(" "); 
   display.print(temp); 
   display.println(" 'C");
   
   display.print(" "); 
   display.print(humi); 
   display.println(" %"); 
     
   display.display();
   
/*
 * =========UDP送信==========
*/
//dtostrf(変換する値,変換後の総文字数,小数点以下の桁数,変換後格納する変数);
    
    char udpStr1[6];
    char udpStr2[6];
    char buf[10];
    
    dtostrf(temp,5,2,udpStr1);
    dtostrf(humi,5,2,udpStr2);
    
    sprintf(buf,"%d,%s,%s",deviceNo,udpStr1,udpStr2);
    Serial.println(buf);
    
    udp.broadcastTo(buf, PORTNO);

/*
 * =========後処理==========
*/

   Ltika();
   ESP32_Sleep(10*60);
}

/*
 * =========SHT31の温湿度取得==========
*/

float SHT31_TEMP(){
    // SHT31から温度データを取得
  SHT31.GetTempHum();
  return SHT31.Temperature();
}

float SHT31_HUMI(){
    // SHT31から湿度データを取得
  SHT31.GetTempHum();
  return SHT31.Humidity();
}

/*
 * =========ESP32 DeepSleep==========
*/

void ESP32_Sleep(int sleepime){
  
  delay(1000); //Take some time to open up the Serial Monitor
  ++bootCount;

  print_wakeup_reason();

  esp_sleep_enable_timer_wakeup(sleepime * uS_TO_S_FACTOR);
  esp_deep_sleep_start();

}

/*
 * =========Lチカ==========
*/

void Ltika(){    
    for (int i=0;i<3;i++){
      digitalWrite(LEDPIN,HIGH);
      delay(100);
      digitalWrite(LEDPIN,LOW);
      delay(100);
    }
}
```

204行目の、sprintf(buf,"%d,%s,%s",deviceNo,udpStr1,udpStr2);　
でデバイスNo・温度・湿度のデータをカンマ区切りでまとめて送信しています。
これは後にUDP受信した後に、ポジション毎にデータを振り分ける為です。

###起動

マイコンに書き込み、起動すると、ディスプレイに温湿度が表示されます。
通信に成功すると、ESP32ボード上の青色LEDが3回点滅します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361605/1e789416-529d-6ffb-e4e5-682df07e060e.png)

次はラズベリーパイ側の記事を書く予定です。