From 53c55d27262e4b81e0eb10fad974a45312883e8b Mon Sep 17 00:00:00 2001 From: bonamin Date: Wed, 28 Jan 2026 10:28:05 +0200 Subject: [PATCH] Added Sync Time to LCD, Fixed UTC Timestamp issues --- .../src/BuiltInMelodies/BuiltInMelodies.hpp | 520 ++++++++++++++---- .../CommandHandler/CommandHandler.cpp | 64 ++- .../CommandHandler/CommandHandler.hpp | 1 + vesper/src/Player/Player.cpp | 7 - vesper/vesper.ino | 3 +- 5 files changed, 478 insertions(+), 117 deletions(-) diff --git a/vesper/src/BuiltInMelodies/BuiltInMelodies.hpp b/vesper/src/BuiltInMelodies/BuiltInMelodies.hpp index 906361d..17bc5ac 100644 --- a/vesper/src/BuiltInMelodies/BuiltInMelodies.hpp +++ b/vesper/src/BuiltInMelodies/BuiltInMelodies.hpp @@ -47,120 +47,465 @@ struct MelodyInfo { const char* uid; // Unique identifier const uint16_t* data; // Pointer to melody data in PROGMEM uint16_t stepCount; // Number of steps - uint16_t defaultSpeed; // Default speed in milliseconds per beat }; // ═════════════════════════════════════════════════════════════════════════════════ -// EXAMPLE MELODIES - Add your melodies here! +// BuiltIn Melodies // More can be added here // ═════════════════════════════════════════════════════════════════════════════════ -// Example: Simple Scale (C-D-E-F-G-A-B-C) -const uint16_t PROGMEM melody_simple_scale[] = { - 0x0001, 0x0002, 0x0004, 0x0008, - 0x0010, 0x0020, 0x0040, 0x0080 +// 1 Bell Test Melody +const uint16_t PROGMEM builtin_1bell_test[] = { + 0x0001, 0x0000, 0x0001, 0x0000 }; -// Example: Happy Birthday (simplified) -const uint16_t PROGMEM melody_happy_birthday[] = { - 0x0001, 0x0001, 0x0002, 0x0001, - 0x0008, 0x0004, 0x0001, 0x0001, - 0x0002, 0x0001, 0x0010, 0x0008, - 0x0001, 0x0001, 0x0080, 0x0008, - 0x0004, 0x0002, 0x0040, 0x0040, - 0x0008, 0x0004, 0x0002 +// Doxology Traditional +const uint16_t PROGMEM builtin_doxology_traditional[] = { + 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0004, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0008, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, + 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0008, 0x0000, 0x0000 }; -// Example: Jingle Bells (simplified) -const uint16_t PROGMEM melody_jingle_bells[] = { - 0x0004, 0x0004, 0x0004, 0x0000, - 0x0004, 0x0004, 0x0004, 0x0000, - 0x0004, 0x0008, 0x0001, 0x0002, - 0x0004, 0x0000, 0x0000, 0x0000, - 0x0008, 0x0008, 0x0008, 0x0008, - 0x0008, 0x0004, 0x0004, 0x0004, - 0x0002, 0x0002, 0x0004, 0x0002, - 0x0008, 0x0000, 0x0000, 0x0000 +// Doxology Alternative +const uint16_t PROGMEM builtin_doxology_alternative[] = { + 0x0001, 0x0000, 0x0002, 0x0004, 0x0000, 0x0018, 0x0000, 0x0001, + 0x0000, 0x0002, 0x0004, 0x0000, 0x0018, 0x0000, 0x0001, 0x0000, + 0x0002, 0x0004, 0x0000, 0x0018, 0x0000, 0x0001, 0x0002, 0x0001, + 0x0002, 0x0004, 0x0000, 0x0018, 0x0000 }; -// Example: Westminster Chimes -const uint16_t PROGMEM melody_westminster_chimes[] = { - 0x0008, 0x0004, 0x0002, 0x0001, - 0x0001, 0x0002, 0x0008, 0x0004, - 0x0008, 0x0001, 0x0002, 0x0004, - 0x0002, 0x0008, 0x0004, 0x0001 +// Doxology Festive +const uint16_t PROGMEM builtin_doxology_festive[] = { + 0x0002, 0x0004, 0x0009, 0x0004, 0x0002, 0x0004, 0x0011, 0x0004, + 0x0002, 0x0004, 0x0021, 0x0004, 0x0002, 0x0004, 0x0011, 0x0004 }; -// Example: Alarm Pattern -const uint16_t PROGMEM melody_alarm[] = { - 0x0001, 0x0080, 0x0001, 0x0080, - 0x0001, 0x0080, 0x0001, 0x0080, - 0x0000, 0x0000, 0x0001, 0x0080, - 0x0001, 0x0080, 0x0001, 0x0080 +// Vesper Traditional +const uint16_t PROGMEM builtin_vesper_traditional[] = { + 0x0001, 0x0002, 0x0004, 0x0000, 0x0001, 0x0002, 0x0004, 0x0000, + 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0004, 0x0000 }; -// Example: Doorbell -const uint16_t PROGMEM melody_doorbell[] = { - 0x0004, 0x0008, 0x0004, 0x0008 +// Vesper Alternative +const uint16_t PROGMEM builtin_vesper_alternative[] = { + 0x0001, 0x0002, 0x0000, 0x0000, 0x0001, 0x0002, 0x0000, 0x0000, + 0x0001, 0x0004, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0000, 0x0000, 0x0001, 0x0002, 0x0000, 0x0000, + 0x0001, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0000, 0x0000, 0x0001, 0x0002, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0000, 0x0000, 0x0001, 0x0002, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0000, 0x0000, 0x0001, 0x0004, 0x0000, 0x0000, + 0x0001, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; -// Example: Single Bell Test -const uint16_t PROGMEM melody_single_bell[] = { - 0x0001 +// Catehetical +const uint16_t PROGMEM builtin_catehetical[] = { + 0x0001, 0x0002, 0x0004, 0x0008, 0x0010 }; +// Orthros Traditional +const uint16_t PROGMEM builtin_orthros_traditional[] = { + 0x0001, 0x0000, 0x0002, 0x0000, 0x0004, 0x0008, 0x0000, 0x0010, + 0x0000, 0x0020, 0x0000, 0x0040, 0x0080, 0x0000 +}; + +// Orthros Alternative +const uint16_t PROGMEM builtin_orthros_alternative[] = { + 0x0001, 0x0000, 0x0002, 0x0001, 0x0000, 0x0002, 0x0000, 0x0001, + 0x0000, 0x0001, 0x0002, 0x0001, 0x0000, 0x0004, 0x0000 +}; + +// Mournfull Toll +const uint16_t PROGMEM builtin_mournfull_toll[] = { + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0002, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +}; + +// Mournfull Toll Alternative +const uint16_t PROGMEM builtin_mournfull_toll_alternative[] = { + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0004, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0002, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +// Mournfull Toll Meg Par +const uint16_t PROGMEM builtin_mournfull_toll_meg_par[] = { + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0004, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0002, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0002, 0x0002, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +}; + +// Sematron +const uint16_t PROGMEM builtin_sematron[] = { + 0x0001, 0x0001, 0x0001, 0x0002, 0x0001, 0x0001, 0x0001, 0x0008, + 0x0001, 0x0001, 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0008 +}; + +// Sematron Alternative +const uint16_t PROGMEM builtin_sematron_alternative[] = { + 0x0001, 0x0001, 0x0001, 0x0002, 0x0001, 0x0001, 0x0001, 0x0008, + 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0001, 0x0001, 0x0008 +}; + +// Athonite 1 2 Voices +const uint16_t PROGMEM builtin_athonite_1_2_voices[] = { + 0x0001, 0x0002, 0x0001, 0x0001, 0x0002, 0x0001, 0x0001, 0x0002, + 0x0001, 0x0001, 0x0002, 0x0001, 0x0002 +}; + +// Athonite 3 Voices +const uint16_t PROGMEM builtin_athonite_3_voices[] = { + 0x0002, 0x0001, 0x0000, 0x0000, 0x0002, 0x0001, 0x0000, 0x0000, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0000, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0000, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, + 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, + 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0004 +}; + +// Athonite 3 4 Voices +const uint16_t PROGMEM builtin_athonite_3_4_voices[] = { + 0x0002, 0x0001, 0x0000, 0x0000, 0x0002, 0x0001, 0x0000, 0x0000, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0000, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0000, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, + 0x0002, 0x0001, 0x0000, 0x0005, 0x0002, 0x0001, 0x0000, 0x0005, + 0x0002, 0x0001, 0x0000, 0x0005, 0x0002, 0x0001, 0x0002, 0x0005, + 0x0002, 0x0001, 0x0008, 0x0005, 0x0002, 0x0001, 0x0000, 0x0005, + 0x0002, 0x0001, 0x0000, 0x0005, 0x0002, 0x0001, 0x0002, 0x0005, + 0x0002, 0x0001, 0x0009, 0x0002, 0x0001, 0x0005, 0x0002, 0x0001, + 0x000A, 0x0002, 0x0001, 0x0006, 0x0002, 0x0001, 0x0009, 0x0002, + 0x0001, 0x0005, 0x0002, 0x0001, 0x000A, 0x0002, 0x0001, 0x0006, + 0x0002, 0x0001, 0x0009 +}; + +// Athonite 4 8 Voices +const uint16_t PROGMEM builtin_athonite_4_8_voices[] = { + 0x0002, 0x0001, 0x0000, 0x0000, 0x0002, 0x0001, 0x0000, 0x0000, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0000, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0000, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, + 0x0002, 0x0001, 0x0000, 0x0005, 0x0002, 0x0001, 0x0000, 0x0005, + 0x0002, 0x0001, 0x0000, 0x0005, 0x0002, 0x0001, 0x0002, 0x0005, + 0x0002, 0x0001, 0x0008, 0x0005, 0x0002, 0x0001, 0x0000, 0x0005, + 0x0002, 0x0001, 0x0000, 0x0005, 0x0002, 0x0001, 0x0002, 0x0005, + 0x0002, 0x0001, 0x0009, 0x0002, 0x0001, 0x0011, 0x0002, 0x0001, + 0x0022, 0x0002, 0x0001, 0x0081, 0x0002, 0x0001, 0x000A, 0x0002, + 0x0001, 0x0041, 0x0002, 0x0001, 0x0012, 0x0002, 0x0001, 0x0021, + 0x0002, 0x0001, 0x0082, 0x0002, 0x0001, 0x0009, 0x0002, 0x0001, + 0x0042, 0x0002, 0x0001, 0x0011, 0x0002, 0x0001, 0x0022, 0x0002, + 0x0001, 0x0081, 0x0002, 0x0001, 0x000A, 0x0002, 0x0001, 0x0041, + 0x0002, 0x0001, 0x0000, 0x0005, 0x0002, 0x0001, 0x0000, 0x0005, + 0x0002, 0x0001, 0x0002, 0x0005, 0x0002, 0x0001, 0x0000, 0x0000, + 0x0000 +}; + +// Onebyone 2 3 Voices +const uint16_t PROGMEM builtin_onebyone_2_3_voices[] = { + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, + 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, + 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, 0x0004, + 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, 0x0004, + 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, 0x0004, + 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, 0x0004, + 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, 0x0004, + 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, 0x0004, + 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, + 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002 +}; + +// Onebyone 4 8 Voices +const uint16_t PROGMEM builtin_onebyone_4_8_voices[] = { + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, + 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, + 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, 0x0004, + 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, 0x0004, + 0x0002, 0x0004, 0x0008, 0x0004, 0x0002, 0x0011, 0x0002, 0x0004, + 0x0008, 0x0004, 0x0002, 0x0021, 0x0002, 0x0004, 0x0008, 0x0004, + 0x0002, 0x0041, 0x0002, 0x0004, 0x0008, 0x0004, 0x0002, 0x0081, + 0x0002, 0x0004, 0x0008, 0x0004, 0x0002, 0x0041, 0x0002, 0x0004, + 0x0008, 0x0004, 0x0002, 0x0021, 0x0002, 0x0004, 0x0008, 0x0004, + 0x0002, 0x0041, 0x0002, 0x0004, 0x0008, 0x0004, 0x0002, 0x0081, + 0x0002, 0x0004, 0x0008, 0x0004, 0x0002, 0x0041, 0x0002, 0x0004, + 0x0008, 0x0004, 0x0002, 0x0021, 0x0002, 0x0004, 0x0008, 0x0004, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, + 0x0004, 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, + 0x0004, 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0002, 0x0001, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, + 0x0002, 0x0001, 0x0000 +}; + +// Festive 1Voice +const uint16_t PROGMEM builtin_festive_1voice[] = { + 0x0001, 0x0001, 0x0001, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0000, 0x0001, 0x0000, 0x0001, 0x0001, 0x0001, 0x0000, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0001, 0x0000 +}; + +// Festive 4Voices +const uint16_t PROGMEM builtin_festive_4voices[] = { + 0x0001, 0x0002, 0x0004, 0x0009, 0x0002, 0x0001, 0x0004, 0x0009 +}; + +// Festive 5Voices +const uint16_t PROGMEM builtin_festive_5voices[] = { + 0x0001, 0x0002, 0x0004, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, + 0x0008, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0004, 0x0002, + 0x0001, 0x0002, 0x0001, 0x0002, 0x0010, 0x0002, 0x0001, 0x0002 +}; + +// Festive 5Voice Alternative +const uint16_t PROGMEM builtin_festive_5voice_alternative[] = { + 0x0004, 0x0002, 0x0008, 0x0001, 0x0004, 0x0004, 0x0002, 0x0008, + 0x0001, 0x0010, 0x0004, 0x0002, 0x0008, 0x0001, 0x0004, 0x0004, + 0x0002, 0x0008, 0x0001, 0x0011, 0x0004, 0x0002, 0x0008, 0x0001, + 0x0004, 0x0004, 0x0002, 0x0008, 0x0001, 0x0011, 0x0004, 0x0002, + 0x0008, 0x0001, 0x0005, 0x0004, 0x0002, 0x0008, 0x0001, 0x0011, + 0x0004, 0x0002, 0x0008, 0x0001, 0x0005, 0x0004, 0x0002, 0x0008, + 0x0001, 0x0011, 0x0004, 0x0002, 0x0008, 0x0001, 0x0004, 0x0004, + 0x0002, 0x0008, 0x0001, 0x0010, 0x0004, 0x0002, 0x0008, 0x0001, + 0x0004, 0x0004, 0x0002, 0x0008, 0x0001, 0x0010 +}; + +// Festive 6Voices +const uint16_t PROGMEM builtin_festive_6voices[] = { + 0x0001, 0x0002, 0x0004, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, + 0x0008, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0004, 0x0002, + 0x0001, 0x0002, 0x0001, 0x0002, 0x0010, 0x0002, 0x0001, 0x0002, + 0x0001, 0x0002, 0x0009, 0x0002, 0x0001, 0x0002, 0x0011, 0x0002, + 0x0001, 0x0002, 0x0005, 0x0002, 0x0001, 0x0002, 0x0021, 0x0002, + 0x0001, 0x0002, 0x0009, 0x0002, 0x0001, 0x0002, 0x0011, 0x0002, + 0x0001, 0x0002, 0x0005, 0x0002, 0x0001, 0x0002, 0x0021, 0x0002, + 0x0001, 0x0002, 0x0009, 0x0002, 0x0001, 0x0002, 0x0011, 0x0002, + 0x0001, 0x0002, 0x0005, 0x0002, 0x0001, 0x0002, 0x0021, 0x0002, + 0x0001, 0x0002 +}; + +// Festive 8Voices +const uint16_t PROGMEM builtin_festive_8voices[] = { + 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080 +}; + +// Ormilia +const uint16_t PROGMEM builtin_ormilia[] = { + 0x0002, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0000, 0x0001, 0x0002, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, + 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0009, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0005, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0002, 0x0009, 0x0000, 0x0001, 0x0002, 0x0005, 0x0000, 0x0001, + 0x0002, 0x0009, 0x0000, 0x0001, 0x0002, 0x0005, 0x0000, 0x0001, + 0x0002, 0x0011, 0x0002, 0x0001, 0x0002, 0x0021, 0x0002, 0x0001, + 0x0002, 0x0011, 0x0002, 0x0001, 0x0002, 0x0021, 0x0002, 0x0041, + 0x0002, 0x0081, 0x0002, 0x0009, 0x0002, 0x0041, 0x0002, 0x0081, + 0x0002, 0x0009, 0x0002, 0x0041, 0x0002, 0x0081, 0x0002, 0x0005, + 0x0002, 0x0001, 0x0000 +}; + + // ═════════════════════════════════════════════════════════════════════════════════ // MELODY LIBRARY - Array of all built-in melodies // ═════════════════════════════════════════════════════════════════════════════════ const MelodyInfo MELODY_LIBRARY[] = { { - "Simple Scale", - "builtin_scale", - melody_simple_scale, - sizeof(melody_simple_scale) / sizeof(uint16_t), - 200 // 200ms per beat + "1 Bell Test", + "builtin_1bell_test", + builtin_1bell_test, + sizeof(builtin_1bell_test) / sizeof(uint16_t) }, { - "Happy Birthday", - "builtin_happy_birthday", - melody_happy_birthday, - sizeof(melody_happy_birthday) / sizeof(uint16_t), - 250 + "Doxology Traditional", + "builtin_doxology_traditional", + builtin_doxology_traditional, + sizeof(builtin_doxology_traditional) / sizeof(uint16_t) }, { - "Jingle Bells", - "builtin_jingle_bells", - melody_jingle_bells, - sizeof(melody_jingle_bells) / sizeof(uint16_t), - 180 + "Doxology Alternative", + "builtin_doxology_alternative", + builtin_doxology_alternative, + sizeof(builtin_doxology_alternative) / sizeof(uint16_t) }, { - "Westminster Chimes", - "builtin_westminster", - melody_westminster_chimes, - sizeof(melody_westminster_chimes) / sizeof(uint16_t), - 400 + "Doxology Festive", + "builtin_doxology_festive", + builtin_doxology_festive, + sizeof(builtin_doxology_festive) / sizeof(uint16_t) }, { - "Alarm", - "builtin_alarm", - melody_alarm, - sizeof(melody_alarm) / sizeof(uint16_t), - 150 + "Vesper Traditional", + "builtin_vesper_traditional", + builtin_vesper_traditional, + sizeof(builtin_vesper_traditional) / sizeof(uint16_t) }, { - "Doorbell", - "builtin_doorbell", - melody_doorbell, - sizeof(melody_doorbell) / sizeof(uint16_t), - 300 + "Vesper Alternative", + "builtin_vesper_alternative", + builtin_vesper_alternative, + sizeof(builtin_vesper_alternative) / sizeof(uint16_t) }, { - "Single Bell Test", - "builtin_single_bell", - melody_single_bell, - sizeof(melody_single_bell) / sizeof(uint16_t), - 100 + "Catehetical", + "builtin_catehetical", + builtin_catehetical, + sizeof(builtin_catehetical) / sizeof(uint16_t) + }, + { + "Orthros Traditional", + "builtin_orthros_traditional", + builtin_orthros_traditional, + sizeof(builtin_orthros_traditional) / sizeof(uint16_t) + }, + { + "Orthros Alternative", + "builtin_orthros_alternative", + builtin_orthros_alternative, + sizeof(builtin_orthros_alternative) / sizeof(uint16_t) + }, + { + "Mournfull Toll", + "builtin_mournfull_toll", + builtin_mournfull_toll, + sizeof(builtin_mournfull_toll) / sizeof(uint16_t) + }, + { + "Mournfull Toll Alternative", + "builtin_mournfull_toll_alternative", + builtin_mournfull_toll_alternative, + sizeof(builtin_mournfull_toll_alternative) / sizeof(uint16_t) + }, + { + "Mournfull Toll Meg Par", + "builtin_mournfull_toll_meg_par", + builtin_mournfull_toll_meg_par, + sizeof(builtin_mournfull_toll_meg_par) / sizeof(uint16_t) + }, + { + "Sematron", + "builtin_sematron", + builtin_sematron, + sizeof(builtin_sematron) / sizeof(uint16_t) + }, + { + "Sematron Alternative", + "builtin_sematron_alternative", + builtin_sematron_alternative, + sizeof(builtin_sematron_alternative) / sizeof(uint16_t) + }, + { + "Athonite 1 2 Voices", + "builtin_athonite_1_2_voices", + builtin_athonite_1_2_voices, + sizeof(builtin_athonite_1_2_voices) / sizeof(uint16_t) + }, + { + "Athonite 3 Voices", + "builtin_athonite_3_voices", + builtin_athonite_3_voices, + sizeof(builtin_athonite_3_voices) / sizeof(uint16_t) + }, + { + "Athonite 3 4 Voices", + "builtin_athonite_3_4_voices", + builtin_athonite_3_4_voices, + sizeof(builtin_athonite_3_4_voices) / sizeof(uint16_t) + }, + { + "Athonite 4 8 Voices", + "builtin_athonite_4_8_voices", + builtin_athonite_4_8_voices, + sizeof(builtin_athonite_4_8_voices) / sizeof(uint16_t) + }, + { + "Onebyone 2 3 Voices", + "builtin_onebyone_2_3_voices", + builtin_onebyone_2_3_voices, + sizeof(builtin_onebyone_2_3_voices) / sizeof(uint16_t) + }, + { + "Onebyone 4 8 Voices", + "builtin_onebyone_4_8_voices", + builtin_onebyone_4_8_voices, + sizeof(builtin_onebyone_4_8_voices) / sizeof(uint16_t) + }, + { + "Festive 1Voice", + "builtin_festive_1voice", + builtin_festive_1voice, + sizeof(builtin_festive_1voice) / sizeof(uint16_t) + }, + { + "Festive 4Voices", + "builtin_festive_4voices", + builtin_festive_4voices, + sizeof(builtin_festive_4voices) / sizeof(uint16_t) + }, + { + "Festive 5Voices", + "builtin_festive_5voices", + builtin_festive_5voices, + sizeof(builtin_festive_5voices) / sizeof(uint16_t) + }, + { + "Festive 5Voice Alternative", + "builtin_festive_5voice_alternative", + builtin_festive_5voice_alternative, + sizeof(builtin_festive_5voice_alternative) / sizeof(uint16_t) + }, + { + "Festive 6Voices", + "builtin_festive_6voices", + builtin_festive_6voices, + sizeof(builtin_festive_6voices) / sizeof(uint16_t) + }, + { + "Festive 8Voices", + "builtin_festive_8voices", + builtin_festive_8voices, + sizeof(builtin_festive_8voices) / sizeof(uint16_t) + }, + { + "Ormilia", + "builtin_ormilia", + builtin_ormilia, + sizeof(builtin_ormilia) / sizeof(uint16_t) } }; @@ -225,29 +570,10 @@ inline String getBuiltInMelodiesJSON() { json += "{"; json += "\"name\":\"" + String(MELODY_LIBRARY[i].name) + "\","; json += "\"uid\":\"" + String(MELODY_LIBRARY[i].uid) + "\","; - json += "\"steps\":" + String(MELODY_LIBRARY[i].stepCount) + ","; - json += "\"speed\":" + String(MELODY_LIBRARY[i].defaultSpeed); json += "}"; } json += "]"; return json; } -} // namespace BuiltInMelodies - -// ═══════════════════════════════════════════════════════════════════════════════════ -// USAGE EXAMPLE: -// ═══════════════════════════════════════════════════════════════════════════════════ -/* - // Check if melody is built-in - if (BuiltInMelodies::isBuiltInMelody(uid)) { - // Load it from firmware - std::vector melodyData; - if (BuiltInMelodies::loadBuiltInMelody(uid, melodyData)) { - // Use melodyData... - } - } else { - // Load from SD card as usual - } -*/ -// ═══════════════════════════════════════════════════════════════════════════════════ +} \ No newline at end of file diff --git a/vesper/src/Communication/CommandHandler/CommandHandler.cpp b/vesper/src/Communication/CommandHandler/CommandHandler.cpp index ef60a1a..d9d710a 100644 --- a/vesper/src/Communication/CommandHandler/CommandHandler.cpp +++ b/vesper/src/Communication/CommandHandler/CommandHandler.cpp @@ -283,6 +283,8 @@ void CommandHandler::handleSystemInfoCommand(JsonVariant contents, const Message handleNetworkInfoCommand(context); } else if (action == "get_full_settings") { handleGetFullSettingsCommand(context); + } else if (action == "sync_time_to_lcd") { + handleSyncTimeToLcdCommand(context); } else { LOG_WARNING("Unknown system info action: %s", action.c_str()); sendErrorResponse("system_info", "Unknown action: " + action, context); @@ -636,19 +638,26 @@ void CommandHandler::handleSetClockEnabledCommand(JsonVariant contents, const Me } void CommandHandler::handleGetDeviceTimeCommand(const MessageContext& context) { - StaticJsonDocument<256> response; + StaticJsonDocument<384> response; response["status"] = "SUCCESS"; response["type"] = "device_time"; - + if (_timeKeeper) { - // Get Unix timestamp from Timekeeper - unsigned long timestamp = _timeKeeper->getTime(); - response["payload"]["timestamp"] = timestamp; + // RTC stores LOCAL time (already timezone-adjusted) + unsigned long localTimestamp = _timeKeeper->getTime(); + + // Get timezone offset to calculate UTC + const auto& timeConfig = _configManager.getTimeConfig(); + long totalOffset = timeConfig.gmtOffsetSec + timeConfig.daylightOffsetSec; + unsigned long utcTimestamp = localTimestamp - totalOffset; + + response["payload"]["local_timestamp"] = localTimestamp; + response["payload"]["utc_timestamp"] = utcTimestamp; response["payload"]["rtc_available"] = true; - - // Convert to readable format - time_t rawTime = (time_t)timestamp; - struct tm* timeInfo = localtime(&rawTime); + + // Convert LOCAL timestamp to readable format using gmtime (no additional offset) + time_t rawTime = (time_t)localTimestamp; + struct tm* timeInfo = gmtime(&rawTime); // Use gmtime to avoid double-offset response["payload"]["year"] = timeInfo->tm_year + 1900; response["payload"]["month"] = timeInfo->tm_mon + 1; response["payload"]["day"] = timeInfo->tm_mday; @@ -656,15 +665,16 @@ void CommandHandler::handleGetDeviceTimeCommand(const MessageContext& context) { response["payload"]["minute"] = timeInfo->tm_min; response["payload"]["second"] = timeInfo->tm_sec; } else { - response["payload"]["timestamp"] = millis() / 1000; + response["payload"]["local_timestamp"] = millis() / 1000; + response["payload"]["utc_timestamp"] = millis() / 1000; response["payload"]["rtc_available"] = false; LOG_WARNING("TimeKeeper reference not set for device time request"); } - + String responseStr; serializeJson(response, responseStr); sendResponse(responseStr, context); - + LOG_DEBUG("Device time requested"); } @@ -858,7 +868,37 @@ void CommandHandler::handleGetFullSettingsCommand(const MessageContext& context) LOG_DEBUG("Full settings sent (%d bytes)", responseStr.length()); } +void CommandHandler::handleSyncTimeToLcdCommand(const MessageContext& context) { + StaticJsonDocument<256> response; + response["status"] = "SUCCESS"; + response["type"] = "sync_time_to_lcd"; + // Get the local timestamp from TimeKeeper (RTC stores local time) + unsigned long localTimestamp = 0; + if (_timeKeeper) { + localTimestamp = _timeKeeper->getTime(); + } else { + // Fallback to millis if TimeKeeper not available + localTimestamp = millis() / 1000; + LOG_WARNING("TimeKeeper not available for LCD time sync"); + } + + // Get timezone offset from ConfigManager (in seconds) + const auto& timeConfig = _configManager.getTimeConfig(); + long totalOffset = timeConfig.gmtOffsetSec + timeConfig.daylightOffsetSec; + + // Calculate UTC timestamp by subtracting the offset from local time + unsigned long utcTimestamp = localTimestamp - totalOffset; + + response["payload"]["timestamp"] = utcTimestamp; + response["payload"]["offset"] = totalOffset; + + String responseStr; + serializeJson(response, responseStr); + sendResponse(responseStr, context); + + LOG_DEBUG("LCD time sync: UTC=%lu, offset=%ld", utcTimestamp, totalOffset); +} void CommandHandler::handleSetNetworkConfigCommand(JsonVariant contents, const MessageContext& context) { // Validate that we have at least one parameter to update diff --git a/vesper/src/Communication/CommandHandler/CommandHandler.hpp b/vesper/src/Communication/CommandHandler/CommandHandler.hpp index 7507971..e185142 100644 --- a/vesper/src/Communication/CommandHandler/CommandHandler.hpp +++ b/vesper/src/Communication/CommandHandler/CommandHandler.hpp @@ -140,6 +140,7 @@ private: void handleGetFirmwareStatusCommand(const MessageContext& context); void handleNetworkInfoCommand(const MessageContext& context); void handleGetFullSettingsCommand(const MessageContext& context); + void handleSyncTimeToLcdCommand(const MessageContext& context); // Network configuration void handleSetNetworkConfigCommand(JsonVariant contents, const MessageContext& context); diff --git a/vesper/src/Player/Player.cpp b/vesper/src/Player/Player.cpp index 99b322c..80b61a1 100644 --- a/vesper/src/Player/Player.cpp +++ b/vesper/src/Player/Player.cpp @@ -263,13 +263,6 @@ void Player::loadMelodyInRAM() { if (BuiltInMelodies::loadBuiltInMelody(uidStr, _melodySteps)) { LOG_INFO("✅ Built-in melody loaded successfully: %d steps", _melodySteps.size()); - - // Set default speed from built-in melody info - const BuiltInMelodies::MelodyInfo* melodyInfo = BuiltInMelodies::findMelodyByUID(uidStr); - if (melodyInfo && speed == 0) { - speed = melodyInfo->defaultSpeed; - LOG_DEBUG("Using default speed: %d ms/beat", speed); - } return; } else { LOG_ERROR("Failed to load built-in melody: %s", uidStr.c_str()); diff --git a/vesper/vesper.ino b/vesper/vesper.ino index bf2d163..b8f39bc 100644 --- a/vesper/vesper.ino +++ b/vesper/vesper.ino @@ -64,7 +64,7 @@ * 👨‍💻 AUTHOR: BellSystems bonamin */ -#define FW_VERSION "151" +#define FW_VERSION "152" /* @@ -79,6 +79,7 @@ * v138 - Removed Ethernet, added default WiFi creds (Mikrotik AP) and fixed various Clock issues * v140 - Changed FW Updates to Direct-to-Flash and added manual update functionality with version check * v151 - Fixed Clock Alerts not running properly + * v152 - Fix RTC Time Reports, added sync_time_to_LCD functionality * ═══════════════════════════════════════════════════════════════════════════════ */