DIY IoT Motion Sensor for Remotely Monitoring Elderly Relatives

We have an elderly relative who, in the coming years, we expect have to keep a closer eye on. It’s not like we don’t have almost daily contact with them already, but having an early heads up of any mobility issues would be beneficial & give a degree of peace of mind.

Having a wifi-enabled camera installed is one option, but would be pretty intrusive, and I don’t want to have to watch it to figure out if there are any problems.

What I realised I needed was a Passive Infrared (PIR) movement sensor which could ping a service in the Cloud & alert me for anything out of the ordinary.

There are such solutions sold by a bunch of companies, but cost upwards of £100 and tend to have a subscription charge.

I started to think I’d roll my own solution using a development board and PIR sensor, but I remembered I actually have an old battery-powered PIR which activates a mains adapter (the idea is you’d maybe have a lamp in the socket for home security).

The adapter I have is from a company called Timeguard, but it’s about 15 years old and is obsolete.. they don’t have any current products of this type, but you can find similar ones on Amazon easily enough.

What I like about this, is that I can concentrate on the IoT piece, and let the adapter + sensor do their thing without worrying about the electronics.

All I needed to do next was take a small ESP8266 board I had lying around and code it up to connect to the local wifi & call a URL.. which in my case will be an Azure Logic App. Logic Apps are great.. you can get them up and running very easily, at minimal cost, and without writing any code!

At first, the code for the ESP8266 just used the examples from the Arduino IDE. In very little time I had it connected to Wi-Fi and ready to make a HTTP call to wherever I wanted. However, I soon discovered the examples only worked with non-HTTPS sites (Logic Apps are HTTPS-only).

After a bunch of Googling, I found this library from gojimmypi on GitHub, which allows you to make HTTPS calls.

After switching to that & rewriting portions of the code, the board called the Logic App URL without issues and I received a 202 response (Accepted), and I could see the call in History;

Now we’re cooking! The motion sensor will activate the power adapter, which boots up the ESP8266 board, connects to wifi & calls Azure. The adapter will stay powered for 15s to 15min.. so having it set to 15 minutes means we’re not repeatedly powering the board & calling Azure (and incurring a load of cost).

The Logic App can do whatever we want to record the event.. update a table, or write a small text file with a timestamp.

Now we have that, we can have a secondary Logic App running on a schedule to monitor the events & alert us by email (or whatever) if it falls outside what we typically expect. For example, at 9am check that there’s been motion detected in the last 3 hours. If there hasn’t, send me an email so I can give the relative a quick call to check they’re ok.

With Azure, it’s always good to keep an eye on costs. In this case, lets look at the worst case scenario where we have a very active elderly relative who trips the motion sensor every 15 minutes from 7am to 11pm.. so that’s 16hrs x 4 = 64 possible calls a day.

Logic Apps cost you per Action block, and cost a bit more for Standard + Premium actions. In our case we have 1 trigger block and 1 standard block to write to a Storage Account (table or file).

The Azure cost calculator can then be used to figure out the monthly cost..

That’s a maximum of 21 pence (GBP) a month if it triggers every 15 min (which it won’t).. not bad!

We’ll also have the ‘event monitor’ Logic App, but that won’t run as often.. maybe every 4 hours starting at 9am, finishing at 9pm.. so that’s 4 times a day, with a few more action blocks in it to figure out what to do.. so maybe 10-15 blocks, 5 of which might be ‘Standard’…

As you can see, the monthly costs are minimal, and helps illustrate how useful Azure can be for something like this!

It took a few hours to put this all together & I’m pretty happy with the solution. We can put the battery-powered PIR sensor in somewhere like the kitchen, or hallway and be safe in the knowledge we’d get an alert if there wasn’t the level of activity we’d typically expect to see.

If you’re interested in the ESP8266 source, here it is;

// WIFI SETUP & LOGIC APP URL
char ssid[] = "YOUR_WIFI_SSID";
char pass[] = "YOUR_WIFI_PASSWORD";
char logicAppURL[] = "https://YOUR_LOGIC_APP_URL";
// HTTP AND WIFI
// Needed to go here & install board support for ESP8266. https://github.com/gojimmypi/ESP8266-Arduino
// This gave access to the WiFiClientSecureBearSSL client library (which is needed for HTTPS).
// See install instructions on that GitHub page.
// Also installed h/w support for the TTGO OLED board I have.
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
// OLED INCLUDES
#include <Arduino.h>
#include <U8g2lib.h> // make sure to add U8g2 library and restart Arduino IDE
#include <SPI.h>
#include <Wire.h>
#define OLED_SDA 2
#define OLED_SCL 14
#define OLED_RST 4
U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, OLED_SCL, OLED_SDA , OLED_RST);
ESP8266WiFiMulti WiFiMulti;
void setup()
{
Serial.begin(115200);
Serial.println();
oledInit();
oledPrint("Start…", false);
delay(500);
oledPrint("Wifi connect ..", false);
delay(500);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFiMulti.addAP(ssid, pass);
String progress = ".";
while (WiFiMulti.run() != WL_CONNECTED) {
delay(500);
Serial.print(progress);
oledPrint(progress, false);
progress = progress + ".";
}
oledPrint("Wifi connected", false);
delay(1000);
Serial.println("Calling HTTP");
httpGET(logicAppURL);
}
void loop()
{
delay(10000);
}
void httpGET(String url) {
std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
client->setInsecure();
HTTPClient https;
Serial.print("[HTTPS] begin…\n");
oledPrint("[HTTPS] begin", false);
if (https.begin(*client, url)) { // HTTPS
Serial.print("[HTTPS] GET…\n");
oledPrint("[HTTPS] GET…", false);
// start connection and send HTTP header
int httpCode = https.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTPS] GET… code: %d\n", httpCode);
oledPrint("[HTTPS] GET " + String(httpCode), false);
// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = https.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTPS] GET… failed, error: %s\n", https.errorToString(httpCode).c_str());
oledPrint("[HTTPS] GET " + String(https.errorToString(httpCode)), false);
}
https.end();
} else {
Serial.printf("[HTTPS] Unable to connect\n");
oledPrint("[HTTPS] GET Err", false);
}
}
void oledInit() {
Serial.println("OLED Start..");
u8g2.begin();
u8g2.setFont(u8g2_font_6x10_tf);
}
void oledPrint(String message, bool frame) {
char charBuf[15];
message.toCharArray(charBuf, 25);
u8g2.clearBuffer();
u8g2.drawStr(10, 25, charBuf);
if (frame) u8g2.drawRFrame(0,0,128,32,4); // https://github.com/olikraus/u8g2/wiki/u8g2reference#drawrbox
u8g2.sendBuffer();
}

Leave a comment