macsbug

M5Stack CoinMarketCap

leave a comment »

M5Stack で 仮想通貨の時価総額 ( CoinMarketCap ) を表示しました。 ORG:2019.05.26, rev:2019.05.30

.
CoinMarketCap ( 仮想通貨の時価総額 ) は リアルタイムに 数値とグラフを見る事ができます。
bitcoin, cardano, ethereum, litecoin, xrp(ripple) の5つを M5Stack に表示します。
オリジナルは mnett0氏の ESP32+ILI9341「CryptoMoneyTicker」です。mnett0氏に感謝!
この「CryptoMoneyTicker」を TTGO が TTGO-T4-DEMO 「T4_9341_NEW」に移植。
そして「TTGO-T4-DEMO」を基に M5Stack用に移植致しました。


.
手順:
1. 開発環境:Arduino IDE。
2. ArduinoJson を Arduino IDE の Library へ Install します。
_ version は 5 を使用します。ArduinoJson-5.13.5。注:version 6 では 動作しません。
3. 最下位にある スケッチ「M5Stack_CoinMarketCap」をコピーし
_ 「M5Stack_CoinMarketCap.ino」Folder を 作ります。
4. 以下の8つの表示画像を 用意し、SD File か HEX File か どちらかで行ないます。
_ 
_ 画像表示の為に 画像を microSD に入れて使用するか、HEX File に変換し
_ 「M5Stack_CoinMarketCap.ino」 Folder に入れます。
_ Free_Fonts.h は M5Stack/examples/Advanced/Display/Free_Font_Demo/
_ にありますので DL してください。
 
_ ⭕ SD File の場合:
_  
_  microSDに 「coin_image」 Folder を作り 以下の表示画像( jpg ) を入れます。
.
表示画像:

bitcoin_.jpg cardano_.jpg ethereum_.jpg litecoin_.jpg xrp_.jpg

.

wifi_1.jpg wifi_2.jpg wifi_3.jpg

.
_ ⭕ HEX Fileの場合:
_  
_  1. 8つの表示画像( jpg ) を 変換し DL(ダウンロード)します。事例:bitcoin_.jpg
_  2. ブラウザーで「PicturetoC_Hex_converter」に接続し jpg を hex に変換します。
_  3. your の選択ボタンで DL した File を選択します。
_  4. width は 「64」, Height は 「64」 を入力。
_  5. User for は 「256 color byte/pixel:RRRGGGBB, for EDM1」を選択します。
_  6. 「Get C String」ボタンを押すと Image data: が作成されます。
_  7. Image data (0xff 等) をコピーし 「bitcoin_.c」File を作ります。
_   ( 左下の「Download data」を選択し DL する方法は DL した bin を変換しますが
_    この方法は 変換方法が解らず 説明は省きます。)
_  8. 8つの Hex File を 「M5Stack_CoinMarketCap.ino」 Folder に入れます。
_

4. Arduino IDE で M5Stackに書き込みます。


.
追記:2019.05.30
⭕ HEX File 変換:その2:「LCD image Converter 」アプリで変換する。
_ 「LCD image Converter 」は Windowsアプリです。
_ 「lcd-image-converter 20180211-beta」を使用します。
_  メモ:投稿時 最新の20190317 は エラーで動作しません。
_ Mac では「Wine.app」を使用しWindows アプリケーションを動かすことができます。
_ Wine.app Downloads:例 Wine 2.0 を 選択し Download を押します。
_ 約5sec後に「Continue」が表示されますので「Continue」を選択します。
_ 約4sec後に 右上(のアイコン) を選択します。Wine_2.0.dmg 175.6MB が DLされます。
_ 解凍すると Wine.app ができます。
_

HEX File 変換方法:
1. Wine.app を起動し LCD image Converter を動作させます。
_ 事前に Wine.app や LCD image Converter の動かし方や 配置を把握しておきます。
_ 初めての場合は Winの配置等に慣れない為に時間を要するかと思います。
2. LCD image Converter:
_ File Menu から png 又は Jpg を読み込みます。読み込まれると画像が表示されます。
_ Option Menu を選択します。一番上の Preset: は「Color R5G6B5」を選択します。
_ Image を選択し Block size: は「8 bit」を選択します。「OK」を押します。
_ File Menu にある 「Convert… 」 で 例「bitcoin_.c」が出力されます。
_  事前に読み込み先 ong や 出力先を把握しておきます。
3. .c の編集:そのままではエラーが出ますので修正します。
_ 最下位にある 「const tImage ethereum_ = ,,, }; 」は コメントアウト「//)」します。
_ 上にある 例「static const uint8_t image_data_bitcoin_[8192] = {」は
_  名前の「image_data_」を削除すると短く見やすくなります。
_  「static const uint8_t bitcoin_[8192] = {」に変更します。
_ これにより 例「bitcoin_.c」を作成する事ができます。
_ 


.
移植メモ:
1. オリジナルの 「CryptoMoneyTicker」:
_ ログを CSV File で SDに保存できる。
_ ボタン操作で 表示を選択できる。
_ 表示の為の画像(bitmap.c) は そのままでは M5Stack に使用できない。

2. TTGO の TTGO-T4-DEMO 「T4_9341_NEW」:
_ ログを CSV File で SDに保存できない。
_ ボタン操作は 無し。
_ 表示の為の画像(bitmap.c) は そのままでは M5Stack に使用できない。

3. 移植の課題と対策:
_ 画像の問題:
_ 「CryptoMoneyTicker」や「T4_9341_NEW」にある画像 bitmap.c は
_  M5Stack では使用できません。さらに これまでの Arduino等にある HEX画像も
_  そのままでは使用できません。
_  理由は Display の表示に関し RGB の配置変更(BGR)や鏡面反転している為です。
_  素直に RGB 配置にすれば これまでの資産がスムーズに使用できますが
_  配置変更をした為 都度 画像の変換や 新規作成が必要となります。
_  これは 手間と時間を要し M5Stackの発展を妨げます。
_  参照:TFT_eSPI Library supports M5STACK
_  PC環境やOSにより 画像フォーマットが変化し 動作しない場合が考えられます。
_  OS環境により 不可視ファイルが出来る場合があります。

_ 画像の対策:
_ 1. M5Stack で使用可能な Jpg File を microSDに保存して使用する。
_  スケッチ例:M5.Lcd.drawJpgFile(SD,”/coin_image/bitcoin_.jpg”,0,0,64,64);
_ 2. ブラウザーで使用可能な png to hex 又は jpg to hex を使用し hex を作成する。
_  png to hex が可能で 「256 color byte/pixel:RRRGGGBB, for EDM1」の選択が
_  必要となります。この変換データーは大きくなりますが使用できます。
_  他に可能な方法があるかと思いますが 現在知り得る方法です。
_  スケッチ例:M5.Lcd.pushImage(0, 0, 64, 64, (uint8_t *)bitcoin_);
_  それにしても 簡単な変換方法を探していますが なかなか思うように行きません。

_ 今回の機能:
_ 1. 画像は SD と hex 両方が使用出来る記述にしました。
_  必要に応じて 不要な場所は 削除や変更をしてください。
_ 2. ログの SD保存 は 特に必要なく追加しませんでした。
_  グラフに興味がある場合は SD へ CSV 保存すると便利になるかと思います。
_ 3. ボタンスイッチによる 表示の切り替えは無しにしました。
_  繰り返し表示の時間設定は 18行目の interval = 60000; です。
_  必要に応じて 数値を変更してください。
_  マニュアルで画面切り替えが 便利な場合は スイッチ操作を加えると
_  便利になるかと思います。


.
参照:
M5StickC docs:概要(電源操作、サポート ボーレート、ピンマップ)
github:M5StickC Library:M5StickC ライブラリー
Market Capitalization:データーのソース基。
CryptoMoneyTicker:オリジナル版 mnett0氏のページ。
TTGO-T40DEMO:TTGOのデモ
png to hex:Hex変換。
png to jpg:jpg変換。


.
感想:
仮想通貨は使用していませんので必要ありませんが、TTGO のサンプルの
表示が綺麗でなく M5Stack では どうなるか試してみました。

画像処理:M5Stack用の画像準備には時間がかかります。
_ もう少し簡単に出来る方法は無いかと模索しましたが 私の力量では
_ この位かと思います。
_ png は 透明処理が可能ですが M5Stack上ではマスター出来ませんでした。
_ よって 左上のアイコン画像は 背景部を透明にして試しましたが 表示
_ できない為に 背景を白で仕上げました。

当初 TTGO製のスケッチかと思いましたが mnett0氏の作品である事が解りました。
_ CryptoMoneyTicker_LITE ( ESP8266 + OLED ) もあり 小型でケースも出来ています。

勉強:
M5Stack の Github には Graphic のサンプルがあり 基本的な使用方法が あります。
今回の移植後に気づき、サンプルを先にマスターしておくべきだったかと 思っています。
 1. drawXBitmap/xbm.h:モノクロ画像を扱う。
 2. TFT_Flash_Bitmap:カラー画像を扱う。


.
スケッチ:M5Stack_CoinMarketCap : 2019.05.26 Transplant by macsbug

/*
The MIT License (MIT)

Copyright © 2018 Médéric NETTO

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// M5Stack_CoinMarketCap : 2019.05.26 Transplant by macsbug
// https://macsbug.wordpress.com/2019/05/26/m5stack-coinmarketcap/
// https://coinmarketcap.com // Market Capitalization
// https://github.com/mnett0/CryptoMoneyTicker // CryptoMoneyTicker
// https://github.com/LilyGO/TTGO-T4-DEMO // TTGO-T40DEMO
// https://www.digole.com/tools/PicturetoC_Hex_converter.php // png to hex
// https://onlinejpgtools.com/convert-png-to-jpg // png to jpg
#include <M5Stack.h>
#include "M5StackUpdater.h"
#include "Free_Fonts.h"
#include <driver/dac.h>
#include <ArduinoJson.h> // with ArduinoJson 5.xx
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <TimeLib.h>
#define SD_ // with SD File
#if defined(SD_)
#else
  #include "bitcoin_.c"
  #include "cardano_.c"
  #include "ethereum_.c"
  #include "litecoin_.c"
  #include "xrp_.c" // ripple
  #include "wifi_1.c"
  #include "wifi_2.c"
  #include "wifi_3.c"
#endif
const char* ssid = "your wifi ssid";
const char* password = "your wifi password";
const char host[] = "api.coinmarketcap.com";
int COLOR;
#define CUSTOM_DARK 0x4228 // Background color
unsigned long previousMillis = 0;
long interval = 0;
int coin = 0;
String crypto[] = {"bitcoin", "cardano", "ethereum", "litecoin", "ripple"};
String oldPrice[5];

void setup() {
  M5.begin();
  Wire.begin();if(digitalRead(39)==0){updateFromFS(SD);ESP.restart();}
  dac_output_disable(DAC_CHANNEL_1); // DAC OFF
  M5.Lcd.setRotation(0);
  M5.Lcd.fillScreen(CUSTOM_DARK); 
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setTextWrap(true);
  M5.Lcd.setCursor(0, 170);
  M5.Lcd.setFreeFont(FM9); 
  M5.Lcd.println(">>> Connecting to: ");
  M5.Lcd.println(" ");
  M5.Lcd.println(ssid);
  Serial.println("start");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    #if defined(SD_)
      M5.Lcd.drawJpgFile(SD,"/coin_image/wifi_3.jpg",56,64,128,128);delay(250);
      M5.Lcd.drawJpgFile(SD,"/coin_image/wifi_2.jpg",56,64,128,128);delay(250);
      M5.Lcd.drawJpgFile(SD,"/coin_image/wifi_1.jpg",56,64,128,128);delay(250);
    #else
      M5.Lcd.pushImage(56, 64, 128, 128, (uint8_t *)wifi_3);delay(250);
      M5.Lcd.pushImage(56, 64, 128, 128, (uint8_t *)wifi_2);delay(250);
      M5.Lcd.pushImage(56, 64, 128, 128, (uint8_t *)wifi_1);delay(250);
      M5.Lcd.fillRect (56, 64, 128, 128, CUSTOM_DARK);
    #endif
  }
  //Serial.println("start");
  M5.Lcd.println(" ");
  M5.Lcd.print(">>> WiFi connected");
  //M5.Lcd.print("IP address: ");
  //M5.Lcd.println(WiFi.localIP());

  delay(1500);
  M5.Lcd.fillScreen(CUSTOM_DARK);
  M5.Lcd.setTextColor(YELLOW);
  M5.Lcd.setCursor(0, 150);
  M5.Lcd.setFreeFont(FM9);
  M5.Lcd.println("CryptoMoneyTicker_v1");
  M5.Lcd.println("porting : 2019.05.26");
  M5.Lcd.drawLine(0,130,240,130, WHITE);
  M5.Lcd.drawLine(0,185,240,185, WHITE);

  M5.Lcd.setFreeFont(FM9);
  M5.Lcd.setCursor(5, 307);
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.println("Data from: CoinMarketCap.com");
}

void loop() {
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setCursor(1, 10);
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    interval = 60000; //  <<<--------------------  
    if(coin == 5 ){ coin = 0; }
  //Serial.print(">>> Connecting to ");
  //Serial.println(host);
  WiFiClientSecure client;
  const int httpsPort = 443;
  if (!client.connect(host, httpsPort)) {
    M5.Lcd.fillScreen(CUSTOM_DARK);
    M5.Lcd.println(">>> Connection failed");
    return;
  }
  //Serial.print("Requesting URL: ");
  //Serial.println("Connected to server!");
  client.println("GET /v1/ticker/" + crypto[coin] + "/ HTTP/1.1");
  client.println("Host: api.coinmarketcap.com");
  client.println("Connection: close");
  client.println();

  unsigned long timeout = millis();
  while (client.available() == 0) {
    if (millis() - timeout > 5000) {
      M5.Lcd.fillScreen(CUSTOM_DARK);
      M5.Lcd.println(">>> Client Timeout!");
      client.stop();
      return;
    }
  }

  String data;
  while(client.available()) {
    data = client.readStringUntil('\r');
    //Serial.println(data);
  }
  data.replace('[', ' ');
  data.replace(']', ' ');
  char buffer[data.length() + 1];
  data.toCharArray(buffer, sizeof(buffer));
  buffer[data.length() + 1] = '\0';
  const size_t bufferSize = JSON_OBJECT_SIZE(15) + 110;
  DynamicJsonBuffer jsonBuffer(bufferSize);
  JsonObject& root = jsonBuffer.parseObject(buffer);
  if (!root.success()) {
    M5.Lcd.println("parseObject() failed");
    return;
  }

  String name = root["name"];                          // "Bitcoin"
  String symbol = root["symbol"];                      // "BTC"
  String price_usd = root["price_usd"];                // "573.137"
  String percent_change_1h = root["percent_change_1h"];// "0.04"
  String last_updated = root["last_updated"];          // "1472762067"<--Unix Time Stamp
  String error = root["error"];                        // id not found

  printTransition();

  switch (coin) {
  case 0 : // Bitcoin
  #if defined(SD_)
    M5.Lcd.drawJpgFile(SD,"/coin_image/bitcoin_.jpg",0,0,64,64);
  #else
    M5.Lcd.pushImage(0, 0, 64, 64, (uint8_t *)bitcoin_);
  #endif
  printName(name, symbol);
  printPrice(price_usd);
  printChange(percent_change_1h);
  printTime(last_updated);
  printPagination();
  printError(error);
  M5.Lcd.fillCircle(82, 300, 8, WHITE);
  break;

  case 1 : // cardano
  #if defined(SD_)
    M5.Lcd.drawJpgFile(SD,"/coin_image/cardano_.jpg",0,0,64,64);
  #else
    M5.Lcd.pushImage(0, 0, 64, 64, (uint8_t *)cardano_);
  #endif
  printName(name, symbol);
  printPrice(price_usd);
  printChange(percent_change_1h);
  printTime(last_updated);
  printPagination();
  printError(error);
  M5.Lcd.fillCircle(100, 300, 8, WHITE);
  break;

  case 2 : // ethereum
  #if defined(SD_)
    M5.Lcd.drawJpgFile(SD,"/coin_image/ethereum_.jpg",0,0,64,64);
  #else
    M5.Lcd.pushImage(0, 0, 64, 64, (uint8_t *)ethereum_);
  #endif
  printName(name, symbol);
  printPrice(price_usd);
  printChange(percent_change_1h);
  printTime(last_updated);
  printPagination();
  printError(error);
  M5.Lcd.fillCircle(118, 300, 8, WHITE);
  break;

  case 3 : // litecoin
  #if defined(SD_)
    M5.Lcd.drawJpgFile(SD,"/coin_image/litecoin_.jpg",0,0,64,64);
  #else
    M5.Lcd.pushImage(0, 0, 64, 64, (uint8_t *)litecoin_);
  #endif
  printName(name, symbol);
  printPrice(price_usd);
  printChange(percent_change_1h);
  printTime(last_updated);
  printPagination();
  printError(error);
  M5.Lcd.fillCircle(136, 300, 8, WHITE);
  break;

  case 4 : // ripple ( xrp )
  #if defined(SD_)
    M5.Lcd.drawJpgFile(SD,"/coin_image/xrp_.jpg",0,0,64,64);
  #else
    M5.Lcd.pushImage(0, 0, 64, 64, (uint8_t *)ripple_);
  #endif
  printName(name, symbol);
  printPrice(price_usd);
  printChange(percent_change_1h);
  printTime(last_updated);
  printPagination();
  printError(error);
  M5.Lcd.fillCircle(154, 300, 8, WHITE);
  break;
  }
  oldPrice[coin] = price_usd;
  coin++;
  }
}

void printName(String name, String symbol) {
  M5.Lcd.setFreeFont(FM12);
  M5.Lcd.setCursor(75, 15);
  M5.Lcd.println(name);
  M5.Lcd.setFreeFont(FM12);
  M5.Lcd.setCursor(75, 42);
  M5.Lcd.print(symbol);
  M5.Lcd.drawLine(75, 54, 240, 54, WHITE);
}

void printPrice(String price_usd) {
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setFreeFont(FM12);
  M5.Lcd.setCursor(5, 85);
  M5.Lcd.print("Price:");
  if(price_usd != oldPrice[coin]){
    if(price_usd > oldPrice[coin]){
    COLOR = GREENYELLOW;
    }else{
    COLOR = RED;
    }
  }
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.setTextColor(COLOR);
  M5.Lcd.setCursor(20, 126);
  M5.Lcd.print("$");
  M5.Lcd.println(price_usd.substring(0,8));
}

void printChange(String percent_change_1h) {
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setFreeFont(FM12);
  M5.Lcd.setCursor(5, 160);
  M5.Lcd.print("Change(1h):");
  if(percent_change_1h >= "0"){
    M5.Lcd.setTextColor(GREENYELLOW);
    }else{
    M5.Lcd.setTextColor(RED);
  }
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.setCursor(20, 199);
  M5.Lcd.print(percent_change_1h);
  M5.Lcd.print("%");
}

void printTime(String last_updated) {
  long int timeData = last_updated.toInt();
  time_t t = timeData;
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setFreeFont(FM12);
  M5.Lcd.setCursor(5, 230);
  M5.Lcd.print("Last Updated:");
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.setCursor(20, 266);
  /*
  M5.Lcd.setFreeFont(FM9);
  printDigits(day(t));  M5.Lcd.print("/");
  printDigits(month(t));M5.Lcd.print("/");
  M5.Lcd.print(year(t));M5.Lcd.print(" ");
  */
  printDigits(hour(t) + 1); // +1 for the French time
  M5.Lcd.print(":");
  printDigits(minute(t));
  //M5.Lcd.print(":");
  //printDigits(second(t));
}

void printPagination() {
  M5.Lcd.drawCircle( 82, 300, 8, WHITE);
  M5.Lcd.drawCircle(100, 300, 8, WHITE);
  M5.Lcd.drawCircle(118, 300, 8, WHITE);
  M5.Lcd.drawCircle(136, 300, 8, WHITE);
  M5.Lcd.drawCircle(154, 300, 8, WHITE);
}

void printError(String error) {
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setFreeFont(FM9);
  M5.Lcd.setCursor(65, 22);
  M5.Lcd.println(error);
}

void printTransition(){
  M5.Lcd.fillScreen(CUSTOM_DARK);
  M5.Lcd.fillScreen(RED);
  M5.Lcd.fillScreen(GREEN);
  M5.Lcd.fillScreen(BLUE);
  M5.Lcd.fillScreen(CUSTOM_DARK);
}

void printDigits(int digits) {
 if (digits < 10)  // prints preceding colon and leading 0
 M5.Lcd.print('0');
 M5.Lcd.print(digits);
}

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
M5Stack , CoinMarketCap , RGB , GBR png to hex , png to jpg , macsbug , TTGO ,
HEX , HEX File 変換 , LCD image Converter , Wine , Wine_2.0 ,

Written by macsbug

5月 26, 2019 @ 12:00 pm

カテゴリー: M5STACK

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。