Problem using ifttt/dweet.io with my ESP8266 to light up WS2811 LEDs

Hi there coders! :smiley:

I have 3 WS2811 through hole individually addressable LEDs hooked up to a NodeMCU 1.0.
I want to use them as notification lights using IFTTT i.e. to have them light up when I get mail or whatever.
Eventually I would also like to communicate in the other direction e.g. wirelessly report temperature readings.

I've got the LEDS working fine using the FastLED library and some example code so no issue there.

I found this tutorial, that uses this code.

The webhook part of my applet looks like this:

I modified the code, slightly, to use the LEDs instead of the servo as in the video.

When I run the code on my device, serial monitor returns the following:

WiFi Connected
192.168.1.60
Receiving Data for MyESP
Connecting to : dweet.io
Connected Successfully!

Closing Connection

Key not found
Receiving Data for MyESP
Connecting to : dweet.io
Connected Successfully!

Closing Connection

[etc...]

If I just load the dweet.io url directly in a browser while the NodeMCU is running it returns:

{"this":"failed","because":"Rate limit exceeded, try again in 1 second(s)."}

And when the NodeMCU is turned off:

{"this":"failed","with":404,"because":"we couldn't find this"}

I have a reasonable amount of hobby experience using arduinos with sensors and actuators and whatnot but frankly the whole IOT aspect of the ESP8266 is completely foreign to me and I don't have a clue what I'm doing or how dweet.io is supposed to work... C++ is the only language I have any knowledge of and I honestly find all this lua/json/html stuff very confusing. :o

Besides getting this demo up and running I'd love to have someone explain how one generally goes about making an ESP and services like ifttt talk to each other. Good tutorials on this topic seem hard to come by.

In the current applet I'm using the button widget for testing and it shows up in the activity log so that part works, but I don't understand what happens during a webhook request and why this example would trigger a GET and not a POST command to make the ESP do something. If there are convenient alternatives to using dweet.io to achieve what I'm going for I'm open to suggestions.

I'll add the exact code I'm running as an attachment. The returns from the serial monitor tell me the issue is somewhere in the PrintValue() function, most of which I do not understand. :confused:

Looking forward to your -sure to be enlightening- replies. Thanks in advance.

iftttled.ino (4.02 KB)

The code isn't that long so I'll just embed it in this comment:

#include <ArduinoJson.h> // Install this library from Sketch->Include Library->Libray Manager
#include <ESP8266WiFi.h>
#include <FastLED.h>

//LED setup
#define NUM_LEDS 3
CRGBArray<NUM_LEDS> leds;

const char* THING = "MyESP"; // Put your thing name here
const char* key = "LED"; // Put your key name here

const char* WIFISSID = "REDACTED"; // Put your WiFi SSID here
const char* PASSWORD = "REDACTED"; // Put your WiFi password here

const char* host = "dweet.io";
String ans;
String response;
uint8_t bodyPosinit;
uint8_t bodyPosend;
String dweetKey =""";
int length = dweetKey.length();

void setup()
{

FastLED.addLeds<WS2811, 4>(leds, NUM_LEDS);
leds.fadeToBlackBy(40);

Serial.begin(115200);

Serial.print("Connecting to : ");
Serial.println(WIFISSID);
WiFi.begin(WIFISSID,PASSWORD);
while(WiFi.status()!= WL_CONNECTED)
{
delay(100);
Serial.print(".");
}
Serial.println("\nWiFi Connected");
Serial.println(WiFi.localIP());

ans="False";
dweetKey += key;
dweetKey += "":";
}

void loop()
{
FastLED.delay(700);
receiveDweet();
printValue();
Serial.println(ans);
if(ans=="True")
{
Serial.println("Turning LED on!");

void SetRed();

sendDweet();
}
}

void SetRed()
{
for(int i = 0; i < NUM_LEDS; i++)
{
// fade everything out
leds.fadeToBlackBy(40);

// let's set an led value
leds = CHSV(0,255,255);

  • FastLED.delay(10);*

  • }*
    }
    void sendDweet()
    {

  • Serial.print("Setting ");*

  • Serial.print(key);*

  • Serial.print(" of ");*

  • Serial.print(THING);*

  • Serial.println(" to FALSE.");*

  • WiFiClient client;*

  • const int httpPort = 80;*

  • Serial.print("Connecting to : ");*

  • Serial.println(host);*

  • if (!client.connect(host, httpPort)) {*

  • Serial.println("Connection Failed");*

  • return;*

  • }*

  • Serial.println("Connected Successfully!");*

  • client.print(String("GET /dweet/for/"));*

  • client.print(THING);*

  • client.print(String("?"));*

  • client.print(key);*

  • client.print(String("=False HTTP/1.1\r\n Host: dweet.io \r\n Connection: close\r\n\r\n"));*

  • delay(10);*

  • while(client.available()){*

  • String line = client.readStringUntil('\r');*

  • Serial.print(line);*

  • Serial.println("\nClosing Connection");*

  • Serial.println("Going to Sleep for 10 min");*
    _ ESP.deepSleep(600*1000000);_

  • }*

  • Serial.println("\nClosing Connection");*
    }
    void receiveDweet()
    {

  • Serial.print("Receiving Data for ");*

  • Serial.println(THING);*

  • WiFiClient client;*

  • const int httpPort = 80;*

  • Serial.print("Connecting to : ");*

  • Serial.println(host);*

  • if (!client.connect(host, httpPort)) {*

  • Serial.println("Connection Failed");*

  • return;*

  • }*

  • Serial.println("Connected Successfully!");*

  • client.print(String("GET /get/latest/dweet/for/"));*

  • client.print(THING);*

  • client.print(String(" HTTP/1.1\r\n Host: dweet.io \r\n Connection: close\r\n\r\n"));*

  • delay(10);*

  • while(client.available()){*

  • response = client.readStringUntil('\r');*

  • Serial.print(response);*

  • }*

  • Serial.println("\nClosing Connection");*
    }
    void printValue()
    {

  • bodyPosinit =4+ response.indexOf("\r\n\r\n");*

  • response = response.substring(bodyPosinit);*

  • Serial.println(response);*

  • bodyPosinit =10+ response.indexOf(""content"");*

  • bodyPosend = response.indexOf("}]}");*

  • response = response.substring(bodyPosinit,bodyPosend);*

  • Serial.println(response);*

  • if (response.indexOf(dweetKey) == -1) {*

  • ans = "Key not found";*

  • } else {*

  • StaticJsonBuffer<200> jsonBuffer;*

  • JsonObject& root = jsonBuffer.parseObject(response);*

  • if (!root.success()){*

  • Serial.println("parseObject() failed");*

  • ans = "parse error.";*

  • } else {*
    _ const char* val = root[key];_

  • ans = String(val);*

  • }*

  • }*
    }
    [/quote]

Your issue is most likely caused by using FastLED.delay(700); Througout your code, rather then the normal delay(). The FastLED library, thinking itself the most important thing in the world, has it's own delay() functio which consists of updating the LED's . For updating the leds it turns off interrupts (as one has to for getting the timing right) but if you use FastLED.delay() you basically turn the interrupts off for an extended period of time (as far as i remember not even a yield()(or a normal delay() ) is called during that time, now that i think of it i wonder if the wdt ever gets reset) which while nothing changes in the ledstrip buffer is a really pointless exercise. Not only that, your Wifi connection really needs interrupts turned on for most the time, and i suspect those nice built in FastLED effects also use FastLED.delay() for their timing, as they are clearly blocking in their nature.

Interesting! I had assumed that feature just used milis(). I'll comment out all FastLED code and test with just serialprint functions. The problem actually already manifested before I added that specific delay in an effort to fix the rate complaints I quoted but there is at least one more instance of it in there. I haven't tried running the original code unmodified so that's probably a good start.

Doesn't change the fact that I don't really understand what I'm doing with the calls to dweet.io. Is the value of the LED boolean stored on their server somewhere? I.e. do I have to simultaneously make the web request from ifttt and the NodeMCU to communicate that value or can there be some time in between those events?

TheNr24:
Interesting! I had assumed that feature just used milis().

Yes it does, but calls .show() until it times out, actually since the FastLED internal functions use it as well, one would be better of changing that function within the library. Ah looking it up now, it does do yield();

void CFastLED::delay(unsigned long ms) {
	unsigned long start = millis();
        do {
#ifndef FASTLED_ACCURATE_CLOCK
		// make sure to allow at least one ms to pass to ensure the clock moves
		// forward
		::delay(1);
#endif
		show();
		yield();
	}
	while((millis()-start) < ms);
}

but for maintaining a WIFI-connection interrupts should not be turned off for the majority of the time. (I have a project with a ration of 1 to 10 and it still sometimes loses connection.)

Alright I ran the code without any FastLED components and the problem is precisely the same.
To me it seems like the issue is that the String response stays empty as indicated by the empty Printlines after "Connected Successfully!" That would lead to the following line returning True, right?

if (response.indexOf(dweetKey) == -1)
{
ans = "Key not found";
}

Also, since "https://dweet.io/get/latest/dweet/for/MyESP" returns:

{"this":"failed","with":404,"because":"we couldn't find this"}

I believe the issue is that my ifttt applet isn't creating any dweets for that thing.

I just now discovered by going through dweet.io - Share your thing- like it ain't no thang. that when I load https://dweet.io/dweet/for/MyESP?LED=True instead of https://dweet.io/get/latest/dweet/for/MyESP?LED=True and then load https://dweet.io/get/latest/dweet/for/MyESP it returns

{"this":"succeeded","by":"getting","the":"dweets","with":[{"thing":"MyESP","created":"2019-02-26T14:32:21.976Z","content":{"LED":"True"}}]}

instead!

so that is a step in the right direction but it means that at least that part of the tutorial is wrong?
However the code still returns the same values so it's still not reading that "True" into "response".

Hi there,

Sounds like you figured out that you will need to POST to dweet the message that you want stored, then you can GET that message from IFTTT, or anywhere else.

If you GET a dweet from a thing-name that has not POSTed anything, the dweet service will let you know that it could not find that thing.

This may help: IoT Tools and Solutions — dweet.io paired with Arduino gives table game a live scoreboard