BG96 Module MQTT client example

Dependencies:   MQTT NetworkSocketAPI mbed

Fork of Nucleo_NbIotBG96_A2_cloud_IBM by Avnet Silica

main.cpp

Committer:
WaleedElmughrabi
Date:
2018-09-09
Revision:
3:e26690c0e2c7
Parent:
2:b72797c38464

File content as of revision 3:e26690c0e2c7:

/* BG96 NetworkSocketAPI Example Program
 * Copyright (c) 2015 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 "BG96Interface.h"
#include "TCPSocket.h"
#include "MQTTClient.h"
#include "MQTT_GSM.h"
#include <ctype.h>
#include "BG96.h"

//------------------------------------
// Hyperterminal default configuration
// 9600 bauds, 8-bit data, no parity
//------------------------------------
Serial pc(SERIAL_TX, SERIAL_RX); 
DigitalOut myled(LED1);
bool quickstartMode = true;    

#define MQTT_MAX_PACKET_SIZE 300   
#define MQTT_MAX_PAYLOAD_SIZE 500 


#define ORG_QUICKSTART         							// comment to connect to play.internetofthings.ibmcloud.com
//#define SUBSCRIBE              							// uncomment to subscribe to broker msgs (not to be used with IBM broker) 

 // Configuration values needed to connect to IBM IoT Cloud
//#define BROKER_URL "BTL-IOT-Hub.azure-devices.net";     
#define BROKER_URL ".messaging.internetofthings.ibmcloud.com";  

#ifdef ORG_QUICKSTART
	#define ORG "quickstart"     								// connect to quickstart.internetofthings.ibmcloud.com/ For a registered connection, replace with your org 
	#define ID ""
	#define AUTH_TOKEN ""
	#define DEFAULT_TYPE_NAME "iotsample-mbed-Nucleo"
	#define TOPIC  "iot-2/evt/status/fmt/json" 
#else   // not def ORG_QUICKSTART
	#define ORG "Test-Device-1"             						// connect to play.internetofthings.ibmcloud.com/ For a registered connection, replace with your org
	#define ID "Test-Device-1"       		// For a registered connection, replace with your id
	#define AUTH_TOKEN ""	// For a registered connection, replace with your auth-token
	#define DEFAULT_TYPE_NAME "Test-Device-1"
	#define TOPIC   "devices/Test-Device-1/messages/events" 
#endif

// network credential
#define APN   "m2m.tele2.com"  //VODAFONE apn definition's
//#define APN			"internet.wind"		//WIND apn definition's
#define PASSW  "Waleed29"
#define USNAME "Ianthomson"

#define TYPE DEFAULT_TYPE_NAME       // For a registered connection, replace with your type
#define MQTT_PORT 1883
#define MQTT_TLS_PORT 8883
#define IBM_IOT_PORT MQTT_PORT
    
char id[30] = ID;                 // mac without colons  
char org[12] = ORG;        
int connack_rc = 0; // MQTT connack return code
//const char* ip_addr = "11.12.13.14";
//char* host_addr = "11.12.13.14";
char sensor_id[50];
char type[30] = TYPE;
char auth_token[30] = AUTH_TOKEN; // Auth_token is only used in non-quickstart mode
bool netConnecting = false;
int connectTimeout = 1000;
bool mqttConnecting = false;
bool netConnected = false;
bool connected = false;
int retryAttempt = 0;
char subscription_url[MQTT_MAX_PAYLOAD_SIZE];



#define FW_REV						"1.0a"



MQTT::Message message;
MQTTString TopicName={TOPIC};
MQTT::MessageData MsgData(TopicName, message);



void subscribe_cb(MQTT::MessageData & msgMQTT) {
    char msg[MQTT_MAX_PAYLOAD_SIZE];
    msg[0]='\0';
    strncat (msg, (char*)msgMQTT.message.payload, msgMQTT.message.payloadlen);
    printf ("--->>> subscribe_cb msg: %s\n\r", msg);
}

int subscribe(MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_GSM* ipstack)
{
    char* pubTopic = TOPIC;    
    return client->subscribe(pubTopic, MQTT::QOS1, subscribe_cb);
}

int connect(MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_GSM* ipstack)
{ 
    const char* iot_ibm = BROKER_URL; 

    
    char hostname[strlen(org) + strlen(iot_ibm) + 1];
    sprintf(hostname, "%s%s", org, iot_ibm);
	

    // Construct clientId - d:org:type:id
    char clientId[strlen(org) + strlen(type) + strlen(id) + 5];  
	
		#ifdef ORG_QUICKSTART
    sprintf(clientId, "d:%s:%s:%s", org, type, id);  //@@
		#else
		sprintf(clientId, "g:%s:%s:%s", org, type, id);  //@@
		#endif
	
    sprintf(subscription_url, "%s.%s/#/device/%s/sensor/", org, "internetofthings.ibmcloud.com",id);
		
    netConnecting = true;
    ipstack->open(&ipstack->getGSM());
    int rc = ipstack->connect(hostname, IBM_IOT_PORT, connectTimeout);    
    if (rc != 0)
    {
        //WARN("IP Stack connect returned: %d\n", rc);    
        return rc;
    }
    pc.printf ("--->TCP Connected\n\r");
    netConnected = true;
    netConnecting = false;

    // MQTT Connect
    mqttConnecting = true;
    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.MQTTVersion = 3;
    data.struct_version=0;
    data.clientID.cstring = clientId;
 
    if (!quickstartMode) 
    {        
        data.username.cstring = "use-token-auth";
        data.password.cstring = auth_token;
    }   
    if ((rc = client->connect(data)) == 0) 
    {       
        connected = true;
        pc.printf ("--->MQTT Connected\n\r");
	#ifdef SUBSCRIBE
        if (!subscribe(client, ipstack)) printf ("--->>>MQTT subscribed to: %s\n\r",TOPIC);
	#endif           
    }
    else {
        //WARN("MQTT connect returned %d\n", rc);        
    }
    if (rc >= 0)
        connack_rc = rc;
    mqttConnecting = false;
    return rc;
}


int getConnTimeout(int attemptNumber)
{  // First 10 attempts try within 3 seconds, next 10 attempts retry after every 1 minute
   // after 20 attempts, retry every 10 minutes
    return (attemptNumber < 10) ? 3 : (attemptNumber < 20) ? 60 : 600;
}

void attemptConnect(MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_GSM* ipstack)
{
    connected = false;
           
    while (connect(client, ipstack) != MQTT_CONNECTION_ACCEPTED) 
    {    
        if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD) {
            printf ("File: %s, Line: %d Error: %d\n\r",__FILE__,__LINE__, connack_rc);        
            return; // don't reattempt to connect if credentials are wrong
        } 
        int timeout = getConnTimeout(++retryAttempt);
        //WARN("Retry attempt number %d waiting %d\n", retryAttempt, timeout);
        
        // if ipstack and client were on the heap we could deconstruct and goto a label where they are constructed
        //  or maybe just add the proper members to do this disconnect and call attemptConnect(...)        
        // this works - reset the system when the retry count gets to a threshold
        if (retryAttempt == 5){
						pc.printf ("\n\n\rFAIL!! system reset!!\n\n\r");
            NVIC_SystemReset();
				}
        else
            wait(timeout);
    }
}
float hum_global = 50.0;
uint32_t n_msg = 0;

int publish(MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_GSM* ipstack)
{
    MQTT::Message message;
    char* pubTopic = TOPIC;
            
    char buf[MQTT_MAX_PAYLOAD_SIZE];
    float temp, temp1, temp2, press, hum;

		temp=25.5;
		hum_global +=0.1;
		if (hum_global>99.0)
			hum_global = 50.0;
		hum=hum_global;
		press=999;

		
	#ifdef ORG_QUICKSTART
    sprintf(buf,
     "{\"d\":{\"ST\":\"Nucleo-IoT-mbed\",\"Temp\":%0.4f,\"Pressure\":%0.4f,\"Humidity\":%0.4f}}",
              temp, press, hum);
	#else
		sprintf (buf, 
		"{\"%s\": {\"temp\":%0.4f,\"humidity\":%0.4f,\"pressure\":%0.4f,\"ambient\":0,\"uv\":0,\"accel_X\":0,\"accel_Y\":0,\"accel_Z\":0}}", 
				sensor_id, temp, hum, press);
	#endif
		
		message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf);
    
		//LOG("Publishing %s\n\r", buf);
		n_msg++;
    pc.printf("Publishing V%s #%d %s\n\r", FW_REV, n_msg, buf);
    return client->publish(pubTopic, message);
} 
    

int loop_count = 0;  
void test_sens(void);

int main()
{
    const char * apn = APN; // Network must be visible otherwise it can't connect
    const char * username = USNAME;
		const char * password = PASSW;
    BG96Interface bg96_if(PG_7, PG_8, false);
		//sprintf(sensor_id,"%s",bg96_if.get_mac_address()); 
		//Timer tyeld;

		//change serial baud to 115200
		pc.baud(115200);
		wait(0.1);
	
    myled=1;
		//wait(0.5);
    pc.printf("\r\n*************************************************");
	  wait( 0.1 ); 
		pc.printf("\r\nAvnet Silica NbIotBG96 A02 mbed-os application\r\n");  
    wait( 0.1 );   
    pc.printf("MBED online version %s\r\n", FW_REV);     
    wait( 0.1 );
    //pc.printf("\r\nwait for APN ready ...\r\n");  
    //wait( 0.1 );     
	

	

   quickstartMode=false;
   if (strcmp(org, "quickstart") == 0){quickstartMode = true;}
   MQTT_GSM ipstack(bg96_if, apn, username, password);
   MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack);
   if (quickstartMode){
        char mac[50];  // remove all : from mac
        char *digit=NULL;
        sprintf (id,"%s", "");                
        sprintf (mac,"%s",ipstack.getGSM().get_mac_address()); 
        digit = strtok (mac,":");
        while (digit != NULL)
        {
            strcat (id, digit);
            digit = strtok (NULL, ":");
        }     
   }
   attemptConnect(&client, &ipstack);
   if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD)    
   {
      while (true)
      wait(1.0); // Permanent failures - don't retry
   }
		myled=0;      
		sprintf(sensor_id,"%s",bg96_if.get_mac_address()); 

    while (true)
    {
        if (++loop_count == 60)
        {   
						// Publish a message every 30 second
						pc.printf("\n");
						myled=1;
            if (publish(&client, &ipstack) != 0) { 
                myled=0;
                attemptConnect(&client, &ipstack);   // if we have lost the connection                
            } 
						//else 
						myled=0;
            loop_count = 0;
        }        
//      int start = tyeld.read_ms();
        client.yield(500);  // allow the MQTT client to receive messages
				pc.printf ("loop %d\r", (loop_count+1));		//: %d\n\r",tyeld.read_ms()-start);

    }

}




/* Helper function for printing floats & doubles */
static char *print_double(char* str, double v, int decimalDigits=2)
{
  int i = 1;
  int intPart, fractPart;
  int len;
  char *ptr;

  /* prepare decimal digits multiplicator */
  for (;decimalDigits!=0; i*=10, decimalDigits--);

  /* calculate integer & fractinal parts */
  intPart = (int)v;
  fractPart = (int)((v-(double)(int)v)*i);

  /* fill in integer part */
  sprintf(str, "%i.", intPart);

  /* prepare fill in of fractional part */
  len = strlen(str);
  ptr = &str[len];

  /* fill in leading fractional zeros */
  for (i/=10;i>1; i/=10, ptr++) {
    if (fractPart >= i) {
      break;
    }
    *ptr = '0';
  }

  /* fill in (rest of) fractional part */
  sprintf(ptr, "%i", fractPart);

  return str;
}