// Uncomment the following line to enable serial debug output
//#define ENABLE_DEBUG
#ifdef ENABLE_DEBUG
#define DEBUG_ESP_PORT Serial
#define NODEBUG_WEBSOCKETS
#define NDEBUG
#endif
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include "SinricPro.h"
#include "SinricProSwitch.h"
#include <map>
#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASS ""
#define APP_KEY "c9b93268-8e83-4217-9e4b-a5b85a530322"
#define APP_SECRET "09ee2670-76d4-41c3-8b18-211c1e6da614-31465693-d034-4cec-ad84-737147fb8b0b"
#define device_ID_1 "6555a3cd22527fb23182836e"
#define device_ID_2 "6555a3fb22527fb23182838d"
#define device_ID_3 "6555a416377c5cde8693c77a"
#define device_ID_4 "SWITCH_ID_NO_4_HERE"
#define RelayPin1 13
#define RelayPin2 12
#define RelayPin3 14
#define RelayPin4 27
#define SwitchPin1 26
#define SwitchPin2 25
#define SwitchPin3 33
#define SwitchPin4 32
#define wifiLed 16
//#define TACTILE_BUTTON 1
#define BAUD_RATE 9600
#define DEBOUNCE_TIME 250
typedef struct {
int relayPIN;
int flipSwitchPIN;
} deviceConfig_t;
std::map<String, deviceConfig_t> devices = {
{device_ID_1, { RelayPin1, SwitchPin1 }},
{device_ID_2, { RelayPin2, SwitchPin2 }},
{device_ID_3, { RelayPin3, SwitchPin3 }},
{device_ID_4, { RelayPin4, SwitchPin4 }}
};
typedef struct {
String deviceId;
bool lastFlipSwitchState;
unsigned long lastFlipSwitchChange;
} flipSwitchConfig_t;
std::map<int, flipSwitchConfig_t> flipSwitches;
void setupRelays() {
for (auto &device : devices) {
int relayPIN = device.second.relayPIN;
pinMode(relayPIN, OUTPUT);
digitalWrite(relayPIN, HIGH);
}
}
void setupFlipSwitches() {
for (auto &device : devices) {
flipSwitchConfig_t flipSwitchConfig;
flipSwitchConfig.deviceId = device.first;
flipSwitchConfig.lastFlipSwitchChange = 0;
flipSwitchConfig.lastFlipSwitchState = true;
int flipSwitchPIN = device.second.flipSwitchPIN;
flipSwitches[flipSwitchPIN] = flipSwitchConfig;
pinMode(flipSwitchPIN, INPUT_PULLUP);
}
}
bool onPowerState(String deviceId, bool &state)
{
Serial.printf("%s: %s\r\n", deviceId.c_str(), state ? "on" : "off");
int relayPIN = devices[deviceId].relayPIN;
digitalWrite(relayPIN, state ? HIGH : LOW); // Toggle the relay state
return true;
}
void handleFlipSwitches() {
unsigned long actualMillis = millis();
for (auto &flipSwitch : flipSwitches) {
unsigned long lastFlipSwitchChange = flipSwitch.second.lastFlipSwitchChange;
if (actualMillis - lastFlipSwitchChange > DEBOUNCE_TIME) {
int flipSwitchPIN = flipSwitch.first;
bool lastFlipSwitchState = flipSwitch.second.lastFlipSwitchState;
bool flipSwitchState = digitalRead(flipSwitchPIN);
if (flipSwitchState != lastFlipSwitchState) {
#ifdef TACTILE_BUTTON
if (flipSwitchState) {
#endif
flipSwitch.second.lastFlipSwitchChange = actualMillis;
String deviceId = flipSwitch.second.deviceId;
int relayPIN = devices[deviceId].relayPIN;
// Toggle the relay state only when the button is pressed (not released)
if (flipSwitchState) {
bool newRelayState = !digitalRead(relayPIN);
digitalWrite(relayPIN, newRelayState);
SinricProSwitch &mySwitch = SinricPro[deviceId];
mySwitch.sendPowerStateEvent(!newRelayState);
}
#ifdef TACTILE_BUTTON
}
#endif
flipSwitch.second.lastFlipSwitchState = flipSwitchState;
}
}
}
}
void setupWiFi()
{
Serial.printf("\r\n[Wifi]: Connecting");
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED)
{
Serial.printf(".");
delay(250);
}
digitalWrite(wifiLed, LOW);
Serial.printf("connected!\r\n[WiFi]: IP-Address is %s\r\n", WiFi.localIP().toString().c_str());
}
void setupSinricPro()
{
for (auto &device : devices)
{
const char *deviceId = device.first.c_str();
SinricProSwitch &mySwitch = SinricPro[deviceId];
mySwitch.onPowerState(onPowerState);
}
SinricPro.begin(APP_KEY, APP_SECRET);
SinricPro.restoreDeviceStates(true);
}
void setup()
{
Serial.begin(BAUD_RATE);
pinMode(wifiLed, OUTPUT);
digitalWrite(wifiLed, HIGH);
setupRelays();
setupFlipSwitches();
setupWiFi();
setupSinricPro();
}
void loop()
{
SinricPro.handle();
handleFlipSwitches();
}