/********************************************************************************** Modified by: Randy N. CaƱada * TITLE: ESP RainMaker + IR + Manual Button control 2 Relays using ESP32 (Real time feedback + no WiFi control) * Download the libraries * AceButton Library (1.9.2): https://github.com/bxparks/AceButton * IRremote Library (3.6.1): https://github.com/Arduino-IRremote/Arduino-IRremote **********************************************************************************/ #include "RMaker.h" #include "WiFi.h" #include "WiFiProv.h" #include #include using namespace ace_button; const char *service_name = "PROV_1234RB8"; const char *pop = "12345RB8"; // define the Chip Id uint32_t espChipId = 0; // define the Node Name char nodeName[] = "ESP32_Relay_2B"; // define the Device Names char deviceName_1[] = "Fan"; char deviceName_2[] = "Switch2"; //Update the HEX code of IR Remote buttons 0x #define IR_Button_1 0xF30CFF00 //fan #define IR_Button_2 0xE718FF00 //switch 2 #define IR_All_on 0xB847FF00 //all on #define IR_All_Off 0xBA45FF00 // all off // define the GPIO connected with Relays and switches static uint8_t RelayPin1 = 13; //D13 static uint8_t LEDrelay1= 33; //pilot light relay 1 static uint8_t RelayPin2 = 12; //D12 static uint8_t LEDrelay2= 32; //pilot light relay2 static uint8_t SwitchPin1 = 23; //D23 static uint8_t SwitchPin2 = 22; //D12 static uint8_t wifiLed = 2; // D2 static uint8_t gpio_reset = 0; // Press BOOT for reset WiFi static uint8_t IRpin =35; // D35 (IR receiver pin) /* Variable for reading pin status*/ bool toggleState_1 = LOW; //Define integer to remember the toggle state for relay 1 bool toggleState_2 = LOW; //Define integer to remember the toggle state for relay 2 bool isLEDon = HIGH; IRrecv IR(IRpin); ButtonConfig config1; AceButton button1(&config1); ButtonConfig config2; AceButton button2(&config2); void handleEvent1(AceButton*, uint8_t, uint8_t); void handleEvent2(AceButton*, uint8_t, uint8_t); //The framework provides some standard device types like switch, lightbulb, fan, temperature sensor. static Switch my_switch1(deviceName_1, &RelayPin1); static Switch my_switch2(deviceName_2, &RelayPin2); void sysProvEvent(arduino_event_t *sys_event) { switch (sys_event->event_id) { case ARDUINO_EVENT_PROV_START: #if CONFIG_IDF_TARGET_ESP32 Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop); printQR(service_name, pop, "ble"); #else Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", service_name, pop); printQR(service_name, pop, "softap"); #endif break; case ARDUINO_EVENT_WIFI_STA_CONNECTED: Serial.printf("\nConnected to Wi-Fi!\n"); digitalWrite(wifiLed, true); break; } } //------This function is the one to control the rainmaker app and google/alexa voice control-------------- void write_callback(Device *device, Param *param, const param_val_t val, void *priv_data, write_ctx_t *ctx) { const char *device_name = device->getDeviceName(); const char *param_name = param->getParamName(); if(strcmp(device_name, deviceName_1) == 0) { Serial.printf("Lightbulb = %s\n", val.val.b? "true" : "false"); if(strcmp(param_name, "Power") == 0) { Serial.printf("Received value = %s for %s - %s\n", val.val.b? "true" : "false", device_name, param_name); toggleState_1 = val.val.b; (toggleState_1 == false) ? digitalWrite(RelayPin1, HIGH) : digitalWrite(RelayPin1, LOW); isLEDon = val.val.b; (isLEDon== true) ? digitalWrite(LEDrelay1,HIGH) : digitalWrite(LEDrelay1,LOW); param->updateAndReport(val); } } if(strcmp(device_name, deviceName_2) == 0) { Serial.printf("Switch value = %s\n", val.val.b? "true" : "false"); if(strcmp(param_name, "Power") == 0) { Serial.printf("Received value = %s for %s - %s\n", val.val.b? "true" : "false", device_name, param_name); toggleState_2 = val.val.b; (toggleState_2 == false) ? digitalWrite(RelayPin2, HIGH) : digitalWrite(RelayPin2, LOW); isLEDon = val.val.b; (isLEDon== true) ? digitalWrite(LEDrelay2,HIGH) : digitalWrite(LEDrelay2,LOW); param->updateAndReport(val); } } } void ir_remote(){ while (IR.decode()) { Serial.println(IR.decodedIRData.decodedRawData,HEX); switch(IR.decodedIRData.decodedRawData){ case IR_Button_1: digitalWrite(RelayPin1,toggleState_1 ); digitalWrite(LEDrelay1,!toggleState_1); toggleState_1 = !toggleState_1; my_switch1.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_1); break; case IR_Button_2: digitalWrite(RelayPin2, toggleState_2); digitalWrite(LEDrelay2,!toggleState_2); toggleState_2 = !toggleState_2; delay(100); break; case IR_All_on: digitalWrite(RelayPin1, toggleState_1); digitalWrite(LEDrelay1,!toggleState_1); toggleState_1 = !toggleState_1; my_switch1.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_1); digitalWrite(RelayPin2, toggleState_2); digitalWrite(LEDrelay2,!toggleState_2); toggleState_2 = !toggleState_2; my_switch2.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_2); delay(100); break; case IR_All_Off: all_SwitchOff(); digitalWrite(LEDrelay1,LOW); digitalWrite(LEDrelay2,LOW); break; default : break; } delay(100); IR.resume(); } } void all_SwitchOff(){ toggleState_1 = 0; digitalWrite(RelayPin1, HIGH); my_switch1.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_1); delay(100); toggleState_2 = 0; digitalWrite(RelayPin2, HIGH); my_switch2.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_2); delay(100); } void all_SwitchOn(){ toggleState_1 = 1; digitalWrite(RelayPin1, LOW); my_switch1.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_1); delay(100); toggleState_2 = 1; digitalWrite(RelayPin2, LOW); my_switch2.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_2); delay(100); } void setup() { Serial.begin(115200); // Set the Relays GPIOs as output mode pinMode(RelayPin1, OUTPUT); pinMode(RelayPin2, OUTPUT); pinMode(LEDrelay1,OUTPUT); pinMode(LEDrelay2,OUTPUT); pinMode(wifiLed, OUTPUT); // Configure the input GPIOs pinMode(SwitchPin1, INPUT_PULLUP); pinMode(SwitchPin2, INPUT_PULLUP); pinMode(gpio_reset, INPUT); // Write to the GPIOs the default state on booting digitalWrite(RelayPin1, !toggleState_1); digitalWrite(RelayPin2, !toggleState_2); IR.enableIRIn(); // Enabling IR sensor config1.setEventHandler(button1Handler); config2.setEventHandler(button2Handler); button1.init(SwitchPin1); button2.init(SwitchPin2); Node my_node; my_node = RMaker.initNode(nodeName); //Standard switch device my_switch1.addCb(write_callback); my_switch2.addCb(write_callback); //Add switch device to the node my_node.addDevice(my_switch1); my_node.addDevice(my_switch2); //This is optional RMaker.enableOTA(OTA_USING_PARAMS); //If you want to enable scheduling, set time zone for your region using setTimeZone(). //The list of available values are provided here https://rainmaker.espressif.com/docs/time-service.html // RMaker.setTimeZone("Asia/Shanghai"); // Alternatively, enable the Timezone service and let the phone apps set the appropriate timezone RMaker.enableTZService(); RMaker.enableSchedule(); //Service Name for(int i=0; i<17; i=i+8) { espChipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i; } Serial.printf("\nChip ID: %d Service Name: %s\n", espChipId, service_name); Serial.printf("\nStarting ESP-RainMaker\n"); RMaker.start(); WiFi.onEvent(sysProvEvent); #if CONFIG_IDF_TARGET_ESP32 WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name); #else WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name); #endif my_switch1.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, false); my_switch2.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, false); } void loop() { // Read GPIO0 (external button to reset device if(digitalRead(gpio_reset) == LOW) { //Push button pressed Serial.printf("Reset Button Pressed!\n"); // Key debounce handling delay(100); int startTime = millis(); while(digitalRead(gpio_reset) == LOW) delay(50); int endTime = millis(); if ((endTime - startTime) > 10000) { // If key pressed for more than 10secs, reset all Serial.printf("Reset to factory.\n"); RMakerFactoryReset(2); } else if ((endTime - startTime) > 3000) { Serial.printf("Reset Wi-Fi.\n"); // If key pressed for more than 3secs, but less than 10, reset Wi-Fi RMakerWiFiReset(2); } } delay(100); if (WiFi.status() != WL_CONNECTED) { //Serial.println("WiFi Not Connected"); digitalWrite(wifiLed, false); } else { //Serial.println("WiFi Connected"); digitalWrite(wifiLed, true); } ir_remote(); //IR remote Control button1.check(); button2.check(); } //-----This function is for the physical button------------ void button1Handler(AceButton* button, uint8_t eventType, uint8_t buttonState) { Serial.println("EVENT1"); switch (eventType) { case AceButton::kEventReleased: digitalWrite(RelayPin1, toggleState_1); digitalWrite(LEDrelay1,!toggleState_1); toggleState_1 = !toggleState_1; my_switch1.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_1); break; } } void button2Handler(AceButton* button, uint8_t eventType, uint8_t buttonState) { Serial.println("EVENT2"); switch (eventType) { case AceButton::kEventReleased: digitalWrite(RelayPin2, toggleState_2); digitalWrite(LEDrelay2,!toggleState_2); toggleState_2 = !toggleState_2; my_switch2.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_2); break; } }