From dd5a8b28f70d2e6922e595b5ce70ae68af2bcdfe Mon Sep 17 00:00:00 2001 From: Fatima Idrees Date: Sun, 18 May 2025 10:06:27 +0300 Subject: [PATCH] Version 02 of Relay --- README.md | 32 ++--- examples/Master/Master.ino | 104 ++++++++------- examples/Slave/Slave.ino | 252 ++++++++++++++++++++++++------------- src/I2CRelay.cpp | 170 +++++++++++++------------ src/I2CRelay.h | 22 ++-- 5 files changed, 343 insertions(+), 237 deletions(-) diff --git a/README.md b/README.md index 96b9324..aee4603 100644 --- a/README.md +++ b/README.md @@ -77,19 +77,23 @@ The I2CRelay library offers broad versatility for automation through its configu ### API Overview -| Method / Constructor | Description | Parameters / Usage Example | -|---------------------------------------------------|-------------------------------------------------------------------------------------------------------------|------------------------------------------------------| -| `I2CRelay(uint8_t address = 0x08, uint8_t sda = 8, uint8_t scl = 3)` | Create an I2CRelay object with optional I2C address and pin selection. | `I2CRelay relay;`
`I2CRelay relay(0x10, 21, 22);` | -| `void begin()` | Initialize I2C communication with the configured pins. | `relay.begin();` | -| `void setRelay(uint8_t relayNum, uint8_t state)` | Turn relay (1–8) ON or OFF. | `relay.setRelay(3, 1); // ON relay 3` | -| `void setAllRelays(uint8_t state)` | Turn all relays ON or OFF at once. | `relay.setAllRelays(0); // OFF all relays` | -| `void setDeviceName(const String &name)` | Set the name of the I2C relay device (up to 24 chars). | `relay.setDeviceName("MainPanel");` | -| `void setI2CAddress(uint8_t newAddr)` | Change the I2C address of the relay slave. | `relay.setI2CAddress(0x12);` | -| `String getIdentification()` | Query the slave for its identification string (address, type, name, states). | `String id = relay.getIdentification();` | -| `void handleSerialCommand(const String &cmd)` | Parse and execute a serial command string (e.g., `"r 2 1"`, `"all 0"`). | `relay.handleSerialCommand("r 2 1");` | +| Function | Description | Example Usage | +|--------------------------------------------------------------------------|-----------------------------------------------------------------------------|-----------------------------------------------| +| **I2CRelay(uint8_t sda, uint8_t scl)** | Constructor: set I2C SDA/SCL pins (optional, defaults to board pins) | `I2CRelay relay(8, 3);` | +| **void begin()** | Initialize the I2C bus | `relay.begin();` | +| **void scan(Stream &out = Serial)** | Scan and print all I2C devices on the bus | `relay.scan();` | +| **void setSlaveAddress(uint8_t oldAddr, uint8_t newAddr, Stream &out = Serial)** | Change the slave’s I2C address | `relay.setSlaveAddress(0x08, 0x09);` | +| **void setSlaveName(uint8_t addr, const char* name, Stream &out = Serial)** | Change the slave’s device name | `relay.setSlaveName(0x08, "MyRelay");` | +| **String requestSlaveInfo(uint8_t addr)** | Get info string from the slave | `String info = relay.requestSlaveInfo(0x08);` | +| **bool setRelay(uint8_t addr, uint8_t relayNum, uint8_t state)** | Set relay (1–8) ON/OFF (`state`: 1=ON, 0=OFF) | `relay.setRelay(0x08, 3, 1);` | +| **bool setAllRelays(uint8_t addr, uint8_t state)** | Set all relays ON/OFF (`state`: 1=ON, 0=OFF) | `relay.setAllRelays(0x08, 0);` | +| **bool setRelayTimer(uint8_t addr, uint8_t relayNum, uint32_t ms)** | Set relay (1–8) ON for given ms, then auto-OFF | `relay.setRelayTimer(0x08, 2, 2000);` | +| **bool setAllRelaysTimer(uint8_t addr, uint32_t ms)** | Set all relays ON for given ms, then auto-OFF | `relay.setAllRelaysTimer(0x08, 3000);` | -**Notes:** -- `relayNum` is 1–8 (user-facing), mapped internally to 0–7. -- `state` is `1` (ON) or `0` (OFF). -- All methods are non-blocking except `setAllRelays`, which adds a small delay between commands. +### Parameter Notes + +- **addr**: I2C address of the slave (e.g. `0x08`) +- **relayNum**: Relay number **1–8** +- **state**: `1` = ON, `0` = OFF +- **ms**: Duration in milliseconds diff --git a/examples/Master/Master.ino b/examples/Master/Master.ino index 41d02e0..dbbf70f 100644 --- a/examples/Master/Master.ino +++ b/examples/Master/Master.ino @@ -1,57 +1,75 @@ -#include +#include +#include "I2CRelay.h" -I2CRelay relay; +I2CRelay relay(8, 3); // Use your SDA/SCL pins void setup() { - Serial.begin(115200); - delay(1000); - Serial.println("I2CRelay Master Example with 'i' command for ID"); - relay.begin(); + Serial.begin(115200); + relay.begin(); - // Run test functions as before - relay.setRelay(1, 1); - relay.setRelay(8, 1); - Serial.println("Turned ON relay 1 and relay 8"); - delay(500); + uint8_t addr = 0x08; - relay.setRelay(1, 0); - relay.setRelay(8, 0); - Serial.println("Turned OFF relay 1 and relay 8"); - delay(500); + // 1. Scan the I2C bus + Serial.println("=== I2C Scan ==="); + relay.scan(); - relay.setAllRelays(1); - Serial.println("Turned ON all relays"); - delay(500); + // 2. Get info from the slave + Serial.println("=== Request Info ==="); + String info = relay.requestSlaveInfo(addr); + Serial.print("Info: "); + Serial.println(info); - relay.setAllRelays(0); - Serial.println("Turned OFF all relays"); - delay(500); + // 3. Change the slave name + Serial.println("=== Change Name ==="); + relay.setSlaveName(addr, "FirstRelay"); + delay(100); + Serial.println("Name changed."); - relay.setDeviceName("TestPanel"); - Serial.println("Device name set to 'TestPanel'"); - delay(500); + // 4. Turn relay 1 ON + Serial.println("=== Turn Relay 1 ON ==="); + relay.setRelay(addr, 1, 1); // 1 = ON + delay(1500); - String id = relay.getIdentification(); - Serial.print("Identification string: "); - Serial.println(id); - delay(500); + // 5. Turn relay 1 OFF + Serial.println("=== Turn Relay 1 OFF ==="); + relay.setRelay(addr, 1, 0); // 0 = OFF + delay(500); - relay.setI2CAddress(0x09); - Serial.println("Changed I2C address to 0x09"); - Serial.println("** Update master address to 0x09 for further communication **"); + // 6. Turn all relays ON + Serial.println("=== Turn All Relays ON ==="); + relay.setAllRelays(addr, 1); // 1 = ON + delay(500); + + // 7. Turn all relays OFF + Serial.println("=== Turn All Relays OFF ==="); + relay.setAllRelays(addr, 0); // 0 = OFF + delay(500); + + // 8. Turn relay 2 ON for 2 seconds + Serial.println("=== Relay 2 ON for 2 seconds ==="); + relay.setRelayTimer(addr, 2, 2000); // relay 2, 2000 ms + delay(2500); + + // 9. Turn all relays ON for 3 seconds + Serial.println("=== All relays ON for 3 seconds ==="); + relay.setAllRelaysTimer(addr, 3000); // 3000 ms + delay(3500); + + // 10. Change slave address from 0x08 to 0x09 + Serial.println("=== Change Address 0x08 -> 0x09 ==="); + relay.setSlaveAddress(0x08, 0x08); + addr = 0x08; // Use new address for further commands + delay(1500); + + // 11. Confirm new address by requesting info + Serial.println("=== Request Info from 0x09 ==="); + info = relay.requestSlaveInfo(addr); + Serial.print("Info: "); + Serial.println(info); + + Serial.println("=== Test Complete ==="); } void loop() { - if (Serial.available()) { - String cmd = Serial.readStringUntil('\n'); - cmd.trim(); - // Replace "id" with "i" here: - if (cmd == "i") { - String id = relay.getIdentification(); - Serial.print("ID: "); - Serial.println(id); - } else { - relay.handleSerialCommand(cmd); - } - } + // Nothing here } diff --git a/examples/Slave/Slave.ino b/examples/Slave/Slave.ino index cf8eecf..7002a52 100644 --- a/examples/Slave/Slave.ino +++ b/examples/Slave/Slave.ino @@ -1,105 +1,181 @@ #include #include -#define DEFAULT_ADDRESS 0x08 -#define MAX_NAME_LENGTH 24 +#define EEPROM_SIZE 64 +#define EEPROM_ADDR_LOC 0 // EEPROM location for I2C address +#define EEPROM_NAME_LOC 1 // EEPROM location for device name +#define DEVICE_NAME_LEN 24 +#define DEFAULT_I2C_ADDR 0x08 // Default I2C address -// EEPROM Structure -struct Config { - uint8_t address; - char deviceName[MAX_NAME_LENGTH+1]; - uint8_t relayStates; +char deviceName[DEVICE_NAME_LEN] = "Relay"; +uint8_t i2cAddress = DEFAULT_I2C_ADDR; + +// I2C command codes +enum Command : uint8_t { + CMD_SET_ADDR = 0x01, + CMD_SET_NAME = 0x02, }; -Config config; +// --- RELAY FEATURE ADDITIONS --- const int relayPins[8] = {0, 1, 2, 3, 4, 5, 6, 7}; // GPIOs 0-7 +uint8_t relayStates[8] = {0}; // 0=OFF, 1=ON +unsigned long relayTimers[8] = {0}; // millis() when to turn off, 0 = no timer -void handleCommand(int numBytes); -void saveConfig(); -void loadConfig(); -void emergencyStop(); +enum RelayCommand : uint8_t { + CMD_RELAY_SET = 0x10, // [relay#][0|1] (relay# = 1..8) + CMD_RELAY_ALL = 0x11, // [0|1] + CMD_RELAY_TIMER = 0x12, // [relay#][ms_L][ms_H][ms_U][ms_T] + CMD_RELAY_ALL_TIMER = 0x13 // [ms_L][ms_H][ms_U][ms_T] +}; + +// *** INVERTED RELAY LOGIC *** +// User relay numbers: 1–8. Array indices: 0–7. +void setRelay(uint8_t relayNum, uint8_t state) { + if (relayNum >= 1 && relayNum <= 8) { + uint8_t idx = relayNum - 1; + relayStates[idx] = (state == 1 ? 1 : 0); + // Inverted logic: LOW = ON, HIGH = OFF + digitalWrite(relayPins[idx], relayStates[idx] ? LOW : HIGH); + } +} + +void setAllRelays(uint8_t state) { + for (uint8_t i = 1; i <= 8; i++) setRelay(i, state); +} +// --- END RELAY FEATURE ADDITIONS --- + +void storeAddressToEEPROM(uint8_t addr) { + EEPROM.write(EEPROM_ADDR_LOC, addr); + EEPROM.commit(); +} + +uint8_t readAddressFromEEPROM() { + uint8_t addr = EEPROM.read(EEPROM_ADDR_LOC); + if (addr == 0xFF || addr == 0x00) { + addr = DEFAULT_I2C_ADDR; + storeAddressToEEPROM(addr); + } + return addr; +} + +void storeNameToEEPROM(const char* name) { + for (int i = 0; i < DEVICE_NAME_LEN; i++) { + EEPROM.write(EEPROM_NAME_LOC + i, name[i]); + if (name[i] == '\0') break; + } + EEPROM.commit(); +} + +void readNameFromEEPROM(char* name) { + for (int i = 0; i < DEVICE_NAME_LEN; i++) { + name[i] = EEPROM.read(EEPROM_NAME_LOC + i); + if (name[i] == '\0') break; + } + name[DEVICE_NAME_LEN - 1] = '\0'; +} + +// Handle data received from master +void onReceive(int len) { + if (len < 1) return; + uint8_t cmd = Wire.read(); + switch (cmd) { + case CMD_SET_ADDR: + if (Wire.available()) { + uint8_t newAddr = Wire.read(); + if (newAddr > 0x00 && newAddr < 0x78) { + storeAddressToEEPROM(newAddr); + ESP.restart(); + } + } + break; + case CMD_SET_NAME: { + int i = 0; + while (Wire.available() && i < DEVICE_NAME_LEN - 1) { + deviceName[i++] = Wire.read(); + } + deviceName[i] = '\0'; + storeNameToEEPROM(deviceName); + break; + } + // --- RELAY FEATURE ADDITIONS --- + case CMD_RELAY_SET: + if (Wire.available() >= 2) { + uint8_t relayNum = Wire.read(); // Now 1..8 + uint8_t state = Wire.read(); // 0|1 + setRelay(relayNum, state); + if (relayNum >= 1 && relayNum <= 8) relayTimers[relayNum-1] = 0; + } + break; + case CMD_RELAY_ALL: + if (Wire.available() >= 1) { + uint8_t state = Wire.read(); // 0|1 + setAllRelays(state); + for (int i = 0; i < 8; i++) relayTimers[i] = 0; + } + break; + case CMD_RELAY_TIMER: + if (Wire.available() >= 5) { + uint8_t relayNum = Wire.read(); // 1..8 + uint32_t ms = Wire.read(); + ms |= ((uint32_t)Wire.read()) << 8; + ms |= ((uint32_t)Wire.read()) << 16; + ms |= ((uint32_t)Wire.read()) << 24; + setRelay(relayNum, 1); + if (relayNum >= 1 && relayNum <= 8) + relayTimers[relayNum-1] = millis() + ms; + } + break; + case CMD_RELAY_ALL_TIMER: + if (Wire.available() >= 4) { + uint32_t ms = Wire.read(); + ms |= ((uint32_t)Wire.read()) << 8; + ms |= ((uint32_t)Wire.read()) << 16; + ms |= ((uint32_t)Wire.read()) << 24; + setAllRelays(1); + unsigned long offTime = millis() + ms; + for (int i = 0; i < 8; i++) relayTimers[i] = offTime; + } + break; + // --- END RELAY FEATURE ADDITIONS --- + default: + break; + } +} + +// Handle data requested by master +void onRequest() { + String response = String(i2cAddress, HEX) + ",GENERIC," + deviceName; + Wire.write((const uint8_t*)response.c_str(), response.length()); +} void setup() { Serial.begin(115200); - EEPROM.begin(sizeof(Config)); - loadConfig(); - - // Initialize relays - for(int i=0; i<8; i++) { + EEPROM.begin(EEPROM_SIZE); + + i2cAddress = readAddressFromEEPROM(); + readNameFromEEPROM(deviceName); + + Wire.begin(i2cAddress); + Wire.onReceive(onReceive); + Wire.onRequest(onRequest); + + for (int i = 0; i < 8; i++) { pinMode(relayPins[i], OUTPUT); - digitalWrite(relayPins[i], HIGH); // Active-low logic + digitalWrite(relayPins[i], HIGH); // Inverted logic: HIGH = OFF at start } - - Wire.onReceive(handleCommand); - Wire.onRequest([]() { - String response = String(config.address) + ",8-relay," + - config.deviceName + "," + - String(config.relayStates, BIN); - Wire.print(response); - }); - - Wire.begin((uint8_t)config.address); + + Serial.print("I2C Slave started at address 0x"); + Serial.println(i2cAddress, HEX); + Serial.print("Device name: "); + Serial.println(deviceName); } -void loop() { /* Empty */ } - -void handleCommand(int numBytes) { - uint8_t cmd = Wire.read(); - - switch(cmd) { - case 0xA0: // Set relay state - if(numBytes == 3) { - uint8_t relay = Wire.read(); - uint8_t state = Wire.read(); - if(relay < 8) { - digitalWrite(relayPins[relay], state ? LOW : HIGH); - bitWrite(config.relayStates, relay, state); - } - } - break; - - case 0xB0: // Emergency stop - emergencyStop(); - break; - - case 0xC0: // Set address - if(numBytes == 2) { - config.address = Wire.read(); - saveConfig(); - Wire.begin((uint8_t)config.address); - } - break; - - case 0xD0: // Set device name - if(numBytes > 1) { - uint8_t i = 0; - while(Wire.available() && i < MAX_NAME_LENGTH) { - config.deviceName[i++] = Wire.read(); - } - config.deviceName[i] = '\0'; - saveConfig(); - } - break; +void loop() { + unsigned long now = millis(); + for (int i = 0; i < 8; i++) { + if (relayTimers[i] && now >= relayTimers[i]) { + setRelay(i+1, 0); // Use relay number 1..8 + relayTimers[i] = 0; + } } } - -void emergencyStop() { - for(int i=0; i<8; i++) { - digitalWrite(relayPins[i], HIGH); - } - config.relayStates = 0; -} - -void loadConfig() { - EEPROM.get(0, config); - if(config.address < 0x08 || config.address > 0x77) { - config.address = DEFAULT_ADDRESS; - strcpy(config.deviceName, "8-Relay Module"); - saveConfig(); - } -} - -void saveConfig() { - EEPROM.put(0, config); - EEPROM.commit(); -} diff --git a/src/I2CRelay.cpp b/src/I2CRelay.cpp index 2b9ebef..cfbb12c 100644 --- a/src/I2CRelay.cpp +++ b/src/I2CRelay.cpp @@ -1,102 +1,110 @@ #include "I2CRelay.h" -I2CRelay::I2CRelay(uint8_t address, uint8_t sda, uint8_t scl) - : _address(address), _sda(sda), _scl(scl) {} +// Command codes +#define CMD_SET_ADDR 0x01 +#define CMD_SET_NAME 0x02 +#define CMD_RELAY_SET 0x10 +#define CMD_RELAY_ALL 0x11 +#define CMD_RELAY_TIMER 0x12 +#define CMD_RELAY_ALL_TIMER 0x13 + +I2CRelay::I2CRelay(uint8_t sda, uint8_t scl) + : _sda(sda), _scl(scl) {} void I2CRelay::begin() { Wire.begin(_sda, _scl); } -void I2CRelay::setRelay(uint8_t relayNum, uint8_t state) { - if (relayNum < 1 || relayNum > 8) return; - Wire.beginTransmission(_address); - Wire.write(0xA0); - Wire.write(relayNum - 1); // Map 1-8 to 0-7 - Wire.write(state); - Wire.endTransmission(); -} - -void I2CRelay::setAllRelays(uint8_t state) { - for (uint8_t i = 1; i <= 8; i++) { - setRelay(i, state); - delay(10); +void I2CRelay::scan(Stream &out) { + out.println("Scanning I2C bus..."); + uint8_t count = 0; + for (uint8_t address = 1; address < 127; address++) { + Wire.beginTransmission(address); + uint8_t error = Wire.endTransmission(); + if (error == 0) { + out.print("I2C device found at address 0x"); + if (address < 16) out.print("0"); + out.print(address, HEX); + out.println(" !"); + count++; + } + delay(2); } -} - -void I2CRelay::setDeviceName(const String &name) { - Wire.beginTransmission(_address); - Wire.write(0xD0); - for (uint8_t i = 0; i < name.length() && i < 24; i++) { - Wire.write(name[i]); + if (count == 0) { + out.println("No I2C devices found."); + } else { + out.print("Scan complete, devices found: "); + out.println(count); } - Wire.endTransmission(); + out.println(); } -void I2CRelay::setI2CAddress(uint8_t newAddr) { - if (newAddr < 8 || newAddr > 119) return; - Wire.beginTransmission(_address); - Wire.write(0xC0); +void I2CRelay::setSlaveAddress(uint8_t oldAddr, uint8_t newAddr, Stream &out) { + Wire.beginTransmission(oldAddr); + Wire.write(CMD_SET_ADDR); Wire.write(newAddr); Wire.endTransmission(); + out.print("Sent address change command: 0x"); + out.print(oldAddr, HEX); + out.print(" -> 0x"); + out.println(newAddr, HEX); + delay(1200); // Give slave time to restart } -String I2CRelay::getIdentification() { - Wire.requestFrom(_address, (uint8_t)40); - String id = ""; +void I2CRelay::setSlaveName(uint8_t addr, const char* newName, Stream &out) { + Wire.beginTransmission(addr); + Wire.write(CMD_SET_NAME); + Wire.write((const uint8_t*)newName, strlen(newName)); + Wire.endTransmission(); + out.print("Sent name change command to 0x"); + out.print(addr, HEX); + out.print(": "); + out.println(newName); +} + +String I2CRelay::requestSlaveInfo(uint8_t addr) { + Wire.requestFrom(addr, (uint8_t)40); + String response = ""; while (Wire.available()) { char c = Wire.read(); - id += c; + response += c; } - return id; + return response; } -void I2CRelay::handleSerialCommand(const String &cmd) { - if (cmd.startsWith("r ")) { - int space1 = cmd.indexOf(' '); - int space2 = cmd.indexOf(' ', space1 + 1); - if (space1 > 0 && space2 > space1) { - int relay = cmd.substring(space1 + 1, space2).toInt(); - int state = cmd.substring(space2 + 1).toInt(); - if (relay >= 1 && relay <= 8 && (state == 0 || state == 1)) { - setRelay(relay, state); - Serial.print("Relay "); - Serial.print(relay); - Serial.print(" set to "); - Serial.println(state ? "ON" : "OFF"); - } else { - Serial.println("Invalid relay number or state. Use 1-8 and 0/1."); - } - } else { - Serial.println("Usage: r <0|1>"); - } - } else if (cmd.startsWith("all ")) { - int state = cmd.substring(4).toInt(); - if (state == 0 || state == 1) { - setAllRelays(state); - Serial.print("All relays set to "); - Serial.println(state ? "ON" : "OFF"); - } else { - Serial.println("Invalid state for all."); - } - } else if (cmd.startsWith("name ")) { - String name = cmd.substring(5); - setDeviceName(name); - Serial.print("Device name set to: "); - Serial.println(name); - } else if (cmd.startsWith("addr ")) { - int newAddr = cmd.substring(5).toInt(); - if (newAddr >= 8 && newAddr <= 119) { - setI2CAddress(newAddr); - Serial.print("I2C address set to: "); - Serial.println(newAddr, HEX); - } else { - Serial.println("Invalid address."); - } - } else if (cmd == "id") { - String id = getIdentification(); - Serial.print("ID: "); - Serial.println(id); - } else { - Serial.println("Unknown command."); - } +// Relay control +bool I2CRelay::setRelay(uint8_t addr, uint8_t relay, bool on) { + Wire.beginTransmission(addr); + Wire.write(CMD_RELAY_SET); + Wire.write(relay); + Wire.write(on ? 1 : 0); + return Wire.endTransmission() == 0; +} + +bool I2CRelay::setAllRelays(uint8_t addr, bool on) { + Wire.beginTransmission(addr); + Wire.write(CMD_RELAY_ALL); + Wire.write(on ? 1 : 0); + return Wire.endTransmission() == 0; +} + +bool I2CRelay::setRelayTimer(uint8_t addr, uint8_t relay, uint32_t ms) { + Wire.beginTransmission(addr); + Wire.write(CMD_RELAY_TIMER); + Wire.write(relay); + Wire.write((uint8_t)(ms & 0xFF)); + Wire.write((uint8_t)((ms >> 8) & 0xFF)); + Wire.write((uint8_t)((ms >> 16) & 0xFF)); + Wire.write((uint8_t)((ms >> 24) & 0xFF)); + return Wire.endTransmission() == 0; +} + +bool I2CRelay::setAllRelaysTimer(uint8_t addr, uint32_t ms) { + Wire.beginTransmission(addr); + Wire.write(CMD_RELAY_ALL_TIMER); + Wire.write((uint8_t)(ms & 0xFF)); + Wire.write((uint8_t)((ms >> 8) & 0xFF)); + Wire.write((uint8_t)((ms >> 16) & 0xFF)); + Wire.write((uint8_t)((ms >> 24) & 0xFF)); + return Wire.endTransmission() == 0; } diff --git a/src/I2CRelay.h b/src/I2CRelay.h index 2d69406..a86b774 100644 --- a/src/I2CRelay.h +++ b/src/I2CRelay.h @@ -6,22 +6,22 @@ class I2CRelay { public: - I2CRelay(uint8_t address = 0x08, uint8_t sda = 8, uint8_t scl = 3); + I2CRelay(uint8_t sda = SDA, uint8_t scl = SCL); void begin(); - void setRelay(uint8_t relayNum, uint8_t state); - void setAllRelays(uint8_t state); - void setDeviceName(const String &name); - void setI2CAddress(uint8_t newAddr); - String getIdentification(); + void scan(Stream &out = Serial); + void setSlaveAddress(uint8_t oldAddr, uint8_t newAddr, Stream &out = Serial); + void setSlaveName(uint8_t addr, const char* newName, Stream &out = Serial); + String requestSlaveInfo(uint8_t addr); - // Helper for command parsing (optional) - void handleSerialCommand(const String &cmd); + // Relay control + bool setRelay(uint8_t addr, uint8_t relay, bool on); + bool setAllRelays(uint8_t addr, bool on); + bool setRelayTimer(uint8_t addr, uint8_t relay, uint32_t ms); + bool setAllRelaysTimer(uint8_t addr, uint32_t ms); private: - uint8_t _address; - uint8_t _sda; - uint8_t _scl; + uint8_t _sda, _scl; }; #endif