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,32 +1,34 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void handlePlaybackCommands(char * command);
|
void handlePlaybackCommands(char * command);
|
||||||
|
void setRelayDurations(JsonDocument& doc);
|
||||||
|
|
||||||
void handleJSON(char * payload) {
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
|
||||||
|
JsonDocument handleJSON(char * payload) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
DeserializationError error = deserializeJson(doc, payload);
|
DeserializationError error = deserializeJson(doc, payload);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
Serial.print("deserializeJson() failed: ");
|
Serial.print("deserializeJson() failed: ");
|
||||||
Serial.println(error.c_str());
|
Serial.println(error.c_str());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return doc;
|
||||||
setMelodyAttributes(doc);
|
|
||||||
loadMelodyInRAM(melody_steps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuscribeMqtt() {
|
void SuscribeMqtt() {
|
||||||
|
|
||||||
String topicPlayback = String("vesper/") + DEV_ID + "/control/playback";
|
String topicPlayback = String("vesper/") + DEV_ID + "/control/playback";
|
||||||
String topicSetMelody = String("vesper/") + DEV_ID + "/control/setMelody";
|
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);
|
uint16_t control_id = mqttClient.subscribe(topicPlayback.c_str(), 2);
|
||||||
Serial.print("Subscribing to Playback Control topic, QoS 2, packetId: ");
|
Serial.print("Subscribing to Playback Control topic, QoS 2, packetId: ");
|
||||||
Serial.println(control_id);
|
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.print("Subscribing to Set-Melody topic, QoS 2, packetId: ");
|
||||||
Serial.println(set_melody_id);
|
Serial.println(set_melody_id);
|
||||||
|
|
||||||
@@ -35,15 +37,20 @@ void SuscribeMqtt() {
|
|||||||
Serial.print("Subscribing to Add-Melody topic, QoS 2, packetId: ");
|
Serial.print("Subscribing to Add-Melody topic, QoS 2, packetId: ");
|
||||||
Serial.println(add_melody_id);
|
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) {
|
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 topicPlayback = String("vesper/") + DEV_ID + "/control/playback";
|
||||||
String topicSetMelody = String("vesper/") + DEV_ID + "/control/setMelody";
|
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);
|
//String payloadContent = String(payload).substring(0, len);
|
||||||
|
|
||||||
if (String(topic) == topicPlayback){
|
if (String(topic) == topicPlayback){
|
||||||
@@ -51,7 +58,8 @@ void OnMqttReceived(char * topic, char * payload, AsyncMqttClientMessageProperti
|
|||||||
}
|
}
|
||||||
|
|
||||||
else if (String(topic) == topicSetMelody) {
|
else if (String(topic) == topicSetMelody) {
|
||||||
handleJSON(payload);
|
setMelodyAttributes(handleJSON(payload));
|
||||||
|
loadMelodyInRAM(melody_steps);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (String(topic) == topicAddMelody) {
|
else if (String(topic) == topicAddMelody) {
|
||||||
@@ -59,22 +67,17 @@ void OnMqttReceived(char * topic, char * payload, AsyncMqttClientMessageProperti
|
|||||||
Serial.println("Adding melody...");
|
Serial.println("Adding melody...");
|
||||||
// You can call a function here to handle adding the melody
|
// You can call a function here to handle adding the melody
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (String(topic) == topicRelayTimers) {
|
||||||
|
setRelayDurations(handleJSON(payload));
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
// Handle unknown topics
|
// Handle unknown topics
|
||||||
Serial.println("Unknown topic received.");
|
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) {
|
void PublishMqtt(const char *data) {
|
||||||
String topicData = String("vesper/") + DEV_ID + "/data";
|
String topicData = String("vesper/") + DEV_ID + "/data";
|
||||||
mqttClient.publish(topicData.c_str(), 0, true, data);
|
mqttClient.publish(topicData.c_str(), 0, true, data);
|
||||||
|
|||||||
@@ -2,11 +2,25 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
extern melody_attributes melody;
|
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 loop_playback(std::vector<uint16_t> &melody_steps);
|
||||||
|
void relayControlTask(void *param);
|
||||||
void itsHammerTime(uint16_t note);
|
void itsHammerTime(uint16_t note);
|
||||||
|
void turnOffRelays(uint64_t now);
|
||||||
|
|
||||||
void bellEngine(void *parameter) {
|
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) {
|
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.");
|
Serial.println("SINGLE LOOP OVER.");
|
||||||
//if (!melody.isPlaying) break; // Stop playback only after completing the loop
|
//if (!melody.isPlaying) break; // Stop playback only after completing the loop
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void itsHammerTime(uint16_t note){
|
// Function to activate relays for a specific note
|
||||||
|
void itsHammerTime(uint16_t note) {
|
||||||
// THIS NEEDS REWORK, TO WAIT, DYNAMICLY PER RELAY
|
uint64_t now = millis();
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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]});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
data/melody4.bin
Normal file
BIN
data/melody4.bin
Normal file
Binary file not shown.
@@ -1,10 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
extern std::vector<uint16_t> melody_steps;
|
extern std::vector<uint16_t> melody_steps;
|
||||||
|
extern uint16_t relayDurations[16];
|
||||||
|
|
||||||
void setMelodyAttributes(JsonDocument doc);
|
void setMelodyAttributes(JsonDocument doc);
|
||||||
void loadMelodyInRAM(std::vector<uint16_t> &melody_steps);
|
void loadMelodyInRAM(std::vector<uint16_t> &melody_steps);
|
||||||
|
void loadRelayTimings();
|
||||||
|
void saveRelayTimings();
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
|
||||||
void setMelodyAttributes(JsonDocument doc){
|
void setMelodyAttributes(JsonDocument doc){
|
||||||
|
|
||||||
@@ -68,3 +73,72 @@ void loadMelodyInRAM(std::vector<uint16_t> &melody_steps) {
|
|||||||
// closing the file
|
// 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 {
|
class melody_attributes {
|
||||||
public:
|
public:
|
||||||
uint16_t id; // The (internal) ID of the selected melody. Not specificly used anywhere atm. Might be used later.
|
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
|
std::string name = "melody1"; // Name of the Melody saved. Will be used to read the file: /name.bin
|
||||||
uint16_t speed; // Time to wait per beat. (In Miliseconds)
|
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 duration = 15000; // Total Duration that program will run (In Miliseconds)
|
||||||
uint32_t loop_duration = 0; // Duration of the playback per segment
|
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
|
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;
|
melody_attributes melody;
|
||||||
std::vector<uint16_t> melody_steps;
|
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 "config.h"
|
||||||
#include "functions.hpp"
|
#include "functions.hpp"
|
||||||
#include "MQTT_Message_Handling.hpp"
|
#include "MQTT_Message_Handling.hpp"
|
||||||
@@ -109,25 +106,11 @@ void setup()
|
|||||||
ConnectWiFi_STA();
|
ConnectWiFi_STA();
|
||||||
delay(1000);
|
delay(1000);
|
||||||
|
|
||||||
xTaskCreatePinnedToCore(
|
xTaskCreatePinnedToCore(bellEngine,"bellEngine", 8192, NULL, 1, &bellEngineHandle, 1);
|
||||||
bellEngine, // Task function
|
xTaskCreatePinnedToCore(durationTimer, "durationTimer", 8192, NULL, 2, NULL, 1);
|
||||||
"bellEngine", // Task name
|
xTaskCreatePinnedToCore(relayControlTask, "Relay Control Task", 2048, NULL, 2, NULL, 1);
|
||||||
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(
|
loadRelayTimings();
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user