LoginSignup
5
4

More than 5 years have passed since last update.

M5Stackでbitflyerのビットコイン価格を表示

Posted at

M5Stackでbitflyer のビットコイン価格を表示してみました。

m5bf.jpg

M5Stackは液晶が付いていてWi-Fi接続できるプログラム可能なデバイスです。 aliexpressで売っています。技適のシールも付いています。

前回の記事との違いは、HTTPSを使っている点です。 

HTTPSのルート証明書の準備

  • bitflyerのAPIはHTTPS経由でアクセスします。
  • HTTPSでアクセスするためにはルート証明書の設定が必要です。
  • PCのブラウザでbitflyerにアクセスして、ルート証明書の情報を調べます。
  • bitflyer は DigiCertHighAssuranceEVRootCA を使うのでブラウザからエクスポートするか、DigiCertからダウンロードします。
  • ブラウザからエクスポートした方が簡単な気がします。
  • DigiCertからダウンロードした場合はOpenSSLのコマンドでx509なテキスト形式に変換します。
  • ルート証明書はソースコードに埋め込みます。

メモ

  • esp_log_level_set("*", ESP_LOG_VERBOSE) でesp-idfのログを有効化できる
  • HTTPSの接続エラーは、最近追加されたlastError()メソッドでエラーの内容を確認できます。
  • CONNECTION CLOSE を指定しても、接続が切断されないので JSONの終わりの"}"を検出して結果の終わりを検出している。 今回はネストしていないjsonなので、これでも動く。

ソースコードです。


#include <M5Stack.h>
#include <WiFiClientSecure.h>

WiFiMulti WiFiMulti;

int status = WL_IDLE_STATUS;
int lastPrice = 0;
int currentPrice;
int minPrice = 9999999; 
int maxPrice = 0;
const char *servername = "api.bitflyer.jp";
String answer;
WiFiClientSecure client;

//echo | openssl s_client -showcerts -servername api.bitflyer.jp -connect api.bitflyer.jp:443 2>/dev/null | openssl x509 
//echo | openssl s_client -showcerts -servername api.bitflyer.jp -connect api.bitflyer.jp:443 2>/dev/null | openssl x509 -inform pem -noout -text
//https://www.digicert.com/digicert-root-certificates.htm
//https://www.digicert.com/CACerts/DigiCertHighAssuranceEVRootCA.crt
//openssl x509 -inform DER -in DigiCertHighAssuranceEVRootCA.crt -text
//openssl x509 -inform DER -in DigiCertHighAssuranceEVRootCA.crt -out outcert.pem -text

const char* root_ca = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs\n" \
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \
"d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\n" \
"ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL\n" \
"MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\n" \
"LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug\n" \
"RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm\n" \
"+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW\n" \
"PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM\n" \
"xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB\n" \
"Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3\n" \
"hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg\n" \
"EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF\n" \
"MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA\n" \
"FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec\n" \
"nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z\n" \
"eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF\n" \
"hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2\n" \
"Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\n" \
"vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep\n" \
"+OkuE6N36B9K\n" \
"-----END CERTIFICATE-----";

// the setup routine runs once when M5Stack starts up
void setup(){

  esp_log_level_set("*", ESP_LOG_VERBOSE);

  WiFiMulti.addAP("SSID", "PASSWORD");
  Serial.begin(115200);

  // Initialize the M5Stack object
  M5.begin();

  // LCD display
  M5.Lcd.println("bitcoin");

  while (WiFiMulti.run() != WL_CONNECTED) {
    delay(500);
    M5.Lcd.printf(".");
  }
  M5.Lcd.println("wifi connect ok");

  ConnectToClient();
}

void ConnectToClient(){

    client.setCACert(root_ca);

  if (client.connect(servername, 443)) {
    // Make a HTTPS request:
    client.print(String("GET https://api.bitflyer.jp/v1/getticker?product_code=FX_BTC_JPY HTTP/1.1\r\n")  +
                 "Host: api.bitflyer.jp\r\n" +
                 "User-Agent: esp-idf/1.0 esp32\r\n" +
                 "Connection: close\r\n\r\n");
  }
  else {
    char buf[256]; 
    client.lastError(buf, 256);
    Serial.println("Connection failed!");
    Serial.printf("reason %s\n", buf);
  }
}

// the loop routine runs over and over again forever
void loop() {

  if (client.available()) {
    char c = client.read();
    answer += c;
  }

  // if detect of JSON, stop the client:
  if (answer.charAt(answer.length() - 1) == '}' ) {
    m5.update();
    client.stop();

    String jsonAnswer;
    int jsonIndex;

    for (int i = 0; i < answer.length(); i++) {
      if (answer[i] == '{') {
        jsonIndex = i;
        break;
      }
    }

    jsonAnswer = answer.substring(jsonIndex);
    jsonAnswer.trim();

    int rateIndex = jsonAnswer.indexOf("ltp");
    String priceString = jsonAnswer.substring(rateIndex + 5, rateIndex + 12);
    Serial.println(jsonAnswer);
    Serial.println("");
    Serial.println(priceString);
    priceString.trim();
    String Amount =  priceString ;
    currentPrice = (priceString).toInt();

    minPrice = min(minPrice,currentPrice);
    maxPrice = max(maxPrice,currentPrice);

    m5.Lcd.fillScreen(0x0000);
    m5.Lcd.setFont(&FreeSans9pt7b);

    m5.Lcd.setTextColor(RED);
    m5.Lcd.setCursor(20, 20);
    m5.Lcd.printf(("Min: " + String(minPrice).substring(0,priceString.length()) ).c_str());

    m5.Lcd.setTextColor(GREEN);
    m5.Lcd.setCursor(205, 20);
    m5.Lcd.printf(("Max: " + String(maxPrice).substring(0,priceString.length()) ).c_str());

    m5.Lcd.setTextColor(WHITE);
    m5.Lcd.setCursor(5, 80);
    m5.Lcd.setFont(&FreeMonoBold24pt7b);
    m5.Lcd.printf("BitFlyer FX");
    m5.Lcd.printf("\r\n");

    m5.Lcd.setCursor(50, 140);
    m5.Lcd.printf(Amount.c_str());

    if (currentPrice >= lastPrice) //UP
    {
      m5.Lcd.fillTriangle(140, 205, 180, 205, 160, 180, GREEN);
    }
    else if (currentPrice < lastPrice) //Down
    {
      m5.Lcd.fillTriangle(140, 205, 180, 205, 160, 230, RED);
    }

    lastPrice = currentPrice;

    // wait 30 seconds and key check
    for (int i = 0; i < 30; i++){
      if(M5.BtnA.wasPressed()) {
        m5.lcd.setBrightness(0);
      }
      if(M5.BtnB.wasPressed()) {
        m5.lcd.setBrightness(25);
      }
      if(M5.BtnC.wasPressed()) {
        m5.lcd.setBrightness(150);
      }
      m5.update();
      delay(1000);
    }
    answer = "";
    Amount = "";
    currentPrice = 0;
    ConnectToClient();
  }
}
5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4