diff --git a/data b/data index 924be8f..65b6df5 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 924be8fc2eb02fe384a20b53da1a9fa3d8db8a05 +Subproject commit 65b6df5d92f3f936e823a5c1413681aee85ab0c5 diff --git a/platformio.ini b/platformio.ini index be29cbe..90f1cc0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -43,7 +43,7 @@ lib_deps = https://github.com/dsbaars/universal_pin#feature/mcp23017_rt https://github.com/dsbaars/GxEPD2#universal_pin https://github.com/tzapu/WiFiManager.git#v2.0.17 - rblb/Nostrduino@1.2.8 + https://github.com/dsbaars/nostrduino#feature/fix-btclock [env:lolin_s3_mini] extends = btclock_base @@ -71,7 +71,11 @@ board = btclock_rev_b board_build.partitions = partition_8mb.csv build_flags = ${btclock_base.build_flags} - -D MCP_INT_PIN=8 + -D MCP_INT_PIN=8docker run --rm -e RENOVATE_TOKEN -e LOG_LEVEL=debug \ + -e "RENOVATE_REPOSITORIES=[\"your-repo-name\"]" \ + renovate/renovate \ + --platform local \ + --dry-run -D NEOPIXEL_PIN=15 -D NEOPIXEL_COUNT=4 -D NUM_SCREENS=7 diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index bad593d..d19002c 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -27,8 +27,8 @@ void setupNostrNotify(bool asDatasource, bool zapNotify) String pubKey = preferences.getString("nostrPubKey"); pools.push_back(pool); - std::vector>> filters; - + std::vector *relays = pool->getConnectedRelays(); + if (zapNotify) { subscribeZaps(pool, relay, 60); @@ -46,31 +46,29 @@ void setupNostrNotify(bool asDatasource, bool zapNotify) }}, handleNostrEventCallback, onNostrSubscriptionClosed, - onNostrSubscriptionEose); + onNostrSubscriptionEose + ); - Serial.println("[ Nostr ] Subscribing to Nostr Data Feed"); + Serial.println(F("[ Nostr ] Subscribing to Nostr Data Feed")); } - std::vector *relays = pool->getConnectedRelays(); for (nostr::NostrRelay *relay : *relays) { Serial.println("[ Nostr ] Registering to connection events of: " + relay->getUrl()); - relay->getConnection()->addConnectionStatusListener([&](const nostr::ConnectionStatus &status) - { - String sstatus="UNKNOWN"; - if(status==nostr::ConnectionStatus::CONNECTED){ - nostrIsConnected = true; - sstatus="CONNECTED"; - }else if(status==nostr::ConnectionStatus::DISCONNECTED){ - nostrIsConnected = false; + relay->getConnection()->addConnectionStatusListener([](const nostr::ConnectionStatus &status) + { + static const char* STATUS_STRINGS[] = {"UNKNOWN", "CONNECTED", "DISCONNECTED", "ERROR"}; + int statusIndex = static_cast(status); + + nostrIsConnected = (status == nostr::ConnectionStatus::CONNECTED); + if (!nostrIsConnected) { nostrIsSubscribed = false; - sstatus="DISCONNECTED"; - }else if(status==nostr::ConnectionStatus::ERROR){ - sstatus = "ERROR"; } - Serial.println("[ Nostr ] Connection status changed: " + sstatus); - }); + + Serial.println("[ Nostr ] Connection status changed: " + String(STATUS_STRINGS[statusIndex])); + }); } + } catch (const std::exception &e) { @@ -103,7 +101,7 @@ void nostrTask(void *pvParameters) void setupNostrTask() { - xTaskCreate(nostrTask, "nostrTask", 16384, NULL, 10, &nostrTaskHandle); + xTaskCreate(nostrTask, "nostrTask", 8192, NULL, 10, &nostrTaskHandle); } boolean nostrConnected() @@ -129,55 +127,57 @@ void onNostrSubscriptionEose(const String &subId) 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(); event->toSendableEvent(arr); - // Access the second element which is the object + + // Early return if array is invalid + if (arr.size() < 2 || !arr[1].is()) { + return; + } + JsonObject obj = arr[1].as(); JsonArray tags = obj["tags"].as(); + if (!tags) { + return; + } - // Flag to check if the tag was found - bool tagFound = false; - uint medianFee = 0; + // Use direct value access instead of multiple comparisons 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 medianFee = 0; + + for (JsonArray tag : tags) { + if (tag.size() != 2) continue; + + const char *key = tag[0]; + if (!key) continue; + + // Use switch for better performance on string comparisons + switch (key[0]) { + case 't': // type + if (strcmp(key, "type") == 0) { + const char *value = tag[1]; + if (value) typeValue = value; + } + break; + case 'm': // medianFee + if (strcmp(key, "medianFee") == 0) { + medianFee = tag[1].as(); + } + break; } } - if (tagFound) - { - if (typeValue.equals("priceUsd")) - { + + // Process the data + if (!typeValue.isEmpty()) { + if (typeValue == "priceUsd") { processNewPrice(obj["content"].as(), CURRENCY_USD); } - else if (typeValue.equals("blockHeight")) - { + else if (typeValue == "blockHeight") { processNewBlock(obj["content"].as()); } - if (medianFee != 0) - { + if (medianFee != 0) { processNewBlockFee(medianFee); } } @@ -202,7 +202,27 @@ void subscribeZaps(nostr::NostrPool *pool, const String &relay, int minutesAgo) {"kinds", {"9735"}}, {"limit", {"1"}}, {"since", {String(getMinutesAgo(minutesAgo))}}, - {"#p", {preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY)}}, + {"#p", {preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY) }}, + // {"#p", [&]() { + // std::initializer_list pubkeys; + // String pubkeysStr = preferences.getString("nostrZapPubkeys", ""); + // if (pubkeysStr.length() > 0) { + // // Assuming pubkeys are comma-separated + // char* str = strdup(pubkeysStr.c_str()); + // char* token = strtok(str, ","); + // std::vector keys; + // while (token != NULL) { + // keys.push_back(String(token)); + // token = strtok(NULL, ","); + // } + // free(str); + // return std::initializer_list(keys.begin(), keys.end()); + // } + // // Return default if no pubkeys found + // return std::initializer_list{ + // preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY) + // }; + // }()}, }, }, handleNostrZapCallback, @@ -212,56 +232,63 @@ void subscribeZaps(nostr::NostrPool *pool, const String &relay, int minutesAgo) } void handleNostrZapCallback(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(); event->toSendableEvent(arr); - // Access the second element which is the object + + // Early return if invalid + if (arr.size() < 2 || !arr[1].is()) { + return; + } + JsonObject obj = arr[1].as(); JsonArray tags = obj["tags"].as(); + if (!tags) { + return; + } - // 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]; + uint64_t zapAmount = 0; + String zapPubkey; + + for (JsonArray tag : tags) { + if (tag.size() != 2) continue; + + const char *key = tag[0]; + const char *value = tag[1]; + if (!key || !value) continue; - if (strcmp(key, "bolt11") == 0) - { - Serial.print(F("Got a zap of ")); - - int64_t satsAmount = getAmountInSatoshis(std::string(value)); - Serial.print(satsAmount); - Serial.println(F(" sats")); - - std::array textEpdContent = parseZapNotify(satsAmount, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); - - 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)); - if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP)) - { - queueLedEffect(LED_EFFECT_NOSTR_ZAP); - } - if (timerPeriod > 0) - { - esp_timer_start_periodic(screenRotateTimer, - timerPeriod * usPerSecond); - } - } + if (key[0] == 'b' && strcmp(key, "bolt11") == 0) { + zapAmount = getAmountInSatoshis(std::string(value)); + } + else if (key[0] == 'p' && strcmp(key, "p") == 0) { + zapPubkey = value; } } + + if (zapAmount == 0) return; + + std::array textEpdContent = parseZapNotify(zapAmount, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); + + Serial.printf("Got a zap of %llu sats for %s\n", zapAmount, zapPubkey.c_str()); + + 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)); + if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP)) + { + queueLedEffect(LED_EFFECT_NOSTR_ZAP); + } + if (timerPeriod > 0) + { + esp_timer_start_periodic(screenRotateTimer, + timerPeriod * usPerSecond); + } } \ No newline at end of file