mirror of https://github.com/LaskaKit/ESPlan.git
115 lines
4.0 KiB
C++
Executable File
115 lines
4.0 KiB
C++
Executable File
/*
|
||
* relay.cpp – Ovladani RS485 rele modulu (8 / 16 kanalu)
|
||
*/
|
||
|
||
#include "relay.h"
|
||
|
||
static bool sendCmd(ModbusClient& mb, RelayState& st, uint8_t addr,
|
||
uint16_t reg, uint16_t val, const String& actionDesc) {
|
||
ModbusStatus s = mb.writeRegister(addr, reg, val);
|
||
st.lastCmdMs = millis();
|
||
st.lastAction = actionDesc;
|
||
if (s == ModbusStatus::OK) {
|
||
st.commError = false;
|
||
st.errorMsg = "";
|
||
Serial.printf("[REL] %s : OK\n", actionDesc.c_str());
|
||
return true;
|
||
} else {
|
||
st.commError = true;
|
||
st.errorMsg = mb.statusStr(s);
|
||
Serial.printf("[REL] %s : %s\n", actionDesc.c_str(), mb.statusStr(s));
|
||
return false;
|
||
}
|
||
}
|
||
|
||
static inline bool validCh(uint8_t channel, const RelayConfig& cfg) {
|
||
return (channel >= 1 && channel <= cfg.channelCount);
|
||
}
|
||
|
||
bool relaySet(ModbusClient& mb, RelayState& st, const RelayConfig& cfg,
|
||
uint8_t channel, bool on) {
|
||
if (!validCh(channel, cfg)) return false;
|
||
uint16_t reg = REG_CHANNEL_BASE + (channel - 1);
|
||
uint16_t val = makeVal(on ? FN_OPEN : FN_CLOSE);
|
||
String d = String("ch") + channel + (on ? " ON" : " OFF");
|
||
bool ok = sendCmd(mb, st, cfg.modbusAddr, reg, val, d);
|
||
if (ok) st.channels[channel - 1] = on;
|
||
return ok;
|
||
}
|
||
|
||
bool relayToggle(ModbusClient& mb, RelayState& st, const RelayConfig& cfg,
|
||
uint8_t channel) {
|
||
if (!validCh(channel, cfg)) return false;
|
||
uint16_t reg = REG_CHANNEL_BASE + (channel - 1);
|
||
uint16_t val = makeVal(FN_TOGGLE);
|
||
String d = String("ch") + channel + " TOGGLE";
|
||
bool ok = sendCmd(mb, st, cfg.modbusAddr, reg, val, d);
|
||
if (ok) st.channels[channel - 1] = !st.channels[channel - 1];
|
||
return ok;
|
||
}
|
||
|
||
bool relayLatch(ModbusClient& mb, RelayState& st, const RelayConfig& cfg,
|
||
uint8_t channel) {
|
||
if (!validCh(channel, cfg)) return false;
|
||
uint16_t reg = REG_CHANNEL_BASE + (channel - 1);
|
||
uint16_t val = makeVal(FN_LATCH);
|
||
String d = String("ch") + channel + " LATCH";
|
||
bool ok = sendCmd(mb, st, cfg.modbusAddr, reg, val, d);
|
||
if (ok) {
|
||
// Inter-locking: jen tento kanal ON, ostatni OFF
|
||
for (uint8_t i = 0; i < cfg.channelCount; i++) {
|
||
st.channels[i] = (i == (channel - 1));
|
||
}
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
bool relayMomentary(ModbusClient& mb, RelayState& st, const RelayConfig& cfg,
|
||
uint8_t channel) {
|
||
if (!validCh(channel, cfg)) return false;
|
||
uint16_t reg = REG_CHANNEL_BASE + (channel - 1);
|
||
uint16_t val = makeVal(FN_MOMENTARY);
|
||
String d = String("ch") + channel + " MOMENTARY (1s)";
|
||
// Pri momentary se rele po 1s vrati do OFF. SW shadow nemenime –
|
||
// dalsi periodicky FC03 sync stav doplni.
|
||
return sendCmd(mb, st, cfg.modbusAddr, reg, val, d);
|
||
}
|
||
|
||
bool relayDelay(ModbusClient& mb, RelayState& st, const RelayConfig& cfg,
|
||
uint8_t channel, uint8_t seconds) {
|
||
if (!validCh(channel, cfg)) return false;
|
||
uint16_t reg = REG_CHANNEL_BASE + (channel - 1);
|
||
uint16_t val = makeVal(FN_DELAY, seconds);
|
||
String d = String("ch") + channel + " DELAY " + seconds + "s";
|
||
bool ok = sendCmd(mb, st, cfg.modbusAddr, reg, val, d);
|
||
if (ok) st.channels[channel - 1] = true; // okamzite ON, pak FC03 zjisti OFF
|
||
return ok;
|
||
}
|
||
|
||
bool relayAll(ModbusClient& mb, RelayState& st, const RelayConfig& cfg, bool on) {
|
||
uint16_t val = makeVal(on ? FN_ALL_ON : FN_ALL_OFF);
|
||
String d = on ? "ALL ON" : "ALL OFF";
|
||
bool ok = sendCmd(mb, st, cfg.modbusAddr, REG_ALL_CHANNELS, val, d);
|
||
if (ok) {
|
||
for (uint8_t i = 0; i < cfg.channelCount; i++) st.channels[i] = on;
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
bool relayReadAll(ModbusClient& mb, RelayState& st, const RelayConfig& cfg) {
|
||
uint16_t r[MAX_CHANNEL_COUNT] = {0};
|
||
ModbusStatus s = mb.readRegisters(cfg.modbusAddr,
|
||
REG_CHANNEL_BASE, cfg.channelCount, r);
|
||
st.lastUpdateMs = millis();
|
||
if (s != ModbusStatus::OK) {
|
||
Serial.printf("[REL] Cteni stavu: %s (shadow zachovan)\n",
|
||
mb.statusStr(s));
|
||
return false;
|
||
}
|
||
// Dle datasheetu: 0x0001 = open(ON), 0x0000 = close(OFF)
|
||
for (uint8_t i = 0; i < cfg.channelCount; i++) {
|
||
st.channels[i] = (r[i] != 0);
|
||
}
|
||
return true;
|
||
}
|