diff --git a/MQTT_Message_Handling.hpp b/MQTT_Message_Handling.hpp index 3b042c4..fb2da9b 100644 --- a/MQTT_Message_Handling.hpp +++ b/MQTT_Message_Handling.hpp @@ -1,32 +1,34 @@ #pragma once void handlePlaybackCommands(char * command); +void setRelayDurations(JsonDocument& doc); -void handleJSON(char * payload) { + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +JsonDocument handleJSON(char * payload) { JsonDocument doc; DeserializationError error = deserializeJson(doc, payload); - if (error) { Serial.print("deserializeJson() failed: "); Serial.println(error.c_str()); - return; } - - setMelodyAttributes(doc); - loadMelodyInRAM(melody_steps); + return doc; } void SuscribeMqtt() { String topicPlayback = String("vesper/") + DEV_ID + "/control/playback"; String topicSetMelody = String("vesper/") + DEV_ID + "/control/setMelody"; - String topicAddMelody = String("vesper/") + DEV_ID + "/control/add_melody"; + String topicAddMelody = String("vesper/") + DEV_ID + "/control/addMelody"; + String topicRelayTimers = String("vesper/") + DEV_ID + "/control/settings/relayTimers"; uint16_t control_id = mqttClient.subscribe(topicPlayback.c_str(), 2); Serial.print("Subscribing to Playback Control topic, QoS 2, packetId: "); Serial.println(control_id); - uint16_t set_melody_id = mqttClient.subscribe(topicSetMelody.c_str(), 2); + uint16_t set_melody_id = mqttClient.subscribe(topicSetMelody.c_str(), 2); Serial.print("Subscribing to Set-Melody topic, QoS 2, packetId: "); Serial.println(set_melody_id); @@ -35,15 +37,20 @@ void SuscribeMqtt() { Serial.print("Subscribing to Add-Melody topic, QoS 2, packetId: "); Serial.println(add_melody_id); + uint16_t relay_timers_id = mqttClient.subscribe(topicRelayTimers.c_str(), 2); + Serial.print("Subscribing to Relay-Timers topic, QoS 2, packetId: "); + Serial.println(relay_timers_id); + } void OnMqttReceived(char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { String topicPlayback = String("vesper/") + DEV_ID + "/control/playback"; String topicSetMelody = String("vesper/") + DEV_ID + "/control/setMelody"; - String topicAddMelody = String("vesper/") + DEV_ID + "/control/add_melody"; - + String topicAddMelody = String("vesper/") + DEV_ID + "/control/addMelody"; + String topicRelayTimers = String("vesper/") + DEV_ID + "/control/settings/relayTimers"; + // Don't know what this is. Check it out later. //String payloadContent = String(payload).substring(0, len); if (String(topic) == topicPlayback){ @@ -51,7 +58,8 @@ void OnMqttReceived(char * topic, char * payload, AsyncMqttClientMessageProperti } else if (String(topic) == topicSetMelody) { - handleJSON(payload); + setMelodyAttributes(handleJSON(payload)); + loadMelodyInRAM(melody_steps); } else if (String(topic) == topicAddMelody) { @@ -59,22 +67,17 @@ void OnMqttReceived(char * topic, char * payload, AsyncMqttClientMessageProperti Serial.println("Adding melody..."); // You can call a function here to handle adding the melody } + + else if (String(topic) == topicRelayTimers) { + setRelayDurations(handleJSON(payload)); + } + else { // Handle unknown topics Serial.println("Unknown topic received."); } } -// void PublishMqtt(unsigned long data) { -// -// //Doesn't publish anything yet. -// String topicData = String("vesper/") + DEV_ID + "/data"; -// String payload = String(data); -// mqttClient.publish(topicData.c_str(), 0, true, (char*)payload.c_str()); -// -// } - - void PublishMqtt(const char *data) { String topicData = String("vesper/") + DEV_ID + "/data"; mqttClient.publish(topicData.c_str(), 0, true, data); diff --git a/bellEngine.hpp b/bellEngine.hpp index d094a0a..c59edd4 100644 --- a/bellEngine.hpp +++ b/bellEngine.hpp @@ -2,11 +2,25 @@ #include extern melody_attributes melody; -extern uint16_t relayMask; + +// Define a structure to track active solenoids +struct ActiveRelay { + uint8_t relayIndex; // Index of the relay + uint64_t activationTime; // Activation start time + uint16_t duration; // Duration for which it should remain active +}; + +// Array of durations for each relay (configure remotely) +uint16_t relayDurations[16] = {90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90}; +// Vector to track active solenoids +std::vector activeRelays; + + void loop_playback(std::vector &melody_steps); +void relayControlTask(void *param); void itsHammerTime(uint16_t note); - +void turnOffRelays(uint64_t now); void bellEngine(void *parameter) { @@ -26,6 +40,25 @@ void bellEngine(void *parameter) { } +// Task to deactivate relays dynamically +void relayControlTask(void *param) { + while (true) { + uint64_t now = millis(); + + // Iterate through active relays and deactivate those whose duration has elapsed + for (auto it = activeRelays.begin(); it != activeRelays.end();) { + if (now - it->activationTime >= it->duration) { + relays.digitalWrite(it->relayIndex, HIGH); // Deactivate the relay + it = activeRelays.erase(it); // Remove from the active list + } else { + ++it; // Move to the next relay + } + } + + vTaskDelay(pdMS_TO_TICKS(10)); // Check every 10ms + } +} + void loop_playback(std::vector &melody_steps) { @@ -41,28 +74,20 @@ void loop_playback(std::vector &melody_steps) { Serial.println("SINGLE LOOP OVER."); //if (!melody.isPlaying) break; // Stop playback only after completing the loop - } - } -void itsHammerTime(uint16_t note){ - - // THIS NEEDS REWORK, TO WAIT, DYNAMICLY PER RELAY - // MUST BE CONFIGURABLE REMOTELY - - for (uint8_t i=0; i<16; i++) { - if (note & (1 << i)) { - relays.digitalWrite(i, LOW); - } - } - - vTaskDelay(pdMS_TO_TICKS(relayDurations[0])); - - for (uint8_t i=0; i<16; i++) { - relays.digitalWrite(i, HIGH); - } +// Function to activate relays for a specific note +void itsHammerTime(uint16_t note) { + uint64_t now = millis(); + for (uint8_t i = 0; i < 16; i++) { + if (note & (1 << i)) { // Check if this relay needs to activate + relays.digitalWrite(i, LOW); // Activate the relay + // Add to the activeRelays list + activeRelays.push_back({i, now, relayDurations[i]}); + } + } } diff --git a/data/melody4.bin b/data/melody4.bin new file mode 100644 index 0000000..7e4eb7c Binary files /dev/null and b/data/melody4.bin differ diff --git a/functions.hpp b/functions.hpp index 80f1ae2..668c446 100644 --- a/functions.hpp +++ b/functions.hpp @@ -1,10 +1,15 @@ #pragma once extern std::vector melody_steps; - +extern uint16_t relayDurations[16]; void setMelodyAttributes(JsonDocument doc); void loadMelodyInRAM(std::vector &melody_steps); +void loadRelayTimings(); +void saveRelayTimings(); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - + void setMelodyAttributes(JsonDocument doc){ @@ -68,3 +73,72 @@ void loadMelodyInRAM(std::vector &melody_steps) { // closing the file } + +void setRelayDurations(JsonDocument doc) { + // Iterate through the relays in the JSON payload + for (uint8_t i = 0; i < 16; i++) { + String key = String("b") + (i + 1); // Generate "b1", "b2", ... + if (doc.containsKey(key)) { + relayDurations[i] = doc[key].as(); + Serial.printf("Relay %d duration set to %d ms\n", i + 1, relayDurations[i]); + } else { + Serial.printf("Relay %d not found in JSON payload. Keeping previous duration: %d ms\n", i + 1, relayDurations[i]); + } + } + saveRelayTimings(); +} + +void saveRelayTimings() { + StaticJsonDocument<512> doc; // Adjust size if needed + + // Populate the JSON object with relay durations + for (uint8_t i = 0; i < 16; i++) { + String key = String("b") + (i + 1); + doc[key] = relayDurations[i]; + } + + // Open the file for writing + File file = SPIFFS.open("/settings/relayTimings.json", FILE_WRITE); + if (!file) { + Serial.println("Failed to open file for writing"); + return; + } + + // Serialize JSON to the file + if (serializeJson(doc, file) == 0) { + Serial.println("Failed to write JSON to file"); + } else { + Serial.println("Relay timings saved successfully"); + } + + file.close(); +} + +void loadRelayTimings() { + // Open the file for reading + File file = SPIFFS.open("/settings/relayTimings.json", FILE_READ); + if (!file) { + Serial.println("Settings file not found. Using default relay timings."); + return; + } + + // Parse the JSON file + StaticJsonDocument<512> doc; // Adjust size if needed + DeserializationError error = deserializeJson(doc, file); + if (error) { + Serial.println("Failed to parse settings file. Using default relay timings."); + file.close(); + return; + } + + // Populate relayDurations array + for (uint8_t i = 0; i < 16; i++) { + String key = String("b") + (i + 1); + if (doc.containsKey(key)) { + relayDurations[i] = doc[key].as(); + Serial.printf("Loaded relay %d duration: %d ms\n", i + 1, relayDurations[i]); + } + } + + file.close(); +} diff --git a/vesper.ino b/vesper.ino index 2aa2366..ce91748 100644 --- a/vesper.ino +++ b/vesper.ino @@ -15,8 +15,8 @@ AsyncMqttClient mqttClient; class melody_attributes { public: uint16_t id; // The (internal) ID of the selected melody. Not specificly used anywhere atm. Might be used later. - std::string name; // Name of the Melody saved. Will be used to read the file: /name.bin - uint16_t speed; // Time to wait per beat. (In Miliseconds) + std::string name = "melody1"; // Name of the Melody saved. Will be used to read the file: /name.bin + uint16_t speed = 500; // Time to wait per beat. (In Miliseconds) uint32_t duration = 15000; // Total Duration that program will run (In Miliseconds) uint32_t loop_duration = 0; // Duration of the playback per segment uint32_t interval = 0; // Indicates the Duration of the Interval between finished segments, IF "inf" is true @@ -63,9 +63,6 @@ public: melody_attributes melody; std::vector melody_steps; -uint16_t relayMask = 0; // Bitmask indicating which relays to activate -uint8_t relayDurations[16] = {5,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100}; // Deactivation timers for each relay in milliseconds - #include "config.h" #include "functions.hpp" #include "MQTT_Message_Handling.hpp" @@ -109,25 +106,11 @@ void setup() ConnectWiFi_STA(); delay(1000); - xTaskCreatePinnedToCore( - bellEngine, // Task function - "bellEngine", // Task name - 8192, // Stack size - NULL, // Task input parameters - 1, // Task priority, be carefull when changing this - &bellEngineHandle, // Task handle, add one if you want control over the task (resume or suspend the task) - 1 // Core to run the task on - ); + xTaskCreatePinnedToCore(bellEngine,"bellEngine", 8192, NULL, 1, &bellEngineHandle, 1); + xTaskCreatePinnedToCore(durationTimer, "durationTimer", 8192, NULL, 2, NULL, 1); + xTaskCreatePinnedToCore(relayControlTask, "Relay Control Task", 2048, NULL, 2, NULL, 1); - xTaskCreatePinnedToCore( - durationTimer, // Task function - "durationTimer", // Task name - 8192, // Stack size - NULL, // Task input parameters - 2, // Task priority, be carefull when changing this - NULL, // Task handle, add one if you want control over the task (resume or suspend the task) - 1 // Core to run the task on - ); + loadRelayTimings(); }