With MKR1000 and Azure IoT Hub, STM32F4 Discovery Board is used to send acceleration and other random telemetry data to Azure IoT Hub.
Things used in this project
Hardware components |
||||||
|
× | 1 | ||||
|
× | 1 | ||||
Software apps and online services |
||||||
|
||||||
|
Story
Overview
.
The original idea of this project involves a WiFi component so that telemetry data will be sent thru internet to a cloud IoT hub. Since the lack of the WiFi part, this project uses the Tx/Rx serial together with MKR1000 to send data to an Azure IoT Hub.
.
Set Up Azure IoT Hub
.
I have set up an IoT hub and an IoT device on the Azure cloud following this quickstart tutorial. Take note of the hub name, device name and their corresponding connection string. These info is needed for the configuration in the code.
The ReadDeviceToCloudMessages.js shows the messages sent to the IoT hub. There is a picture showing a list of telemetry messages below.
.
Set Up MKR1000
.
Set up WiFi for MKR1000 by following the instruction at this link.
Azure IoT Hub library for Arduino is used to allow MKR1000 communicating to Azure IoT hub.
.
Set Up STM32F4 Discovery Board
.
For STM32F4 info, refer here.
Download the required and install the software. They can be found here. Both the gnat-community-2018-20180611-x86_64-windows-bin.exe and gnat-community-2018-20180523-arm-elf-windows64-bin.exe are needed.
Check out video tutorials here.
.
Some Pictures
.
.
.
.
Some Codes
.
The following is the code fragment which gets accelerometer values and sends the X value thru Tx/Rx communication a byte at a time.
Accelerometer.Get_Accelerations (Values);
F := Float (Values.X);
Move(Float'Image (F), Fs);
for C of Fs loop -- arbitrary
Put_Blocking (USART_1, Character'Pos (C));
My_Delay (1000);
end loop;
.
STM32F4 MKR1000
PB7 (Rx) ------> D14 (Tx)
PB6 (Tx) ------> D13(Rx)
Above is the pin configuration between STM32F4 Discovery Board and MKR1000.
.
Future Works
.
- Make use of WiFi component
- Add more sensors
- Builld a dashboard for visualization
- Build using other IoT plaforms
.
Summary
.
This is a very simple setup of a STM32F4 node sending telemetry data to Azure IoT Hub. Different sensor devices like gas and air quality sensors can be add to the setup to make a more practical project.
.
Code
my_usart_polling.adb
ADA
------------------------------------------------------------------------------
-- --
-- Copyright (C) 2015-2017, AdaCore --
-- --
-- --
------------------------------------------------------------------------------
-- The file declares the main procedure for the demonstration.
with Ada.Strings.Fixed; use Ada.Strings.fixed;
with Ada.Real_Time; use Ada.Real_Time;
with HAL; use HAL;
with STM32.GPIO; use STM32.GPIO;
with STM32.USARTs; use STM32.USARTs;
with STM32.Device; use STM32.Device;
with STM32.Board; use STM32.Board;
with LIS3DSH; use LIS3DSH;
procedure My_USART_Polling is
Values : LIS3DSH.Axes_Accelerations;
procedure My_Delay (Milli : Natural);
procedure My_Delay (Milli : Natural) is
begin
delay until Clock + Milliseconds (Milli);
end My_Delay;
TX_Pin : constant GPIO_Point := PB7;
RX_Pin : constant GPIO_Point := PB6;
procedure Initialize_UART_GPIO;
procedure Initialize;
procedure Await_Send_Ready (This : USART) with Inline;
procedure Put_Blocking (This : in out USART; Data : UInt16);
--------------------------
-- Initialize_UART_GPIO --
--------------------------
procedure Initialize_UART_GPIO is
begin
Enable_Clock (USART_1);
Enable_Clock (RX_Pin & TX_Pin);
Configure_IO
(RX_Pin & TX_Pin,
(Mode => Mode_AF,
AF => GPIO_AF_USART1_7,
Resistors => Pull_Up,
AF_Speed => Speed_50MHz,
AF_Output_Type => Push_Pull));
end Initialize_UART_GPIO;
----------------
-- Initialize --
----------------
procedure Initialize is
begin
Initialize_UART_GPIO;
Disable (USART_1);
Set_Baud_Rate (USART_1, 115_200);
Set_Mode (USART_1, Tx_Rx_Mode);
Set_Stop_Bits (USART_1, Stopbits_1);
Set_Word_Length (USART_1, Word_Length_8);
Set_Parity (USART_1, No_Parity);
Set_Flow_Control (USART_1, No_Flow_Control);
Enable (USART_1);
end Initialize;
----------------------
-- Await_Send_Ready --
----------------------
procedure Await_Send_Ready (This : USART) is
begin
loop
exit when Tx_Ready (This);
end loop;
end Await_Send_Ready;
------------------
-- Put_Blocking --
------------------
procedure Put_Blocking (This : in out USART; Data : UInt16) is
begin
Await_Send_Ready (This);
Transmit (This, UInt9 (Data));
end Put_Blocking;
F : Float;
Fs: String (1 .. 12);
begin
Initialize;
Initialize_Accelerometer;
Accelerometer.Configure
(Output_DataRate => Data_Rate_100Hz,
Axes_Enable => XYZ_Enabled,
SPI_Wire => Serial_Interface_4Wire,
Self_Test => Self_Test_Normal,
Full_Scale => Fullscale_2g,
Filter_BW => Filter_800Hz);
Accelerometer.Get_Accelerations (Values);
F := Float (Values.X);
Move(Float'Image (F), Fs);
for C of Fs loop -- arbitrary
Put_Blocking (USART_1, Character'Pos (C));
My_Delay (1000);
end loop;
end My_USART_Polling;
simplesample_http.c
C/C++
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "iot_configs.h"
/* This sample uses the _LL APIs of iothub_client for example purposes.
That does not mean that HTTP only works with the _LL APIs.
Simply changing the using the convenience layer (functions not having _LL)
and removing calls to _DoWork will yield the same results. */
#include "AzureIoTHub.h"
/*String containing Hostname, Device Id & Device Key in the format: */
/* "HostName=<host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>" */
static const char* connectionString = IOT_CONFIG_CONNECTION_STRING;
// Define the Model
BEGIN_NAMESPACE(WeatherStation);
DECLARE_MODEL(ContosoAnemometer,
WITH_DATA(ascii_char_ptr, DeviceId),
WITH_DATA(int, WindSpeed),
WITH_DATA(float, Temperature),
WITH_DATA(float, Humidity),
WITH_DATA(float, AccelerationX),
WITH_ACTION(TurnFanOn),
WITH_ACTION(TurnFanOff),
WITH_ACTION(SetAirResistance, int, Position)
);
END_NAMESPACE(WeatherStation);
static char propText[1024];
EXECUTE_COMMAND_RESULT TurnFanOn(ContosoAnemometer* device)
{
(void)device;
(void)printf("Turning fan on.\r\n");
return EXECUTE_COMMAND_SUCCESS;
}
EXECUTE_COMMAND_RESULT TurnFanOff(ContosoAnemometer* device)
{
(void)device;
(void)printf("Turning fan off.\r\n");
return EXECUTE_COMMAND_SUCCESS;
}
EXECUTE_COMMAND_RESULT SetAirResistance(ContosoAnemometer* device, int Position)
{
(void)device;
(void)printf("Setting Air Resistance Position to %d.\r\n", Position);
return EXECUTE_COMMAND_SUCCESS;
}
void sendCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback)
{
unsigned int messageTrackingId = (unsigned int)(uintptr_t)userContextCallback;
(void)printf("Message Id: %u Received.\r\n", messageTrackingId);
(void)printf("Result Call Back Called! Result is: %s \r\n", ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result));
}
static void sendMessage(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, const unsigned char* buffer, size_t size)
{
static unsigned int messageTrackingId;
IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray(buffer, size);
if (messageHandle == NULL)
{
printf("unable to create a new IoTHubMessage\r\n");
}
else
{
if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle, messageHandle, sendCallback, (void*)(uintptr_t)messageTrackingId) != IOTHUB_CLIENT_OK)
{
printf("failed to hand over the message to IoTHubClient");
}
else
{
printf("IoTHubClient accepted the message for delivery\r\n");
}
IoTHubMessage_Destroy(messageHandle);
}
free((void*)buffer);
messageTrackingId++;
}
/*this function "links" IoTHub to the serialization library*/
static IOTHUBMESSAGE_DISPOSITION_RESULT IoTHubMessage(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback)
{
IOTHUBMESSAGE_DISPOSITION_RESULT result;
const unsigned char* buffer;
size_t size;
if (IoTHubMessage_GetByteArray(message, &buffer, &size) != IOTHUB_MESSAGE_OK)
{
printf("unable to IoTHubMessage_GetByteArray\r\n");
result = IOTHUBMESSAGE_ABANDONED;
}
else
{
/*buffer is not zero terminated*/
char* temp = malloc(size + 1);
if (temp == NULL)
{
printf("failed to malloc\r\n");
result = IOTHUBMESSAGE_ABANDONED;
}
else
{
EXECUTE_COMMAND_RESULT executeCommandResult;
(void)memcpy(temp, buffer, size);
temp[size] = '\0';
executeCommandResult = EXECUTE_COMMAND(userContextCallback, temp);
result =
(executeCommandResult == EXECUTE_COMMAND_ERROR) ? IOTHUBMESSAGE_ABANDONED :
(executeCommandResult == EXECUTE_COMMAND_SUCCESS) ? IOTHUBMESSAGE_ACCEPTED :
IOTHUBMESSAGE_REJECTED;
free(temp);
}
}
return result;
}
void simplesample_http_run(float value)
{
if (platform_init() != 0)
{
printf("Failed to initialize the platform.\r\n");
}
else
{
if (serializer_init(NULL) != SERIALIZER_OK)
{
(void)printf("Failed on serializer_init\r\n");
}
else
{
IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle = IoTHubClient_LL_CreateFromConnectionString(connectionString, HTTP_Protocol);
int avgWindSpeed = 10;
float minTemperature = 20.0;
float minHumidity = 60.0;
srand((unsigned int)time(NULL));
if (iotHubClientHandle == NULL)
{
(void)printf("Failed on IoTHubClient_LL_Create\r\n");
}
else
{
// Because it can poll "after 9 seconds" polls will happen
// effectively at ~10 seconds.
// Note that for scalabilty, the default value of minimumPollingTime
// is 25 minutes. For more information, see:
// https://azure.microsoft.com/documentation/articles/iot-hub-devguide/#messaging
unsigned int minimumPollingTime = 9;
ContosoAnemometer* myWeather;
if (IoTHubClient_LL_SetOption(iotHubClientHandle, "MinimumPollingTime", &minimumPollingTime) != IOTHUB_CLIENT_OK)
{
printf("failure to set option \"MinimumPollingTime\"\r\n");
}
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// For mbed add the certificate information
if (IoTHubClient_LL_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK)
{
(void)printf("failure to set option \"TrustedCerts\"\r\n");
}
#endif // SET_TRUSTED_CERT_IN_SAMPLES
myWeather = CREATE_MODEL_INSTANCE(WeatherStation, ContosoAnemometer);
if (myWeather == NULL)
{
(void)printf("Failed on CREATE_MODEL_INSTANCE\r\n");
}
else
{
if (IoTHubClient_LL_SetMessageCallback(iotHubClientHandle, IoTHubMessage, myWeather) != IOTHUB_CLIENT_OK)
{
printf("unable to IoTHubClient_SetMessageCallback\r\n");
}
else
{
/* wait for commands */
int sendCycle = 15;
int currentCycle = 0;
bool done = false;
while (!done)
{
if(currentCycle >= sendCycle) {
currentCycle = 0;
myWeather->DeviceId = IOT_DEVICE_ID;
myWeather->WindSpeed = avgWindSpeed + (rand() % 4 + 2);
myWeather->Temperature = minTemperature + (rand() % 10);
myWeather->Humidity = minHumidity + (rand() % 20);
myWeather->AccelerationX = value;
{
unsigned char* destination;
size_t destinationSize;
if (SERIALIZE(&destination, &destinationSize, myWeather->DeviceId, myWeather->WindSpeed, myWeather->Temperature, myWeather->Humidity, myWeather->AccelerationX) != CODEFIRST_OK)
{
(void)printf("Failed to serialize\r\n");
}
else
{
IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray(destination, destinationSize);
if (messageHandle == NULL)
{
printf("unable to create a new IoTHubMessage\r\n");
}
else
{
MAP_HANDLE propMap = IoTHubMessage_Properties(messageHandle);
(void)sprintf_s(propText, sizeof(propText), myWeather->Temperature > 28 ? "true" : "false");
if (Map_AddOrUpdate(propMap, "temperatureAlert", propText) != MAP_OK)
{
printf("ERROR: Map_AddOrUpdate Failed!\r\n");
}
if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle, messageHandle, sendCallback, (void*)1) != IOTHUB_CLIENT_OK)
{
printf("failed to hand over the message to IoTHubClient");
}
else
{
printf("cycle=%d, windspeed=%d, temperature=%f, humidity=%f, accelerationX=%f\r\n", currentCycle, myWeather->WindSpeed, myWeather->Temperature, myWeather->Humidity, myWeather->AccelerationX);
printf("IoTHubClient accepted the message for delivery\r\n");
done = true;
}
IoTHubMessage_Destroy(messageHandle);
}
free(destination);
ThreadAPI_Sleep(10000);
}
}
}
IoTHubClient_LL_DoWork(iotHubClientHandle);
ThreadAPI_Sleep(100);
currentCycle++;
}
}
DESTROY_MODEL_INSTANCE(myWeather);
}
IoTHubClient_LL_Destroy(iotHubClientHandle);
}
serializer_deinit();
}
platform_deinit();
}
}
void sample_run(float value)
{
simplesample_http_run(value);
}
ReadDeviceToCloudMessages.js
JavaScript
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
'use strict';
//
// Using the Azure CLI:
// az iot hub show-connection-string --hub-name {YourIoTHubName} --output table
var connectionString = 'iot hub connection string';
// The sample connects to an IoT hub's Event Hubs-compatible endpoint
// to read messages sent from a device.
var { EventHubClient, EventPosition } = require('@azure/event-hubs');
var printError = function (err) {
console.log(err.message);
};
// Display the message content - telemetry and properties.
// - Telemetry is sent in the message body
// - The device can add arbitrary application properties to the message
// - IoT Hub adds system properties, such as Device Id, to the message.
var printMessage = function (message) {
console.log('Telemetry received: ');
console.log(JSON.stringify(message.body));
console.log('Application properties (set by device): ')
console.log(JSON.stringify(message.applicationProperties));
console.log('System properties (set by IoT Hub): ')
console.log(JSON.stringify(message.annotations));
console.log('');
};
// Connect to the partitions on the IoT Hub's Event Hubs-compatible endpoint.
// This example only reads messages sent after this application started.
var ehClient;
EventHubClient.createFromIotHubConnectionString(connectionString).then(function (client) {
console.log("Successully created the EventHub Client from iothub connection string.");
ehClient = client;
return ehClient.getPartitionIds();
}).then(function (ids) {
console.log("The partition ids are: ", ids);
return ids.map(function (id) {
return ehClient.receive(id, printMessage, printError, { eventPosition: EventPosition.fromEnqueuedTime(Date.now()) });
});
}).catch(printError);
iot_configs.h
C/C++
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef IOT_CONFIGS_H
#define IOT_CONFIGS_H
/**
* WiFi setup
*/
#define IOT_CONFIG_WIFI_SSID "wifi ssid"
#define IOT_CONFIG_WIFI_PASSWORD "wifi password"
/**
* Find under Microsoft Azure IoT Suite -> DEVICES -> <your device> -> Device Details and Authentication Keys
* String containing Hostname, Device Id & Device Key in the format:
* "HostName=<host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>"
*/
#define IOT_CONFIG_CONNECTION_STRING "iot device connection string"
#define IOT_DEVICE_ID "AdaDevice01"
/**
* Choose the transport protocol
*/
// #define IOT_CONFIG_MQTT // uncomment this line for MQTT
#define IOT_CONFIG_HTTP // uncomment this line for HTTP
#endif /* IOT_CONFIGS_H */
sample.h
C/C++
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SAMPLE_H
#define SAMPLE_H
#ifdef __cplusplus
extern "C" {
#endif
void sample_run(float);
#ifdef __cplusplus
}
#endif
#endif /* SAMPLE_H */
simplesample_http.h
C/C++
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SIMPLESAMPLEHTTP_H
#define SIMPLESAMPLEHTTP_H
#ifdef __cplusplus
extern "C" {
#endif
void simplesample_http_run(float);
#ifdef __cplusplus
}
#endif
#endif /* SIMPLESAMPLEHTTP_H */
simplesample_http_sonyhub.c
C/C++
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// Please use an Arduino IDE 1.6.8 or greater
// You must set the device id, device key, IoT Hub name and IotHub suffix in
// iot_configs.h
#include "iot_configs.h"
#include <AzureIoTHub.h>
#if defined(IOT_CONFIG_MQTT)
#include <AzureIoTProtocol_MQTT.h>
#elif defined(IOT_CONFIG_HTTP)
#include <AzureIoTProtocol_HTTP.h>
#endif
#include "sample.h"
#include "samd/sample_init.h"
static char ssid[] = IOT_CONFIG_WIFI_SSID;
static char pass[] = IOT_CONFIG_WIFI_PASSWORD;
int i;
byte buffer[12];
float getAccelerationX() {
while (Serial1.available() > 0) {
int inByte = Serial1.read();
if (inByte == 32 || inByte == 45) { // space or - sign
buffer[++i] = 0;
float value = String((char *)buffer).toFloat();
Serial.println(value);
i = 0;
buffer[i] = inByte;
return value;
} else {
buffer[++i] = inByte;
}
}
}
void setup() {
sample_init(ssid, pass); // must run this line
Serial1.begin(115200);
}
// Azure IoT samples contain their own loops, so only run them once
static bool done = false;
void loop() {
Serial.println("loop");
if (!done)
{
float valueX = getAccelerationX();
Serial.println(valueX);
// Run the sample
// You must set the device id, device key, IoT Hub name and IotHub suffix in
// iot_configs.h
if (valueX != 0.00) sample_run(valueX);
valueX = 0.00;
delay(5000);
}
else
{
delay(500);
Serial.println("delay 500");
}
}
Source : IoT Node with STM32F4 Discovery, MKR1000 and Azure IoT Hub