I2CRelay/examples/Slave/Slave.ino

182 lines
5.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <Wire.h>
#include <EEPROM.h>
#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
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,
};
// --- 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
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: 18. Array indices: 07.
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(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); // Inverted logic: HIGH = OFF at start
}
Serial.print("I2C Slave started at address 0x");
Serial.println(i2cAddress, HEX);
Serial.print("Device name: ");
Serial.println(deviceName);
}
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;
}
}
}