Compare commits

...

4 Commits

5 changed files with 83 additions and 31 deletions

View File

@ -7,11 +7,11 @@
#define WINDOWS_GPIO D6 #define WINDOWS_GPIO D6
#define LIGHT_GPIO D7 #define LIGHT_GPIO D7
Input door("greenhouse/door", DOOR_GPIO, true, "CLOSEABLE_BOOLEAN"); Input door("greenhouse/door", "DOOR",DOOR_GPIO, true);
Input windows("greenhouse/windows", WINDOWS_GPIO, true, "CLOSEABLE_BOOLEAN"); Input windows("greenhouse/windows", "WINDOW", WINDOWS_GPIO, true);
Output light("greenhouse/light", LIGHT_GPIO, true, "LIGHT_BOOLEAN"); Output light("greenhouse/light", "LIGHT",LIGHT_GPIO, true);
TSL2561 greenhouseTSL("greenhouse"); TSL2561 greenhouseTSL("greenhouse");
@ -33,4 +33,8 @@ void sensorsLoop() {
greenhouseDHT22.loop(); greenhouseDHT22.loop();
} }
void mqttReceive(const String& topic, const String& payload) {
light.cmd(topic, payload);
}
#endif #endif

View File

@ -11,8 +11,6 @@ class Input {
const boolean inverted; const boolean inverted;
const char* unit;
unsigned long debounceMs; unsigned long debounceMs;
unsigned long sendMs; unsigned long sendMs;
@ -27,7 +25,15 @@ public:
const String name; const String name;
explicit Input(String name, const int pin, const boolean inverted, const char* unit, const unsigned long debounceMs = 500, const unsigned long sendMs = 5000) : pin(pin), inverted(inverted), unit(unit), debounceMs(debounceMs), sendMs(sendMs), name(std::move(name)) { const String category;
explicit Input(String name, String category, const int pin, const boolean inverted, const unsigned long debounceMs = 500, const unsigned long sendMs = 5000) :
pin(pin),
inverted(inverted),
debounceMs(debounceMs),
sendMs(sendMs),
name(std::move(name)),
category(std::move(category)) {
// //
} }
@ -49,7 +55,7 @@ public:
if (changed || lastSent == 0 || now - lastSent >= sendMs) { if (changed || lastSent == 0 || now - lastSent >= sendMs) {
lastSent = now; lastSent = now;
mqttPublishValue(name, state, unit); mqttPublishSwitcher(name, category, state);
} }
} }

View File

@ -11,8 +11,6 @@ class Output {
const boolean inverted; const boolean inverted;
const char* unit;
unsigned long sendMs; unsigned long sendMs;
unsigned long lastSent = 0UL; unsigned long lastSent = 0UL;
@ -23,7 +21,14 @@ public:
const String name; const String name;
explicit Output(String name, const int pin, const boolean inverted, const char* unit, const unsigned long sendMs = 5000) : pin(pin), inverted(inverted), unit(unit), sendMs(sendMs), name(std::move(name)) { const String category;
explicit Output(String name, String category, const int pin, const boolean inverted, const unsigned long sendMs = 5000) :
pin(pin),
inverted(inverted),
sendMs(sendMs),
name(std::move(name)),
category(std::move(category)) {
// //
} }
@ -37,18 +42,35 @@ public:
if (changed || lastSent == 0 || now - lastSent >= sendMs) { if (changed || lastSent == 0 || now - lastSent >= sendMs) {
lastSent = now; lastSent = now;
digitalWrite(pin, inverted ^ state); digitalWrite(pin, inverted ^ state);
mqttPublishValue(name, state, unit); mqttPublishSwitcher(name, category, state);
} }
} }
void setState(const boolean newState) { void setState(const boolean newState) {
this->state = newState; if (this->state != newState) {
this->state = newState;
Log.info("State changed: name=%s, state=%s", name.c_str(), this->state ? "true" : "false");
}
} }
[[nodiscard]] boolean getState() const { [[nodiscard]] boolean getState() const {
return state; return state;
} }
void cmd(const String& topic, const String& payload) {
const String expected = String("/cmd/" + name + "/setState");
if (!topic.equals(expected)) {
return;
}
if (payload.equals("true")) {
setState(true);
} else if (payload.equals("false")) {
setState(false);
} else {
Log.error("Invalid payload for command: topic=%s, payload=%s", topic.c_str(), payload.c_str());
}
}
}; };
#endif #endif

View File

@ -17,28 +17,33 @@ unsigned long mqttFailureMillis = 0;
// ReSharper disable once CppUseAuto // ReSharper disable once CppUseAuto
const String logTopic = String("log/") + HOSTNAME; const String logTopic = String("log/") + HOSTNAME;
// ReSharper disable once CppUseAuto
const String cmdTopic = String("cmd/") + HOSTNAME;
void mqttCallback(char* topic, const uint8_t* payload, unsigned int length) { void mqttCallback(char* topic, const uint8_t* payload, unsigned int length) {
char message[500]; char message[500];
length = min(sizeof message - 1, length); length = min(sizeof message - 1, length);
memcpy(message, payload, length); memcpy(message, payload, length);
*(message + length) = 0; *(message + length) = 0;
Log.info(R"(MQTT received: topic="%s", message="%s")", topic, message); const String topicStr = String(topic);
if (strcmp(message, "help") == 0) { const String messageStr = String(message);
Log.info("HELP"); Log.info(R"(MQTT received: topic="%s", message="%s")", topicStr.c_str(), messageStr.c_str());
Log.info(" %s", "help"); if (topicStr.equals(String("/cmd/") + HOSTNAME)) {
Log.info(" %s", "info"); if (messageStr.equals("help")) {
Log.info(" %s", "restart"); Log.info("HELP");
} else if (strcmp(message, "info") == 0) { Log.info(" %s", "help");
Log.info("INFO"); Log.info(" %s", "info");
Log.info(" %-10s %s", "SSID:", WiFi.SSID().c_str()); Log.info(" %s", "restart");
Log.info(" %-10s %s", "IP:", WiFi.localIP().toString().c_str()); } else if (messageStr.equals("info")) {
Log.info(" %-10s %d", "RSSI:", WiFi.RSSI()); Log.info("INFO");
Log.info(" %-10s %s", "uptime:", uptimeString().c_str()); Log.info(" %-10s %s", "SSID:", WiFi.SSID().c_str());
} else if (strcmp(message, "restart") == 0) { Log.info(" %-10s %s", "IP:", WiFi.localIP().toString().c_str());
systemRequestRestart(); Log.info(" %-10s %d", "RSSI:", WiFi.RSSI());
Log.info(" %-10s %s", "uptime:", uptimeString().c_str());
} else if (messageStr.equals("restart")) {
systemRequestRestart();
} else {
Log.warn("Unknown node command: %s", messageStr.c_str());
}
} else {
mqttReceive(topicStr, messageStr);
} }
} }
@ -49,7 +54,7 @@ void mqttLoop() {
yield(); yield();
mqttPublish(logTopic, "connected\n"); mqttPublish(logTopic, "connected\n");
mqtt.setCallback(mqttCallback); mqtt.setCallback(mqttCallback);
mqtt.subscribe(cmdTopic.c_str()); mqtt.subscribe("/cmd/#");
Log.info("MQTT connected as \"%s\".", HOSTNAME); Log.info("MQTT connected as \"%s\".", HOSTNAME);
mqttFailureMillis = 0; mqttFailureMillis = 0;
} else { } else {
@ -64,7 +69,7 @@ void mqttDisconnect() {
} }
void mqttPublishValue(const String& name, const boolean value, const char* unit) { void mqttPublishValue(const String& name, const boolean value, const char* unit) {
mqttPublishValue(name, String(value ? "true" : "false"), unit); mqttPublishValue(name, String(value ? 1 : 0), unit);
} }
void mqttPublishValue(const String& name, const int32_t value, const char* unit) { void mqttPublishValue(const String& name, const int32_t value, const char* unit) {
@ -97,6 +102,17 @@ void mqttPublishValue(const String& name, const double value, const char* unit)
mqttPublishValue(name, String(value), unit); mqttPublishValue(name, String(value), unit);
} }
void mqttPublishSwitcher(const String& name, const String& category, const boolean state) {
char buffer[200];
snprintf(buffer, sizeof buffer, R"({"name": "%s", "type": "SWITCHER", "category": "%s", "timestamp": %lld, "state": %s})",
name.c_str(),
category.c_str(),
time(nullptr),
state ? "true" : "false"
);
mqttPublish(name + "/type/SWITCHER", buffer);
}
void mqttPublishValue(const String& name, const String& value, const char* unit) { void mqttPublishValue(const String& name, const String& value, const char* unit) {
char buffer[200]; char buffer[200];
snprintf(buffer, sizeof buffer, R"({"name": "%s", "timestamp": %lld, "value": %s, "unit": "%s"})", name.c_str(), time(nullptr), value.c_str(), unit); snprintf(buffer, sizeof buffer, R"({"name": "%s", "timestamp": %lld, "value": %s, "unit": "%s"})", name.c_str(), time(nullptr), value.c_str(), unit);

View File

@ -44,10 +44,14 @@ void mqttPublishValue(const String& name, float value, const char* unit);
void mqttPublishValue(const String& name, double value, const char* unit); void mqttPublishValue(const String& name, double value, const char* unit);
void mqttPublishSwitcher(const String& name, const String& category, boolean state);
void mqttPublishValue(const String& name, const String& value, const char* unit); void mqttPublishValue(const String& name, const String& value, const char* unit);
void mqttPublish(const String& topic, const String& payload); void mqttPublish(const String& topic, const String& payload);
void mqttReceive(const String& topic, const String& payload);
class LogClass final : public Stream { class LogClass final : public Stream {
PubSubClient& mqtt; PubSubClient& mqtt;