Separate library that holds helper functions for the main OMF code.

osisoft-omf.cpp

Committer:
danielelopez
Date:
2018-11-29
Revision:
19:9b357e31f61d
Parent:
18:c6c9cce5d990

File content as of revision 19:9b357e31f61d:

//Copyright 2018 OSIsoft, 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 "osisoft-omf.h"
#include "mbed.h"
#include "https_request.h"
#include "ntp-client/NTPClient.h"
#include "config.egressSettings.h"
#include "config.SSLCertificates.h"
#include "config.producerToken.h"
#include "config.OMFContainerAndLINKJSON.h"
#include "config.OMFDynamicAndStaticTypesAndAssetJSON.h"

// ---------------------------------------------------------------------------------------------------

// The clock is set usign NTP; if that fails, the clock defaults to the below time
const int DEFAULT_HARD_CODED_UTC_TIME = 1513175347;

// ---------------------------------------------------------------------------------------------------

// ************************************************************************
// Helper function: prints out an HTTP response
// ************************************************************************
 
void OMFLib_dump_response(HttpResponse* res)
{
    printf("\n\r----- HTTPS POST response -----\n\r");
    // Print the status code
    mbedtls_printf("Status: %d - %s\n\r", res->get_status_code(), res->get_status_message().c_str());
    // Print the headers
    mbedtls_printf("Response headers:\n\r");
    for (size_t ix = 0; ix < res->get_headers_length(); ix++) {
        mbedtls_printf("\t%s: %s\n\r", res->get_headers_fields()[ix]->c_str(), res->get_headers_values()[ix]->c_str());
    }
    // Print the body
    mbedtls_printf("Response body (%d bytes):\n\n%s", res->get_body_length(), res->get_body_as_string().c_str());
}

// ************************************************************************
// Helper function that casts floats into strings
// ************************************************************************

string OMFLib_float_to_string(float f) {
    char buffer[20];
    int n = sprintf (buffer, "%f", f);
    // Return -1 if a parse failure ocurred
    if (string(buffer) == "NaN") {
        return string("-1");
    } else {
        return string(buffer);
    }
}

/* Deprecated after changes to TLS Socket 
// ************************************************************************
// Helper function that sends an actual web request
// ************************************************************************

void OMFLib_sendMessageToEndpoint(TLSSocket* socket, const char* action, const char* message_type, const char* body) {
    printf("\n\r----- HTTPS POST request -----\n\r");
    
    // Create the new request
    //HttpsRequest* post_req = new HttpsRequest(network, SSL_CA_PEM, HTTP_POST, TARGET_URL); // Old: doesn't re-use sockets
    HttpsRequest* post_req = new HttpsRequest(socket, HTTP_POST, TARGET_URL);

    // Turn on debugging - this hides TLS connection information (deprecated)
    //post_req->set_debug(true);

    // Add headers: content type and authentication
    post_req->set_header("Content-Type", "application/json");

    // Set OMF headers
    post_req->set_header("producertoken", PRODUCER_TOKEN);
    post_req->set_header("messagetype", message_type);
    post_req->set_header("action", action);
    post_req->set_header("messageformat", "JSON");
    post_req->set_header("omfversion", "1.0");
        
    // Send the body
    printf("Now sending request...");
    printf("\n\rOutgoing message headers:\n\tmessagetype: %s\n\taction: %s", message_type, action);
    printf("\n\rOutgoing message body:\n\t%s\n\r", body);
    HttpResponse* post_res = post_req->send(body, strlen(body));

    // Check the response for an error
    if (!post_res) {
        printf("HttpRequest failed (error code %d)\n\r", post_req->get_error());
        printf("Socket connection status after error: %d\n\r", socket->connected());
        //return 1;
    } else {
        // Print the response
        OMFLib_dump_response(post_res);
    }

    // Free up the request object
    delete post_req;
}
*/

// ************************************************************************
// Helper function that sends an actual web request; does not reuse sockets
// ************************************************************************

#if ENABLE_PRINTOUTS == YES_ENABLE_PRINTOUTS
    void OMFLib_sendMessageToEndpoint_NoSocketReuse(NetworkInterface* network, const char* action, const char* message_type, const char* body) {
        
        printf("\n\r----- HTTPS POST request -----\n\r");
        
        // Create the new request
        HttpsRequest* post_req = new HttpsRequest(network, SSL_CA_PEM, HTTP_POST, TARGET_URL);
    
        // Turn on debugging - this hides TLS connection information (deprecated)
        //post_req->set_debug(true);
    
        // Add headers: content type 
        post_req->set_header("Content-Type", CONTENT_TYPE);
    
        // Set OMF headers
        post_req->set_header("producertoken", PRODUCER_TOKEN);
        post_req->set_header("messagetype", message_type);
        post_req->set_header("action", action);
        post_req->set_header("messageformat", OMF_MESSAGE_FORMAT);
        post_req->set_header("omfversion", OMF_VERSION);
            
        // Send the body
        printf("Now sending request... ");
        //printf("\n\rOutgoing message headers:\n\tmessagetype: %s\n\taction: %s", message_type, action);
        //printf("\n\rOutgoing message body:\n\t%s\n\r", body);
        HttpResponse* post_res = post_req->send(body, strlen(body));
        
        // Check the response for an error
        if (!post_res) {
            printf("HttpRequest failed (error code %d)\n\r", post_req->get_error());
            //return 1;
        } else {
            // Print the response
            printf("Success!\n\r");
            //OMFLib_dump_response(post_res);
        }
    
        // Free up the request object
        delete post_req;
    }
#endif

// Option if printouts should be hidden
#if ENABLE_PRINTOUTS == DO_NOT_ENABLE_PRINTOUTS
    void OMFLib_sendMessageToEndpoint_NoSocketReuse(NetworkInterface* network, const char* action, const char* message_type, const char* body) {

        // Create the new request
        HttpsRequest* post_req = new HttpsRequest(network, SSL_CA_PEM, HTTP_POST, TARGET_URL);
    
        // Turn on debugging - this hides TLS connection information (deprecated)
        //post_req->set_debug(true);
    
        // Add headers: content type 
        post_req->set_header("Content-Type", CONTENT_TYPE);
    
        // Set OMF headers
        post_req->set_header("producertoken", PRODUCER_TOKEN);
        post_req->set_header("messagetype", message_type);
        post_req->set_header("action", action);
        post_req->set_header("messageformat", OMF_MESSAGE_FORMAT);
        post_req->set_header("omfversion", OMF_VERSION);
            
        // Send the body
        HttpResponse* post_res = post_req->send(body, strlen(body));
    
        // Free up the request object
        delete post_req;
    }
#endif

// ************************************************************************
// Gets the current time in the appropriate OMF format
// See https://os.mbed.com/blog/entry/103/
// ************************************************************************
const int TIMESTAMP_BUFFER_SIZE = 21;
string OMFLib_getCurrentTimeString() {
    // Declar vars
    char timestampBuffer[TIMESTAMP_BUFFER_SIZE]; // The format is YYYY-MM-DDThh:mm:ssZ
    time_t now;
    //struct tm ts;
    
    // Set the "now" var to the current time
    time(&now);
    
    // Cast the current time into UTC seconds
    //ts = *localtime(&now);
    
    // Print out the time in seconds as a formatted string to the timestamp buffer
    //strftime(timestampBuffer, sizeof(timestampBuffer), "%Y-%m-%dT%H:%M:%SZ", &ts);
    //strftime(timestampBuffer, sizeof(timestampBuffer), "%Y-%m-%dT%H:%M:%SZ", &ts);
    strftime(timestampBuffer, TIMESTAMP_BUFFER_SIZE, "%Y-%m-%dT%H:%M:%SZ", localtime(&now));
    
    // Return the result
    return string(timestampBuffer);
}

// ************************************************************************
// Sets the clock via NTP via the nwtwork; can point to a local or internet-based server
// ************************************************************************

void OMFLib_syncClockViaNTP(NetworkInterface* network) {
    // Hard-code a start time... see https://www.epochconverter.com/   
    set_time(DEFAULT_HARD_CODED_UTC_TIME);
    
    printf("\n\r----- Setting internal clock -----\n\r");
    // See https://github.com/ARMmbed/ntp-client-example/blob/master/main.cpp
    
    // Connect the ntp object to the network
    NTPClient ntp(network);
    
    // Set the ntp server to either an internet-based server OR to a local server
    ntp.set_server("2.pool.ntp.org", 123);
    
    // Get the timestamp via NTP
    time_t timestamp = ntp.get_timestamp();
    
    // Set the current timestamp to the NTP timestamp
    set_time(timestamp);
    
    // Print the result
    printf("Attempt done; clock set to UTC %s", ctime(&timestamp));
}

// ************************************************************************
// Sends the dynamic types, static types, assets, and links messages
// Uses the SEND_ASSETS_AND_LINKS MACRO found in config.egressSettings and
// Uses the custom OMF JSON found in config.customOMFJSONStructures.h
// ************************************************************************

#if SEND_ASSETS_AND_LINKS == YES_SEND_ASSETS_AND_LINKS
    void OMFLib_sendInitialOMFMessages(NetworkInterface* __network_interface) {
        // Send the DYNAMIC types message, so that these types can be referenced in all later messages
        printf("\n\r!!!!!!!! Sending DYNAMIC Types message... !!!!!!!!\n\r");
        //OMFLib_sendMessageToEndpoint(socket, "create", "Type", dynamic_types_message_JSON.c_str());
        //OMFLib_sendMessageToEndpoint_NoSocketReuse(network, "create", "Type", DYNAMIC_TYPES_MESSAGE_JSON.c_str());
        OMFLib_sendMessageToEndpoint_NoSocketReuse(__network_interface, "create", "Type", DYNAMIC_TYPES_MESSAGE_JSON.c_str());
    
        // Send the container message, to instantiate this particular container; we can now directly start sending data to it using its Id
        printf("\n\r!!!!!!!! Sending Containers message... !!!!!!!!\n\r");
        //OMFLib_sendMessageToEndpoint(socket, "create", "Container", CONTAINERS_MESSAGE_JSON.c_str());  
        //OMFLib_sendMessageToEndpoint_NoSocketReuse(network, "create", "Container", CONTAINERS_MESSAGE_JSON.c_str());  
        OMFLib_sendMessageToEndpoint_NoSocketReuse(__network_interface, "create", "Container", CONTAINERS_MESSAGE_JSON.c_str()); 
        
        // ************************************************************************  
        // Send the STATIC types message, so that these types can be referenced in all later messages
        // ************************************************************************
    
        printf("\n\r!!!!!!!! Sending STATIC Types message... !!!!!!!!\n\r");
        //OMFLib_sendMessageToEndpoint(socket, "create", "Type", static_types_message_JSON.c_str()); 
        //OMFLib_sendMessageToEndpoint_NoSocketReuse(network, "create", "Type", STATIC_TYPES_MESSAGE_JSON.c_str());         
        OMFLib_sendMessageToEndpoint_NoSocketReuse(__network_interface, "create", "Type", STATIC_TYPES_MESSAGE_JSON.c_str());
    
        // ************************************************************************
        // Send the message to create the PI AF asset; it will not appear in PI AF, though, because it has not yet been positioned...
        // ************************************************************************
    
        printf("\n\r!!!!!!!! Sending Assets message... !!!!!!!!\n\r");
        //OMFLib_sendMessageToEndpoint(socket, "create", "Data", assets_message_JSON.c_str());
        //OMFLib_sendMessageToEndpoint_NoSocketReuse(network, "create", "Data", ASSETS_MESSAGE_JSON.c_str());  
        OMFLib_sendMessageToEndpoint_NoSocketReuse(__network_interface, "create", "Data", ASSETS_MESSAGE_JSON.c_str());
        
        // ************************************************************************
        // Send the message to link the PI AF asset
        // ************************************************************************
        
        printf("\n\r!!!!!!!! Sending Links message... !!!!!!!!\n\r");
        //OMFLib_sendMessageToEndpoint(socket, "create", "Data", LINKS_MESSAGE_JSON.c_str());
        //OMFLib_sendMessageToEndpoint_NoSocketReuse(network, "create", "Data", LINKS_MESSAGE_JSON.c_str());  
        OMFLib_sendMessageToEndpoint_NoSocketReuse(__network_interface, "create", "Data", LINKS_MESSAGE_JSON.c_str());
    }
#endif

// If assets and links should be skipped...
#if SEND_ASSETS_AND_LINKS == DO_NOT_SEND_ASSETS_AND_LINKS
    void OMFLib_sendInitialOMFMessages(NetworkInterface* __network_interface) {
        // Send the DYNAMIC types message, so that these types can be referenced in all later messages
        printf("\n\r!!!!!!!! Sending DYNAMIC Types message... !!!!!!!!\n\r");
        //OMFLib_sendMessageToEndpoint(socket, "create", "Type", dynamic_types_message_JSON.c_str());
        //OMFLib_sendMessageToEndpoint_NoSocketReuse(network, "create", "Type", DYNAMIC_TYPES_MESSAGE_JSON.c_str());
        OMFLib_sendMessageToEndpoint_NoSocketReuse(__network_interface, "create", "Type", DYNAMIC_TYPES_MESSAGE_JSON.c_str());
    
        // Send the container message, to instantiate this particular container; we can now directly start sending data to it using its Id
        printf("\n\r!!!!!!!! Sending Containers message... !!!!!!!!\n\r");
        //OMFLib_sendMessageToEndpoint(socket, "create", "Container", CONTAINERS_MESSAGE_JSON.c_str());  
        //OMFLib_sendMessageToEndpoint_NoSocketReuse(network, "create", "Container", CONTAINERS_MESSAGE_JSON.c_str());  
        OMFLib_sendMessageToEndpoint_NoSocketReuse(__network_interface, "create", "Container", CONTAINERS_MESSAGE_JSON.c_str()); 
    }
#endif