sinricpro / esp8266-esp32-sdk

Library for https://sinric.pro - simple way to connect your device to Alexa, Google Home, SmartThings and cloud
https://sinric.pro
Other
236 stars 125 forks source link

Multiple Input and Output #31

Closed philb1192 closed 4 years ago

philb1192 commented 4 years ago

Hi, with the switch example I was able to add a physical toggle switch and activate a device with it. Would it be possible to add more switch and devices on the same ESP8266 (4 Switch and 4 Device)? How could I modify my code to achieve that? Thanks.

` // 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

ifdef ESP8266

   #include <ESP8266WiFi.h>

endif

ifdef ESP32

   #include <WiFi.h>

endif

include "SinricPro.h"

include "SinricProSwitch.h"

define WIFI_SSID ""

define WIFI_PASS ""

define APP_KEY "" // Should look like "de0bxxxx-1x3x-4x3x-ax2x-5dabxxxxxxxx"

define APP_SECRET "" // Should look like "5f36xxxx-x3x7-4x3x-xexe-e86724a9xxxx-4c4axxxx-3x3x-x5xe-x9x3-333d65xxxxxx"

define SWITCH_ID "" // Should look like "5dc1564130xxxxxxxxxxxxxx"

define BAUD_RATE 9600 // Change baudrate to your need

bool myPowerState = false; int device_1 = 5; int pass_1 = 0; int storedvalue_1 = 0; int switch_1 = 13;

bool onPowerState(const String &deviceId, bool &state) { Serial.printf("Device %s turned %s (via SinricPro) \r\n", deviceId.c_str(), state?"on":"off"); myPowerState = state; digitalWrite(device_1, myPowerState?HIGH:LOW); return true; // request handled properly }

void handleButtonPress() { if(pass_1 == 0) { storedvalue_1 = digitalRead(switch_1); pass_1 = 1; } if(storedvalue_1 != digitalRead(switch_1)) { if (myPowerState) { // flip myPowerState: if it was true, set it to false, vice versa myPowerState = false; } else { myPowerState = true; } digitalWrite(device_1, myPowerState?LOW:HIGH); // if myPowerState indicates device turned on: turn on led (builtin led uses inverted logic: LOW = LED ON / HIGH = LED OFF) SinricProSwitch& mySwitch = SinricPro[SWITCH_ID]; mySwitch.sendPowerStateEvent(myPowerState); // send the new powerState to SinricPro server Serial.printf("Device %s turned %s (manually via flashbutton)\r\n", mySwitch.getDeviceId(), myPowerState?"on":"off"); digitalWrite(device_1, myPowerState?HIGH:LOW); delay(1000); storedvalue_1 = digitalRead(switch_1); pass_1 = 0; } } // setup function for WiFi connection void setupWiFi() { Serial.printf("\r\n[Wifi]: Connecting"); WiFi.begin(WIFI_SSID, WIFI_PASS);

while (WiFi.status() != WL_CONNECTED) { Serial.printf("."); delay(250); } IPAddress localIP = WiFi.localIP(); Serial.printf("connected!\r\n[WiFi]: IP-Address is %d.%d.%d.%d\r\n", localIP[0], localIP[1], localIP[2], localIP[3]); }

// setup function for SinricPro void setupSinricPro() { // add device to SinricPro SinricProSwitch& mySwitch = SinricPro[SWITCH_ID];

// set callback function to device mySwitch.onPowerState(onPowerState);

// setup SinricPro SinricPro.onConnected([](){ Serial.printf("Connected to SinricPro\r\n"); }); SinricPro.onDisconnected([](){ Serial.printf("Disconnected from SinricPro\r\n"); }); SinricPro.begin(APP_KEY, APP_SECRET); }

// main setup function void setup() { pinMode(device_1, OUTPUT); // define LED GPIO as output digitalWrite(device_1, LOW); // turn off LED on bootup pinMode(switch_1, INPUT);

Serial.begin(BAUD_RATE); Serial.printf("\r\n\r\n"); setupWiFi(); setupSinricPro(); }

void loop() { handleButtonPress(); SinricPro.handle(); }`

sivar2311 commented 4 years ago

Hi Phil,

there are multiple ways to run more than one device on the same ESP module. Using different onPowerStateCallbacks:

  SinricProSwitch &mySwitch1 = SinricPro[SWITCH_ID_1];
  mySwitch1.onPowerState(onPowerState1);

  SinricProSwitch &mySwitch2 = SinricPro[SWITCH_ID_2];
  mySwitch1.onPowerState(onPowerState2);

  SinricProSwitch &mySwitch3 = SinricPro[SWITCH_ID_3];
  mySwitch1.onPowerState(onPowerState3);

Pro:

Con:

Using same callback (you must check for deviceId inside the callback):

  SinricProSwitch &mySwitch1 = SinricPro[SWITCH_ID_1];
  mySwitch1.onPowerState(onPowerState);

  SinricProSwitch &mySwitch2 = SinricPro[SWITCH_ID_2];
  mySwitch1.onPowerState(onPowerState);

  SinricProSwitch &mySwitch3 = SinricPro[SWITCH_ID_3];
  mySwitch1.onPowerState(onPowerState);

Pro:

Con:

Please take a look at the code i mentioned in this issue. This code using a std::map to keep all neccessary device information like deviceId, PIN and current state.

If you want to switch each device manually by using a push button: You need to change your handleButtonPress function to send the powerStateEvent on corresponding device. I recommend to use second std:map for this, to map the button PIN to deviceID.

philb1192 commented 4 years ago

Thank You for your help! I was able to add more device but I have a hard time with the '' handleButtonPress '' function to add more switch. I've looked into the std:map. but I'm clueless on how it works, I'm more of a hobbyist than a programmer hehe. Could you help me with it? My goal is to change every switch in my house with SinricPro.

sivar2311 commented 4 years ago

I am currently working on an example for you ;)

Edit: I think you like to have a push-button for each relay, to switch each relay manually?

redneal commented 4 years ago

Atualmente, estou trabalhando em um exemplo para você;)

Edit: Eu acho que você gostaria de ter um botão para cada relé, para alternar cada relé manualmente?

Hello! Thanks for your answers helped a lot. Following his guidance, I finally managed to reach the goal.

I am also more of a hobby as our friend philb1192!

But I would like that if possible, you could analyze my changes and guide me on how I can improve it.

Thank you! _____CODE__

// 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

ifdef ESP8266

   #include <ESP8266WiFi.h>

endif

ifdef ESP32

   #include <WiFi.h>

endif

include "SinricPro.h"

include "SinricProSwitch.h"

define WIFI_SSID "RednealSystem"

define WIFI_PASS "L1a1e1n1d1"

define APP_KEY "**" // Should look like "de0bxxxx-1x3x-4x3x-ax2x-5dabxxxxxxxx"

define APP_SECRET "**" // Should look like "5f36xxxx-x3x7-4x3x-xexe-e86724a9xxxx-4c4axxxx-3x3x-x5xe-x9x3-333d65xxxxxx"

define SWITCH_IDL "**" // Should look like "5dc1564130xxxxxxxxxxxxxx"

define SWITCH_IDLJ "**"

define SWITCH_IDI "**"

define BAUD_RATE 9600 // Change baudrate to your need

define BTN_FLASH 0

define luz 4

define luzJ 5

define irriga 15

bool myPowerState = false; unsigned long lastBtnPress = 0;

bool onPowerState1(const String &deviceId, bool &state) { Serial.printf("Device %s turned %s (via SinricPro) \r\n", deviceId.c_str(), state?"on":"off"); myPowerState = state; digitalWrite(luz, myPowerState?HIGH:LOW); return true; // request handled properly } bool onPowerState2(const String &deviceId, bool &state) { Serial.printf("Device %s turned %s (via SinricPro) \r\n", deviceId.c_str(), state?"on":"off"); myPowerState = state; digitalWrite(luzJ, myPowerState?HIGH:LOW); return true; // request handled properly } bool onPowerState3(const String &deviceId, bool &state) { Serial.printf("Device %s turned %s (via SinricPro) \r\n", deviceId.c_str(), state?"on":"off"); myPowerState = state; digitalWrite(irriga, myPowerState?HIGH:LOW); return true; // request handled properly }

void handleButtonPress() { unsigned long actualMillis = millis(); // get actual millis() and keep it in variable actualMillis if (digitalRead(BTN_FLASH) == LOW && actualMillis - lastBtnPress > 1000) { // is button pressed (inverted logic! button pressed = LOW) and debounced? if (myPowerState) { // flip myPowerState: if it was true, set it to false, vice versa myPowerState = false; } else { myPowerState = true; }

if (onPowerState1) digitalWrite(luz, myPowerState?HIGH:LOW); 
if (onPowerState2) digitalWrite(luzJ, myPowerState?HIGH:LOW);
if (onPowerState3) digitalWrite(irriga, myPowerState?HIGH:LOW);

// get Switch device back
SinricProSwitch& mySwitch1 = SinricPro[SWITCH_IDL];
SinricProSwitch& mySwitch2 = SinricPro[SWITCH_IDLJ];
SinricProSwitch& mySwitch3 = SinricPro[SWITCH_IDI];
// send powerstate event
mySwitch1.sendPowerStateEvent(myPowerState); // send the new powerState to SinricPro server
mySwitch2.sendPowerStateEvent(myPowerState); // send the new powerState to SinricPro server
mySwitch3.sendPowerStateEvent(myPowerState); // send the new powerState to SinricPro server
Serial.printf("Device %s turned %s (manually via flashbutton)\r\n", mySwitch1.getDeviceId(), myPowerState?"on":"off");
Serial.printf("Device %s turned %s (manually via flashbutton)\r\n", mySwitch2.getDeviceId(), myPowerState?"on":"off");
Serial.printf("Device %s turned %s (manually via flashbutton)\r\n", mySwitch3.getDeviceId(), myPowerState?"on":"off");

lastBtnPress = actualMillis;  // update last button press variable

} }

// setup function for WiFi connection void setupWiFi() { Serial.printf("\r\n[Wifi]: Connecting"); WiFi.begin(WIFI_SSID, WIFI_PASS);

while (WiFi.status() != WL_CONNECTED) { Serial.printf("."); delay(250); } IPAddress localIP = WiFi.localIP(); Serial.printf("connected!\r\n[WiFi]: IP-Address is %d.%d.%d.%d\r\n", localIP[0], localIP[1], localIP[2], localIP[3]); }

// setup function for SinricPro void setupSinricPro() { // add device to SinricPro SinricProSwitch& mySwitch1 = SinricPro[SWITCH_IDL]; SinricProSwitch& mySwitch2 = SinricPro[SWITCH_IDLJ]; SinricProSwitch& mySwitch3 = SinricPro[SWITCH_IDI];

// set callback function to device mySwitch1.onPowerState(onPowerState1); mySwitch2.onPowerState(onPowerState2); mySwitch3.onPowerState(onPowerState3);

// setup SinricPro SinricPro.onConnected([](){ Serial.printf("Connected to SinricPro\r\n"); }); SinricPro.onDisconnected([](){ Serial.printf("Disconnected from SinricPro\r\n"); }); SinricPro.begin(APP_KEY, APP_SECRET); }

// main setup function void setup() { Serial.begin(115200); pinMode(BTN_FLASH, INPUT_PULLUP); // GPIO 0 as input, pulled high pinMode(luz, OUTPUT);
digitalWrite(luz, LOW); pinMode(luzJ, OUTPUT); digitalWrite(luzJ, LOW); pinMode(irriga, OUTPUT); digitalWrite(irriga, LOW);

Serial.begin(BAUD_RATE); Serial.printf("\r\n\r\n"); setupWiFi(); setupSinricPro(); }

void loop() { handleButtonPress(); SinricPro.handle(); }

sivar2311 commented 4 years ago

Ok guys, please put your seat in upright position and check this: https://github.com/sinricpro/esp8266-esp32-sdk/tree/master/examples/Switch

WARNING: This code contains "advanced stuff" (std::map).

But the main features are:

Limitations are only on

EDIT: Link changed to examples folder

sivar2311 commented 4 years ago

@redneal Your sketch is something i would call "the basic version" for multi device. Using different callbacks for different devices is still okay and supported by SinricPro library.

The main disadvantage on your code is: most of the configuration is hard coded. Adding new device will end up in a lot of new lines of code.

The advanced example i did, is more flexible. To add a new device including relay and button, you only need to add one line to devices map.

You can even make it more flexible by running a webserver on the ESP and serve a webpage that allows you to add and remove devices dynamicly.

redneal commented 4 years ago

OK ! I will endeavor to migrate to your guidance! Thanks for the help buddy!

philb1192 commented 4 years ago

Ok guys, please put your seat in upright position and check this: https://gist.github.com/sivar2311/0efc578d70716fc9c9160effaa84b1ad

WARNING: This code contains "advanced stuff" (std::map).

But the main features are:

* supports nearly unlimited switch devices on one ESP module

* supports relays and corresponding buttons to switch relays manually

* supports events to send notifications to SinricPro server when relay state changed manually

* easy configuration (just change the device "std::map")

Limitations are only on

* available PINs,

* RAM,

* how much SinricPro devices you have ;)

Hi Boris, your code is working perfectly a huge thank you! But instead for a push button I would like to use a toggle switch to change the state of the relay (if the relay is ''ON'' the toggle will switch it ''OFF'' in either direction and the same if the relay was ''ON'' it would turn it ''OFF'') i was able to achieve this with my first code by changing the handleButtonPress()

`void handleButtonPress() { if(pass_1 == 0) { storedvalue_1 = digitalRead(switch_1); pass_1 = 1; } if(storedvalue_1 != digitalRead(switch_1)) { // Do the action needed }

but when i try to modify your code with this approach it give me this error.

Arduino: 1.8.11 (Windows 7), Board: "NodeMCU 1.0 (ESP-12E Module), 80 MHz, Flash, Disabled, All SSL ciphers (most compatible), 4M (no SPIFFS), v2 Lower Memory, Disabled, None, Only Sketch, 115200"

sketch_feb01a:72:1: error: could not convert '{{"5e34ab83fe4eb5157d695505", {D1, D2}}, {"5e34ab8bfe4eb5157d695507", {D3, D4}}}' from '' to 'std::map<String, deviceConfig_t>'

};

^

C:\Users\Phil\Desktop\Backup\Sinric\3_Way_Switch\sketch_feb01a\sketch_feb01a.ino: In function 'void handleButtons()':

sketch_feb01a:115:6: error: 'storedvalue_1' was not declared in this scope

if(storedvalue_1 != digitalRead(switch_1))

  ^

sketch_feb01a:115:35: error: 'switch_1' was not declared in this scope

if(storedvalue_1 != digitalRead(switch_1))

                               ^

exit status 1 could not convert '{{"5e34ab83fe4eb5157d695505", {D1, D2}}, {"5e34ab8bfe4eb5157d695507", {D3, D4}}}' from '' to 'std::map<String, deviceConfig_t>'

This report would have more information with "Show verbose output during compilation" option enabled in File -> Preferences.

sivar2311 commented 4 years ago

@philb1192
1st question: You want to use a toggle switch only to turn off? 2nd question: Only one toggle switch for all relays, or each relay have its own toggle switch?

philb1192 commented 4 years ago

@philb1192 1st question: You want to use a toggle switch only to turn off? 2nd question: Only one toggle switch for all relays, or each relay have its own toggle switch?

I would like to use 4 toggle switch to change the state of 4 different relays (each relay would have its own switch) and update the sinric server If I turn on the light physically with the toggle switch, Alexa would be able to turn it off. And if I turn on the light with Alexa, I would be able to turn it off physically with the toggle switch.

I made a little video of what I would like. Exactly like that but with 4 different switches that will control 4 different relays. https://drive.google.com/open?id=1T0sNHAGvt1F6rTGC61B9dcCwmu9KToqZ

The ESP8266 stored the status of the toggle switch (LOW or HIGH) into a variable. Then in the next cycle, it compared if the variables are the same as the switch. If not it will change the status of the relay, LOW would become HIGH or HIGH will become LOW and uptade into the sinric server.

I prefer using a toggle switch instead of pushbutton because i don't want to change the switch in my house. The device I wanna make would simply be retrofit to make any toggle switch a smart switch with Alexa.

sivar2311 commented 4 years ago

Ok, i will do this after i finished the PUSH-BUTTON version i am currently working on.

sivar2311 commented 4 years ago

Wiring diagramm has been added to (push-button) example. (Notify: PIN assignment changed a bit for better wire routing)

sivar2311 commented 4 years ago

@philb1192 Basicly this should be only removing 2 lines of code (the check for button press). Please have a look at this: https://github.com/sinricpro/esp8266-esp32-sdk/tree/master/examples/Switch and give it a try. I only have buttons here, so i didn't tested it.

Edit: I tested this using my buttons and keep it pressed / released to simulate a switch. Works as expected :)

EDIT: Link changed to example folder

philb1192 commented 4 years ago

@philb1192 Basicly this should be only removing 2 lines of code (the check for button press). Please have a look at this: https://gist.github.com/sivar2311/56a7a3f22442fabc14df8872f20ba7f1 and give it a try. I only have buttons here, so i didn't tested it.

Edit: I tested this using my buttons and keep it pressed / released to simulate a switch. Works as expected :)

Thank you so much, buddy! I've been trying to make it work for almost a year now, and your code is just flawless it works perfectly :P. I aware that I'm asking a lot but, I have just a small and last request. Would it be possible to make it work also when the internet is down? If my internet doesn't work, I would like to be able to physically turn on or off the relay with the same toggle switch.

sivar2311 commented 4 years ago

It will run if there is no internetconnection. But right now it wont work if there is no wifi connection. You have to change the setupWiFi() not waiting for wifi.

philb1192 commented 4 years ago

It will run if there is no internetconnection. But right now it wont work if there is no wifi connection. You have to change the setupWiFi() not waiting for wifi.

Perfect! I just tried it and it work :P Again a big thank you :D

sivar2311 commented 4 years ago

Examples for multi device setup are available now. See Switch examples (MultiSwitch_Simple.ino, MultiSwitch_Medium.ino, MultiSwitch_Advanced.ino)