Thursday, April 14, 2016

#(23) Amazon's Internet of Things Play - continued 

Digging into the SDK



Starting with the end, the summary is their Linux C SDK is pretty darned good. Stuff works out of the box. There. The End.  


But - again - it's not all peaches and cream. I'm working on modifying my Things now to use their SDK.  And that means work on predominantly two fronts: switching to JSON for my MQTT packets and pulling out Mosquitto (my MQTT implementation) and plugging in theirs.


I guess a relevant question is - do I need to do both? Yes and no. I can certainly switch to JSON without leveraging their SDK and I'd be willing to get I could be the Mosquitto based MQTT implementation to talk to the AWS IoT MQTT Broker.

But where's the fun in that? 

SDK Step by Step

So, to keep things simple, let's move on to the next-to-the-last chapter and talk about Lessons Learned in playing with their SDK.  We'll be following along in their Developer's Guide in the SDK section.

 
First - do download and build their SDK. Build their samples, run their samples. Convince yourself that your AWS setup is working by running their sample programs successfully. Note that I picked the "mbedtls from ARM" version of their SDK - well, just because I plan on running mostly Raspberry Pis and it looked smaller, neater.


Second - note that when you build and run their SDK samples, three TLS static libraries are created. In gleeful anticpation of linking against them later, I went ahead and moved them into /usr/local/lib:

pconroy@pconroy-VirtualBox:/usr/local/lib$ ls *mbed*
libmbedcrypto.a  libmbedtls.a  libmbedx509.a



Third note that I couldn't step (as in single step debugger) through the samples with gdb and my IDE (Netbeans).  The aws_connect() immediately failed, as did the publish. Looking at their Paho based MQTT source, it's implemented some timers and slow stepping through or even over a call was causing the call to fail.  Just set a breakpoint after any aws_iot_xxx() call and things were working again.

Note that I don't recall ever having this issue with the Mosquitto based implementation of MQTT.  That might be reason enough to switch back to Mosquitto at some point.

Fourth: I went ahead and created an AWS IoT Everything library. I took all of their SDK, dumped it into a Single NetBeans project and created a static library.  This kitchen-sink approach took about an hour, but now I have a simple library to pull into my other projects.

Again - in gleeful anticipation - I've copied the new library into /usr/local/lib and run ldconfig.

Nota Bene: if you're using gcc to compile and link, the link order of the mbed TLS libraries is important.  Link your code with those libraries in this order:
  • mbedtls.a
  • mbedx509.a
  • mbedcrypto.a

You'll get unresolved symbol errors unless you honor the above order.

Let's go to the code!

Time to pull up some code and see if we can connect! I'll start with the initialization and connection code.




And, right off the bat, I'm a bit confused (without RTFMing and without looking at the code) there seems to be some amalgamation of AWS-MQTT-ishness and Paho MQTTishness that's a bit hard to decipher. At least for me coming from experience with Mosquitto.




There are two structures that look a bit similar to me, at a glance:
MQTTClient_t        mqttClient;
MQTTConnectParams   connectionParams;

There's some overlap between the two, in terms of the callback. For now, we'll ignore the first and concentrate on the second call.

Here's what I used to successfully connect to my AWS IoT instance:

connectionParams.KeepAliveInterval_sec = 10;
connectionParams.MQTTVersion = MQTT_3_1_1;
connectionParams.disconnectHandler = AWSIoTMQTT_DisconnectHandler;
connectionParams.enableAutoReconnect = (uint8_t) FALSE;
connectionParams.isCleansession = (_Bool) TRUE;
connectionParams.isSSLHostnameVerify = (_Bool) TRUE;
connectionParams.isWillMsgPresent = (_Bool) FALSE;
connectionParams.mqttCommandTimeout_ms = 2000;
connectionParams.pClientID = "WS2308_ClientID";
connectionParams.pDeviceCertLocation = deviceCertFileLocation;     
connectionParams.pDevicePrivateKeyLocation = privateKeyCertFileLocation;
connectionParams.pHostURL = aSystem->mqtt.brokerHost;
connectionParams.pPassword = NULL;
connectionParams.pRootCALocation = rootCertFileLocation;
connectionParams.pUserName = NULL;
connectionParams.port = aSystem->mqtt.portNumber;
connectionParams.tlsHandshakeTimeout_ms = 5000;    

connectionParams.will.isRetained = FALSE;                 
connectionParams.will.pMessage = "LWT Message";
connectionParams.will.pTopicName = "LWT_Topic";
connectionParams.will.qos = 0;


Let's run through the highlighted ones and make comments:
  • Keep Alive Interval set to 10 - this was pulled from the AWS Sample Code
  • SSL Host Name Verify - must be set to True to connect
  • the MQTT Command Timeout of 2000 was pulled from the sample code
  • the MQTT Broker Host, pHostURL is the AWS IoT MQTT Address and can be found by issuing the command "$ aws iot describe-endpoint"
  • The port number is 8883 for the default AWS IoT broker
  • the TLS Handshake Timeout of 5000 is also pulled from the sample code

With these settings, and if you don't single step the call, the call succeeds; we can connect to our AWS instance.

rc = aws_iot_mqtt_connect( &connectionParams );
if (rc != NONE_ERROR) {
    Logger_LogError( "Call to 'aws_iot_mqtt_connect()' failed. Error: [%s]\n", 

                     AWSIoTErrorToString( rc ) );
    return;
}


With Mosquitto, you (can) setup the callbacks before you connect. And that's what I prefer to do, I'll need to figure out how and when to set those, which I assume may have something to do with the MQTTClient_t structure.


Callbacks? What Callbacks?

Ah Ha! Here's what's apparently going on.  The MQTTClient_t struct is passed into the "aws_iot_mqtt_init()" function.  According to the API docs:
This function provides a way to pass in an MQTT client implementation to the AWS IoT MQTT wrapper layer. This is done through function pointers to the interface functions.
So those function pointers in MQTTClient_t are not callbacks - they're the implementations.  Oh!  That's a bit different from the Mosquitto parts I've used.

I think I get it - most of the callbacks I implemented in Mosquitto were more out of curiosity than purpose. If the AWS SDK dumps the Connection Acknowledged callback, do I care?  Probably not.

Anyway, we're connected. So we'll keep adding in some AWS calls.

No comments :

Post a Comment