Added Separate Timings for each Relay

The setting is saved on a file in:
/settings/relayTimings.json

Then during bootup, it's read and restored. 
Settings can be set via MQTT command on Topic: 
vesoer/*dev-id*/control/settings/relayTimers
using a json format. 
{ "b1":50, b2...}
where b1 is Bell 1, b2 Bell 2, etc..
This commit is contained in:
2025-01-21 11:42:23 +02:00
parent a33f626dde
commit 84534025f4
5 changed files with 150 additions and 65 deletions

View File

@@ -1,26 +1,28 @@
#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: ");
@@ -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);

View File

@@ -2,11 +2,25 @@
#include <vector>
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<ActiveRelay> activeRelays;
void loop_playback(std::vector<uint16_t> &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<uint16_t> &melody_steps) {
@@ -41,28 +74,20 @@ void loop_playback(std::vector<uint16_t> &melody_steps) {
Serial.println("SINGLE LOOP OVER.");
//if (!melody.isPlaying) break; // Stop playback only after completing the loop
}
}
// Function to activate relays for a specific note
void itsHammerTime(uint16_t note) {
// THIS NEEDS REWORK, TO WAIT, DYNAMICLY PER RELAY
// MUST BE CONFIGURABLE REMOTELY
uint64_t now = millis();
for (uint8_t i = 0; i < 16; i++) {
if (note & (1 << i)) {
relays.digitalWrite(i, LOW);
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]});
}
}
vTaskDelay(pdMS_TO_TICKS(relayDurations[0]));
for (uint8_t i=0; i<16; i++) {
relays.digitalWrite(i, HIGH);
}
}

BIN
data/melody4.bin Normal file

Binary file not shown.

View File

@@ -1,10 +1,15 @@
#pragma once
extern std::vector<uint16_t> melody_steps;
extern uint16_t relayDurations[16];
void setMelodyAttributes(JsonDocument doc);
void loadMelodyInRAM(std::vector<uint16_t> &melody_steps);
void loadRelayTimings();
void saveRelayTimings();
// - - - - - - - - - - - - - - - - - - - - - - - - - - -
void setMelodyAttributes(JsonDocument doc){
@@ -68,3 +73,72 @@ void loadMelodyInRAM(std::vector<uint16_t> &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<uint16_t>();
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<uint16_t>();
Serial.printf("Loaded relay %d duration: %d ms\n", i + 1, relayDurations[i]);
}
}
file.close();
}

View File

@@ -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<uint16_t> 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();
}