#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(); deviceState["power"] = actuators[i].on ? "on" : "off"; } }