A Telegram BOT for this awesome all-in-one board.

Dependencies:   BSP_B-L475E-IOT01 mbed es_wifi jsmn

Telegram Bot for DISCO_L475VG_IOT01

This application embeds aTelegram chatbot into the DISCO_L475VG_IOT01 board.

The Bot answers to the users queries about:

  • Real time environmental data taken from the on board sensors.
  • Environmental data history of the latest 24 hours stored on board.
  • Camera images taken from the Arducam-mini-2mp (optional).

This software uses:

Compilation

Import in your compiler and modify the following defines:

  • WIFI_SSID
  • WIFI_PASSWORD
  • TELEGRAM_BOT_APIKEY

Please follow the Telegram bots documentation (https://core.telegram.org/bots) to better understand how the Telegram API works and how to create your bot.

In order to support the Arducam-Mini-2MP set WITH_ARDUCAM_2640 #define to 1.

Screenshots

/media/uploads/dvddnr/screenshot_20180130-073732.png /media/uploads/dvddnr/screenshot_20180130-073703.png /media/uploads/dvddnr/arducam.jpeg /media/uploads/dvddnr/screenshot_20180216-102601.png

Security

The Inventek wifi module creates the ssl connection but does not authenticate the server's certificate ( AT cmd P9=0 ).

For more details http://www.inventeksys.com/IWIN/programming-certificates-tcp-ssltls/

main.cpp

Committer:
dvddnr
Date:
2018-02-16
Revision:
10:28cf58359411
Parent:
9:d24842a5a468

File content as of revision 10:28cf58359411:

#include "mbed.h"

#include "stm32l475e_iot01_tsensor.h"
#include "stm32l475e_iot01_hsensor.h"
#include "stm32l475e_iot01_psensor.h"
#include "es_wifi.h"
#include "es_wifi_io.h"
#include "jsmn.h"
#include "TCPConnector.h"
#include "HTTPHelper.h"


#define WIFI_SSID ""
#define WIFI_PASSWORD ""
#define TELEGRAM_BOT_APIKEY ""
#define WITH_ARDUCAM_2640 0

#define CONNECTION_TRIAL_MAX 10

// LED 
DigitalOut g_alivenessLED(LED1);

// secure tcp connector
TCPConnector g_tcp_connector;
// http parser utils
HTTPHelper g_http_parser;
// arducam driver
#if WITH_ARDUCAM_2640
#include "ArduCAM2640.h"
ArduCAM2640 g_arducam;
/* jpeg buffer */
#define IMAGE_JPG_SIZE 16*1024
uint8_t g_image_buffer[IMAGE_JPG_SIZE];
#endif

// http I/O buffer
char g_http_io_buffer[ES_WIFI_DATA_SIZE];

// Telegram json I/O buffer
#define TBOT_JSON_BUFFER_SIZE 3 * 1024
char g_json_io_buffer[TBOT_JSON_BUFFER_SIZE];

// telegram REST API
const char TELEGRAM_GETUPDATES[]  = "GET /bot"  TELEGRAM_BOT_APIKEY "/getUpdates?offset=%d&timeout=20&limit=1 HTTP/1.1\r\nHost: api.telegram.org\r\nUser-Agent: curl/7.50.1\r\nAccept: */*\r\n\r\n";
const char TELEGRAM_SENDMESSAGE[] = "GET /bot" TELEGRAM_BOT_APIKEY "/sendMessage HTTP/1.1\r\nHost: api.telegram.org\r\nUser-Agent: curl/7.50.1\r\nAccept: */*\r\nContent-Type: application/json\r\nContent-Length: %d\r\n\r\n";
const char TELEGRAM_SENDPHOTO[]   = "POST /bot" TELEGRAM_BOT_APIKEY "/sendPhoto HTTP/1.1\r\nHost: api.telegram.org\r\nUser-Agent: curl/7.47.0\r\nAccept: */*\r\nContent-Length: %d\r\nConnection: close\r\n";
#if WITH_ARDUCAM_2640
const char TELEGRAM_CUSTOM_KEYBOARD[] = "{\"keyboard\": [[\"Temperature\",\"Humidity\",\"Pressure\"],[\"Daily\",\"RTC\",\"Camera\"]],\"one_time_keyboard\": true}";
#else
const char TELEGRAM_CUSTOM_KEYBOARD[] = "{\"keyboard\": [[\"Temperature\",\"Humidity\",\"Pressure\"],[\"Daily\",\"RTC\"]],\"one_time_keyboard\": true}";
#endif
bool telegram_get_update(int32_t update_id);
bool telegram_send_message(char *json_msg);
bool telegram_send_photo(uint8_t *image, uint32_t image_size, int32_t chat_id, char *caption);
#define TELEGRAM_BOT_INCOMING_CMD_SIZE 80
char g_incoming_msg[TELEGRAM_BOT_INCOMING_CMD_SIZE];
void telegram_bot();

// now.httpbin.org
const char NOW_HTTPBIN_ORG[]  = "GET / HTTP/1.1\r\nHost: now.httpbin.org\r\nUser-Agent: curl/7.50.1\r\nAccept: */*\r\n\r\n";
bool set_rtc_from_network(void);

// JSON parser
#define JSON_MAX_TOKENS 128
jsmn_parser g_json_parser;
jsmntok_t g_json_tokens[JSON_MAX_TOKENS];
bool jsoneq(const char *json, jsmntok_t *tok, const char *s,jsmntype_t type);

// Data history 
float g_daily_data_history_temp[24][60];
float g_daily_data_history_pres[24][60];
float g_daily_data_history_humi[24][60];
void daily_history_update(int hour, int min,float t, float p, float h);
int32_t daily_humidity_history_chart(char *report_buffer, uint32_t buffer_len);
int32_t daily_temperature_history_chart(char *report_buffer, uint32_t buffer_len);
int32_t daily_pressure_history_chart(char *report_buffer, uint32_t buffer_len);


int main()
{

    printf("> DISCO_L475VG_IOT01-Telegram-BOT started\r\n");
    
#if WITH_ARDUCAM_2640
    /* Setup camera */
    I2C camI2C(PB_9,PB_8);
    SPI camSPI(PA_7,PA_6,PA_5);
    DigitalOut cam_spi_cs(PA_2);

    if( g_arducam.Setup( OV_RESOLUTION_CIF,92, &cam_spi_cs, &camSPI, &camI2C) == false)
    {
        printf("Arducam setup error \r\n");
        while(1);
    } 
#endif

    /* Setup env sensors */
    BSP_TSENSOR_Init();
    BSP_HSENSOR_Init();
    BSP_PSENSOR_Init();
   

    /* start chatbot */
    telegram_bot();
}








void telegram_bot()
{
    int32_t update_id = 0;
    int32_t chat_id = 0;
    int json_results;
    bool well_done = false;
    time_t timestamp;
    struct tm *timestamp_tm;
    float temp,pres,humi;
    

    /* wifi connect */
    if(g_tcp_connector.wifi_connect(WIFI_SSID,WIFI_PASSWORD,CONNECTION_TRIAL_MAX))
    {
        printf("> Wifi connected\r\n");
    }
    else
    {
        NVIC_SystemReset();
    }


    /* set RTC */
    set_rtc_from_network();
    
    /* init data history */
    for(int i=0; i<24; i++)
    {
        for(int ii=0; ii<60; ii++)
        {
            g_daily_data_history_temp[i][ii]=0.0F;
            g_daily_data_history_pres[i][ii]=0.0F;
            g_daily_data_history_humi[i][ii]=0.0F;
        }
    }
    

    /* main loop */
    while (1)
    {
        g_alivenessLED = !g_alivenessLED;
        
        /* history update */
        timestamp = time(NULL);
        timestamp_tm = localtime(&timestamp);
        temp = BSP_TSENSOR_ReadTemp();
        pres = BSP_PSENSOR_ReadPressure();
        humi = BSP_HSENSOR_ReadHumidity();
        daily_history_update( timestamp_tm->tm_hour, timestamp_tm->tm_min, temp, pres, humi );
                                                            
        
        // Get updates -- API method getUpdates
        printf("> Get updates\r\n");
        g_json_io_buffer[0]=0;
        if (telegram_get_update(update_id + 1) == false)
        {
            printf("> ERROR telegram_get_update\r\n> Reset wifi connection\r\n");
            
            g_tcp_connector.wifi_connect(WIFI_SSID,WIFI_PASSWORD,CONNECTION_TRIAL_MAX);
            continue;
        }
        printf("> JSON content: %s\r\n", g_json_io_buffer);
       
        // Parsing json response
        jsmn_init(&g_json_parser);
        json_results = jsmn_parse(&g_json_parser,g_json_io_buffer,strlen(g_json_io_buffer),g_json_tokens,JSON_MAX_TOKENS);
        if(json_results < 4)
        {
            printf("> ERROR invalid json response\r\n");
            continue;
        }

        /* check ok */
        if( jsoneq(g_json_io_buffer,&g_json_tokens[1],"ok",JSMN_STRING) == false ) continue;
        if( jsoneq(g_json_io_buffer,&g_json_tokens[2],"true",JSMN_PRIMITIVE) == false ) continue;

        /* fetch update id */
        well_done = false;
        for(int i=3;i<json_results;i++)
        {
            if( jsoneq(g_json_io_buffer,&g_json_tokens[i],"update_id",JSMN_STRING) == true )
            {
                g_json_io_buffer[g_json_tokens[i+1].end]=0;
                update_id = atoi(g_json_io_buffer+g_json_tokens[i+1].start);
                well_done = true;
            } 
        }

        // update_id not found ?
        if(well_done == false) continue;

        /* fetch chat id */
        well_done = false;
        for(int i=3;i<json_results;i++)
        {
            if( jsoneq(g_json_io_buffer,&g_json_tokens[i],"id",JSMN_STRING) == true )
            {
                g_json_io_buffer[g_json_tokens[i+1].end]=0;
                chat_id = atoi(g_json_io_buffer+g_json_tokens[i+1].start);
                well_done = true;
            } 
        }

        // chat_id not found ?
        if(well_done == false) continue;

        /*fetch message */
        well_done = false;
        g_incoming_msg[0]=0;
        for(int i=3;i<json_results;i++)
        {
            if( jsoneq(g_json_io_buffer,&g_json_tokens[i],"text",JSMN_STRING) == true )
            {
                int msg_len = g_json_tokens[i+1].end - g_json_tokens[i+1].start;
                if( msg_len < TELEGRAM_BOT_INCOMING_CMD_SIZE)
                {
                    memcpy(g_incoming_msg,g_json_io_buffer+g_json_tokens[i+1].start,msg_len);
                    g_incoming_msg[msg_len] = 0;
                    well_done = true;
                }
                break;
            } 
        }

        printf("> Incoming msg: %s\n\r",g_incoming_msg);

        // parse incoming message
        if( strstr(g_incoming_msg,"Temperature") != NULL)
        {
            snprintf(g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,"{\"chat_id\":%d,\"text\":\"Temperature %.2f degC\",\"reply_markup\":%s}",
                     chat_id,temp,TELEGRAM_CUSTOM_KEYBOARD);
        }
        else if( strstr(g_incoming_msg,"Humidity") != NULL)
        {
            snprintf(g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,"{\"chat_id\":%d,\"text\":\"Humidity %.2f %%\",\"reply_markup\":%s}",
                     chat_id,humi,TELEGRAM_CUSTOM_KEYBOARD);
        }
        else if( strstr(g_incoming_msg,"Pressure") != NULL)
        {
            snprintf(g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,"{\"chat_id\":%d,\"text\":\"Pressure %.2f mBar\",\"reply_markup\":%s}",
                     chat_id,pres,TELEGRAM_CUSTOM_KEYBOARD);
        }
        else if( strstr(g_incoming_msg,"RTC") != NULL)
        {
            snprintf(g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,"{\"chat_id\":%d,\"text\":\"%s UTC\",\"reply_markup\":%s}",
                     chat_id,ctime(&timestamp),TELEGRAM_CUSTOM_KEYBOARD);
        }
        else if( strstr(g_incoming_msg,"Daily") != NULL )
        {
            int pivot = snprintf(g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,"{\"chat_id\":%d,\"text\":\"", chat_id); 
            pivot += daily_temperature_history_chart(   g_json_io_buffer + pivot, TBOT_JSON_BUFFER_SIZE - pivot );
            snprintf( g_json_io_buffer + pivot, TBOT_JSON_BUFFER_SIZE - pivot, "\"}");
            if( telegram_send_message(g_json_io_buffer) == false)
            {
                printf("> ERROR telegram_send_message\r\n");
                continue;
            }
            
            pivot = snprintf(g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,"{\"chat_id\":%d,\"text\":\"", chat_id); 
            pivot += daily_humidity_history_chart(   g_json_io_buffer + pivot, TBOT_JSON_BUFFER_SIZE - pivot );
            snprintf( g_json_io_buffer + pivot, TBOT_JSON_BUFFER_SIZE - pivot, "\"}");
            if( telegram_send_message(g_json_io_buffer) == false)
            {
                printf("> ERROR telegram_send_message\r\n");
                continue;
            }
            
            pivot = snprintf(g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,"{\"chat_id\":%d,\"text\":\"", chat_id); 
            pivot += daily_pressure_history_chart(   g_json_io_buffer + pivot, TBOT_JSON_BUFFER_SIZE - pivot );
            snprintf( g_json_io_buffer + pivot, TBOT_JSON_BUFFER_SIZE - pivot, "\",\"reply_markup\":%s}",TELEGRAM_CUSTOM_KEYBOARD);
            
            
        }
#if WITH_ARDUCAM_2640
        else if( strstr(g_incoming_msg,"Camera") != NULL )
        {
            uint32_t image_size;
            uint32_t idx;

            snprintf(g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,"{\"chat_id\":%d,\"text\":\"Sending photos ...\",\"reply_markup\":%s}",
                     chat_id,TELEGRAM_CUSTOM_KEYBOARD);
            if( telegram_send_message(g_json_io_buffer) == false)
            {
                printf("> ERROR telegram_send_message\r\n");
                continue;
            }

            for(int i=0; i<3; i++)
            {                     
                image_size = g_arducam.CaptureImage(g_image_buffer,IMAGE_JPG_SIZE,&idx);
                if( image_size == 0 || telegram_send_photo(g_image_buffer+idx, image_size, chat_id, "Images from space") == false )
                {
                    printf("Photo failure %d\r\n",image_size);
                    break;
                }
            }

            snprintf(g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,"{\"chat_id\":%d,\"text\":\"Done.\",\"reply_markup\":%s}",
                     chat_id,TELEGRAM_CUSTOM_KEYBOARD);
        }
#endif
        else
        {
            snprintf(g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,"{\"chat_id\":%d,\"text\":\"Available commands\",\"reply_markup\":%s}",
                     chat_id,TELEGRAM_CUSTOM_KEYBOARD);
        }
        
        if( telegram_send_message(g_json_io_buffer) == false)
        {
            printf("> ERROR telegram_send_message\r\n");
            continue;
        }
        
        jsmn_init(&g_json_parser);
        json_results = jsmn_parse(&g_json_parser,g_json_io_buffer,strlen(g_json_io_buffer),g_json_tokens,JSON_MAX_TOKENS);
        if(json_results < 4)
        {
            printf("> ERROR invalid json response\r\n");
            continue;
        }

        /* check ok */
        if( jsoneq(g_json_io_buffer,&g_json_tokens[1],"ok",JSMN_STRING) == false ) continue;
        if( jsoneq(g_json_io_buffer,&g_json_tokens[2],"true",JSMN_PRIMITIVE) == false ) continue;

    }
}

/*****************************************************************************************
*
*
* Daily history update
*
*
******************************************************************************************/
void daily_history_update( int hour, int min, float t, float p, float h )
{
    g_daily_data_history_temp[hour][min] = t;
    g_daily_data_history_pres[hour][min] = p;
    g_daily_data_history_humi[hour][min] = h;    
}


int32_t daily_temperature_history_chart(char *report_buffer, uint32_t buffer_len)
{
    float sum;
    uint32_t num;
    int32_t pivot = 0;
    
    // temperature chart   
    pivot = snprintf(report_buffer,buffer_len,"Daily temperature chart\n\nhttps://image-charts.com/chart?chxt=x,y&chxr=1,0,%d&cht=lc&chd=t:",50);
    for(int i=0;i<24;i++)
    {
        sum = 0.0F;
        num = 0;
        for(int ii=0;ii<60;ii++)
        {
            if(g_daily_data_history_temp[i][ii] > 0.0F)
            {
                num++;
                sum += g_daily_data_history_temp[i][ii];
            }
        }
        pivot += snprintf(report_buffer+pivot,buffer_len-pivot,"%d,",(num>0)?(int32_t)sum/num:0);
    }
    pivot--;
    pivot += snprintf(report_buffer+pivot,buffer_len-pivot,"%s","&chco=76A4FB&chls=2.0&chs=600x300&chg=10,10");
    
    report_buffer[pivot]=0;
    return pivot;
}

int32_t daily_humidity_history_chart(char *report_buffer, uint32_t buffer_len)
{
    float sum;
    uint32_t num;
    int32_t pivot = 0;
    
    // humidity chart 
    pivot += snprintf(report_buffer+pivot,buffer_len-pivot,"Daily humidity chart\n\nhttps://image-charts.com/chart?chxt=x,y&chxr=1,0,%d&cht=lc&chd=t:",100);
    for(int i=0;i<24;i++)
    {
        sum = 0.0F;
        num = 0;
        for(int ii=0;ii<60;ii++)
        {
            if(g_daily_data_history_humi[i][ii] > 0.0F)
            {
                num++;
                sum += g_daily_data_history_humi[i][ii];
            }
        }
        pivot += snprintf(report_buffer+pivot,buffer_len-pivot,"%d,",(num>0)?(int32_t)sum/num:0);
    }
    pivot--;
    pivot += snprintf(report_buffer+pivot,buffer_len-pivot,"%s","&chco=76A4FB&chls=2.0&chs=600x300&chg=10,10\n\n");
    
    report_buffer[pivot]=0;
    return pivot;
}

    
int32_t daily_pressure_history_chart(char *report_buffer, uint32_t buffer_len)
{
    float sum;
    uint32_t num;
    int32_t pivot = 0;
    
    // pressure chart 
    pivot += snprintf(report_buffer+pivot,buffer_len-pivot,"Daily pressure chart\n\nhttps://image-charts.com/chart?chxt=x,y&chxr=1,%d,%d&cht=lc&chd=t:",900,1100);
    for(int i=0;i<24;i++)
    {
        sum = 0.0F;
        num = 0;
        for(int ii=0;ii<60;ii++)
        {
            if(g_daily_data_history_pres[i][ii] > 0.0F)
            {
                num++;
                sum += g_daily_data_history_pres[i][ii];
            }
        }
        pivot += snprintf(report_buffer+pivot,buffer_len-pivot,"%d,",(num>0)?(int32_t)sum/num:0);
    }
    pivot--;
    pivot += snprintf(report_buffer+pivot,buffer_len-pivot,"%s","&chco=76A4FB&chls=2.0&chs=600x300&chg=10,10&chds=a");
    
    report_buffer[pivot]=0;
    return pivot;
}

/*****************************************************************************************
 * 
 * 
 * update RTC using now.httpbin.org free service
 * 
 * 
 * ***************************************************************************************/

#define HTTPBIN_EPOCH_TAG "epoch\":"
bool set_rtc_from_network(void)
{
    uint32_t http_content_len=0;
    bool http_ok = false;

    /* prepare http get header */
    strcpy(g_http_io_buffer,NOW_HTTPBIN_ORG);

    
    // CONNECT http://now.httpbin.org
    if( g_tcp_connector.tcp_connect(0x01,"now.httpbin.org",80,false,3) )
    {
        // send HTML GET 
        if( g_tcp_connector.tcp_write(0x01,g_http_io_buffer,strlen(g_http_io_buffer)))
        {
            // read json response
            if( g_http_parser.HttpParseResponse(&g_tcp_connector,0x01,g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,&http_ok,&http_content_len) )
            {
                if(http_ok) 
                {
                    g_json_io_buffer[http_content_len] = 0;
                } 
            }
        }
    }
    g_tcp_connector.tcp_close(0x01);

    // parse and set time
    if( http_ok )
    {
        char *epoch = strstr(g_json_io_buffer,HTTPBIN_EPOCH_TAG);
        if(epoch == NULL) return false;
        epoch += sizeof( HTTPBIN_EPOCH_TAG );
        for(int i=0;i<20;i++)
        {
            if( epoch[i] == '.')
            {
                epoch[i] = 0;
                printf("> now.httpbin.org epoch: %s\r\n",epoch);
                set_time( atoi(epoch) );
                return true;
            }
        }
    }

    return false;

}

/*****************************************************************************************
*
*
*   telegram rest api
*
*
******************************************************************************************/

bool telegram_get_update(int32_t update_id)
{
    uint32_t http_content_len=0;
    bool http_ok = false;

    /* prepare http get header */
    snprintf(g_http_io_buffer, ES_WIFI_PAYLOAD_SIZE, TELEGRAM_GETUPDATES, update_id);


    // CONNECT https://api.telegram.org
    if( g_tcp_connector.tcp_connect(0x01,"api.telegram.org",443,true,3) )
    {
        // send HTML GET getUpdates
        if( g_tcp_connector.tcp_write(0x01,g_http_io_buffer,strlen(g_http_io_buffer)))
        {
            // read json response
            if( g_http_parser.HttpParseResponse(&g_tcp_connector,0x01,g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,&http_ok,&http_content_len) )
            {
                if(http_ok) 
                {
                    g_json_io_buffer[http_content_len] = 0;
                } 
            }
        }
        g_tcp_connector.tcp_close(0x01);
    }

    return http_ok;
}



bool telegram_send_message(char *json_msg)
{
    uint32_t http_content_len=0,msg_len;
    bool http_ok = false;
    
    msg_len = strlen(json_msg);

    /* prepare http get header */
    snprintf(g_http_io_buffer, ES_WIFI_PAYLOAD_SIZE, TELEGRAM_SENDMESSAGE, msg_len);

   // CONNECT https://api.telegram.org
    if( g_tcp_connector.tcp_connect(0x01,"api.telegram.org",443,true,3) )
    {
        // send HTML GET sendMessage
        if( g_tcp_connector.tcp_write(0x01,g_http_io_buffer,strlen(g_http_io_buffer)))
        {
            // send payload
            if( g_tcp_connector.tcp_write(0x01,json_msg,msg_len) )
            {
                // read json response
                if( g_http_parser.HttpParseResponse(&g_tcp_connector,1,g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,&http_ok,&http_content_len) )
                {
                    if(http_ok) 
                    {
                        g_json_io_buffer[http_content_len] = 0;
                    } 
                }
            }
        }
        g_tcp_connector.tcp_close(0x01);
    }

    return http_ok;
}


bool telegram_send_photo(uint8_t *image, uint32_t image_size, int32_t chat_id, char *caption)
{
    char chat_id_str[32];
    uint32_t content_len = 0;
    uint32_t http_content_len=0;
    bool http_ok = false;

        content_len = 383; // pre-calculated boundary len
        content_len += snprintf(chat_id_str,sizeof(chat_id_str),"%d",chat_id);
        content_len += strlen(caption);
        content_len += image_size;

        /* prepare http post header */
        snprintf(g_http_io_buffer, ES_WIFI_PAYLOAD_SIZE, TELEGRAM_SENDPHOTO, content_len);
        
        // CONNECT https://api.telegram.org
        if( g_tcp_connector.tcp_connect(0x01,"api.telegram.org",443,true,3) )
        {
            // send HTML POST sendMessage
            if( g_tcp_connector.tcp_write(0x01,g_http_io_buffer,strlen(g_http_io_buffer)))
            {
                strcpy(g_http_io_buffer,"Content-Type: multipart/form-data; boundary=------------------------660d8ea934533f2b\r\n");
                if( g_tcp_connector.tcp_write(0x01,g_http_io_buffer,strlen(g_http_io_buffer)))
                {
                    snprintf(g_http_io_buffer, ES_WIFI_PAYLOAD_SIZE, "\r\n--------------------------660d8ea934533f2b\r\nContent-Disposition: form-data; name=\"chat_id\"\r\n\r\n%s", chat_id_str);
                    if( g_tcp_connector.tcp_write(0x01,g_http_io_buffer,strlen(g_http_io_buffer)))
                    {   
                        snprintf(g_http_io_buffer, ES_WIFI_PAYLOAD_SIZE, "\r\n--------------------------660d8ea934533f2b\r\nContent-Disposition: form-data; name=\"caption\"\r\n\r\n%s", caption);
                        if( g_tcp_connector.tcp_write(0x01,g_http_io_buffer,strlen(g_http_io_buffer)))
                        {   
                            strcpy(g_http_io_buffer, "\r\n--------------------------660d8ea934533f2b\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"acam2640.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n");
                            if( g_tcp_connector.tcp_write(0x01,g_http_io_buffer,strlen(g_http_io_buffer)))
                            {   
                                if( g_tcp_connector.tcp_write(0x01,(char*)image,image_size))
                                {   
                                    strcpy(g_http_io_buffer,"\r\n--------------------------660d8ea934533f2b--\r\n");
                                    if( g_tcp_connector.tcp_write(0x01,g_http_io_buffer,strlen(g_http_io_buffer)) )
                                    {
                                        // read json response
                                        if( g_http_parser.HttpParseResponse(&g_tcp_connector,0x01,g_json_io_buffer,TBOT_JSON_BUFFER_SIZE,&http_ok,&http_content_len) )
                                        {
                                            if(http_ok) 
                                            {
                                                g_json_io_buffer[http_content_len] = 0;
                                            } 
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            g_tcp_connector.tcp_close(0x01);
        }

        return http_ok;        
}

/*****************************************************************************************
*
*
*   JSON parsing
*
*
******************************************************************************************/

bool jsoneq(const char *json, jsmntok_t *tok, const char *s,jsmntype_t type) 
{
    if (tok->type == type && (int) strlen(s) == tok->end - tok->start &&
            strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
        return true;
    }
    return false;
}