Use own nostrduino fork, improve nostr code, WebUI update
This commit is contained in:
parent
957a947bc5
commit
66c662e1fd
3 changed files with 132 additions and 101 deletions
2
data
2
data
|
@ -1 +1 @@
|
||||||
Subproject commit 924be8fc2eb02fe384a20b53da1a9fa3d8db8a05
|
Subproject commit 65b6df5d92f3f936e823a5c1413681aee85ab0c5
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue