GroveStreams is a helper class to assist with pushing data into the GroveStreams.com IoT platform.

Dependents:   GroveStreams-Temp

GroveStreams.cpp

Committer:
mmills
Date:
2017-01-05
Revision:
0:8b675b2726b7

File content as of revision 0:8b675b2726b7:

/*
 GroveStreams is a helper class to assist with pushing data into the
  GroveStreams.com IoT platform.
  
 License:
  Copyright (C) 2017 GroveStreams LLC.
  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 "GroveStreams.h"

GroveStreams::GroveStreams(const char* apiKey, LcdDiscoF746NgTracer* pLcd)
{
    init(apiKey, pLcd);
}

GroveStreams::GroveStreams(const char* apiKey)
{
    init(apiKey, NULL);
}

GroveStreams::~GroveStreams() {
    _eth.disconnect();
}

int GroveStreams::init(const char* apiKey, LcdDiscoF746NgTracer* pLcd)
{
    _domain = "grovestreams.com";
    _port = 80;
    _apiKey = apiKey;
    _myIPAddress = NULL;  //Don't Change. Set below from DHCP. Needed by GroveStreams to verify that a device is not uploading more than once every 10s.
    _pLcd = pLcd;

    return startEthernet();
}

void GroveStreams::printf(const char* format, ...)
{

    va_list args;
    va_start(args, format);

    if (_pLcd != NULL) {
        char sbuffer[512];
        vsprintf(sbuffer, format, args);
        _pLcd->println(sbuffer);
    } else {
        vprintf(format, args);
    }

    va_end(args);
}

unsigned long GroveStreams::send(const char* componentId, const char* samples)
{
    char resultBuffer[256]= {0};
    return send(componentId, samples, NULL, NULL, resultBuffer, sizeof resultBuffer);
}

unsigned long GroveStreams::send(const char* componentId, const char* samples, char* resultBuffer, size_t resultBufferSize)
{
    return send(componentId, samples, NULL, NULL, resultBuffer, resultBufferSize);
}
   
unsigned long GroveStreams::send(const char* componentId, const char* samples, const char* componentName, 
                                 const char* compTmplId, char* resultBuffer, size_t resultBufferSize)
{
    int failedCounter = 0;
    int result = 1;

    while (failedCounter < 3 && result != 0) {
        
        result = sendNoRetry(componentId, samples, componentName, compTmplId, resultBuffer, resultBufferSize);
        
        this->printf("send result code: %d", result);
        
        if (result != 0) {
            //Wait and try again
            failedCounter++;
            this->printf("send failed %d times", failedCounter);
            wait(2);
        }

        if (failedCounter > 3 ) {
            this->printf("Too many failures. Restarting Ethernet.");
            startEthernet();
        }
    }

    return result;
}

unsigned long GroveStreams::sendNoRetry(const char* componentId, const char* samples, const char* componentName, 
                                        const char* compTmplId, char* resultBuffer, size_t resultBufferSize)
{
    //Assemble the url that is used to pass the temperature readings to GroveStreams and call it

    network::tcp::Socket socket;

    int openResult = socket.open();
    if (openResult == 0) {

        int connResult = socket.connect(_domain, _port);
        if(connResult == 0) {

            char compNamePart[100] = {0};
            if (strlen(componentName) > 0) {
                sprintf(compNamePart, "&compName=%s",componentName);
            }

            char compTmplIdPart[100] = {0};
            if (strlen(compTmplId) > 0) {
                sprintf(compTmplIdPart, "&compTmplId=%s",compTmplId);
            }

            //You may need to increase the size of sbuffer if any other char array sizes have increased
            char sbuffer[512]= {0};

            sprintf(sbuffer, "PUT /api/feed?compId=%s%s%s&api_key=%s%s HTTP/1.1\r\nHost: \r\nConnection: close\r\nX-Forwarded-For:%s\r\n\r\n",
                    componentId, compTmplIdPart, compNamePart, _apiKey, samples, _myIPAddress);

            this->printf("send sbuffer size: %d", strlen(sbuffer));

            int scount = socket.write(sbuffer, strlen(sbuffer));
            this->printf("sent %d bytes: [%.*s]", scount, strstr(sbuffer, "\r\n")-sbuffer, sbuffer);

            //Read status line
            
            int rcount = socket.read(resultBuffer, resultBufferSize);

            this->printf("HTTP Response size: %d bytes", rcount);
            this->printf("HTTP Response Status:[%.*s]", strstr(resultBuffer, "\r\n")-resultBuffer, resultBuffer);
            
            //Only return the body
            strcpy(resultBuffer, strstr(resultBuffer, "\r\n\r\n") + strlen("\r\n\r\n"));
            strcat(resultBuffer, "\0");
            this->printf("HTTP Body: [%s]", resultBuffer);
            
            socket.close();
        } else {

            this->printf("Socket Connect Failed: %d", connResult);
        }

    } else {
        this->printf("Socket Open Failed: %d", openResult);
        socket.close();
        return 1;
    }

    return 0;
}


int GroveStreams::startEthernet()
{
    //Start or restart the Ethernet connection.
    int result = _eth.disconnect();
    if (result != 0) {
        this->printf("Ethernet diconnect Failed: %d", result);
        return result;
    }

    this->printf("Connecting STM32 to network...");

    //Connect to the network and obtain an IP address using DHCP
    result = _eth.init();
    if (result != 0) {
        this->printf("Ethernet init Failed: %d", result);
        return result;
    }

    result = _eth.connect();
    if (result != 0) {
        this->printf("Ethernet connect Failed: %d", result);
        return result;
    } else {
        this->printf("STM32 connected to network");

        //Set the mac and ip variables so that they can be used during sensor uploads later
        _myIPAddress = _eth.getIPAddress();

        this->printf("IP address: %s", _myIPAddress ? _myIPAddress : "No IP");
    }

    return 0;
}

const char* GroveStreams::getMACAddress()
{
    return _eth.getMACAddress();
}