LEDs and buttons working
This commit is contained in:
parent
4f2fbd8a36
commit
91fd921e2e
33 changed files with 3877 additions and 136 deletions
|
@ -1,8 +1,7 @@
|
|||
#include "block_notify.hpp"
|
||||
|
||||
const char *wsServer = "wss://mempool.space/api/v1/ws";
|
||||
// WebsocketsClient client;
|
||||
esp_websocket_client_handle_t client;
|
||||
char *wsServer;
|
||||
esp_websocket_client_handle_t blockNotifyClient = NULL;
|
||||
unsigned long int currentBlockHeight;
|
||||
|
||||
void setupBlockNotify()
|
||||
|
@ -36,15 +35,17 @@ void setupBlockNotify()
|
|||
xTaskNotifyGive(blockUpdateTaskHandle);
|
||||
}
|
||||
|
||||
// std::strcpy(wsServer, String("wss://" + mempoolInstance + "/api/v1/ws").c_str());
|
||||
|
||||
esp_websocket_client_config_t config = {
|
||||
.uri = "wss://mempool.bitcoin.nl/api/v1/ws",
|
||||
};
|
||||
|
||||
Serial.printf("Connecting to %s\r\n", config.uri);
|
||||
|
||||
client = esp_websocket_client_init(&config);
|
||||
esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY, onWebsocketEvent, client);
|
||||
esp_websocket_client_start(client);
|
||||
blockNotifyClient = esp_websocket_client_init(&config);
|
||||
esp_websocket_register_events(blockNotifyClient, WEBSOCKET_EVENT_ANY, onWebsocketEvent, blockNotifyClient);
|
||||
esp_websocket_client_start(blockNotifyClient);
|
||||
}
|
||||
|
||||
void onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
|
@ -58,7 +59,7 @@ void onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_i
|
|||
Serial.println("Connected to Mempool.space WebSocket");
|
||||
|
||||
sub = "{\"action\": \"want\", \"data\":[\"blocks\"]}";
|
||||
if (esp_websocket_client_send_text(client, sub.c_str(), sub.length(), portMAX_DELAY) == -1)
|
||||
if (esp_websocket_client_send_text(blockNotifyClient, sub.c_str(), sub.length(), portMAX_DELAY) == -1)
|
||||
{
|
||||
Serial.println("Mempool.space WS Block Subscribe Error");
|
||||
}
|
||||
|
@ -92,8 +93,10 @@ void onWebsocketMessage(esp_websocket_event_data_t *event_data)
|
|||
Serial.print("New block found: ");
|
||||
Serial.println(block["height"].as<long>());
|
||||
|
||||
if (blockUpdateTaskHandle != nullptr)
|
||||
if (blockUpdateTaskHandle != nullptr) {
|
||||
xTaskNotifyGive(blockUpdateTaskHandle);
|
||||
queueLedEffect(LED_FLASH_BLOCK_NOTIFY);
|
||||
}
|
||||
}
|
||||
|
||||
doc.clear();
|
||||
|
@ -102,4 +105,10 @@ void onWebsocketMessage(esp_websocket_event_data_t *event_data)
|
|||
unsigned long getBlockHeight()
|
||||
{
|
||||
return currentBlockHeight;
|
||||
}
|
||||
|
||||
bool isBlockNotifyConnected() {
|
||||
if (blockNotifyClient == NULL)
|
||||
return false;
|
||||
return esp_websocket_client_is_connected(blockNotifyClient);
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <Arduino.h>
|
||||
#include <HTTPClient.h>
|
||||
|
@ -8,6 +9,7 @@
|
|||
|
||||
#include "esp_websocket_client.h"
|
||||
#include "screen_handler.hpp"
|
||||
#include "led_handler.hpp"
|
||||
|
||||
//using namespace websockets;
|
||||
|
||||
|
@ -16,4 +18,5 @@ void setupBlockNotify();
|
|||
void onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data);
|
||||
void onWebsocketMessage(esp_websocket_event_data_t* event_data);
|
||||
|
||||
unsigned long getBlockHeight();
|
||||
unsigned long getBlockHeight();
|
||||
bool isBlockNotifyConnected();
|
||||
|
|
|
@ -18,22 +18,21 @@ void buttonTask(void *parameter)
|
|||
{
|
||||
uint pin = mcp.getLastInterruptPin();
|
||||
|
||||
Serial.printf("Button pressed: %d", pin);
|
||||
// switch (pin)
|
||||
// {
|
||||
// case 3:
|
||||
// toggleScreenTimer();
|
||||
// break;
|
||||
// case 2:
|
||||
// nextScreen();
|
||||
// break;
|
||||
// case 1:
|
||||
// previousScreen();
|
||||
// break;
|
||||
// case 0:
|
||||
// showNetworkSettings();
|
||||
// break;
|
||||
// }
|
||||
switch (pin)
|
||||
{
|
||||
case 3:
|
||||
toggleTimerActive();
|
||||
break;
|
||||
case 2:
|
||||
nextScreen();
|
||||
break;
|
||||
case 1:
|
||||
previousScreen();
|
||||
break;
|
||||
case 0:
|
||||
showSystemStatusScreen();
|
||||
break;
|
||||
}
|
||||
}
|
||||
mcp.clearInterrupts();
|
||||
// Very ugly, but for some reason this is necessary
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include "shared.hpp"
|
||||
#include "screen_handler.hpp"
|
||||
|
||||
extern TaskHandle_t buttonTaskHandle;
|
||||
|
||||
|
|
|
@ -1,27 +1,22 @@
|
|||
#include "config.hpp"
|
||||
|
||||
#ifndef NEOPIXEL_PIN
|
||||
#define NEOPIXEL_PIN 34
|
||||
#endif
|
||||
#ifndef NEOPIXEL_COUNT
|
||||
#define NEOPIXEL_COUNT 4
|
||||
#endif
|
||||
|
||||
|
||||
#define MAX_ATTEMPTS_WIFI_CONNECTION 20
|
||||
|
||||
Preferences preferences;
|
||||
Adafruit_MCP23X17 mcp;
|
||||
Adafruit_NeoPixel pixels(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
|
||||
std::map<int, std::string> screenNameMap;
|
||||
|
||||
void setup()
|
||||
{
|
||||
setupHardware();
|
||||
if (mcp.digitalRead(3) == LOW) {
|
||||
if (mcp.digitalRead(3) == LOW)
|
||||
{
|
||||
WiFi.eraseAP();
|
||||
blinkDelay(100, 3);
|
||||
}
|
||||
|
||||
|
||||
setupDisplays();
|
||||
tryImprovSetup();
|
||||
|
||||
|
@ -47,9 +42,9 @@ void tryImprovSetup()
|
|||
// blinkDelay(100, 3);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// WiFi.begin();
|
||||
// }
|
||||
{
|
||||
WiFi.begin();
|
||||
}
|
||||
|
||||
uint8_t x_buffer[16];
|
||||
uint8_t x_position = 0;
|
||||
|
@ -69,7 +64,8 @@ void tryImprovSetup()
|
|||
x_position = 0;
|
||||
}
|
||||
}
|
||||
// vTaskDelay(1);
|
||||
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,6 +87,15 @@ void setupTime()
|
|||
void setupPreferences()
|
||||
{
|
||||
preferences.begin("btclock", false);
|
||||
|
||||
setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
|
||||
setBgColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR));
|
||||
|
||||
screenNameMap = {{SCREEN_BLOCK_HEIGHT, "Block Height"},
|
||||
{SCREEN_MSCW_TIME, "Sats per dollar"},
|
||||
{SCREEN_BTC_TICKER, "Ticker"},
|
||||
{SCREEN_TIME, "Time"},
|
||||
{SCREEN_HALVING_COUNTDOWN, "Halving countdown"}};
|
||||
}
|
||||
|
||||
void setupWebsocketClients()
|
||||
|
@ -107,18 +112,16 @@ void setupTimers()
|
|||
|
||||
void finishSetup()
|
||||
{
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
clearLeds();
|
||||
}
|
||||
|
||||
std::map<int, std::string> getScreenNameMap() {
|
||||
return screenNameMap;
|
||||
}
|
||||
|
||||
void setupHardware()
|
||||
{
|
||||
pixels.begin();
|
||||
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(1, pixels.Color(0, 255, 0));
|
||||
pixels.setPixelColor(2, pixels.Color(0, 0, 255));
|
||||
pixels.setPixelColor(3, pixels.Color(255, 255, 255));
|
||||
pixels.show();
|
||||
setupLeds();
|
||||
|
||||
if (psramInit())
|
||||
{
|
||||
|
@ -129,7 +132,6 @@ void setupHardware()
|
|||
Serial.println(F("PSRAM not available"));
|
||||
}
|
||||
|
||||
|
||||
Wire.begin(35, 36, 400000);
|
||||
|
||||
if (!mcp.begin_I2C(0x20))
|
||||
|
@ -153,7 +155,6 @@ void setupHardware()
|
|||
{
|
||||
mcp.pinMode(i, OUTPUT);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,41 +195,20 @@ bool improv_connectWifi(std::string ssid, std::string password)
|
|||
return true;
|
||||
}
|
||||
|
||||
void blinkDelay(int d, int times)
|
||||
{
|
||||
for (int j = 0; j < times; j++)
|
||||
{
|
||||
|
||||
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(1, pixels.Color(0, 255, 0));
|
||||
pixels.setPixelColor(2, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(3, pixels.Color(0, 255, 0));
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
|
||||
pixels.setPixelColor(0, pixels.Color(255, 255, 0));
|
||||
pixels.setPixelColor(1, pixels.Color(0, 255, 255));
|
||||
pixels.setPixelColor(2, pixels.Color(255, 255, 0));
|
||||
pixels.setPixelColor(3, pixels.Color(0, 255, 255));
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
}
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void onImprovErrorCallback(improv::Error err)
|
||||
{
|
||||
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(1, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(2, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(3, pixels.Color(255, 0, 0));
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
blinkDelayColor(100, 1, 255,0,0);
|
||||
// pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
||||
// pixels.setPixelColor(1, pixels.Color(255, 0, 0));
|
||||
// pixels.setPixelColor(2, pixels.Color(255, 0, 0));
|
||||
// pixels.setPixelColor(3, pixels.Color(255, 0, 0));
|
||||
// pixels.show();
|
||||
// vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
// pixels.clear();
|
||||
// pixels.show();
|
||||
// vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
std::vector<std::string> getLocalUrl()
|
||||
|
@ -272,7 +252,7 @@ bool onImprovCommandCallback(improv::ImprovCommand cmd)
|
|||
|
||||
if (improv_connectWifi(cmd.ssid, cmd.password))
|
||||
{
|
||||
|
||||
|
||||
blinkDelay(100, 3);
|
||||
// std::array<String, NUM_SCREENS> epdContent = {"S", "U", "C", "C", "E", "S", "S"};
|
||||
// setEpdContent(epdContent);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include <WiFiClientSecure.h>
|
||||
#include <Preferences.h>
|
||||
#include <Adafruit_MCP23X17.h>
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
|
||||
#include "shared.hpp"
|
||||
#include <esp_system.h>
|
||||
|
@ -16,6 +15,7 @@
|
|||
#include "lib/block_notify.hpp"
|
||||
#include "lib/price_notify.hpp"
|
||||
#include "lib/button_handler.hpp"
|
||||
#include "lib/led_handler.hpp"
|
||||
|
||||
#define NTP_SERVER "pool.ntp.org"
|
||||
#define DEFAULT_MEMPOOL_INSTANCE "mempool.space"
|
||||
|
@ -23,6 +23,9 @@
|
|||
#define USER_AGENT "BTClock/2.0"
|
||||
#define MCP_DEV_ADDR 0x20
|
||||
|
||||
#define DEFAULT_FG_COLOR GxEPD_WHITE
|
||||
#define DEFAULT_BG_COLOR GxEPD_BLACK
|
||||
|
||||
#define BITCOIND_HOST ""
|
||||
#define BITCOIND_PORT 8332
|
||||
#define BITCOIND_RPC_USER ""
|
||||
|
@ -36,6 +39,7 @@ void setupHardware();
|
|||
void tryImprovSetup();
|
||||
void setupTimers();
|
||||
void finishSetup();
|
||||
std::map<int, std::string> getScreenNameMap();
|
||||
|
||||
std::vector<std::string> getLocalUrl();
|
||||
bool improv_connectWifi(std::string ssid, std::string password);
|
||||
|
@ -45,4 +49,3 @@ void onImprovErrorCallback(improv::Error err);
|
|||
void improv_set_state(improv::State state);
|
||||
void improv_send_response(std::vector<uint8_t> &response);
|
||||
void improv_set_error(improv::Error error);
|
||||
void blinkDelay(int d, int times);
|
|
@ -76,7 +76,7 @@ void setupDisplays()
|
|||
int *taskParam = new int;
|
||||
*taskParam = i;
|
||||
|
||||
xTaskCreate(updateDisplay, "EpdUpd" + char(i), 4096, taskParam, 1, &tasks[i]); // create task
|
||||
xTaskCreate(updateDisplay, "EpdUpd" + char(i), 4096, taskParam, tskIDLE_PRIORITY, &tasks[i]); // create task
|
||||
}
|
||||
|
||||
epdContent = {"B",
|
||||
|
@ -91,7 +91,7 @@ void setupDisplays()
|
|||
xTaskNotifyGive(tasks[i]);
|
||||
}
|
||||
|
||||
xTaskCreate(taskEpd, "epd_task", 2048, NULL, 1, NULL);
|
||||
xTaskCreate(taskEpd, "epd_task", 2048, NULL, tskIDLE_PRIORITY, NULL);
|
||||
}
|
||||
|
||||
void taskEpd(void *pvParameters)
|
||||
|
|
|
@ -1,18 +1,216 @@
|
|||
#include "led_handler.hpp"
|
||||
|
||||
TaskHandle_t ledTaskHandle = NULL;
|
||||
QueueHandle_t ledTaskQueue = NULL;
|
||||
Adafruit_NeoPixel pixels(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
const TickType_t debounceDelay = pdMS_TO_TICKS(50);
|
||||
uint32_t notificationValue;
|
||||
unsigned long ledTaskParams;
|
||||
|
||||
void ledTask(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if (ledTaskQueue != NULL)
|
||||
{
|
||||
if (xQueueReceive(ledTaskQueue, &ledTaskParams, portMAX_DELAY) == pdPASS)
|
||||
{
|
||||
uint32_t oldLights[NEOPIXEL_COUNT];
|
||||
|
||||
// get current state
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++)
|
||||
{
|
||||
oldLights[i] = pixels.getPixelColor(i);
|
||||
}
|
||||
|
||||
switch (ledTaskParams)
|
||||
{
|
||||
case LED_FLASH_ERROR:
|
||||
blinkDelayColor(250, 3, 255, 0, 0);
|
||||
break;
|
||||
case LED_FLASH_SUCCESS:
|
||||
blinkDelayColor(250, 3, 0, 255, 0);
|
||||
break;
|
||||
case LED_FLASH_UPDATE:
|
||||
break;
|
||||
case LED_FLASH_BLOCK_NOTIFY:
|
||||
blinkDelayTwoColor(250, 3, pixels.Color(224, 67, 0), pixels.Color(8, 2, 0));
|
||||
break;
|
||||
case LED_EFFECT_PAUSE_TIMER:
|
||||
for (int i = NEOPIXEL_COUNT; i >= 0; i--)
|
||||
{
|
||||
for (int j = NEOPIXEL_COUNT; j >= 0; j--)
|
||||
{
|
||||
uint32_t c = pixels.Color(0, 0, 0);
|
||||
if (i == j)
|
||||
c = pixels.Color(0, 255, 0);
|
||||
pixels.setPixelColor(j, c);
|
||||
}
|
||||
|
||||
pixels.show();
|
||||
|
||||
delay(100);
|
||||
}
|
||||
|
||||
delay(900);
|
||||
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
break;
|
||||
case LED_EFFECT_START_TIMER:
|
||||
pixels.clear();
|
||||
pixels.setPixelColor(NEOPIXEL_COUNT, pixels.Color(0, 255, 0));
|
||||
pixels.show();
|
||||
|
||||
delay(900);
|
||||
|
||||
for (int i = NEOPIXEL_COUNT; i--; i > 0)
|
||||
{
|
||||
|
||||
for (int j = NEOPIXEL_COUNT; j--; j > 0)
|
||||
{
|
||||
uint32_t c = pixels.Color(0, 0, 0);
|
||||
if (i == j)
|
||||
c = pixels.Color(0, 255, 0);
|
||||
|
||||
pixels.setPixelColor(j, c);
|
||||
}
|
||||
|
||||
pixels.show();
|
||||
|
||||
delay(100);
|
||||
}
|
||||
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
break;
|
||||
}
|
||||
|
||||
// revert to previous state
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++)
|
||||
{
|
||||
pixels.setPixelColor(i, oldLights[i]);
|
||||
}
|
||||
|
||||
pixels.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setupLeds()
|
||||
{
|
||||
pixels.begin();
|
||||
pixels.setBrightness(preferences.getUInt("ledBrightness", 128));
|
||||
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(1, pixels.Color(0, 255, 0));
|
||||
pixels.setPixelColor(2, pixels.Color(0, 0, 255));
|
||||
pixels.setPixelColor(3, pixels.Color(255, 255, 255));
|
||||
pixels.show();
|
||||
setupLedTask();
|
||||
}
|
||||
|
||||
void setupLedTask()
|
||||
{
|
||||
xTaskCreate(ledTask, "LedTask", 4096, NULL, tskIDLE_PRIORITY, &ledTaskHandle); // Create the FreeRTOS task
|
||||
ledTaskQueue = xQueueCreate(10, sizeof(unsigned long));
|
||||
|
||||
xTaskCreate(ledTask, "LedTask", 4096, NULL, tskIDLE_PRIORITY, &ledTaskHandle);
|
||||
}
|
||||
|
||||
void blinkDelay(int d, int times)
|
||||
{
|
||||
for (int j = 0; j < times; j++)
|
||||
{
|
||||
|
||||
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(1, pixels.Color(0, 255, 0));
|
||||
pixels.setPixelColor(2, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(3, pixels.Color(0, 255, 0));
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
|
||||
pixels.setPixelColor(0, pixels.Color(255, 255, 0));
|
||||
pixels.setPixelColor(1, pixels.Color(0, 255, 255));
|
||||
pixels.setPixelColor(2, pixels.Color(255, 255, 0));
|
||||
pixels.setPixelColor(3, pixels.Color(0, 255, 255));
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
}
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void blinkDelayColor(int d, int times, uint r, uint g, uint b)
|
||||
{
|
||||
for (int j = 0; j < times; j++)
|
||||
{
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++)
|
||||
{
|
||||
pixels.setPixelColor(i, pixels.Color(r, g, b));
|
||||
}
|
||||
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
}
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void blinkDelayTwoColor(int d, int times, uint32_t c1, uint32_t c2)
|
||||
{
|
||||
for (int j = 0; j < times; j++)
|
||||
{
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++)
|
||||
{
|
||||
pixels.setPixelColor(i, c1);
|
||||
}
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++)
|
||||
{
|
||||
pixels.setPixelColor(i, c2);
|
||||
}
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
}
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void clearLeds()
|
||||
{
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void setLights(int r, int g, int b)
|
||||
{
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++)
|
||||
{
|
||||
pixels.setPixelColor(i, pixels.Color(r, g, b));
|
||||
}
|
||||
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
QueueHandle_t getLedTaskQueue()
|
||||
{
|
||||
return ledTaskQueue;
|
||||
}
|
||||
|
||||
bool queueLedEffect(uint effect)
|
||||
{
|
||||
if (ledTaskQueue == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long flashType = effect;
|
||||
xQueueSend(ledTaskQueue, &flashType, portMAX_DELAY);
|
||||
}
|
|
@ -6,7 +6,33 @@
|
|||
#include <Adafruit_NeoPixel.h>
|
||||
#include "shared.hpp"
|
||||
|
||||
#ifndef NEOPIXEL_PIN
|
||||
#define NEOPIXEL_PIN 34
|
||||
#endif
|
||||
#ifndef NEOPIXEL_COUNT
|
||||
#define NEOPIXEL_COUNT 4
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int flashType;
|
||||
} LedTaskParameters;
|
||||
|
||||
const int LED_FLASH_ERROR = 0;
|
||||
const int LED_FLASH_SUCCESS = 1;
|
||||
const int LED_FLASH_UPDATE = 2;
|
||||
const int LED_FLASH_BLOCK_NOTIFY = 3;
|
||||
const int LED_EFFECT_START_TIMER = 4;
|
||||
const int LED_EFFECT_PAUSE_TIMER = 5;
|
||||
|
||||
extern TaskHandle_t ledTaskHandle;
|
||||
|
||||
void ledTask(void *pvParameters);
|
||||
void setupLeds();
|
||||
void setupLedTask();
|
||||
void blinkDelay(int d, int times);
|
||||
void blinkDelayColor(int d, int times, uint r, uint g, uint b);
|
||||
void blinkDelayTwoColor(int d, int times, uint32_t c1, uint32_t c2);
|
||||
void clearLeds();
|
||||
QueueHandle_t getLedTaskQueue();
|
||||
bool queueLedEffect(uint effect);
|
||||
void setLights(int r, int g, int b);
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin";
|
||||
// WebsocketsClient client;
|
||||
esp_websocket_client_handle_t clientPrice;
|
||||
esp_websocket_client_handle_t clientPrice = NULL;
|
||||
unsigned long int currentPrice;
|
||||
|
||||
void setupPriceNotify()
|
||||
|
@ -46,7 +46,6 @@ void onWebsocketPriceMessage(esp_websocket_event_data_t* event_data)
|
|||
|
||||
if (doc.containsKey("bitcoin")) {
|
||||
if (currentPrice != doc["bitcoin"].as<long>()) {
|
||||
// Serial.printf("New price %lu\r\n", currentPrice);
|
||||
|
||||
const unsigned long oldPrice = currentPrice;
|
||||
currentPrice = doc["bitcoin"].as<long>();
|
||||
|
@ -61,4 +60,10 @@ void onWebsocketPriceMessage(esp_websocket_event_data_t* event_data)
|
|||
|
||||
unsigned long getPrice() {
|
||||
return currentPrice;
|
||||
}
|
||||
|
||||
bool isPriceNotifyConnected() {
|
||||
if (clientPrice == NULL)
|
||||
return false;
|
||||
return esp_websocket_client_is_connected(clientPrice);
|
||||
}
|
|
@ -14,4 +14,5 @@ void setupPriceNotify();
|
|||
void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data);
|
||||
void onWebsocketPriceMessage(esp_websocket_event_data_t* event_data);
|
||||
|
||||
unsigned long getPrice();
|
||||
unsigned long getPrice();
|
||||
bool isPriceNotifyConnected();
|
|
@ -61,7 +61,16 @@ void taskScreenRotate(void *pvParameters)
|
|||
{
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
setCurrentScreen((currentScreen+1) % 5);
|
||||
int nextScreen = (currentScreen+ 1) % 5;
|
||||
String key = "screen" + String(nextScreen) + "Visible";
|
||||
|
||||
while (!preferences.getBool(key.c_str(), true))
|
||||
{
|
||||
nextScreen = (nextScreen + 1) % 5;
|
||||
key = "screen" + String(nextScreen) + "Visible";
|
||||
}
|
||||
|
||||
setCurrentScreen(nextScreen);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,20 +152,6 @@ void taskTimeUpdate(void *pvParameters)
|
|||
}
|
||||
}
|
||||
|
||||
const char* int64_to_iso8601(int64_t timestamp) {
|
||||
time_t seconds = timestamp / 1000000; // Convert microseconds to seconds
|
||||
struct tm timeinfo;
|
||||
gmtime_r(&seconds, &timeinfo);
|
||||
|
||||
// Define a buffer to store the formatted time string
|
||||
static char iso8601[21]; // ISO 8601 time string has the format "YYYY-MM-DDTHH:MM:SSZ"
|
||||
|
||||
// Format the time into the buffer
|
||||
strftime(iso8601, sizeof(iso8601), "%Y-%m-%dT%H:%M:%SZ", &timeinfo);
|
||||
|
||||
return iso8601;
|
||||
}
|
||||
|
||||
void IRAM_ATTR minuteTimerISR(void *arg)
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
@ -217,11 +212,8 @@ void setupScreenRotateTimer(void *pvParameters)
|
|||
.name = "screen_rotate_timer"};
|
||||
|
||||
esp_timer_create(&screenRotateTimerConfig, &screenRotateTimer);
|
||||
|
||||
esp_timer_start_periodic(screenRotateTimer, getTimerSeconds() * usPerSecond);
|
||||
|
||||
Serial.println("Set up Screen Rotate Timer");
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
|
@ -240,13 +232,19 @@ void setTimerActive(bool status)
|
|||
if (status)
|
||||
{
|
||||
esp_timer_start_periodic(screenRotateTimer, getTimerSeconds() * usPerSecond);
|
||||
queueLedEffect(LED_EFFECT_START_TIMER);
|
||||
}
|
||||
else
|
||||
{
|
||||
esp_timer_stop(screenRotateTimer);
|
||||
queueLedEffect(LED_EFFECT_PAUSE_TIMER);
|
||||
}
|
||||
}
|
||||
|
||||
void toggleTimerActive() {
|
||||
setTimerActive(!isTimerActive());
|
||||
}
|
||||
|
||||
uint getCurrentScreen()
|
||||
{
|
||||
return currentScreen;
|
||||
|
@ -275,4 +273,56 @@ void setCurrentScreen(uint newScreen)
|
|||
xTaskNotifyGive(priceUpdateTaskHandle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void nextScreen()
|
||||
{
|
||||
int newCurrentScreen = (getCurrentScreen() + 1) % SCREEN_COUNT;
|
||||
String key = "screen" + String(newCurrentScreen) + "Visible";
|
||||
|
||||
while (!preferences.getBool(key.c_str(), true))
|
||||
{
|
||||
newCurrentScreen = (newCurrentScreen + 1) % SCREEN_COUNT;
|
||||
key = "screen" + String(newCurrentScreen) + "Visible";
|
||||
}
|
||||
setCurrentScreen(newCurrentScreen);
|
||||
}
|
||||
|
||||
void previousScreen()
|
||||
{
|
||||
int newCurrentScreen = modulo(getCurrentScreen() - 1, SCREEN_COUNT);
|
||||
String key = "screen" + String(newCurrentScreen) + "Visible";
|
||||
|
||||
while (!preferences.getBool(key.c_str(), true))
|
||||
{
|
||||
newCurrentScreen = modulo(newCurrentScreen - 1, SCREEN_COUNT);
|
||||
key = "screen" + String(newCurrentScreen) + "Visible";
|
||||
}
|
||||
setCurrentScreen(newCurrentScreen);
|
||||
}
|
||||
|
||||
void showSystemStatusScreen()
|
||||
{
|
||||
std::array<String, NUM_SCREENS> sysStatusEpdContent = {"", "", "", "", "", "", ""};
|
||||
|
||||
String ipAddr = WiFi.localIP().toString();
|
||||
String subNet = WiFi.subnetMask().toString();
|
||||
|
||||
sysStatusEpdContent[0] = "IP/Subnet";
|
||||
|
||||
int ipAddrPos = 0;
|
||||
int subnetPos = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
sysStatusEpdContent[1 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) + "/" + subNet.substring(0, subNet.indexOf('.'));
|
||||
ipAddrPos = ipAddr.indexOf('.') + 1;
|
||||
subnetPos = subNet.indexOf('.') + 1;
|
||||
ipAddr = ipAddr.substring(ipAddrPos);
|
||||
subNet = subNet.substring(subnetPos);
|
||||
}
|
||||
sysStatusEpdContent[NUM_SCREENS-2] = "RAM/Status";
|
||||
|
||||
sysStatusEpdContent[NUM_SCREENS-1] = String((int)round(ESP.getFreeHeap()/1024)) + "/" + (int)round(ESP.getHeapSize()/1024);
|
||||
setCurrentScreen(SCREEN_CUSTOM);
|
||||
setEpdContent(sysStatusEpdContent);
|
||||
}
|
|
@ -16,6 +16,10 @@ extern TaskHandle_t taskScreenRotateTaskHandle;
|
|||
|
||||
uint getCurrentScreen();
|
||||
void setCurrentScreen(uint newScreen);
|
||||
void nextScreen();
|
||||
void previousScreen();
|
||||
|
||||
void showSystemStatusScreen();
|
||||
|
||||
void setupTimeUpdateTimer(void *pvParameters);
|
||||
void setupScreenRotateTimer(void *pvParameters);
|
||||
|
@ -31,7 +35,6 @@ void taskScreenRotate(void *pvParameters);
|
|||
uint getTimerSeconds();
|
||||
bool isTimerActive();
|
||||
void setTimerActive(bool status);
|
||||
|
||||
void toggleTimerActive();
|
||||
|
||||
void setupTasks();
|
||||
const char* int64_to_iso8601(int64_t timestamp);
|
|
@ -3,6 +3,7 @@
|
|||
#include <Adafruit_MCP23X17.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <Preferences.h>
|
||||
#include "utils.hpp"
|
||||
|
||||
extern Adafruit_MCP23X17 mcp;
|
||||
extern Preferences preferences;
|
||||
|
@ -15,6 +16,7 @@ const PROGMEM int SCREEN_HALVING_COUNTDOWN = 4;
|
|||
const PROGMEM int SCREEN_COUNTDOWN = 98;
|
||||
const PROGMEM int SCREEN_CUSTOM = 99;
|
||||
const PROGMEM int screens[5] = { SCREEN_BLOCK_HEIGHT, SCREEN_MSCW_TIME, SCREEN_BTC_TICKER, SCREEN_TIME, SCREEN_HALVING_COUNTDOWN };
|
||||
const int SCREEN_COUNT = 5;
|
||||
|
||||
struct SpiRamAllocator {
|
||||
void* allocate(size_t size) {
|
||||
|
|
6
src/lib/utils.cpp
Normal file
6
src/lib/utils.cpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include "utils.hpp"
|
||||
|
||||
int modulo(int x, int N)
|
||||
{
|
||||
return (x % N + N) % N;
|
||||
}
|
1
src/lib/utils.hpp
Normal file
1
src/lib/utils.hpp
Normal file
|
@ -0,0 +1 @@
|
|||
int modulo(int x,int N);
|
|
@ -28,6 +28,10 @@ void setupWebserver()
|
|||
server.on("/api/show/screen", HTTP_GET, onApiShowScreen);
|
||||
server.on("/api/show/text", HTTP_GET, onApiShowText);
|
||||
|
||||
server.on("/api/lights/off", HTTP_GET, onApiLightsOff);
|
||||
server.on("/api/lights/color", HTTP_GET, onApiLightsSetColor);
|
||||
server.on("^\\/api\\/lights\\/([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", HTTP_GET, onApiLightsSetColor);
|
||||
|
||||
server.on("/api/restart", HTTP_GET, onApiRestart);
|
||||
|
||||
server.addRewrite(new OneParamRewrite("/api/show/screen/{s}", "/api/show/screen?s={s}"));
|
||||
|
@ -59,6 +63,10 @@ void onApiStatus(AsyncWebServerRequest *request)
|
|||
root["espFreePsram"] = ESP.getFreePsram();
|
||||
root["espPsramSize"] = ESP.getPsramSize();
|
||||
|
||||
JsonObject conStatus = root.createNestedObject("connectionStatus");
|
||||
conStatus["price"] = isPriceNotifyConnected();
|
||||
conStatus["blocks"] = isBlockNotifyConnected();
|
||||
|
||||
JsonArray data = root.createNestedArray("data");
|
||||
JsonArray rendered = root.createNestedArray("rendered");
|
||||
String epdContent[NUM_SCREENS];
|
||||
|
@ -170,14 +178,16 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
|||
#endif
|
||||
JsonArray screens = root.createNestedArray("screens");
|
||||
|
||||
// for (int i = 0; i < screenNameMap.size(); i++)
|
||||
// {
|
||||
// JsonObject o = screens.createNestedObject();
|
||||
// String key = "screen" + String(i) + "Visible";
|
||||
// o["id"] = i;
|
||||
// o["name"] = screenNameMap[i];
|
||||
// o["enabled"] = preferences.getBool(key.c_str(), true);
|
||||
// }
|
||||
std::map<int, std::string> screenNameMap = getScreenNameMap();
|
||||
|
||||
for (int i = 0; i < screenNameMap.size(); i++)
|
||||
{
|
||||
JsonObject o = screens.createNestedObject();
|
||||
String key = "screen" + String(i) + "Visible";
|
||||
o["id"] = i;
|
||||
o["name"] = screenNameMap[i];
|
||||
o["enabled"] = preferences.getBool(key.c_str(), true);
|
||||
}
|
||||
|
||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||
serializeJson(root, *response);
|
||||
|
@ -274,21 +284,23 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
|
|||
settingsChanged = true;
|
||||
}
|
||||
|
||||
// for (int i = 0; i < screenNameMap.size(); i++)
|
||||
// {
|
||||
// String key = "screen[" + String(i) + "]";
|
||||
// String prefKey = "screen" + String(i) + "Visible";
|
||||
// bool visible = false;
|
||||
// if (request->hasParam(key, true))
|
||||
// {
|
||||
// AsyncWebParameter *screenParam = request->getParam(key, true);
|
||||
// visible = screenParam->value().toInt();
|
||||
// }
|
||||
// Serial.print("Setting screen " + String(i) + " to ");
|
||||
// Serial.println(visible);
|
||||
std::map<int, std::string> screenNameMap = getScreenNameMap();
|
||||
|
||||
// preferences.putBool(prefKey.c_str(), visible);
|
||||
// }
|
||||
for (int i = 0; i < screenNameMap.size(); i++)
|
||||
{
|
||||
String key = "screen[" + String(i) + "]";
|
||||
String prefKey = "screen" + String(i) + "Visible";
|
||||
bool visible = false;
|
||||
if (request->hasParam(key, true))
|
||||
{
|
||||
AsyncWebParameter *screenParam = request->getParam(key, true);
|
||||
visible = screenParam->value().toInt();
|
||||
}
|
||||
Serial.print("Setting screen " + String(i) + " to ");
|
||||
Serial.println(visible);
|
||||
|
||||
preferences.putBool(prefKey.c_str(), visible);
|
||||
}
|
||||
|
||||
if (request->hasParam("tzOffset", true))
|
||||
{
|
||||
|
@ -339,7 +351,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
|
|||
request->send(200);
|
||||
if (settingsChanged)
|
||||
{
|
||||
//flashTemporaryLights(0, 255, 0);
|
||||
queueLedEffect(LED_FLASH_SUCCESS);
|
||||
|
||||
Serial.println(F("Settings changed"));
|
||||
}
|
||||
|
@ -361,6 +373,22 @@ void onApiSystemStatus(AsyncWebServerRequest *request)
|
|||
request->send(response);
|
||||
}
|
||||
|
||||
void onApiLightsOff(AsyncWebServerRequest *request)
|
||||
{
|
||||
setLights(0, 0, 0);
|
||||
request->send(200);
|
||||
}
|
||||
|
||||
void onApiLightsSetColor(AsyncWebServerRequest *request)
|
||||
{
|
||||
String rgbColor = request->pathArg(0);
|
||||
uint r, g, b;
|
||||
sscanf(rgbColor.c_str(), "%02x%02x%02x", &r, &g, &b);
|
||||
setLights(r, g, b);
|
||||
request->send(200, "text/plain", rgbColor);
|
||||
}
|
||||
|
||||
|
||||
void onIndex(AsyncWebServerRequest *request) { request->send(LittleFS, "/index.html", String(), false); }
|
||||
|
||||
void onNotFound(AsyncWebServerRequest *request)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "lib/block_notify.hpp"
|
||||
#include "lib/price_notify.hpp"
|
||||
#include "lib/screen_handler.hpp"
|
||||
|
||||
#include "lib/led_handler.hpp"
|
||||
|
||||
#include "webserver/OneParamRewrite.hpp"
|
||||
|
||||
|
@ -25,6 +25,10 @@ void onApiActionTimerRestart(AsyncWebServerRequest *request);
|
|||
void onApiSettingsGet(AsyncWebServerRequest *request);
|
||||
void onApiSettingsPost(AsyncWebServerRequest *request);
|
||||
|
||||
void onApiLightsOff(AsyncWebServerRequest *request);
|
||||
void onApiLightsSetColor(AsyncWebServerRequest *request);
|
||||
|
||||
|
||||
void onApiRestart(AsyncWebServerRequest *request);
|
||||
|
||||
void onIndex(AsyncWebServerRequest *request);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue