Skip to content

Commit

Permalink
Merge bitstamp-websocket
Browse files Browse the repository at this point in the history
  • Loading branch information
nebman authored Sep 23, 2017
2 parents 5ff9733 + 99c6aa1 commit 651fb69
Showing 1 changed file with 188 additions and 57 deletions.
245 changes: 188 additions & 57 deletions btc-ticker-esp8266.ino
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//#define DEBUGGING 1

#include <ESP8266mDNS.h>
#include <ESP8266HTTPClient.h>
#include <WiFiUdp.h>
Expand All @@ -9,20 +11,29 @@
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
#include <WebSocketClient.h>

#include <LedControl.h>

const String url = "http://api.coindesk.com/v1/bpi/currentprice.json";

const int brightness_full = 8; // 0-15 normal brightness
const int brightness_load = 8; // 0-15 while requesting data
char host[] = "ws.pusherapp.com";
const int port = 80;
char url[] = "/app/de504dc5763aeef9ff52";
WiFiClient client;
WebSocketClient ws;

unsigned long next_refresh = 0;
const int timeout_hard_threshold = 120000; // reconnect after 120sec
const int timeout_soft_threshold = 60000; // timeout default 60sec, send ping to check connection
boolean timeout_soft_sent_ping = false;
unsigned long timeout_next = 0;
unsigned long timeout_flashing_dot = 0;
unsigned int timeout_reconnect_count = 0;

LedControl lc = LedControl(D7, D8, D6, 1);
WiFiManager wifiManager;

HTTPClient http;
int last = 0;
int err = 0;


void setup() {
// start serial for debug output
Expand All @@ -33,27 +44,34 @@ void setup() {
// wakeup 7 segment display
lc.shutdown(0, false);
// set brightness
lc.setIntensity(0, brightness_full);
lc.setIntensity(0, 8);

// start with 8 dots
for (int i=0; i<8; i++) {
lc.setChar(0, i, ' ', true); // all spaces with dot
}
// clear all digits
setAll(' ', false, 0, 8);

// use 8 dots for startup animation
int i=7;

// set first dot... etc
lc.setChar(0, i--, ' ', true);
Serial.println("WIFI AUTO-CONFIG");

// autoconfiguration portal for wifi settings
wifiManager.setAPCallback(configModeCallback);
wifiManager.autoConnect();

// wifi setup finished
lc.setChar(0, i--, ' ', true);
Serial.println("WIFI DONE");

// MDNS
if (!MDNS.begin("esp8266")) {
Serial.println("MDNS ERROR!");
} else {
MDNS.addService("http", "tcp", 80);
Serial.println("mDNS UP");
}
MDNS.addService("http", "tcp", 80);
Serial.println("mDNS UP");
lc.setChar(0, i--, ' ', true);

// Arduino OTA
ArduinoOTA.onStart([]() {
Expand All @@ -63,73 +81,186 @@ void setup() {
Serial.println("OTA End");
});
ArduinoOTA.begin();
lc.setChar(0, i--, ' ', true);
Serial.println("OTA started");

connect(false);
}

void connect(boolean reconnect) {
int i=3;
timeout_soft_sent_ping = false;

if (reconnect) {
timeout_reconnect_count++;
if (timeout_reconnect_count > 2) reboot();
setAll(' ', true, 0, 8);
setAll(' ', false, 0, i);
}

// connect to the server
Serial.println("Client connecting...");
if (client.connect(host, 80)) {
Serial.println("WS Connected");
lc.setChar(0, i--, ' ', true);
} else {
Serial.println("WS Connection failed.");
reboot();
}

// set up websocket details
ws.path = url;
ws.host = host;
ws.protocol = "pusher";

// clear display
for (int i=0; i<8; i++) {
lc.setChar(0,i,' ',0);
if (ws.handshake(client)) {
Serial.println("WS Handshake successful");
lc.setChar(0, i--, ' ', true);
} else {
Serial.println("WS Handshake failed.");
reboot();
}

// subscribe to event channel "live_trades"
Serial.println("WS Subscribe");
ws.sendData("{\"event\": \"pusher:subscribe\", \"data\": {\"channel\": \"live_trades\"}}");
lc.setChar(0, i--, ' ', true);



// Finish setup, complete animation, set first timeout
setAll(' ', true, 0, 8);
timeout_next = millis() + timeout_hard_threshold;
Serial.println("All set up, waiting for first trade...");

Serial.println();
}

void loop() {
ArduinoOTA.handle();

if( (long)(millis() - next_refresh) >= 0)
{
setDashes();
setBrightnessLoading(true);
// check for hard timeout
if( (long)(millis() - timeout_next) >= 0) {
Serial.println();
Serial.println("TIMEOUT -> RECONNECT");
Serial.println();

connect(true);
}

// check for soft timeout (slow day?)
if(!timeout_soft_sent_ping && client.connected() && (long)(millis() - timeout_next + timeout_soft_threshold) >= 0) {
// ok, lets send a PING to check connection
Serial.println("soft timeout -> sending ping to server");
ws.sendData("", WS_OPCODE_PING);
timeout_soft_sent_ping = true;
}

Serial.print("REQUEST ");
Serial.println(url);
if(last && ((long)(millis() - timeout_flashing_dot) >= 0)) {
lc.setDigit(0, 0, (last%10), false);
}

if (client.connected()) {
String line;
uint8_t opcode = 0;

http.begin(url);
int code = http.GET();
Serial.println(code);
ws.getData(line, &opcode);

// check for PING packets, need to reply with PONG, else we get disconnected
if (opcode == WS_OPCODE_PING) {
Serial.println("GOT PING");
ws.sendData("{\"event\": \"pusher:pong\"", WS_OPCODE_PONG);
Serial.println("SENT PONG");
yield();
} else if (opcode == WS_OPCODE_PONG) {
Serial.println("GOT PONG, connection still active");
timeout_soft_sent_ping = false;
timeout_next = millis() + timeout_hard_threshold;
}

// check for data in received packet
if (line.length() > 0) {
#ifdef DEBUGGING
Serial.print("Received data: ");
Serial.println(data);
#endif

// parse JSON
StaticJsonBuffer<768> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(line);

// alright, check for trade events
if (root["event"] == "trade") {
timeout_next = millis() + timeout_hard_threshold;
Serial.print("GOT TRADE ");

// need to deserialize twice, data field is escaped
JsonObject& trade = jsonBuffer.parseObject(root["data"].as<const char*>());

if (!trade.success()) {
Serial.println("parse json failed");
return;
}
#ifdef DEBUGGING
trade.printTo(Serial);
#endif

// extract price
last = trade["price_str"]; // last USD btc

if (code == 200) {
String payload = http.getString();

DynamicJsonBuffer jsonBuffer(1100);
JsonObject& root = jsonBuffer.parseObject(payload);
JsonObject& bpi = root["bpi"];
JsonObject& bpi_USD = bpi["USD"];
int last = bpi_USD["rate_float"]; // last USD btc

Serial.print("last = ");
Serial.println(last);

Serial.print("price = ");
Serial.println(last);

} else {
Serial.println("Unknown Event occured");
Serial.println(root["event"].as<const char*>());
root.printTo(Serial);
Serial.println();
}


lc.setChar(0, 7, 'B',false); // b
lc.setRow (0, 6, B00001111); // t
lc.setChar(0, 5, 'C',false); // c

lc.setDigit(0, 3, (last/1000), false);

// this is gentlemen.
if (last >= 10000) {
lc.setDigit(0, 4, (last/10000), false);
} else {
lc.setChar(0, 4, ' ',false); //
}

lc.setDigit(0, 3, (last%10000)/1000, false);
lc.setDigit(0, 2, (last%1000)/100, false);
lc.setDigit(0, 1, (last%100)/10, false);
lc.setDigit(0, 0, (last%10), false);

setBrightnessLoading(false);
} else {
lc.setChar (0, 3, 'E', true);
lc.setDigit(0, 2, (code%1000)/100, false);
lc.setDigit(0, 1, (code%100)/10, false);
lc.setDigit(0, 0, (code%10), false);
}

http.end();
next_refresh = millis() + 30000;
lc.setDigit(0, 0, (last%10), true);

timeout_flashing_dot = millis() + 100;
}
} else {
Serial.println("Client disconnected.");
connect(true);
}


delay(20);
}

void setDashes (void) {
for (int i=0; i<4; i++) {
lc.setChar(0, i, '-', false);
void setAll(char c, boolean dot = false, int from = 0, int len = 4);
void setAll(char c, boolean dot, int from, int len) {
for (int i=from; i<len; i++) {
lc.setChar(0, i, c, dot);
}
}

void setBrightnessLoading(bool loading) {
lc.setIntensity(0, loading ? brightness_load : brightness_full);
void setDashes (int len = 4);
void setDashes (int len) {
setAll('-', false, 0, len);
}

void reboot (void) {
setDashes(8);
delay(1000);
ESP.reset();
}

void configModeCallback (WiFiManager *myWiFiManager) {
Expand Down

0 comments on commit 651fb69

Please sign in to comment.