Example of AWS IoT connection and Web Dashboard thru STM32 Nucleo evaluation board and mbed OS.

Dependencies:   X_NUCLEO_IKS01A1 mbed FP MQTTPacket DnsQuery ATParser

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* SpwfInterface NetworkSocketAPI Example Program
00002  * Copyright (c) 2015 ARM Limited
00003  * Copyright (c) 2017 KLIKA TECH, LLC
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  
00017  Contributors:
00018   *    Klika Tech - completely adopted to Amazon AWS IoT service
00019 
00020  */
00021 
00022 #include "mbed.h"
00023 #include "SpwfInterface.h"
00024 #include "TCPSocket.h"
00025 #include "MQTTClient.h"
00026 #include "MQTTWiFi.h"
00027 #include <ctype.h>
00028 #include "x_nucleo_iks01a1.h"
00029 
00030 //------------------------------------
00031 // Hyperterminal default configuration
00032 // 9600 bauds, 8-bit data, no parity
00033 //------------------------------------
00034 Serial pc(SERIAL_TX, SERIAL_RX); 
00035 DigitalOut myled(LED2);
00036 DigitalOut butled(LED3);
00037 InterruptIn  mybutton(USER_BUTTON);
00038 
00039 bool myButtonPressed = false;
00040     
00041 #define MQTT_MAX_PACKET_SIZE 350
00042 #define MQTT_MAX_PAYLOAD_SIZE 300 
00043 
00044 #define AWS_IOT_MQTT_HOST              "a3t8vwpkw3sltg.iot.us-east-2.amazonaws.com" //Use your own host.
00045 #define AWS_IOT_MQTT_PORT              8883
00046 #define AWS_IOT_MQTT_CLIENT_ID         "Nucleo" //Should be kept if you are using same device clent.
00047 #define AWS_IOT_MY_THING_NAME          "Nucleo" //Should be kept if you are using same device thing name.
00048 #define AWS_IOT_MQTT_TOPIC_TEST        "Nucleo/test"
00049 #define AWS_IOT_MQTT_TOPIC_DATA        "Nucleo/data"
00050 #define AWS_IOT_MQTT_TOPIC_SHADOW      "$aws/things/Nucleo/shadow/update"
00051 #define AWS_IOT_ID ""
00052 #define AWS_IOT_AUTH_TOKEN ""
00053 
00054 // WiFi network credential
00055 #define SSID   ""  // Network must be visible otherwise it can't connect
00056 #define PASSW  ""
00057 #error "Wifi SSID & password empty"
00058 
00059 #include "stdint.h"
00060 
00061 
00062 /**********************************************************************************************
00063 ***********************************************************************************************
00064                                                     Root CA certificate: Never modify
00065 ***********************************************************************************************
00066 ***********************************************************************************************/
00067 
00068 //This root CA can be used.
00069 const uint8_t rootCA[] = "\
00070 -----BEGIN CERTIFICATE-----\n\
00071 MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB\
00072 yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\
00073 ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\
00074 U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\
00075 ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\
00076 aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL\
00077 MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\
00078 ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln\
00079 biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp\
00080 U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\
00081 aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1\
00082 nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex\
00083 t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz\
00084 SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG\
00085 BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+\
00086 rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/\
00087 NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E\
00088 BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH\
00089 BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy\
00090 aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv\
00091 MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE\
00092 p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y\
00093 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK\
00094 WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ\
00095 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N\
00096 hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao8WNq\n\
00097 -----END CERTIFICATE-----\n";
00098 
00099 /**********************************************************************************************
00100 ***********************************************************************************************
00101                                                     Device Identity Certificates: Modify for your AWS IoT Thing
00102 ***********************************************************************************************
00103 ***********************************************************************************************/
00104 
00105 /****************************************
00106 (somecode)-certificate.pem.crt - Amazon signed PEM sertificate.
00107 *****************************************/
00108 
00109 //This Client cert is example. Use own instead.
00110 const uint8_t clientCRT[] = "\
00111 -----BEGIN CERTIFICATE-----\n\
00112 MIIC8jCCAdqgAwIBAgIVAJrIfpHLnCshC2j/Tp0dBJlSgaFnMA0GCSqGSIb3DQEB\
00113 CwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\
00114 IEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0xNzA5MTUxMjQ3\
00115 NDBaFw00OTEyMzEyMzU5NTlaMIGAMQswCQYDVQQGEwJERTENMAsGA1UECBMERGVt\
00116 bzENMAsGA1UEBxMERGVtbzENMAsGA1UEChMERGVtbzENMAsGA1UECxMERGVtbzEN\
00117 MAsGA1UEAxMERGVtbzEmMCQGCSqGSIb3DQEJARYXcHNhdnloaW5Aa2xpa2EtdGVj\
00118 aC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT5IihA21BQZFW0vSdVxNuD\
00119 VKXAN7rI3Op3/MiWOlXqHEGHZeYs5ug8qEYkDZDkafhO87LNC0xhNSnGsNnNmyPI\
00120 o2AwXjAfBgNVHSMEGDAWgBRF1n2grhwmYjwSZmF74bVqm/enfjAdBgNVHQ4EFgQU\
00121 qSNNYMI1XGRMnnLenZlU1h/WNAkwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMC\
00122 B4AwDQYJKoZIhvcNAQELBQADggEBADTAhidWjd+MD6sLqr8+ZTdIcka0kT0tnMGy\
00123 Chz5ixaDpNI/OS9fi+SfOAd1Dd+/panpNtvJ5OfN0wkYJRd+lhBaN8M5lWsIF7EM\
00124 FvFtc+UV2cvGyYmSW47fFaV3DOv8vL068cmpNkd/HF8q9r0QNd0h2o97G99Xkk9k\
00125 90DIOgzu0C3sSTy5xDankCvfWIM2ibh5Laz3NmIqVW9jnnkMpQ00xViR8IdnfR4g\
00126 ke1C33ZQh1yTGNEE94nVGRMB2cPY62ChrM/ffgmUo4De0M45tX8ucFVL+ZwaCc3E\
00127 pmjMxFza6yZU50a74zZESmWGR5HYp0PSovglr9Xc5jvktqSugKM=\
00128 \n\
00129 -----END CERTIFICATE-----\n";
00130 
00131 
00132 
00133 /**********************************************************************************************
00134 ***********************************************************************************************
00135                                                     Private Key: Modify for your AWS IoT Thing
00136 ***********************************************************************************************
00137 ***********************************************************************************************/
00138 
00139 /********************************************************************8****************************************
00140 nucleo.key.pem - client key generated according to readme.
00141 **************************************************************************************************************/
00142 
00143 //This Client Key is example. Use own instead.
00144 const uint8_t clientKey[] ="\
00145 -----BEGIN EC PARAMETERS-----\n\
00146 BggqhkjOPQMBBw==\
00147 -----END EC PARAMETERS-----\n\
00148 -----BEGIN EC PRIVATE KEY-----\n\
00149 MHcCAQEEIByuPtqukIClJ35+FA0gdvlMs7FmSFiOJGpaYsyQs4wwoAoGCCqGSM49\
00150 AwEHoUQDQgAE+SIoQNtQUGRVtL0nVcTbg1SlwDe6yNzqd/zIljpV6hxBh2XmLObo\
00151 PKhGJA2Q5Gn4TvOyzQtMYTUpxrDZzZsjyA==\
00152 -----END EC PRIVATE KEY-----\n";
00153 
00154 int connack_rc = 0; // MQTT connack return code
00155 int connectTimeout = 1000;
00156 int retryAttempt = 0;
00157 
00158 PressureSensor *pressure_sensor;
00159 HumiditySensor *humidity_sensor;
00160 TempSensor *temp_sensor1;
00161 MagneticSensor *magnetic_sensor;
00162 GyroSensor     *gyro_sensor;
00163 MotionSensor   *accel_sensor;
00164 
00165 MQTT::Message message;
00166 MQTTString TopicName= { AWS_IOT_MQTT_TOPIC_TEST };
00167 MQTT::MessageData MsgData(TopicName, message);
00168 
00169 void subscribe_cb(MQTT::MessageData & msgMQTT) {
00170     char msg[MQTT_MAX_PAYLOAD_SIZE];
00171     msg[0]='\0';
00172     strncat (msg, (char*)msgMQTT.message.payload, msgMQTT.message.payloadlen);
00173     printf ("--->>> subscribe_cb msg: %s\n\r", msg);
00174 }
00175 
00176 int subscribe(MQTT::Client<MQTTWiFi, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTWiFi* ipstack)
00177 {
00178     char* pubTopic = AWS_IOT_MQTT_TOPIC_TEST;
00179     return client->subscribe(pubTopic, MQTT::QOS0, subscribe_cb);
00180 }
00181 
00182 int connect(MQTT::Client<MQTTWiFi, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTWiFi* ipstack)
00183 { 
00184     SpwfSAInterface& WiFi = ipstack->getWiFi();
00185 
00186     // Network debug statements
00187     LOG("=====================================\n\r");
00188     LOG("Connecting WiFi.\n\r");
00189     LOG("Nucleo IP ADDRESS: %s\n\r", WiFi.get_ip_address());
00190     LOG("Nucleo MAC ADDRESS: %s\n\r", WiFi.get_mac_address());
00191     LOG("Server Hostname: %s port: %d\n\r", AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT);
00192     LOG("Client ID: %s\n\r", AWS_IOT_MQTT_CLIENT_ID);
00193     //LOG("Topic: %s\n\r", AWS_IOT_MQTT_TOPIC_TEST);
00194     //LOG("Subscription URL: %s\n\r", subscription_url);
00195     LOG("=====================================\n\r");
00196     
00197     ipstack->open(&ipstack->getWiFi());
00198 
00199     int rc=ipstack->getNTPtime();
00200 
00201     if (rc != 0)
00202     {
00203         WARN("Get NTP time error: %d\n", rc);
00204         return rc;
00205     }
00206 
00207     rc = WiFi.setSocketClientSecurity((uint8_t *)"m", (uint8_t *)rootCA, (uint8_t *)clientCRT, (uint8_t *)clientKey, (uint8_t *)AWS_IOT_MQTT_HOST, ipstack->getTime());
00208 
00209     if (rc != 0)
00210     {
00211         WARN("Set security params error: %d\n", rc);
00212         return rc;
00213     }
00214 
00215     rc = ipstack->connect(AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT, connectTimeout);
00216 
00217     if (rc != 0)
00218     {
00219         WARN("IP Stack connect returned: %d\n\r", rc);
00220         return rc;
00221     }
00222 
00223     printf ("--->TCP Connected\n\r");
00224 
00225     // MQTT Connect
00226     MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
00227     data.MQTTVersion = 4;
00228     data.struct_version=0;
00229     data.clientID.cstring = AWS_IOT_MQTT_CLIENT_ID;
00230     //data.username.cstring = "use-token-auth";
00231     //data.password.cstring = AWS_IOT_AUTH_TOKEN;
00232 
00233     if ((rc = client->connect(data)) == 0) 
00234     {
00235         printf ("--->MQTT Connected\n\r");
00236 
00237         if (!subscribe(client, ipstack)) printf ("--->>>MQTT subscribed to: %s\n\r",AWS_IOT_MQTT_TOPIC_TEST);
00238     }
00239     else
00240     {
00241         WARN("MQTT connect returned %d\n", rc);        
00242     }
00243     if (rc >= 0)
00244         connack_rc = rc;
00245     return rc;
00246 }
00247 
00248 int getConnTimeout(int attemptNumber)
00249 {  // First 10 attempts try within 3 seconds, next 10 attempts retry after every 1 minute
00250    // after 20 attempts, retry every 10 minutes
00251     return (attemptNumber < 10) ? 3 : (attemptNumber < 20) ? 60 : 600;
00252 }
00253 
00254 void attemptConnect(MQTT::Client<MQTTWiFi, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTWiFi* ipstack)
00255 {
00256     while (connect(client, ipstack) != MQTT_CONNECTION_ACCEPTED) 
00257     {    
00258         if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD)
00259         {
00260             printf ("File: %s, Line: %d Error: %d\n\r",__FILE__,__LINE__, connack_rc);        
00261             return; // don't reattempt to connect if credentials are wrong
00262         } 
00263 
00264         int timeout = getConnTimeout(++retryAttempt);
00265         WARN("Retry attempt number %d waiting %d\n\r", retryAttempt, timeout);
00266         
00267         // if ipstack and client were on the heap we could deconstruct and goto a label where they are constructed
00268         //  or maybe just add the proper members to do this disconnect and call attemptConnect(...)        
00269         // this works - reset the system when the retry count gets to a threshold
00270         if (retryAttempt == 2)
00271         {
00272             ipstack->getWiFi().reset_chip();
00273             NVIC_SystemReset();
00274         }
00275         else
00276             wait(timeout);
00277     }
00278 }
00279 
00280 int publish(MQTT::Client<MQTTWiFi, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTWiFi* ipstack)
00281 {
00282     MQTT::Message message;
00283     char* pubTopic = AWS_IOT_MQTT_TOPIC_SHADOW;
00284             
00285     char buf[MQTT_MAX_PAYLOAD_SIZE];
00286     float temp, press, hum;
00287     int32_t magnet[3];
00288     int32_t gyro[3];
00289     int32_t accel[3];
00290 
00291     temp_sensor1->GetTemperature(&temp);
00292     pressure_sensor->GetPressure(&press);
00293     humidity_sensor->GetHumidity(&hum);
00294     magnetic_sensor->Get_M_Axes(magnet);
00295     gyro_sensor->Get_G_Axes(gyro);
00296     accel_sensor->Get_X_Axes(accel);
00297     
00298     if (!myButtonPressed)
00299     {
00300         butled = 1;
00301         sprintf(buf, "{\"state\": {\"reported\": {\"temperature\": %f, \"humidity\": %f, \"pressure\": %f, \"accelerometer\": [%f, %f, %f], \"gyroscope\": [%f, %f, %f], \"magnetometer\": [%f, %f, %f]}}}",
00302                 temp, hum, press, accel[0]/1000.0, accel[1]/1000.0, accel[2]/1000.0, gyro[0]/1000.0, gyro[1]/1000.0, gyro[2]/1000.0, magnet[0]/10.0, magnet[1]/10.0, magnet[2]/10.0);
00303     }
00304     else
00305     {
00306         myButtonPressed = false; // reset state
00307         butled = 0;
00308 
00309         sprintf(buf, "{\"temperature\": %f, \"humidity\": %f, \"pressure\": %f, \"accelerometer\": [%f, %f, %f], \"gyroscope\": [%f, %f, %f], \"magnetometer\": [%f, %f, %f], \"marker\": true}",
00310                         temp, hum, press, accel[0]/1000.0, accel[1]/1000.0, accel[2]/1000.0, gyro[0]/1000.0, gyro[1]/1000.0, gyro[2]/1000.0, magnet[0]/10.0, magnet[1]/10.0, magnet[2]/10.0);
00311         pubTopic = AWS_IOT_MQTT_TOPIC_DATA;
00312     }
00313 
00314     message.qos = MQTT::QOS0;
00315     message.retained = false;
00316     message.dup = false;
00317     message.payload = (void*)buf;
00318     message.payloadlen = strlen(buf);
00319     
00320     printf("Length - %d, Publishing %s\n\r", strlen(buf), buf);
00321 
00322     return client->publish(pubTopic, message);
00323 } 
00324 
00325 void pressed()
00326 {
00327     myButtonPressed = true;
00328 }
00329 
00330 int main()
00331 {
00332     const char * ssid = SSID; // Network must be visible otherwise it can't connect
00333     const char * seckey = PASSW;
00334 
00335     pc.baud(115200);
00336 
00337     SpwfSAInterface spwf(D8, D2, true);
00338     
00339     myled=0;
00340     DevI2C *i2c = new DevI2C(I2C_SDA, I2C_SCL);
00341     i2c->frequency(400000);    
00342     
00343     mybutton.fall(&pressed);
00344 
00345     X_NUCLEO_IKS01A1 *mems_expansion_board = X_NUCLEO_IKS01A1::Instance(i2c);   
00346     pressure_sensor = mems_expansion_board->pt_sensor;
00347     temp_sensor1 =    mems_expansion_board->ht_sensor;
00348     humidity_sensor = mems_expansion_board->ht_sensor;
00349     magnetic_sensor = mems_expansion_board->magnetometer;
00350     gyro_sensor     = mems_expansion_board->GetGyroscope();
00351     accel_sensor    = mems_expansion_board->GetAccelerometer();
00352     
00353     // Due to bug in mbed this workaround is needed to avoid Nucleo hang up when lsm6ds3 is absent
00354     if (mems_expansion_board->gyro_lsm6ds3 == NULL)
00355     {    
00356         NVIC_DisableIRQ(EXTI4_IRQn);
00357         NVIC_ClearPendingIRQ(EXTI4_IRQn);
00358     }
00359     
00360     pc.printf("\r\nX-NUCLEO-IDW01M1 mbed Application\r\n");     
00361     pc.printf("\r\nconnecting to AP\r\n");            
00362 
00363     MQTTWiFi ipstack(spwf, ssid, seckey, NSAPI_SECURITY_WPA2);
00364 
00365     LOG("Connected to WiFI.\r\n");
00366     
00367     spwf.set_debug(false);
00368 
00369     MQTT::Client<MQTTWiFi, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack, 5000);
00370 
00371     attemptConnect(&client, &ipstack);
00372 
00373     if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD)
00374     {
00375       while (true)
00376       wait(1.0); // Permanent failures - don't retry
00377     }
00378 
00379     myled=1;
00380 
00381     int count = 0;
00382 
00383     while (true)
00384     {
00385         if (++count == 1)
00386         {
00387             myled = 0;
00388             // Publish a message every second
00389             if (publish(&client, &ipstack) != 0)
00390             {
00391                 myled=0;
00392                 ipstack.getWiFi().reset_chip();
00393                 NVIC_SystemReset();
00394                 attemptConnect(&client, &ipstack);   // if we have lost the connection
00395             }
00396             else myled=1;
00397 
00398             count = 0;
00399         }
00400 
00401         client.yield(1000);  // allow the MQTT client to receive messages
00402     }
00403 }