
Tx見るやつのコード
ツイッターにアップしたこれです。「Tx見るやつのコード」というタイトルなので、いきなりコード置きます。ちょっとした説明は下に。
// 必要なライブラリ
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>
#include <TFT_eSPI.h>
#include <math.h>
// WiFi情報
const char* ssid = "入れてね";
const char* password = "入れてね";
// 表示と接続用
TFT_eSPI tft = TFT_eSPI();
WebSocketsClient webSocket;
// 消失点(画面中央上)
const int vanishX = 240 / 2;
const int vanishY = 30;
// 最新トランザクションの省略ハッシュ
String latestTxHashShort = "";
// 投影関数(Z中心固定型)
void project(int x, int y, float zOffset, int &outX, int &outY) {
float scale = 1.0 / (1.0 + zOffset / 100.0); // 固定Z中心 = 100px 奥
outX = vanishX + (x - vanishX) * scale;
outY = vanishY + (y - vanishY) * scale;
}
// トランザクションデータ構造
struct Tx {
float btc;
float x;
int size;
String label;
};
#define MAX_TXS 20
Tx txs[MAX_TXS];
int txCount = 0;
unsigned long lastUpdate = 0;
const int screenWidth = 240;
const int screenHeight = 135;
const float speed = 30.0 / 1000.0; // ピクセル毎ミリ秒
// 立方体を描画する関数
void drawCube(int x, int y, int size) {
float centerZ = 60.0;
float halfSize = size / 2.0;
// 立方体の8点 (x,y,z)
int px[8], py[8];
float cx = x + halfSize;
float cy = y + halfSize;
float vx[8] = {
-halfSize, +halfSize, +halfSize, -halfSize,
-halfSize, +halfSize, +halfSize, -halfSize
};
float vy[8] = {
-halfSize, -halfSize, +halfSize, +halfSize,
-halfSize, -halfSize, +halfSize, +halfSize
};
float vz[8] = {
-halfSize, -halfSize, -halfSize, -halfSize,
+halfSize, +halfSize, +halfSize, +halfSize
};
for (int i = 0; i < 8; i++) {
int sx, sy;
project(cx + vx[i], cy + vy[i], centerZ + vz[i], sx, sy);
px[i] = sx;
py[i] = sy;
}
const int edges[12][2] = {
{0,1},{1,2},{2,3},{3,0},
{4,5},{5,6},{6,7},{7,4},
{0,4},{1,5},{2,6},{3,7}
};
for (int i = 0; i < 12; i++) {
tft.drawLine(px[edges[i][0]], py[edges[i][0]], px[edges[i][1]], py[edges[i][1]], TFT_WHITE);
}
}
// 新しいトランザクションを追加
void addTx(float btc) {
if (txCount >= MAX_TXS) return;
float size = cbrt(btc) * 40.0;
if (size < 1.0) size = 1.0;
Serial.print("Adding tx: ");
Serial.print(btc, 8);
Serial.print(" BTC, size: ");
Serial.println(size);
txs[txCount].btc = btc;
txs[txCount].x = 0;
txs[txCount].size = (int)size;
txs[txCount].label = String(btc, 8);
txCount++;
}
// WebSocket イベント
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
switch (type) {
case WStype_DISCONNECTED:
Serial.println("[WebSocket] Disconnected");
break;
case WStype_CONNECTED:
Serial.println("[WebSocket] Connected to server, sending sub msg...");
webSocket.sendTXT("{\"op\":\"unconfirmed_sub\"}");
break;
case WStype_TEXT: {
Serial.println("[WebSocket] Message received");
Serial.println((char*)payload);
DynamicJsonDocument doc(2048);
DeserializationError error = deserializeJson(doc, payload);
if (error) {
Serial.print("deserializeJson failed: ");
Serial.println(error.f_str());
return;
}
if (doc["op"] == "utx") {
JsonArray inputs = doc["x"]["inputs"];
long total = 0;
for (JsonObject input : inputs) {
total += input["prev_out"]["value"] | 0;
}
float btc = total / 100000000.0;
addTx(btc);
// ハッシュを省略形で保存
const char* fullHash = doc["x"]["hash"];
if (fullHash && strlen(fullHash) >= 8) {
String hashStr(fullHash);
latestTxHashShort = hashStr.substring(0, 4) + "..." + hashStr.substring(hashStr.length() - 4);
}
}
break;
}
default:
break;
}
}
// 初期化
void setup() {
Serial.begin(115200);
randomSeed(analogRead(0));
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.setTextDatum(MC_DATUM);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
webSocket.beginSSL("ws.blockchain.info", 443, "/inv");
webSocket.onEvent(webSocketEvent);
webSocket.setReconnectInterval(5000);
}
// トランザクションを描画
void drawTxs() {
Serial.println("Drawing frame...");
tft.fillScreen(TFT_BLACK);
for (int i = 0; i < txCount; i++) {
Tx& tx = txs[i];
int y = (screenHeight - tx.size) / 2 + 30;
drawCube((int)tx.x, y, tx.size);
}
if (txCount > 0) {
tft.setCursor(0, 0);
tft.setTextFont(2);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.print(txs[txCount - 1].label);
tft.setCursor(0, 16);
tft.print(latestTxHashShort);
}
}
// トランザクション位置更新
void updateTxs(unsigned long delta) {
float dx = speed * delta;
int writeIndex = 0;
for (int i = 0; i < txCount; i++) {
txs[i].x += dx;
if (txs[i].x < screenWidth + txs[i].size * 2) {
txs[writeIndex++] = txs[i];
}
}
txCount = writeIndex;
}
// メインループ
void loop() {
webSocket.loop();
unsigned long now = millis();
unsigned long delta = now - lastUpdate;
if (delta >= 30) {
updateTxs(delta);
drawTxs();
lastUpdate = now;
}
}
(blockchain.infoからデータ読んでるだけですね)
Arduino IDEで書き込みます。基本的に最初のライブラリを入れるだけで動くと思いますが、ディスプレイ設定がハマりポイントです。TFT_eSPIディレクトリのUser_Setup_Select.h
を直接いじって(コメントアウトしたり消したりするだけ)合うディスプレイを選びます。ここをうまくやらないと画面サイズが合わなかったり、ノイズ領域が出たり、白黒反転したり、90度回転したりします。もしかしたら上のコードにもちょっとした修正が必要になるかもしれません。ここは工夫して下さい。User_Setup.h
はいじらなくて良かった気がするうろ覚え。
ハードウェア
あんまり詳しくないけどなんでもいいんだと思います。ディスプレイくっついてるのが楽です。こんなやつ。くっついてなくてもいいと思う。
ディスプレイ設定に話を戻しますが、商品ページのどこを見てもディスプレイの種類がわからなったりするので、レビュー欄見ると誰か書いててくれてたりします。
ビバ!🍊
ここより下は何もありません。Tip me!