People usually have some sort of perimeter security for their house or office. A simple passive IR (“PIR”) device can be used to switch on a floodlight but what if you are not at home when an intruder is scouting around your property? I installed an Azure Sphere MT3620 Starter Kit inside a weatherproof box near the perimeter of my property, but within WiFi range. Mains powered via a 5v USB power supply, I added an Adafruit PowerBoost 1000c battery charger and LiPo battery in between so that the Azure Sphere will still be able to send an alert to the cloud if it is tampered with and the power cable is cut. For added security, I used the onboard gyrometer to detect if the device is moved and, if so, an alert is sent to the cloud. I used Microsoft IoT Central "Rules" for the automation. Within IoT Central I used the "Email Action" to send an email if the rule conditions are met.
Steps
1. I added a Mikroelektronika Click Motion sensor to the MikroBUS 1 connector on the Azure Sphere MT3620 board. The MT3620 is powered via an Adafruit PowerBoost 1000c battery charger, LiPo battery and a Raspberry Pi 3 power supply.
2. To program the device, I modified Avnet's Azure Sphere Starter-Kit (Out of Box Demo) “reference design” project from Part 3 (after setting up the device in Part 1). Once I had the device working without the motion sensor, I needed to add code to identify when the motion sensor had been triggered. The motion sensor sends a “high” signal on its OUT pin when it detects motion. On the Azure Sphere board this is connected to GPIO 2. The reference design already has code to identify when button A or B is pressed so it is just a matter of adding another “button” to the code. First, I needed to add GPIO 2 to the list of ports in app_manifest.json.
"Gpio": [ 0, 2, 4, 5, 8, 9, 10, 12, 13, 34 ],
In mt3620_rdb.h, I added the following lines:
/// <summary>Motion is GPIO2
#define MIKRO_INT MT3620_GPIO2
Similarly, in mt3620_avnet_dev.h , I added:
#define MIKRO_INT MT3620_GPIO2
All the other changes are in main.c.
Around Line 77, I set up the file descriptor for the motion sensor:
// File descriptors - initialized to invalid value
int epollFd = -1;
static int buttonPollTimerFd = -1;
static int buttonAGpioFd = -1;
static int buttonBGpioFd = -1;
static int motionGpioFd = -1;
Around Line 93, define and initialise the "button state" variables:
// Button state variables, initilize them to button not-pressed (High) [added motion sensor]
static GPIO_Value_Type buttonAState = GPIO_Value_High;
static GPIO_Value_Type buttonBState = GPIO_Value_High;
static GPIO_Value_Type motionState = GPIO_Value_High;
Around line 300:
static void ButtonTimerEventHandler(EventData *eventData)
{
bool sendTelemetryButtonA = false;
bool sendTelemetryButtonB = false;
bool sendTelemetryMotion = false;
Around Line 360, check for button presses or motion and send telemetry accordingly:
// Check for motion
GPIO_Value_Type newMotionState;
result = GPIO_GetValue(motionGpioFd, &newMotionState);
if (result != 0) {
Log_Debug("ERROR: Could not read motion GPIO: %s (%d).\n", strerror(errno), errno);
terminationRequired = true;
return;
}
// If motion, send a telemetry message
// Has GPIO_Value_Low when motion and GPIO_Value_High when no motion
if (newMotionState != motionState) {
if (newMotionState == GPIO_Value_Low) {
// Send Telemetry here
Log_Debug("Motion detected!\n");
sendTelemetryMotion = true;
}
else {
Log_Debug("No motion!\n");
}
// Update the static variable to use next time we enter this routine
motionState = newMotionState;
}
// If either button was pressed or motion detected, then enter the code to send the telemetry message
if (sendTelemetryButtonA || sendTelemetryButtonB || sendTelemetryMotion) {
char *pjsonBuffer = (char *)malloc(JSON_BUFFER_SIZE);
if (pjsonBuffer == NULL) {
Log_Debug("ERROR: not enough memory to send telemetry");
}
if (sendTelemetryButtonA) {
// construct the telemetry message for Button A
snprintf(pjsonBuffer, JSON_BUFFER_SIZE, cstrButtonTelemetryJson, "buttonA", newButtonAState);
Log_Debug("\n[Info] Sending telemetry %s\n", pjsonBuffer);
AzureIoT_SendMessage(pjsonBuffer);
}
if (sendTelemetryButtonB) {
// construct the telemetry message for Button B
snprintf(pjsonBuffer, JSON_BUFFER_SIZE, cstrButtonTelemetryJson, "buttonB", newButtonBState);
Log_Debug("\n[Info] Sending telemetry %s\n", pjsonBuffer);
AzureIoT_SendMessage(pjsonBuffer);
}
if (sendTelemetryMotion) {
// construct the telemetry message for motion
snprintf(pjsonBuffer, JSON_BUFFER_SIZE, cstrButtonTelemetryJson, "motion", newMotionState);
Log_Debug("\n[Info] Sending telemetry %s\n", pjsonBuffer);
AzureIoT_SendMessage(pjsonBuffer);
}
free(pjsonBuffer);
I have attached the revised main.c for reference. You could just replace the original main.c with this file.
3. After you build and run the project, in debug mode you can now see an entry in the Output window if the motion sensor is triggered. The revised main.c sends the telemetry for the motion sensor to the Azure cloud.
4. Now I made some changes to IoT Central and added a Rule "if motion detected, send email". I also added a rule for the gyrometer "if X-Gforce is greater than 2 during the previous 5 minutes, send an email".
Testing
5. I installed the device in a rarely-visited room in my house and went in to the room from time to time to check that motion detection was working and that I got a “triggered” email. I had to adjust the sensitivity of the sensor (using the onboard potentiometer) until it was working properly and not giving false triggers.
6. Now it is time to put it in a weatherproof box and install it outside near my garage.
Comments