Add zap notify functionality

This commit is contained in:
Djuri 2024-08-24 16:27:55 +03:00
parent 99e622eeef
commit e39a0ccc14
13 changed files with 506 additions and 78 deletions

View file

@ -72,12 +72,13 @@ void setup()
setupTasks();
setupTimers();
if (preferences.getBool("useNostr", DEFAULT_USE_NOSTR))
if (preferences.getBool("useNostr", DEFAULT_USE_NOSTR) || preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED))
{
setupNostrNotify();
setupNostrTask();
}
else
if (!preferences.getBool("useNostr", DEFAULT_USE_NOSTR))
{
xTaskCreate(setupWebsocketClients, "setupWebsocketClients", 8192, NULL,
tskIDLE_PRIORITY, NULL);

View file

@ -24,7 +24,7 @@
#define DEFAULT_USE_NOSTR false
#define DEFAULT_NOSTR_NPUB "642317135fd4c4205323b9dea8af3270657e62d51dc31a657c0ec8aab31c6288"
#define DEFAULT_NOSTR_RELAY "wss://nostr.dbtc.link"
#define DEFAULT_NOSTR_RELAY "wss://relay.primal.net"
#define DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE 30
#define DEFAULT_MINUTES_FULL_REFRESH 60
@ -49,3 +49,5 @@
#define DEFAULT_BITAXE_ENABLED false
#define DEFAULT_BITAXE_HOSTNAME "bitaxe1"
#define DEFAULT_ZAP_NOTIFY_ENABLED false
#define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422"

View file

@ -531,6 +531,10 @@ void renderIcon(const uint dispNum, const String &text, bool partial)
iconIndex = 1;
}
if (text.endsWith("lnbolt")) {
iconIndex = 2;
}
displays[dispNum].drawInvertedBitmap(0,0, epd_icons_allArray[iconIndex], 122, 250, getFgColor());
}

View file

@ -221,9 +221,9 @@ void ledTask(void *parameter)
{
oldLights[i] = pixels.getPixelColor(i);
}
#ifdef HAS_FRONTLIGHT
#ifdef HAS_FRONTLIGHT
uint flDelayTime = preferences.getUInt("flEffectDelay");
#endif
#endif
switch (ledTaskParams)
{
case LED_POWER_TEST:
@ -269,6 +269,43 @@ void ledTask(void *parameter)
pixels.setPixelColor(3, pixels.Color(0, 255, 0));
pixels.show();
break;
case LED_EFFECT_NOSTR_ZAP:
{
#ifdef HAS_FRONTLIGHT
bool frontlightWasOn = false;
if (preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE))
{
if (frontlightOn)
{
frontlightWasOn = true;
frontlightFadeOutAll(flDelayTime, true);
}
else
{
frontlightFadeInAll(flDelayTime, true);
}
}
#endif
blinkDelayColor(250, 3, 142, 48, 235);
// blinkDelayTwoColor(250, 3, pixels.Color(142, 48, 235),
// pixels.Color(169, 21, 255));
#ifdef HAS_FRONTLIGHT
if (preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE))
{
vTaskDelay(pdMS_TO_TICKS(10));
if (frontlightWasOn)
{
frontlightFadeInAll(flDelayTime, true);
}
else
{
frontlightFadeOutAll(flDelayTime, true);
}
}
#endif
break;
}
case LED_FLASH_UPDATE:
break;
case LED_FLASH_BLOCK_NOTIFY:

View file

@ -28,6 +28,7 @@ const int LED_EFFECT_WIFI_CONNECT_ERROR = 102;
const int LED_EFFECT_WIFI_CONNECT_SUCCESS = 103;
const int LED_EFFECT_WIFI_ERASE_SETTINGS = 104;
const int LED_PROGRESS_25 = 200;
const int LED_PROGRESS_50 = 201;
const int LED_PROGRESS_75 = 202;
@ -35,6 +36,9 @@ const int LED_PROGRESS_100 = 203;
const int LED_DATA_PRICE_ERROR = 300;
const int LED_DATA_BLOCK_ERROR = 301;
const int LED_EFFECT_NOSTR_ZAP = 400;
const int LED_FLASH_IDENTIFY = 990;
const int LED_POWER_TEST = 999;
extern TaskHandle_t ledTaskHandle;

View file

@ -22,71 +22,33 @@ void setupNostrNotify()
String relay = preferences.getString("nostrRelay");
String pubKey = preferences.getString("nostrPubKey");
pools.push_back(pool);
// JsonArray filter = {
// {"kinds", {"1"}},
// {"since", {String(timestamp60MinutesAgo)}},
// {"authors", {pubKey}},
// };
// { "kinds", {"9735"}, {"limit",{"1"},
// {"#p", {"b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422"} },
// Lets subscribe to the relay
String subId = pool->subscribeMany(
{relay},
{{// we set the filters here (see
// https://github.com/nostr-protocol/nips/blob/master/01.md#from-client-to-relay-sending-events-and-creating-subscriptions)
{"kinds", {"1"}},
{"since", {String(timestamp60MinutesAgo)}},
{"authors", {pubKey}}}},
[&](const String &subId, nostr::SignedNostrEvent *event)
{
// Received events callback, we can access the event content with
// event->getContent() Here you should handle the event, for this
// test we will just serialize it and print to console
JsonDocument doc;
JsonArray arr = doc["data"].to<JsonArray>();
event->toSendableEvent(arr);
// Access the second element which is the object
JsonObject obj = arr[1].as<JsonObject>();
// Access the "tags" array
JsonArray tags = obj["tags"].as<JsonArray>();
// Flag to check if the tag was found
bool tagFound = false;
uint medianFee = 0;
String typeValue;
// Iterate over the tags array
for (JsonArray tag : tags)
{
// Check if the tag is an array with two elements
if (tag.size() == 2)
{
const char *key = tag[0];
const char *value = tag[1];
// Check if the key is "type" and the value is "priceUsd"
if (strcmp(key, "type") == 0 && (strcmp(value, "priceUsd") == 0 || strcmp(value, "blockHeight") == 0))
{
typeValue = value;
tagFound = true;
}
else if (strcmp(key, "medianFee") == 0)
{
medianFee = tag[1].as<uint>();
}
}
}
if (tagFound)
{
if (typeValue.equals("priceUsd"))
{
processNewPrice(obj["content"].as<uint>());
}
else if (typeValue.equals("blockHeight"))
{
processNewBlock(obj["content"].as<uint>());
}
if (medianFee != 0)
{
processNewBlockFee(medianFee);
}
}
},
{// First filter
{
{"kinds", {"9735"}},
{"limit", {"1"}},
{"since", {String(timestamp60MinutesAgo)}},
{"#p", {preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY)}},
},
// Second filter
{
{"kinds", {"1"}},
{"since", {String(timestamp60MinutesAgo)}},
{"authors", {pubKey}},
}},
handleNostrEventCallback,
[&](const String &subId, const String &reason)
{
// This is the callback that will be called when the subscription is
@ -150,4 +112,109 @@ void setupNostrTask()
boolean nostrConnected()
{
return nostrIsConnected;
}
void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *event)
{
// Received events callback, we can access the event content with
// event->getContent() Here you should handle the event, for this
// test we will just serialize it and print to console
JsonDocument doc;
JsonArray arr = doc["data"].to<JsonArray>();
event->toSendableEvent(arr);
// Access the second element which is the object
JsonObject obj = arr[1].as<JsonObject>();
String json;
// Serial.println(obj["kind"].as<String>());
// Access the "tags" array
JsonArray tags = obj["tags"].as<JsonArray>();
// Flag to check if the tag was found
bool tagFound = false;
uint medianFee = 0;
String typeValue;
// Iterate over the tags array
for (JsonArray tag : tags)
{
// Check if the tag is an array with two elements
if (tag.size() == 2)
{
const char *key = tag[0];
const char *value = tag[1];
// Check if the key is "type" and the value is "priceUsd"
if (strcmp(key, "type") == 0 && (strcmp(value, "priceUsd") == 0 || strcmp(value, "blockHeight") == 0))
{
typeValue = value;
tagFound = true;
}
else if (strcmp(key, "medianFee") == 0)
{
medianFee = tag[1].as<uint>();
}
if (strcmp(key, "bolt11") == 0)
{
String text = String(getAmountInSatoshis(std::string(value)));
std::size_t textLength = text.length();
// Calculate the position where the digits should start
// Account for the position of the "mdi:pickaxe" and the "GH/S" label
std::size_t startIndex = NUM_SCREENS - textLength;
std::array<String, NUM_SCREENS> textEpdContent = {"ZAP", "mdi-lnbolt", "", "", "", "", ""};
// Insert the "mdi:pickaxe" icon just before the digits
if (startIndex > 0 && preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL))
{
textEpdContent[startIndex - 1] = "STS";
}
// Place the digits
for (std::size_t i = 0; i < textLength; i++)
{
textEpdContent[startIndex + i] = text.substring(i, i + 1);
}
uint64_t timerPeriod = 0;
if (isTimerActive())
{
// store timer periode before making inactive to prevent artifacts
timerPeriod = getTimerSeconds();
esp_timer_stop(screenRotateTimer);
}
setCurrentScreen(SCREEN_CUSTOM);
setEpdContent(textEpdContent);
vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250));
queueLedEffect(LED_EFFECT_NOSTR_ZAP);
if (timerPeriod > 0)
{
esp_timer_start_periodic(screenRotateTimer,
timerPeriod * usPerSecond);
}
}
}
}
if (tagFound)
{
if (typeValue.equals("priceUsd"))
{
processNewPrice(obj["content"].as<uint>());
}
else if (typeValue.equals("blockHeight"))
{
processNewBlock(obj["content"].as<uint>());
}
if (medianFee != 0)
{
processNewBlockFee(medianFee);
}
}
}

View file

@ -15,4 +15,5 @@ void setupNostrNotify();
void nostrTask(void *pvParameters);
void setupNostrTask();
boolean nostrConnected();
boolean nostrConnected();
void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *event);

View file

@ -443,7 +443,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
settings["timePerScreen"].as<uint>() * 60);
}
String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname"};
String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "nostrZapPubkey"};
for (String setting : strSettings)
{
@ -478,7 +478,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
String boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd",
"mdnsEnabled", "otaEnabled", "stealFocus",
"mcapBigChar", "useSatsSymbol", "useBlkCountdown",
"suffixPrice", "disableLeds", "ownDataSource", "flAlwaysOn", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled"};
"suffixPrice", "disableLeds", "ownDataSource", "flAlwaysOn", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", "nostrZapNotify"};
for (String setting : boolSettings)
{
@ -601,6 +601,9 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
root["nostrPubKey"] = preferences.getString("nostrPubKey", DEFAULT_NOSTR_NPUB);
root["nostrRelay"] = preferences.getString("nostrRelay", DEFAULT_NOSTR_RELAY);
root["nostrZapNotify"] = preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED);
root["nostrZapPubkey"] = preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY);
root["bitaxeEnabled"] = preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED);
root["bitaxeHostname"] = preferences.getString("bitaxeHostname", DEFAULT_BITAXE_HOSTNAME);