Плата поднимает страницу + JSON API (/api/state, /api/command) на порту 80
для наблюдения и управления актуаторами независимо от MQTT/Laravel.
Команда с веб-UI публикует тот же ack в devices/{id}/ack, что и MQTT-команда,
поэтому device shadow платформы не расходится с реальным состоянием.
Включается/выключается флагом ENABLE_WEB_UI в config.h.
В README добавлены ASCII-схема подключения DHT22/реле и раздел про сборку
через arduino-cli (включая обходной путь для проблемы с правами на
~/Documents/Arduino на macOS).
80 lines
2.2 KiB
C++
80 lines
2.2 KiB
C++
#include "devices.h"
|
|
|
|
#include "config.h"
|
|
|
|
struct Actuator {
|
|
const char* deviceId;
|
|
uint8_t pin;
|
|
bool on;
|
|
};
|
|
|
|
static Actuator actuators[] = {
|
|
{DEVICE_ID_LIGHT, PIN_RELAY_LIGHT, false},
|
|
{DEVICE_ID_PUMP, PIN_RELAY_PUMP, false},
|
|
{DEVICE_ID_FAN, PIN_RELAY_FAN, false},
|
|
};
|
|
static const size_t actuatorCount = sizeof(actuators) / sizeof(actuators[0]);
|
|
|
|
static void relayWrite(uint8_t pin, bool on) {
|
|
bool level = RELAY_ACTIVE_LOW ? !on : on;
|
|
digitalWrite(pin, level ? HIGH : LOW);
|
|
}
|
|
|
|
void devicesBegin() {
|
|
for (size_t i = 0; i < actuatorCount; i++) {
|
|
pinMode(actuators[i].pin, OUTPUT);
|
|
relayWrite(actuators[i].pin, false);
|
|
}
|
|
}
|
|
|
|
static Actuator* findActuator(const String& deviceId) {
|
|
for (size_t i = 0; i < actuatorCount; i++) {
|
|
if (deviceId == actuators[i].deviceId) {
|
|
return &actuators[i];
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Реального диммирования у нас нет (обычные реле on/off), поэтому
|
|
// set_level трактуется как порог: level > 0 включает реле, level <= 0
|
|
// выключает. Ack всегда содержит и power, и level, чтобы отражать
|
|
// реальное состояние железа.
|
|
bool devicesApplyCommand(const String& deviceId, const String& action, double level, JsonDocument& outState) {
|
|
Actuator* actuator = findActuator(deviceId);
|
|
if (actuator == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
if (action == "turn_on") {
|
|
actuator->on = true;
|
|
} else if (action == "turn_off") {
|
|
actuator->on = false;
|
|
} else if (action == "set_level") {
|
|
actuator->on = level > 0;
|
|
outState["level"] = level;
|
|
} else {
|
|
Serial.print("[devices] unknown action for ");
|
|
Serial.print(deviceId);
|
|
Serial.print(": ");
|
|
Serial.println(action);
|
|
return false;
|
|
}
|
|
|
|
relayWrite(actuator->pin, actuator->on);
|
|
outState["power"] = actuator->on ? "on" : "off";
|
|
|
|
Serial.print("[devices] ");
|
|
Serial.print(deviceId);
|
|
Serial.print(" -> ");
|
|
Serial.println(actuator->on ? "on" : "off");
|
|
return true;
|
|
}
|
|
|
|
void devicesGetState(JsonObject& out) {
|
|
for (size_t i = 0; i < actuatorCount; i++) {
|
|
JsonObject deviceState = out[actuators[i].deviceId].to<JsonObject>();
|
|
deviceState["power"] = actuators[i].on ? "on" : "off";
|
|
}
|
|
}
|