Add authorization check and messages
Dependencies: C12832 EthernetInterface LM75B MMA7660 MQTT mbed-rtos mbed
Fork of IBMIoTClientEthernetExample-MACfix-DebugFix by
main.cpp
00001 /******************************************************************************* 00002 * Copyright (c) 2014, 2015 IBM Corp. 00003 * 00004 * All rights reserved. This program and the accompanying materials 00005 * are made available under the terms of the Eclipse Public License v1.0 00006 * and Eclipse Distribution License v1.0 which accompany this distribution. 00007 * 00008 * The Eclipse Public License is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * and the Eclipse Distribution License is available at 00011 * http://www.eclipse.org/org/documents/edl-v10.php. 00012 * 00013 * Contributors: 00014 * Sam Danbury - initial implementation 00015 * Ian Craggs - refactoring to remove STL and other changes 00016 * Sam Grove - added check for Ethernet cable. 00017 * Chris Styles - Added additional menu screen for software revision 00018 * James Sutton - Mac fix and extra debug 00019 * Ian Craggs - add not authorized messages 00020 * 00021 * To do : 00022 * Add magnetometer sensor output to IoT data stream 00023 * 00024 *******************************************************************************/ 00025 00026 #include "LM75B.h" 00027 #include "MMA7660.h" 00028 #include "MQTTClient.h" 00029 #include "MQTTEthernet.h" 00030 #include "C12832.h" 00031 #include "Arial12x12.h" 00032 #include "rtos.h" 00033 00034 // Update this to the next number *before* a commit 00035 #define __APP_SW_REVISION__ "12" 00036 00037 // Configuration values needed to connect to IBM IoT Cloud 00038 #define ORG "quickstart" // For a registered connection, replace with your org 00039 #define ID "" // For a registered connection, replace with your id 00040 #define AUTH_TOKEN "" // For a registered connection, replace with your auth-token 00041 #define TYPE DEFAULT_TYPE_NAME // For a registered connection, replace with your type 00042 00043 #define MQTT_PORT 1883 00044 #define MQTT_TLS_PORT 8883 00045 #define IBM_IOT_PORT MQTT_PORT 00046 00047 #define MQTT_MAX_PACKET_SIZE 250 00048 00049 #if defined(TARGET_UBLOX_C027) 00050 #warning "Compiling for mbed C027" 00051 #include "C027.h" 00052 #elif defined(TARGET_LPC1768) 00053 #warning "Compiling for mbed LPC1768" 00054 #include "LPC1768.h" 00055 #elif defined(TARGET_K64F) 00056 #warning "Compiling for mbed K64F" 00057 #include "K64F.h" 00058 #endif 00059 00060 00061 bool quickstartMode = true; 00062 char org[11] = ORG; 00063 char type[30] = TYPE; 00064 char id[30] = ID; // mac without colons 00065 char auth_token[30] = AUTH_TOKEN; // Auth_token is only used in non-quickstart mode 00066 00067 bool connected = false; 00068 bool mqttConnecting = false; 00069 bool netConnected = false; 00070 bool netConnecting = false; 00071 bool ethernetInitialising = true; 00072 int connack_rc = 0; // MQTT connack return code 00073 int retryAttempt = 0; 00074 int menuItem = 0; 00075 00076 char* joystickPos = "CENTRE"; 00077 int blink_interval = 0; 00078 00079 char* ip_addr = ""; 00080 char* gateway_addr = ""; 00081 char* host_addr = ""; 00082 int connectTimeout = 1000; 00083 00084 // If we wanted to manually set the MAC address, 00085 // this is how to do it. In this example, we take 00086 // the original Mbed Set MAC address and combine it 00087 // with a prefix of our choosing. 00088 /* 00089 extern "C" void $Super$$mbed_mac_address(char *s); 00090 extern "C" void $Sub$$mbed_mac_address(char *s) 00091 { 00092 char originalMAC[6] = ""; 00093 $Super$$mbed_mac_address(originalMAC); 00094 00095 char mac[6]; 00096 mac[0] = 0x00; 00097 mac[1] = 0x08; 00098 mac[2] = 0xdc; 00099 mac[3] = originalMAC[3]; 00100 mac[4] = originalMAC[4]; 00101 mac[5] = originalMAC[5]; 00102 memcpy(s, mac, 6); 00103 } 00104 */ 00105 00106 00107 void off() 00108 { 00109 r = g = b = 1.0; // 1 is off, 0 is full brightness 00110 } 00111 00112 void red() 00113 { 00114 r = 0.7; g = 1.0; b = 1.0; // 1 is off, 0 is full brightness 00115 } 00116 00117 void yellow() 00118 { 00119 r = 0.7; g = 0.7; b = 1.0; // 1 is off, 0 is full brightness 00120 } 00121 00122 void green() 00123 { 00124 r = 1.0; g = 0.7; b = 1.0; // 1 is off, 0 is full brightness 00125 } 00126 00127 00128 void flashing_yellow(void const *args) 00129 { 00130 bool on = false; 00131 while (!connected && connack_rc != MQTT_NOT_AUTHORIZED && connack_rc != MQTT_BAD_USERNAME_OR_PASSWORD) // flashing yellow only while connecting 00132 { 00133 on = !on; 00134 if (on) 00135 yellow(); 00136 else 00137 off(); 00138 wait(0.5); 00139 } 00140 } 00141 00142 00143 void flashing_red(void const *args) // to be used when the connection is lost 00144 { 00145 bool on = false; 00146 while (!connected) 00147 { 00148 on = !on; 00149 if (on) 00150 red(); 00151 else 00152 off(); 00153 wait(2.0); 00154 } 00155 } 00156 00157 00158 void printMenu(int menuItem) 00159 { 00160 lcd.cls(); 00161 lcd.locate(0,0); 00162 switch (menuItem) 00163 { 00164 case 0: 00165 lcd.printf("IBM IoT Cloud"); 00166 lcd.locate(0,16); 00167 lcd.printf("Scroll with joystick"); 00168 break; 00169 case 1: 00170 lcd.printf("Go to:"); 00171 lcd.locate(0,16); 00172 lcd.printf("http://ibm.biz/iotqstart"); 00173 break; 00174 case 2: 00175 lcd.printf("Device Identity:"); 00176 lcd.locate(0,16); 00177 lcd.printf("%s", id); 00178 break; 00179 case 3: 00180 lcd.printf("MQTT Status:"); 00181 lcd.locate(0,16); 00182 if (mqttConnecting) 00183 lcd.printf("Connecting... %d/5", retryAttempt); 00184 else 00185 { 00186 if (connected) 00187 lcd.printf("Connected"); 00188 else 00189 { 00190 switch (connack_rc) 00191 { 00192 case MQTT_CLIENTID_REJECTED: 00193 lcd.printf("Clientid rejected"); 00194 break; 00195 case MQTT_BAD_USERNAME_OR_PASSWORD: 00196 lcd.printf("Invalid username or password"); 00197 break; 00198 case MQTT_NOT_AUTHORIZED: 00199 lcd.printf("Not authorized"); 00200 break; 00201 default: 00202 lcd.printf("Disconnected"); 00203 } 00204 } 00205 } 00206 break; 00207 case 4: 00208 lcd.printf("Ethernet State:"); 00209 lcd.locate(0,16); 00210 lcd.printf(ethernetInitialising ? "Initialising..." : "Initialised"); 00211 break; 00212 case 5: 00213 lcd.printf("Socket State:"); 00214 lcd.locate(0,16); 00215 if (netConnecting) 00216 lcd.printf("Connecting... %d/5", retryAttempt); 00217 else 00218 lcd.printf(netConnected ? "Connected" : "Disconnected"); 00219 break; 00220 case 6: 00221 lcd.printf("IP Address:"); 00222 lcd.locate(0,16); 00223 lcd.printf("%s", ip_addr); 00224 break; 00225 case 7: 00226 lcd.printf("Gateway:"); 00227 lcd.locate(0,16); 00228 lcd.printf("%s", gateway_addr); 00229 break; 00230 case 8: 00231 lcd.printf("App version:"); 00232 lcd.locate(0,16); 00233 lcd.printf("%s", __APP_SW_REVISION__); 00234 break; 00235 case 9: 00236 lcd.printf("Current Timeout:"); 00237 lcd.locate(0,16); 00238 lcd.printf("%d ms", connectTimeout); 00239 break; 00240 } 00241 } 00242 00243 00244 void setMenu() 00245 { 00246 00247 if (Down) 00248 { 00249 joystickPos = "DOWN"; 00250 if (menuItem >= 0 && menuItem < 9) 00251 printMenu(++menuItem); 00252 } 00253 else if (Left) 00254 joystickPos = "LEFT"; 00255 else if (Click) 00256 joystickPos = "CLICK"; 00257 else if (Up) 00258 { 00259 joystickPos = "UP"; 00260 if (menuItem <= 9 && menuItem > 0) 00261 printMenu(--menuItem); 00262 } 00263 else if (Right) 00264 joystickPos = "RIGHT"; 00265 else 00266 joystickPos = "CENTRE"; 00267 } 00268 00269 void menu_loop(void const *args) 00270 { 00271 int count = 0; 00272 while(true) 00273 { 00274 setMenu(); 00275 if (++count % 10 == 0) 00276 printMenu(menuItem); 00277 Thread::wait(100); 00278 } 00279 } 00280 00281 00282 /** 00283 * Display a message on the LCD screen prefixed with IBM IoT Cloud 00284 */ 00285 void displayMessage(char* message) 00286 { 00287 lcd.cls(); 00288 lcd.locate(0,0); 00289 lcd.printf("IBM IoT Cloud"); 00290 lcd.locate(0,16); 00291 lcd.printf(message); 00292 } 00293 00294 00295 int connect(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack) 00296 { 00297 const char* iot_ibm = ".messaging.internetofthings.ibmcloud.com"; 00298 00299 char hostname[strlen(org) + strlen(iot_ibm) + 1]; 00300 sprintf(hostname, "%s%s", org, iot_ibm); 00301 EthernetInterface& eth = ipstack->getEth(); 00302 ip_addr = eth.getIPAddress(); 00303 gateway_addr = eth.getGateway(); 00304 00305 // Construct clientId - d:org:type:id 00306 char clientId[strlen(org) + strlen(type) + strlen(id) + 5]; 00307 sprintf(clientId, "d:%s:%s:%s", org, type, id); 00308 00309 // Network debug statements 00310 LOG("=====================================\n"); 00311 LOG("Connecting Ethernet.\n"); 00312 LOG("IP ADDRESS: %s\n", eth.getIPAddress()); 00313 LOG("MAC ADDRESS: %s\n", eth.getMACAddress()); 00314 LOG("Gateway: %s\n", eth.getGateway()); 00315 LOG("Network Mask: %s\n", eth.getNetworkMask()); 00316 LOG("Server Hostname: %s\n", hostname); 00317 LOG("Client ID: %s\n", clientId); 00318 LOG("=====================================\n"); 00319 00320 netConnecting = true; 00321 int rc = ipstack->connect(hostname, IBM_IOT_PORT, connectTimeout); 00322 if (rc != 0) 00323 { 00324 WARN("IP Stack returned: %d\n", rc); 00325 return rc; 00326 } 00327 netConnected = true; 00328 netConnecting = false; 00329 00330 // MQTT Connect 00331 mqttConnecting = true; 00332 MQTTPacket_connectData data = MQTTPacket_connectData_initializer; 00333 data.MQTTVersion = 3; 00334 data.clientID.cstring = clientId; 00335 00336 if (!quickstartMode) 00337 { 00338 data.username.cstring = "use-token-auth"; 00339 data.password.cstring = auth_token; 00340 } 00341 00342 if ((rc = client->connect(data)) == 0) 00343 { 00344 connected = true; 00345 green(); 00346 displayMessage("Connected"); 00347 wait(1); 00348 displayMessage("Scroll with joystick"); 00349 } 00350 else 00351 WARN("MQTT connect returned %d\n", rc); 00352 if (rc >= 0) 00353 connack_rc = rc; 00354 mqttConnecting = false; 00355 return rc; 00356 } 00357 00358 00359 int getConnTimeout(int attemptNumber) 00360 { // First 10 attempts try within 3 seconds, next 10 attempts retry after every 1 minute 00361 // after 20 attempts, retry every 10 minutes 00362 return (attemptNumber < 10) ? 3 : (attemptNumber < 20) ? 60 : 600; 00363 } 00364 00365 00366 void attemptConnect(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack) 00367 { 00368 connected = false; 00369 00370 // make sure a cable is connected before starting to connect 00371 while (!linkStatus()) 00372 { 00373 wait(1.0f); 00374 WARN("Ethernet link not present. Check cable connection\n"); 00375 } 00376 00377 while (connect(client, ipstack) != MQTT_CONNECTION_ACCEPTED) 00378 { 00379 if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD) 00380 return; // don't reattempt to connect if credentials are wrong 00381 00382 Thread red_thread(flashing_red); 00383 00384 int timeout = getConnTimeout(++retryAttempt); 00385 WARN("Retry attempt number %d waiting %d\n", retryAttempt, timeout); 00386 00387 // if ipstack and client were on the heap we could deconstruct and goto a label where they are constructed 00388 // or maybe just add the proper members to do this disconnect and call attemptConnect(...) 00389 00390 // this works - reset the system when the retry count gets to a threshold 00391 if (retryAttempt == 5) 00392 NVIC_SystemReset(); 00393 else 00394 wait(timeout); 00395 } 00396 } 00397 00398 00399 int publish(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack) 00400 { 00401 MQTT::Message message; 00402 char* pubTopic = "iot-2/evt/status/fmt/json"; 00403 00404 char buf[250]; 00405 sprintf(buf, 00406 "{\"d\":{\"myName\":\"IoT mbed\",\"accelX\":%0.4f,\"accelY\":%0.4f,\"accelZ\":%0.4f,\"temp\":%0.4f,\"joystick\":\"%s\",\"potentiometer1\":%0.4f,\"potentiometer2\":%0.4f}}", 00407 MMA.x(), MMA.y(), MMA.z(), sensor.temp(), joystickPos, ain1.read(), ain2.read()); 00408 message.qos = MQTT::QOS0; 00409 message.retained = false; 00410 message.dup = false; 00411 message.payload = (void*)buf; 00412 message.payloadlen = strlen(buf); 00413 00414 LOG("Publishing %s\n", buf); 00415 return client->publish(pubTopic, message); 00416 } 00417 00418 00419 char* getMac(EthernetInterface& eth, char* buf, int buflen) // Obtain MAC address 00420 { 00421 strncpy(buf, eth.getMACAddress(), buflen); 00422 00423 char* pos; // Remove colons from mac address 00424 while ((pos = strchr(buf, ':')) != NULL) 00425 memmove(pos, pos + 1, strlen(pos) + 1); 00426 return buf; 00427 } 00428 00429 00430 void messageArrived(MQTT::MessageData& md) 00431 { 00432 MQTT::Message &message = md.message; 00433 char topic[md.topicName.lenstring.len + 1]; 00434 00435 sprintf(topic, "%.*s", md.topicName.lenstring.len, md.topicName.lenstring.data); 00436 00437 LOG("Message arrived on topic %s: %.*s\n", topic, message.payloadlen, message.payload); 00438 00439 // Command topic: iot-2/cmd/blink/fmt/json - cmd is the string between cmd/ and /fmt/ 00440 char* start = strstr(topic, "/cmd/") + 5; 00441 int len = strstr(topic, "/fmt/") - start; 00442 00443 if (memcmp(start, "blink", len) == 0) 00444 { 00445 char payload[message.payloadlen + 1]; 00446 sprintf(payload, "%.*s", message.payloadlen, (char*)message.payload); 00447 00448 char* pos = strchr(payload, '}'); 00449 if (pos != NULL) 00450 { 00451 *pos = '\0'; 00452 if ((pos = strchr(payload, ':')) != NULL) 00453 { 00454 int blink_rate = atoi(pos + 1); 00455 blink_interval = (blink_rate <= 0) ? 0 : (blink_rate > 50 ? 1 : 50/blink_rate); 00456 } 00457 } 00458 } 00459 else 00460 WARN("Unsupported command: %.*s\n", len, start); 00461 } 00462 00463 00464 int main() 00465 { 00466 quickstartMode = (strcmp(org, "quickstart") == 0); 00467 00468 lcd.set_font((unsigned char*) Arial12x12); // Set a nice font for the LCD screen 00469 00470 led2 = LED2_OFF; // K64F: turn off the main board LED 00471 00472 displayMessage("Connecting"); 00473 Thread yellow_thread(flashing_yellow); 00474 Thread menu_thread(menu_loop); 00475 00476 LOG("***** IBM IoT Client Ethernet Example *****\n"); 00477 MQTTEthernet ipstack; 00478 ethernetInitialising = false; 00479 MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack); 00480 LOG("Ethernet Initialised.\n"); 00481 00482 if (quickstartMode) 00483 getMac(ipstack.getEth(), id, sizeof(id)); 00484 00485 attemptConnect(&client, &ipstack); 00486 00487 if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD) 00488 { 00489 red(); 00490 while (true) 00491 wait(1.0); // Permanent failures - don't retry 00492 } 00493 00494 if (!quickstartMode) 00495 { 00496 int rc = 0; 00497 if ((rc = client.subscribe("iot-2/cmd/+/fmt/json", MQTT::QOS1, messageArrived)) != 0) 00498 WARN("rc from MQTT subscribe is %d\n", rc); 00499 } 00500 00501 blink_interval = 0; 00502 int count = 0; 00503 while (true) 00504 { 00505 if (++count == 100) 00506 { // Publish a message every second 00507 if (publish(&client, &ipstack) != 0) 00508 attemptConnect(&client, &ipstack); // if we have lost the connection 00509 count = 0; 00510 } 00511 00512 if (blink_interval == 0) 00513 led2 = LED2_OFF; 00514 else if (count % blink_interval == 0) 00515 led2 = !led2; 00516 client.yield(10); // allow the MQTT client to receive messages 00517 } 00518 }
Generated on Wed Jul 13 2022 16:38:45 by 1.7.2