ESP-01でOLED時計(Soft I2C)

#はじめに
ESP-01はESP8266を搭載したWiFiモジュールです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211703/7bd12a70-c004-d37f-34b9-32663c164b3b.png)

Arduinoでの開発環境もあり、Arduinoの資産を活用した開発も簡単におこなえます。IOはGPIO0-3の4本あり、GIPO1とGPIO3はデフォルトでTX, RXに割り当てられています。

ここではNTPで時刻同期し現在時刻をOLEDにて表示してみます。完全無調整の時計となります。

ネット上ではAdafruitのライブラリを使用した作例が多いのですがフォントが固定の様子で時計としては不都合。 [ThingPulse /
esp8266-oled-ssd1306](https://github.com/ThingPulse/esp8266-oled-ssd1306)というライブラリを使用しました。フォントも自由に変更可能です。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211703/61193a20-89a9-3542-c76c-e4b5b938af7f.png)
デバッグ中の様子

#必要なもの
##ESP-01
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211703/7bd12a70-c004-d37f-34b9-32663c164b3b.png)
ESP-01はAliExpressにて1-2USD程度で購入できます。(技的は知りません)

##プログラマFT232
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211703/de35b4bd-7494-c544-1ecd-5b639f723325.png)
ESP-01は3.3VのためFT232を使用すると便利です。1.5USD程度で購入可能です。

##OLED
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211703/3fe07a3f-2d6e-cf76-cee6-d6db1f138362.png)
I2Cの0.96"OLEDモジュールです。128x64のOLEDでも問題なく使用できます。

##その他
Arudino開発環境、抵抗4.7kΩx2、配線、ハンダごてなど。

#開発環境
ESP-01をArduinoで開発する環境はググってください。
その上で[ThingPulse /
esp8266-oled-ssd1306](https://github.com/ThingPulse/esp8266-oled-ssd1306)というライブラリをインストールしてください。

#プログラム環境
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211703/60433804-1518-8813-492e-cfbce84ad7bf.png)
プログラム時にはVCC, RST, CH_PH, GPIO2をVCCに、GPIO0をGNDにする必要があります。
実行時にはGIPO0をVCCにします。
実行時にGIPO0, GPIO2をVCCにする必要があるので,IOとして使用するにはGPIO0, GPIO2を4.7kΩ程度の抵抗でプルアップしておきます。(プルアップしないと実行できません)

#配線
VCC, RST, CH_PHに3.3Vを。
GNDに0Vを。
GPIO0をプルアップしつつ、OLEDのSDAへ
GPIO2をプルアップしつつ、OLEDのSCLへ

#プログラム

```C:ESP_01_TEST.cpp
//////////////////////////////////////////////////////////////
//
//  ESP01 Desktop clock
//  2020/02/02
//
///////////////////////////////////////////////////////////////
//
// Libraries needed:
//  SSD1306.h & SSD1306Wire.h:  https://github.com/squix78/esp8266-oled-ssd1306
//  ESP8266WiFi.h & WifiUDP.h: https://github.com/ekstrand/ESP8266wifi
//
// 128x64 OLED pinout:
// GND goes to ground
// Vin goes to 3.3V
// Data to I2C SDA (GPIO 0)
// Clk to I2C SCL (GPIO 2)


// To create font, use below site
// http://oleddisplay.squix.ch/#/home

#include <ESP8266WiFi.h>
#include <Wire.h>
#include <SSD1306.h>
#include <SSD1306Wire.h>

#include <time.h>     // for time(), localtime()


// Wi-Fi設定
#define WIFI_SSID   "WIFI_SSID"
#define WIFI_PASSWORD "WIFI_PASSWORD"


// NTP設定
#define TIMEZONE_JPN  (3600 * 9)  // JST is UTC+9hours
#define DAYLIGHTOFFSET_JPN  (0)   // No summer time
#define NTP_SERVER1   "ntp.nict.jpntp.nict.jp"  // NTP
#define NTP_SERVER2   "ntp.jst.mfeed.ad.jp"   // sub NTP


// Create a display object
SSD1306  display(0x3c, 0, 2, GEOMETRY_128_32); // OLED Setting 128x64 = GEOMETRY_128_64


void setup ()
{
  Serial.begin(9600); // Serial for debug

  // Soft I2C setting
  Wire.pins(0, 2);  // Start the OLED with GPIO 0 and 2 on ESP-01
  Wire.begin(0, 2); // 0=sda, 2=scl

  // OLED initialing
  display.init();
  display.flipScreenVertically();
  display.setBrightness( 16 ); // 0: low brightness, 254 : high

  // Connect to wifi
  Serial.println("");
  Serial.print("Connecting to ");
  Serial.print(WIFI_SSID);
  display.drawString(0, 10, "Connecting to Wifi...");
  display.display();
  
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }

  
  Serial.println("");
  Serial.print("Connected to WiFi at ");
  Serial.print(WiFi.localIP());
  Serial.println("");
  display.drawString(0, 24, "Connected.");
  display.display();


  // Synchronize to NTP
  configTime( TIMEZONE_JPN, DAYLIGHTOFFSET_JPN, NTP_SERVER1, NTP_SERVER2 );

  Serial.println("NTP READY");
}

void loop()
{
  if (WiFi.status() == WL_CONNECTED) //Check WiFi connection status
  {
    // String table for day and month
    static const char *pszWDay[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
    static const char *pszMonth[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

    // Get current time & date
    time_t timeNow = time(NULL);
    struct tm* tmNow = localtime(&timeNow);

    // DATE
    char szDate[32];
    sprintf( szDate, "%04d/%02d/%02d(%s)",
             tmNow->tm_year + 1900,
             tmNow->tm_mon + 1,
             tmNow->tm_mday,
             pszWDay[tmNow->tm_wday] );

    // TIME
    char szTime[32];
    sprintf( szTime, "%02d:%02d",
             tmNow->tm_hour,
             tmNow->tm_min
             );

    // Output via serial
    Serial.println("");
    Serial.print("Local date: ");
    Serial.print(szDate);
    Serial.println("");
    Serial.print("Local time: ");
    Serial.print(szTime);

    // Display on OLED
    display.clear();
    // TIME
    display.setFont(Lato_Heavy_30);
    display.drawString( 5, 0, szTime);
    // Date
    display.setFont(ArialMT_Plain_16);
    sprintf( szDate, "%02d", tmNow->tm_mday);
    display.drawString( 96, 0, szDate); // day of Month
    display.drawString( 96, 16, pszMonth[tmNow->tm_mon]); // Month
    display.display();
  }
  else // attempt to connect to wifi again if disconnected
  {
    display.clear();
    display.drawString(0, 10, "Connecting to Wifi...");
    display.display();
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    display.drawString(0, 10, "Connected.");
    display.display();
    delay(1000);
  }

  delay(1000);
}
```

display.setFont(Lato_Heavy_30);
でエラーになるはずです。下記でフォントを作成して置き換えてください。

#Font作成
[こちら](http://oleddisplay.squix.ch/#/home)でフォントを作成できます。生成したコードをOLEDDisplayFonts.hに貼り付けて使用してください。

#完成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211703/63d90e6f-0fb4-5ae4-84ea-9159e2bbcdd9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211703/d62919f5-6198-5d8b-18c6-a5d1b35d6284.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211703/0d30bead-9e84-19a8-23c2-489d33ac97c1.png)
ヘッダーコネクタがかさばってますがコンパクトではあると思います。低背のコネクタを使用すれば厚さ1.5cmくらいにはなるかと。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211703/ca8be62d-11d2-916a-0c09-04cf4b74fa41.png)

ケースに入れて完成です。少し斜めってますね。

#おわりに
ESP-WROOM-02でOLEDを使用するアプリケーションは沢山見付かるのですが、ESP-01では随分と苦労しましたので忘備録として記事にします。
現在ニキシー時計を作成しており、ESP-01はNTP同期のRTC程度に使用するつもりでしたが、プログラム容量、動作速度もありで、母艦のAtMega328は不要じゃないかと思いはじめています。このサイズと価格パワフルさでESP-01に惚れました。

20200202