4

この記事は最終更新日から3年以上が経過しています。

@eggman

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

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();
  }
}
ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
  1. あなたにマッチした記事をお届けします
    ユーザーやタグをフォローすることで、あなたが興味を持つ技術分野の情報をまとめてキャッチアップできます
  2. 便利な情報をあとで効率的に読み返せます
    気に入った記事を「ストック」することで、あとからすぐに検索できます
eggman

コメント

この記事にコメントはありません。
あなたもコメントしてみませんか :)
ユーザー登録
すでにアカウントを持っている方はログイン
記事投稿イベント開催中
Qiita 10周年記念イベント - 10年前の自分に伝えたい、勉強しておきたかった技術
~
Qiita 10周年記念イベント - 10年後のために今勉強しておきたい技術
~