Use own nostrduino fork, improve nostr code, WebUI update

This commit is contained in:
Djuri Baars 2024-12-26 21:43:50 +01:00
parent 957a947bc5
commit 66c662e1fd
3 changed files with 132 additions and 101 deletions

2
data

@ -1 +1 @@
Subproject commit 924be8fc2eb02fe384a20b53da1a9fa3d8db8a05 Subproject commit 65b6df5d92f3f936e823a5c1413681aee85ab0c5

View file

@ -43,7 +43,7 @@ lib_deps =
https://github.com/dsbaars/universal_pin#feature/mcp23017_rt https://github.com/dsbaars/universal_pin#feature/mcp23017_rt
https://github.com/dsbaars/GxEPD2#universal_pin https://github.com/dsbaars/GxEPD2#universal_pin
https://github.com/tzapu/WiFiManager.git#v2.0.17 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] [env:lolin_s3_mini]
extends = btclock_base extends = btclock_base
@ -71,7 +71,11 @@ board = btclock_rev_b
board_build.partitions = partition_8mb.csv board_build.partitions = partition_8mb.csv
build_flags = build_flags =
${btclock_base.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_PIN=15
-D NEOPIXEL_COUNT=4 -D NEOPIXEL_COUNT=4
-D NUM_SCREENS=7 -D NUM_SCREENS=7

View file

@ -27,8 +27,8 @@ void setupNostrNotify(bool asDatasource, bool zapNotify)
String pubKey = preferences.getString("nostrPubKey"); String pubKey = preferences.getString("nostrPubKey");
pools.push_back(pool); pools.push_back(pool);
std::vector<std::map<NostrString, std::initializer_list<NostrString>>> filters; std::vector<nostr::NostrRelay *> *relays = pool->getConnectedRelays();
if (zapNotify) if (zapNotify)
{ {
subscribeZaps(pool, relay, 60); subscribeZaps(pool, relay, 60);
@ -46,31 +46,29 @@ void setupNostrNotify(bool asDatasource, bool zapNotify)
}}, }},
handleNostrEventCallback, handleNostrEventCallback,
onNostrSubscriptionClosed, onNostrSubscriptionClosed,
onNostrSubscriptionEose); onNostrSubscriptionEose
);
Serial.println("[ Nostr ] Subscribing to Nostr Data Feed"); Serial.println(F("[ Nostr ] Subscribing to Nostr Data Feed"));
} }
std::vector<nostr::NostrRelay *> *relays = pool->getConnectedRelays();
for (nostr::NostrRelay *relay : *relays) for (nostr::NostrRelay *relay : *relays)
{ {
Serial.println("[ Nostr ] Registering to connection events of: " + relay->getUrl()); Serial.println("[ Nostr ] Registering to connection events of: " + relay->getUrl());
relay->getConnection()->addConnectionStatusListener([&](const nostr::ConnectionStatus &status) relay->getConnection()->addConnectionStatusListener([](const nostr::ConnectionStatus &status)
{ {
String sstatus="UNKNOWN"; static const char* STATUS_STRINGS[] = {"UNKNOWN", "CONNECTED", "DISCONNECTED", "ERROR"};
if(status==nostr::ConnectionStatus::CONNECTED){ int statusIndex = static_cast<int>(status);
nostrIsConnected = true;
sstatus="CONNECTED"; nostrIsConnected = (status == nostr::ConnectionStatus::CONNECTED);
}else if(status==nostr::ConnectionStatus::DISCONNECTED){ if (!nostrIsConnected) {
nostrIsConnected = false;
nostrIsSubscribed = false; 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) catch (const std::exception &e)
{ {
@ -103,7 +101,7 @@ void nostrTask(void *pvParameters)
void setupNostrTask() void setupNostrTask()
{ {
xTaskCreate(nostrTask, "nostrTask", 16384, NULL, 10, &nostrTaskHandle); xTaskCreate(nostrTask, "nostrTask", 8192, NULL, 10, &nostrTaskHandle);
} }
boolean nostrConnected() boolean nostrConnected()
@ -129,55 +127,57 @@ void onNostrSubscriptionEose(const String &subId)
void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *event) 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; JsonDocument doc;
JsonArray arr = doc["data"].to<JsonArray>(); JsonArray arr = doc["data"].to<JsonArray>();
event->toSendableEvent(arr); event->toSendableEvent(arr);
// Access the second element which is the object
// Early return if array is invalid
if (arr.size() < 2 || !arr[1].is<JsonObject>()) {
return;
}
JsonObject obj = arr[1].as<JsonObject>(); JsonObject obj = arr[1].as<JsonObject>();
JsonArray tags = obj["tags"].as<JsonArray>(); JsonArray tags = obj["tags"].as<JsonArray>();
if (!tags) {
return;
}
// Flag to check if the tag was found // Use direct value access instead of multiple comparisons
bool tagFound = false;
uint medianFee = 0;
String typeValue; String typeValue;
uint medianFee = 0;
// Iterate over the tags array
for (JsonArray tag : tags) for (JsonArray tag : tags) {
{ if (tag.size() != 2) continue;
// Check if the tag is an array with two elements
if (tag.size() == 2) const char *key = tag[0];
{ if (!key) continue;
const char *key = tag[0];
const char *value = tag[1]; // Use switch for better performance on string comparisons
switch (key[0]) {
// Check if the key is "type" and the value is "priceUsd" case 't': // type
if (strcmp(key, "type") == 0 && (strcmp(value, "priceUsd") == 0 || strcmp(value, "blockHeight") == 0)) if (strcmp(key, "type") == 0) {
{ const char *value = tag[1];
typeValue = value; if (value) typeValue = value;
tagFound = true; }
} break;
else if (strcmp(key, "medianFee") == 0) case 'm': // medianFee
{ if (strcmp(key, "medianFee") == 0) {
medianFee = tag[1].as<uint>(); medianFee = tag[1].as<uint>();
} }
break;
} }
} }
if (tagFound)
{ // Process the data
if (typeValue.equals("priceUsd")) if (!typeValue.isEmpty()) {
{ if (typeValue == "priceUsd") {
processNewPrice(obj["content"].as<uint>(), CURRENCY_USD); processNewPrice(obj["content"].as<uint>(), CURRENCY_USD);
} }
else if (typeValue.equals("blockHeight")) else if (typeValue == "blockHeight") {
{
processNewBlock(obj["content"].as<uint>()); processNewBlock(obj["content"].as<uint>());
} }
if (medianFee != 0) if (medianFee != 0) {
{
processNewBlockFee(medianFee); processNewBlockFee(medianFee);
} }
} }
@ -202,7 +202,27 @@ void subscribeZaps(nostr::NostrPool *pool, const String &relay, int minutesAgo)
{"kinds", {"9735"}}, {"kinds", {"9735"}},
{"limit", {"1"}}, {"limit", {"1"}},
{"since", {String(getMinutesAgo(minutesAgo))}}, {"since", {String(getMinutesAgo(minutesAgo))}},
{"#p", {preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY)}}, {"#p", {preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY) }},
// {"#p", [&]() {
// std::initializer_list<NostrString> 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<NostrString> keys;
// while (token != NULL) {
// keys.push_back(String(token));
// token = strtok(NULL, ",");
// }
// free(str);
// return std::initializer_list<NostrString>(keys.begin(), keys.end());
// }
// // Return default if no pubkeys found
// return std::initializer_list<NostrString>{
// preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY)
// };
// }()},
}, },
}, },
handleNostrZapCallback, handleNostrZapCallback,
@ -212,56 +232,63 @@ void subscribeZaps(nostr::NostrPool *pool, const String &relay, int minutesAgo)
} }
void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) { 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; JsonDocument doc;
JsonArray arr = doc["data"].to<JsonArray>(); JsonArray arr = doc["data"].to<JsonArray>();
event->toSendableEvent(arr); event->toSendableEvent(arr);
// Access the second element which is the object
// Early return if invalid
if (arr.size() < 2 || !arr[1].is<JsonObject>()) {
return;
}
JsonObject obj = arr[1].as<JsonObject>(); JsonObject obj = arr[1].as<JsonObject>();
JsonArray tags = obj["tags"].as<JsonArray>(); JsonArray tags = obj["tags"].as<JsonArray>();
if (!tags) {
return;
}
// Iterate over the tags array uint64_t zapAmount = 0;
for (JsonArray tag : tags) String zapPubkey;
{
// Check if the tag is an array with two elements for (JsonArray tag : tags) {
if (tag.size() == 2) if (tag.size() != 2) continue;
{
const char *key = tag[0]; const char *key = tag[0];
const char *value = tag[1]; const char *value = tag[1];
if (!key || !value) continue;
if (strcmp(key, "bolt11") == 0) if (key[0] == 'b' && strcmp(key, "bolt11") == 0) {
{ zapAmount = getAmountInSatoshis(std::string(value));
Serial.print(F("Got a zap of ")); }
else if (key[0] == 'p' && strcmp(key, "p") == 0) {
int64_t satsAmount = getAmountInSatoshis(std::string(value)); zapPubkey = value;
Serial.print(satsAmount);
Serial.println(F(" sats"));
std::array<std::string, NUM_SCREENS> 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 (zapAmount == 0) return;
std::array<std::string, NUM_SCREENS> 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);
}
} }