If This Then That interface library. Designed to hook up to various services provided by IFTTT.

Fork of IFTTT by Austin Blackstone

ifttt.cpp

Committer:
MACRUM
Date:
2015-10-06
Revision:
7:dfe2a659ca43
Parent:
6:15c6c9f87c32

File content as of revision 7:dfe2a659ca43:

/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mbed.h"
#include "ifttt.h"
#include <string>

#if 0
#define DBG(x, ...)  printf("[IFTTT : DBG]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
#define WARN(x, ...) printf("[IFTTT : WARN]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
#define ERR(x, ...)  printf("[IFTTT : ERR]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
#else
#define DBG(x, ...) //wait_us(10);
#define WARN(x, ...) //wait_us(10);
#define ERR(x, ...)
#endif

#if 1
#define INFO(x, ...) printf("[IFTTT : INFO]"x" \r\n",##__VA_ARGS__);
#else
#define INFO(x, ...)
#endif

//
// Initialize object with Event, Key, and valid socket.
// TODO: accept hostname parameter / implement DNS lookup
//
IFTTT::IFTTT(const char * event, const char * key, TCPSocketConnection * s)
{
    // Error Check
    if(sizeof(event) > IFTTT_MAX_SIZE_EVENTNAME) {
        ERR("Given event > IFTTT_MAX_SIZE_EVENTNAME, increase the max event string size in ifttt.h");
    }
    if(sizeof(key) > IFTTT_MAX_SIZE_SECRETKEY) {
        ERR("Given key > IFTTT_MAX_SIZE_SECRETKEY, increase the max secret key string size in ifttt.h");
    }
    // Copy event name and secret key into object instance
    strcpy(this->eventName,event);
    strcpy(this->secretKey,key);

    // Set up Socket
    if(NULL == s) {
        WARN("Given Socket Pointer is NULL, will try opening a socket.");
    }
    this->socket = s;

    // Set up Host / Port
    this->port = IFTTT_PORT;
    this->host = IFTTT_IP;
    
    // Initialize ingredient values to empty strings.
    v1 = "";
    v2 = "";
    v3 = "";
}

//
// Add ingredients to be sent.
//
bool
IFTTT::addIngredients( char * value1,  char * value2,  char * value3)
{
    // update internal pointers. If variable not given then pass an empty string
    v1 = (NULL == value1)?"":value1;
    v2 = (NULL == value2)?"":value2;
    v3 = (NULL == value3)?"":value3;
    return true;
}

//
// This function sends data to maker.ifttt.org via GET query commands
// return true on sucess, false on fail
//
bool IFTTT::get()
{
    // Connect to maker.ifttt.org
    int retry = 0;
    for(retry=0; retry<IFTTT_MAX_RETRY; retry++) {
        int ret = this->socket->connect(this->host, this->port);
        if(ret == 0) {
            DBG("Successfully Connected socket to host");
            break ;
        }
    }
    if(retry == IFTTT_MAX_RETRY) {
        this->socket->close();
        ERR("Could not connect socket to host\r\n");
        return false;
    }

    // Prep data to send
    // TODO: verify / modify data to be query string compliant (convert spaces to '+', convert non-alpha-numberic characters to the proper encoding... etc)
    char str[IFTTT_MAX_SIZE_STRING] = {0};
    sprintf(str, "GET /trigger/%s/with/key/%s/?value1=%s&value2=%s&value3=%s HTTP/1.1\r\nHost: maker.ifttt.com\r\n\r\n",eventName,secretKey,v1,v2,v3);
    DBG("String to send is:\n\r%s",str);

    // Send Data
    DBG("Sending GET data...");
    int check = 0;
    check = this->socket->send_all(str,sizeof(str));
    if(check) {
        DBG("Sent Sucessfully %d bytes",check);
    } else {
        ERR("Sending failed");
        return false;
    }
    DBG("Waiting on reply ... \r\n");
    int ret = this->socket->receive(str,50);
    str[ret]=0;
    DBG("Received String : %s",str);
    this->socket->close();

    return true;
}

//
// This function sends JSON encoded data encoded in a POST packet, 
//
bool IFTTT::post()
{
    // Connect to maker.ifttt.org
    int retry = 0;
    for(retry=0; retry<IFTTT_MAX_RETRY; retry++) {
        int ret = this->socket->connect(this->host, this->port);
        if(ret == 0) {
            DBG("Successfully Connected socket to host");
            break ;
        }
    }
    if(retry == IFTTT_MAX_RETRY) {
        this->socket->close();
        ERR("Could not connect socket to host\r\n");
        return false;
    }

    // Prep data to send, the Assembled POST packet should look like this
    //
    //
    //POST /trigger/<eventName>/with/key/<secretKey> HTTP/1.1
    //Host: maker.ifttt.com
    //Content-Length: <length of POST data>
    //Content-Type: application/json
    //
    //{"value1":"<v1>","value2":"<v2>","value3":"<v3>"}
    //
    //
    char str[IFTTT_MAX_SIZE_STRING] = {0};
    char header[100] = {0};
    sprintf(header, "POST /trigger/%s/with/key/%s HTTP/1.1\r\n",eventName,secretKey);
    const char * host = "Host: maker.ifttt.com\r\n";
    char contentLen[50] = {0};
    const char * contentType = "Content-Type: application/json\r\n\r\n";
    char valueData [150] = {0};
    sprintf(valueData,"{\"value1\":\"%s\",\"value2\":\"%s\",\"value3\":\"%s\"}\r\n",v1,v2,v3);
    sprintf(contentLen,"Content-Length: %d\r\n",strlen(valueData));
    sprintf(str,"%s%s%s%s%s",header,host,contentLen,contentType,valueData);

    DBG("String to send is:\n\r%s",str);

    // Send Data
    DBG("Sending POST data...");
    int check = 0;
    check = this->socket->send_all(str,strlen(str));
    if(check) {
        DBG("Sent Sucessfully %d bytes",check);
    } else {
        ERR("Sending failed");
        return false;
    }
    DBG("Waiting on reply ... \r\n");
    int ret = this->socket->receive(str,IFTTT_MAX_SIZE_STRING);
    str[ret]=0;
    DBG("Received String : %s",str);
    this->socket->close();

    return true;
}

//
// Send trigger and any values associated to maker.ifttt.com
// currently  unsecured (sends over HTTP, not https)
//
bool
IFTTT::trigger(int triggerType)
{
    int ret = 0;
    switch(triggerType) {
        case IFTTT_GET:
            DBG("Sending Data as GET request");
            ret = get();
            break;
        case IFTTT_POST:
            DBG("Sending Data as POST request");
            ret = post();
            break;

        default:
            WARN("Invalid type, defaulting to sending data as POST request");
            ret = post();
            break;
    }
    DBG("Sending Data return code : %d",ret);
    if(ret){
    INFO("Successfully triggered event: '%s' with v1='%s', v2='%s', v3='%s' !",eventName,v1,v2,v3);
    }
    return ret;
}