This is the individual project for the IoT course of Sapienza University of Rome. It is both a SmartAlarm and a SmartLock that can be used to improve security.
I decided to develop this project inspired by "The Amazing Spider-Man" film where Peter, which is the main character, has a SmartLock, built by itself installed on his door, unfortunately we can't activate it using webs but we can do it using a WebApp :)
The following are analyzed in separate chapters in a more detailed way: the IoT device architecture, the cloud level, and the RIOT-OS code for the IoT device.
DeviceIn the following picture we can see all the sensor attached to the board:
Board : Nucleo-f401re
The Nucleo F401RE is a development board based on the STM32F401RE microcontroller. The STM32F401RE is a high-performance microcontroller from STMicroelectronics that is part of the STM32 family of 32-bit Arm Cortex-M4 microcontrollers. The board includes an ARM Cortex-M4 core microcontroller running at up to 84MHz with 512KB of flash memory and 96KB of RAM. It also includes a variety of peripherals, including multiple timers, communication interfaces (UART, SPI, I2C, CAN), and analog-to-digital converters.
Ultrasonic Sensor : HC-SR04
HC-SR04 is an ultrasonic ranging sensor that provides 2 cm to 400 cm non-contact measurement function. The ranging accuracy can reach 3mm, and the effectual angle is less than 15°. It can be powered from a 5V power supply.
Specifications:
- Working Voltage: DC 5V
- Working Current: 15mA
- Working Frequency: 40Hz
- Max Range: 4m
- Min Range: 2cm
- Measuring Angle: 15 degrees
- Trigger Input Signal: 10µS TTL pulse
- Echo Output Signal: Input TTL lever signal and the range in proportion
- Dimensions: 45 * 20 * 15mm
Buzzer
The buzzer is powered by 6V DC and has the following pin configuration:Positive: Identified by (+) symbol or longer terminal lead. Can be powered by 6V DC.Negative: Identified by short terminal lead. Typically connected to the ground of the circuit.Features and Specifications:Rated Voltage: 6V DCOperating Voltage: 4-8V DCRated Current: <30mASound Type: Continuous BeepResonant Frequency: ~2300 HzSmall and neat sealed packageBreadboard and Perf board friendly
Medium Vibration Sensor
The vibration sensor is used to detect if someone is trying to force the door, in an unintended way, a medium one is used beacuse after some experiments it was the one that acts better, providing more accurate results.
Servo Motor S51
The servo motor is used to open or close the lock installed on the door, based on the value returned by the vibration and ultrasonic sensor, or provided by the user using the web app. (the datasheet of the servo motor can be found here)
Cloud LayerAll the Cloud stuff are managed by AwS, beceause it offers a System called AwS IoT Core,
that provides all the services that are needed in an easy way, starting by the MQTT broker until the data visualization on the web, through another service called AwS Amplify
.
Above we can see a picture of the entire architecture and all the features used.
To set up the project on AwS, follow these steps:
AWS IoT Core Setup:
Create a Thing :
- Access the AWS IoT Core console.
- Define a new Thing to represent your device.
Define IoT Policies:
- Create an IoT policy specifying permissions required by your Thing.
- Grant necessary privileges like publish and subscribe permissions for IoT operations.
IoT Core Rules:
- Configure an IoT Core Rule to process incoming messages from your device.
- Define actions (e.g., invoking Lambda functions) based on subscribed MQTT topics
Develop and Configure Lambda Functions:
Create two Lambda functions:
publish_to_iotcore
: Handles publishing messages to AWS IoT Core.read_data
: Processes incoming messages and stores data in DynamoDB.
IAM Role Configuration:
Configure Lambda execution roles:
- Attach
AWSIoTFullAccess
policy forpublish_to_iotcore
to enable publishing to IoT Core. - Modify the role's policy for
read_data
to grant DynamoDB write permissions (e.g.,dynamodb:PutItem
).
Create a DynamoDB Table:
- Define a DynamoDB table to store data received from the IoT device.
Deploy Web Application with AWS Amplify:
- Utilize AWS Amplify to host your web application.
- Upload and configure contents of the
webApp
folder for deployment on Amplify.
Now we will discuss all the logic behind the code in detail.
The code starts by including essential standard C libraries (stdio.h
, stdlib.h
) for input/output operations and memory management. Additionally, it leverages RIOT OS-specific libraries (periph/gpio.h
, xtimer.h
, thread.h
, periph/adc.h
) to interact with hardware peripherals, manage timing, handle threading, and interface with analog-to-digital converters.
#include <stdio.h>
#include <stdlib.h>
#include "periph/gpio.h"
#include "xtimer.h"
#include "thread.h"
#include "periph/adc.h"
Networking and MQTT ConfigurationFor networking and communication, the code utilizes RIOT OS's EMCUTE library, facilitating MQTT-SN protocol support. It defines macros and constants for MQTT topics, quality of service (QoS) levels, device IP address, and default network interface.
#include "net/emcute.h"
#include "net/ipv6/addr.h"
#define EMCUTE_PRIO (THREAD_PRIORITY_MAIN - 1)
#define MQTT_TOPIC_INT "topic_board"
#define MQTT_TOPIC_EXT "topic_data"
#define MQTT_QoS (EMCUTE_QOS_0)
#define DEVICE_IP_ADDRESS ("fec0:affe::99")
#define DEFAULT_INTERFACE ("4")
Hardware Pin DefinitionsThe code initializes GPIO pins to interface with external hardware components such as an ultrasonic sensor (trigger and echo pins), a buzzer, and an LED for status indication.
gpio_t trigger_pin = GPIO_PIN(PORT_A, 9); // D8 -> trigger
gpio_t echo_pin = GPIO_PIN(PORT_A, 8); // D7 -> echo
gpio_t buzzer_pin = GPIO_PIN(PORT_C, 7); // D9 -> Buzzer
gpio_t led_pin = GPIO_PIN(PORT_B, 10); // D6 -> Led
Initialization and CallbacksInitialization functions are defined to set up GPIO pins for sensor input (ultrasonic sensor) and output (LED, buzzer). Additionally, a callback function (echo_cb
) is implemented to handle interrupts triggered by the ultrasonic sensor for measuring echo time.
void echo_cb(void* arg) {
// Callback function for ultrasonic sensor echo pin
int val = gpio_read(echo_pin);
uint32_t echo_time_stop;
(void) arg;
if (val) {
echo_time_start = xtimer_now_usec();
} else {
echo_time_stop = xtimer_now_usec();
echo_time = echo_time_stop - echo_time_start;
}
}
void sensor_init(void) {
// Initialize GPIO pins for sensors and actuators
gpio_init(trigger_pin, GPIO_OUT);
gpio_init_int(echo_pin, GPIO_IN, GPIO_BOTH, &echo_cb, NULL); // Set callback for echo pin
adc_init(ADC_LINE(0)); // Initialize ADC for analog sensor (if used)
}
MQTT-SN Setup and Message HandlingThe code defines functions to set up MQTT-SN communication, subscribe to MQTT topics, handle received messages (on_pub
function), and publish data to MQTT topics (publish
function) using the EMCUTE library.
static void on_pub(const emcute_topic_t *topic, void *data, size_t len) {
// Handle received MQTT message
(void)topic;
(void)len;
char *in = (char *)data;
// Process incoming message
char msg[len + 1];
strncpy(msg, in, len);
msg[len] = '\0';
printf("\nReceived message: %s\n", msg);
// Additional message processing logic here...
}
static int publish(char *topic_name, char *message) {
// Publish message to MQTT topic
emcute_topic_t topic;
topic.name = topic_name;
if (emcute_reg(&topic) != EMCUTE_OK) {
printf("\nFailed to register MQTT topic: %s\n", topic.name);
return 1;
}
if (emcute_pub(&topic, message, strlen(message), MQTT_QoS) != EMCUTE_OK) {
printf("\nFailed to publish message on topic: %s\n", topic.name);
return 1;
}
printf("\nPublished message: %s on topic: %s\n", message, topic.name);
return 0;
}
static int sub(void) {
// Subscribe to MQTT topic
subscriptions[0].cb = on_pub;
subscriptions[0].topic.name = MQTT_TOPIC_INT;
if (emcute_sub(&subscriptions[0], MQTT_QoS) != EMCUTE_OK) {
printf("\nFailed to subscribe to MQTT topic: %s\n", subscriptions[0].topic.name);
return 1;
}
printf("\nSubscribed to MQTT topic: %s\n", subscriptions[0].topic.name);
return 0;
}
Main FunctionThe main
function orchestrates the initialization, setup, and continuous operation of the IoT device. It configures MQTT-SN connectivity, subscribes to MQTT topics, initializes sensors and actuators, and enters a loop to monitor sensor data, trigger alarms, and publish data to an external MQTT broker based on predefined conditions.
int main(void) {
// Setup MQTT-SN and broker connection
if (setup_mqtt() || connect_broker() || sub()) {
printf("\nInitialization failed. Exiting...\n");
return 1;
}
// Initialize sensors and actuators
xtimer_sleep(3);
sensor_init();
past_read = read_distance();
// Main loop for sensor monitoring and data publishing
while (1) {
int current_distance = read_distance();
printf("Current distance from object: %d\n", current_distance);
printf("Previous distance from object: %d\n", past_read);
xtimer_sleep(2);
// Check for significant distance change (motion detection)
if (abs(current_distance - past_read) > 1000) {
// Motion detected, trigger alarm
current_state = 1;
gpio_set(led_pin);
gpio_set(buzzer_pin);
xtimer_sleep(2);
gpio_clear(led_pin);
gpio_clear(buzzer_pin);
xtimer_sleep(1);
}
// Publish data if an alarm condition is detected
if (current_state == 1) {
char message[80];
sprintf(message, "%d:%d:%d", current_distance, past_read, current_state);
publish(MQTT_TOPIC_EXT, message);
}
// Update previous distance and reset alarm state
past_read = current_distance;
current_state = 0;
}
return 0;
}
ConclusionThis detailed explanation outlines the functionality and structure of the provided C code snippet for an IoT device implementation. It integrates sensor data processing, MQTT-SN communication, and actuator control within a RIOT OS environment.
Comments
Please log in or sign up to comment.