ESPlan/SW/ESPlan_RS485_Relay/relay.cpp

115 lines
4.0 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 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;
}