As the title says... Chat on...

User avatar
By AdrianM
#41033 My objective here is to be able to use IFTTT Maker channel to trigger a hardware event e.g. turn on a light connected to a ESP8266.

So while it's quite simple to set up an IFTTT trigger as a web request to a publicly accessible URL, in order to target the ESP8266 sitting on my local network I'd have to "expose" it using port forwarding and a Dynamic DNS service in order to translate the dynamic IP assigned by my ISP into a known domain name.

...Or alternatively, to avoid drilling holes in my firewall, I could use an agent that the ESP8266 can communicate with over a TCP connection. Such an agent would offer a public URL for posting triggers from IFTTT and another URL that could be interrogated by the ESP8266 to listen for the triggers.The best candidate I can find for such an agent is dweet.io

The only issue (and I'm not sure if it's a show-stopper) is that I don't want to poll the agent, but make use of the real-time subscriptions available to dweets. But this uses "chunked" HTTP responses and I'm not sure how to handle these.

Dweeting is really free and easy to use (no sign-up, but security has to be paid for). An example of creating a dweet might be:
https://dweet.io/dweet/for/my-thing-name?light=on

my-thing-name being a unique string. Then to "listen" for such dweets a GET web request is issued to the URL:
https://dweet.io/listen/for/dweets/from/my-thing-name

Simples!

Code: Select all--dweet.lua
wifi.setmode(wifi.STATION)
wifi.sta.config("ssid","password")
wifi.sta.connect()
tries=0
tmr.alarm(0, 1000, 1, function() 
    if wifi.sta.getip() == nil then
        tries=tries+1
        if tries>10 then
            tmr.stop(0)
            print("unable to get onto LAN after 10 seconds")
        end
    else
        tmr.stop(0)
        --hook up with dweet.io

        if cn then cn:close() cn=nil end
        cn = net.createConnection(net.TCP, 0)
        cn:connect(80,"dweet.io")
        cn:on("receive", function(cn, pl) print("RX:",pl) end)
        cn:on("connection", function(cn,pl)
            -- Wait for connection before sending.
            cn:send("GET /listen/for/dweets/from/am3naY3ui5ap044siUo3  HTTP/1.1\r\nHost: dweet.io\r\ncontent-type: application/json\r\nConnection: keep-alive\r\n\r\n")
        end)
       
        cn:on("sent",function(cn) print("SENT") end)
       
        cn:on("disconnection", function(cn) print("DISCONNECT") end)
    end
end)


Which goes like this:

Code: Select all> dofile('dweet.lua')
> SENT
RX:   HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sat, 13 Feb 2016 14:06:30GMT
Connection: keep-alive

78
72
"{\"thing\":\"am3naY3ui5ap044siUo3\",\"created\":\"2016-02-13T14:06:52.577Z\",\"content\":{\"Light\":\"on\"}}"


All the while the connection is open, additional "chunks" come in asynchronously as they are dweeted:

Code: Select allRX:78
72
"{\"thing\":\"am3naY3ui5ap044siUo3\",\"created\":\"2016-02-13T14:07:18.136Z\",\"content\":{\"Light\":\"off\"}}"

Great! but then after what appears to be a minute elapsing since the last response (or the GET request if no response arrives within a minute) the disconnection callback fires and the fun stops unless I make the GET request once more.

I would like to know "who" is instigating this one-minute time-out and how to leave the connection open
User avatar
By AdrianM
#41065 Still stuck :( As can be seen from the dweet reply above, the GET that starts listening contains: Connection: keep-alive yet the connection still drops after 60 seconds. That has to be their server right? The TCP connection from the ESP8266 doesn't impose any time limit.

Examples of people using dweet like this appear to be non-existant and even dweet themselves gloss over the chunked http saying:
If you don't know what a chunked HTTP response is, it might be easier to use one of our client libraries below.

I looked at those libraries but nothing appears to run along the lines of the script I mostly got working.
What looks like the relevant function to me in their node.js library has an odd looking url for their server, and seems to be miles away from their headline invitation to:

Just make a call to https://dweet.io/listen/for/dweets/from/my-thing-name


Code: Select all//my snip
   var DWEET_SERVER = "https://taylor.dweet.io:443";
//my snip
      self.listen_for = function (thing, key, callback) {
         if (isFunction(key)) {
            callback = key;
            key = null;
         }

         // Initialize our callback list
         if (!listenCallbacks[thing]) {
            listenCallbacks[thing] = [];
         }

         // Add this to our callbacks
         if (listenCallbacks[thing].indexOf(callback) == -1) {
            listenCallbacks[thing].push(callback);
         }

         function createSocket() {
            socket = io.connect(DWEET_SERVER + "/stream");

            socket.on("connect", function () {
               // Subscribe to all of the things that we might have asked for before connecting
               for (var id in listenCallbacks) {
                  socket.emit("subscribe", {thing: id, key: key});
               }
            });

            socket.on("new_dweet", function (msg) {
               if (listenCallbacks[msg.thing]) {
                  normalizeDweets(msg);

                  var callbacks = listenCallbacks[msg.thing];
                  for (var index = 0; index < callbacks.length; index++) {
                     callbacks[index](msg);
                  }
               }
            });
         }

         if (!socket) {
            if (isNode) {
               createSocket();
            }
            else {
               dweet_script_loader([DWEET_SERVER + "/socket.io/socket.io.js"], function () {
                  io = window.io;
                  createSocket();
               });
            }
         }
         if (socket) {
            socket.emit("subscribe", {thing: thing, key: key});
         }
      }

Anyone recognise what's going on in their library code above?