Added Sync Time to LCD, Fixed UTC Timestamp issues

This commit is contained in:
2026-01-28 10:28:05 +02:00
parent 094b1a9620
commit 53c55d2726
5 changed files with 478 additions and 117 deletions

View File

@@ -47,120 +47,465 @@ struct MelodyInfo {
const char* uid; // Unique identifier const char* uid; // Unique identifier
const uint16_t* data; // Pointer to melody data in PROGMEM const uint16_t* data; // Pointer to melody data in PROGMEM
uint16_t stepCount; // Number of steps 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) // 1 Bell Test Melody
const uint16_t PROGMEM melody_simple_scale[] = { const uint16_t PROGMEM builtin_1bell_test[] = {
0x0001, 0x0002, 0x0004, 0x0008, 0x0001, 0x0000, 0x0001, 0x0000
0x0010, 0x0020, 0x0040, 0x0080
}; };
// Example: Happy Birthday (simplified) // Doxology Traditional
const uint16_t PROGMEM melody_happy_birthday[] = { const uint16_t PROGMEM builtin_doxology_traditional[] = {
0x0001, 0x0001, 0x0002, 0x0001, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0004, 0x0000, 0x0000,
0x0008, 0x0004, 0x0001, 0x0001, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0008, 0x0000, 0x0000,
0x0002, 0x0001, 0x0010, 0x0008, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002,
0x0001, 0x0001, 0x0080, 0x0008, 0x0001, 0x0002, 0x0001, 0x0004, 0x0001, 0x0008, 0x0000, 0x0000
0x0004, 0x0002, 0x0040, 0x0040,
0x0008, 0x0004, 0x0002
}; };
// Example: Jingle Bells (simplified) // Doxology Alternative
const uint16_t PROGMEM melody_jingle_bells[] = { const uint16_t PROGMEM builtin_doxology_alternative[] = {
0x0004, 0x0004, 0x0004, 0x0000, 0x0001, 0x0000, 0x0002, 0x0004, 0x0000, 0x0018, 0x0000, 0x0001,
0x0004, 0x0004, 0x0004, 0x0000, 0x0000, 0x0002, 0x0004, 0x0000, 0x0018, 0x0000, 0x0001, 0x0000,
0x0004, 0x0008, 0x0001, 0x0002, 0x0002, 0x0004, 0x0000, 0x0018, 0x0000, 0x0001, 0x0002, 0x0001,
0x0004, 0x0000, 0x0000, 0x0000, 0x0002, 0x0004, 0x0000, 0x0018, 0x0000
0x0008, 0x0008, 0x0008, 0x0008,
0x0008, 0x0004, 0x0004, 0x0004,
0x0002, 0x0002, 0x0004, 0x0002,
0x0008, 0x0000, 0x0000, 0x0000
}; };
// Example: Westminster Chimes // Doxology Festive
const uint16_t PROGMEM melody_westminster_chimes[] = { const uint16_t PROGMEM builtin_doxology_festive[] = {
0x0008, 0x0004, 0x0002, 0x0001, 0x0002, 0x0004, 0x0009, 0x0004, 0x0002, 0x0004, 0x0011, 0x0004,
0x0001, 0x0002, 0x0008, 0x0004, 0x0002, 0x0004, 0x0021, 0x0004, 0x0002, 0x0004, 0x0011, 0x0004
0x0008, 0x0001, 0x0002, 0x0004,
0x0002, 0x0008, 0x0004, 0x0001
}; };
// Example: Alarm Pattern // Vesper Traditional
const uint16_t PROGMEM melody_alarm[] = { const uint16_t PROGMEM builtin_vesper_traditional[] = {
0x0001, 0x0080, 0x0001, 0x0080, 0x0001, 0x0002, 0x0004, 0x0000, 0x0001, 0x0002, 0x0004, 0x0000,
0x0001, 0x0080, 0x0001, 0x0080, 0x0001, 0x0002, 0x0001, 0x0002, 0x0001, 0x0002, 0x0004, 0x0000
0x0000, 0x0000, 0x0001, 0x0080,
0x0001, 0x0080, 0x0001, 0x0080
}; };
// Example: Doorbell // Vesper Alternative
const uint16_t PROGMEM melody_doorbell[] = { const uint16_t PROGMEM builtin_vesper_alternative[] = {
0x0004, 0x0008, 0x0004, 0x0008 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 // Catehetical
const uint16_t PROGMEM melody_single_bell[] = { const uint16_t PROGMEM builtin_catehetical[] = {
0x0001 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 // MELODY LIBRARY - Array of all built-in melodies
// ═════════════════════════════════════════════════════════════════════════════════ // ═════════════════════════════════════════════════════════════════════════════════
const MelodyInfo MELODY_LIBRARY[] = { const MelodyInfo MELODY_LIBRARY[] = {
{ {
"Simple Scale", "1 Bell Test",
"builtin_scale", "builtin_1bell_test",
melody_simple_scale, builtin_1bell_test,
sizeof(melody_simple_scale) / sizeof(uint16_t), sizeof(builtin_1bell_test) / sizeof(uint16_t)
200 // 200ms per beat
}, },
{ {
"Happy Birthday", "Doxology Traditional",
"builtin_happy_birthday", "builtin_doxology_traditional",
melody_happy_birthday, builtin_doxology_traditional,
sizeof(melody_happy_birthday) / sizeof(uint16_t), sizeof(builtin_doxology_traditional) / sizeof(uint16_t)
250
}, },
{ {
"Jingle Bells", "Doxology Alternative",
"builtin_jingle_bells", "builtin_doxology_alternative",
melody_jingle_bells, builtin_doxology_alternative,
sizeof(melody_jingle_bells) / sizeof(uint16_t), sizeof(builtin_doxology_alternative) / sizeof(uint16_t)
180
}, },
{ {
"Westminster Chimes", "Doxology Festive",
"builtin_westminster", "builtin_doxology_festive",
melody_westminster_chimes, builtin_doxology_festive,
sizeof(melody_westminster_chimes) / sizeof(uint16_t), sizeof(builtin_doxology_festive) / sizeof(uint16_t)
400
}, },
{ {
"Alarm", "Vesper Traditional",
"builtin_alarm", "builtin_vesper_traditional",
melody_alarm, builtin_vesper_traditional,
sizeof(melody_alarm) / sizeof(uint16_t), sizeof(builtin_vesper_traditional) / sizeof(uint16_t)
150
}, },
{ {
"Doorbell", "Vesper Alternative",
"builtin_doorbell", "builtin_vesper_alternative",
melody_doorbell, builtin_vesper_alternative,
sizeof(melody_doorbell) / sizeof(uint16_t), sizeof(builtin_vesper_alternative) / sizeof(uint16_t)
300
}, },
{ {
"Single Bell Test", "Catehetical",
"builtin_single_bell", "builtin_catehetical",
melody_single_bell, builtin_catehetical,
sizeof(melody_single_bell) / sizeof(uint16_t), sizeof(builtin_catehetical) / sizeof(uint16_t)
100 },
{
"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 += "{";
json += "\"name\":\"" + String(MELODY_LIBRARY[i].name) + "\","; json += "\"name\":\"" + String(MELODY_LIBRARY[i].name) + "\",";
json += "\"uid\":\"" + String(MELODY_LIBRARY[i].uid) + "\","; json += "\"uid\":\"" + String(MELODY_LIBRARY[i].uid) + "\",";
json += "\"steps\":" + String(MELODY_LIBRARY[i].stepCount) + ",";
json += "\"speed\":" + String(MELODY_LIBRARY[i].defaultSpeed);
json += "}"; json += "}";
} }
json += "]"; json += "]";
return json; return json;
} }
} // namespace BuiltInMelodies }
// ═══════════════════════════════════════════════════════════════════════════════════
// USAGE EXAMPLE:
// ═══════════════════════════════════════════════════════════════════════════════════
/*
// Check if melody is built-in
if (BuiltInMelodies::isBuiltInMelody(uid)) {
// Load it from firmware
std::vector<uint16_t> melodyData;
if (BuiltInMelodies::loadBuiltInMelody(uid, melodyData)) {
// Use melodyData...
}
} else {
// Load from SD card as usual
}
*/
// ═══════════════════════════════════════════════════════════════════════════════════

View File

@@ -283,6 +283,8 @@ void CommandHandler::handleSystemInfoCommand(JsonVariant contents, const Message
handleNetworkInfoCommand(context); handleNetworkInfoCommand(context);
} else if (action == "get_full_settings") { } else if (action == "get_full_settings") {
handleGetFullSettingsCommand(context); handleGetFullSettingsCommand(context);
} else if (action == "sync_time_to_lcd") {
handleSyncTimeToLcdCommand(context);
} else { } else {
LOG_WARNING("Unknown system info action: %s", action.c_str()); LOG_WARNING("Unknown system info action: %s", action.c_str());
sendErrorResponse("system_info", "Unknown action: " + action, context); sendErrorResponse("system_info", "Unknown action: " + action, context);
@@ -636,19 +638,26 @@ void CommandHandler::handleSetClockEnabledCommand(JsonVariant contents, const Me
} }
void CommandHandler::handleGetDeviceTimeCommand(const MessageContext& context) { void CommandHandler::handleGetDeviceTimeCommand(const MessageContext& context) {
StaticJsonDocument<256> response; StaticJsonDocument<384> response;
response["status"] = "SUCCESS"; response["status"] = "SUCCESS";
response["type"] = "device_time"; response["type"] = "device_time";
if (_timeKeeper) { if (_timeKeeper) {
// Get Unix timestamp from Timekeeper // RTC stores LOCAL time (already timezone-adjusted)
unsigned long timestamp = _timeKeeper->getTime(); unsigned long localTimestamp = _timeKeeper->getTime();
response["payload"]["timestamp"] = timestamp;
// 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; response["payload"]["rtc_available"] = true;
// Convert to readable format // Convert LOCAL timestamp to readable format using gmtime (no additional offset)
time_t rawTime = (time_t)timestamp; time_t rawTime = (time_t)localTimestamp;
struct tm* timeInfo = localtime(&rawTime); struct tm* timeInfo = gmtime(&rawTime); // Use gmtime to avoid double-offset
response["payload"]["year"] = timeInfo->tm_year + 1900; response["payload"]["year"] = timeInfo->tm_year + 1900;
response["payload"]["month"] = timeInfo->tm_mon + 1; response["payload"]["month"] = timeInfo->tm_mon + 1;
response["payload"]["day"] = timeInfo->tm_mday; response["payload"]["day"] = timeInfo->tm_mday;
@@ -656,7 +665,8 @@ void CommandHandler::handleGetDeviceTimeCommand(const MessageContext& context) {
response["payload"]["minute"] = timeInfo->tm_min; response["payload"]["minute"] = timeInfo->tm_min;
response["payload"]["second"] = timeInfo->tm_sec; response["payload"]["second"] = timeInfo->tm_sec;
} else { } else {
response["payload"]["timestamp"] = millis() / 1000; response["payload"]["local_timestamp"] = millis() / 1000;
response["payload"]["utc_timestamp"] = millis() / 1000;
response["payload"]["rtc_available"] = false; response["payload"]["rtc_available"] = false;
LOG_WARNING("TimeKeeper reference not set for device time request"); LOG_WARNING("TimeKeeper reference not set for device time request");
} }
@@ -858,7 +868,37 @@ void CommandHandler::handleGetFullSettingsCommand(const MessageContext& context)
LOG_DEBUG("Full settings sent (%d bytes)", responseStr.length()); 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) { void CommandHandler::handleSetNetworkConfigCommand(JsonVariant contents, const MessageContext& context) {
// Validate that we have at least one parameter to update // Validate that we have at least one parameter to update

View File

@@ -140,6 +140,7 @@ private:
void handleGetFirmwareStatusCommand(const MessageContext& context); void handleGetFirmwareStatusCommand(const MessageContext& context);
void handleNetworkInfoCommand(const MessageContext& context); void handleNetworkInfoCommand(const MessageContext& context);
void handleGetFullSettingsCommand(const MessageContext& context); void handleGetFullSettingsCommand(const MessageContext& context);
void handleSyncTimeToLcdCommand(const MessageContext& context);
// Network configuration // Network configuration
void handleSetNetworkConfigCommand(JsonVariant contents, const MessageContext& context); void handleSetNetworkConfigCommand(JsonVariant contents, const MessageContext& context);

View File

@@ -263,13 +263,6 @@ void Player::loadMelodyInRAM() {
if (BuiltInMelodies::loadBuiltInMelody(uidStr, _melodySteps)) { if (BuiltInMelodies::loadBuiltInMelody(uidStr, _melodySteps)) {
LOG_INFO("✅ Built-in melody loaded successfully: %d steps", _melodySteps.size()); 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; return;
} else { } else {
LOG_ERROR("Failed to load built-in melody: %s", uidStr.c_str()); LOG_ERROR("Failed to load built-in melody: %s", uidStr.c_str());

View File

@@ -64,7 +64,7 @@
* 👨‍💻 AUTHOR: BellSystems bonamin * 👨‍💻 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 * 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 * v140 - Changed FW Updates to Direct-to-Flash and added manual update functionality with version check
* v151 - Fixed Clock Alerts not running properly * v151 - Fixed Clock Alerts not running properly
* v152 - Fix RTC Time Reports, added sync_time_to_LCD functionality
* ═══════════════════════════════════════════════════════════════════════════════ * ═══════════════════════════════════════════════════════════════════════════════
*/ */