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:
@@ -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);
|
||||
|
||||
@@ -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
BIN
data/melody4.bin
Normal file
Binary file not shown.
@@ -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();
|
||||
}
|
||||
|
||||
29
vesper.ino
29
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<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();
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user