Project tutorial
Quantified Desk IoT

Quantified Desk IoT © GPL3+

Keep track of how much time you spend sitting (or standing) on your standing desk during the course of a day with this IoT project.

  • 6 views
  • 0 comments
  • 0 respects

Components and supplies

Apps and online services

About this project

As a quantified self enthusiast, I wanted to track how much time I spend sitting versus standing with my standing desk and have that visualized in a graph nicely.

I've been also wanting to work on a personal IoT project using Microsoft Azure, so I dusted off my Genuino MKR1000, hooked it up to an ultrasonic sensor and came up with this project.

The concept is very easy:

  • Use the ultrasonic sensor to measure the height of the desk by having it under the desktop and compute the distance to the floor
  • Send that data periodically to an Azure IoT Hub, and have it routed to a queue service (an Azure Service Bus queue)
  • Consume the data with a Python application to build a real-time Dashboard

The wiring is very simple:

The Setup:

You just need to make sure you place the sensor at a spot in the desk where there won't be obstacles between it and the floor (e.g: any objects on the floor, the chair or you own legs when you're sitting). So place it towards one of the corners.

To avoid "noise" in the computation (i.e. short moments where you might have your legs or arms under the sensor or anything temporarily obstructing the way making the program think you're in sitting position due to the lower measured height) the measurements are taken every 5 seconds, and only the average of the last 12 measurements is used to determine the current position and calculate sitting/standing time before send that data to azure (12*5 = 60 seconds, thus every minute).

Here's the Arduino code (or get it from this link):

/*******************************************************************
This code implements the Quantified Desk project, which consists of
an Arduino/Genuino MKR1000 hooked up to an ultrasonic sensor to measure
the distance to the floor (height) of a standing desk.
It keeps track of the time duration (in minutes) in each state (Sitting/Standing)
which is defined by a distance threshold above which the desk is considered to be
in standing position, and below which it is considered in sitting position.
A time counter for each state increases if the corresponding state is the current state.
This data is periodically sent to Azure IoT Hub along with a timestamp.
Complete Project with Dashboard visualization
https://github.com/vmehmeri/az-iot/QuantifiedDesk
PRE-REQUISITE
Setup Azure IoT Hub and upload SSL certificate to device (for your
IoT Hub hostname). With older firmware versions the HTTP Post function
will be unreliable and may fail on several requests, so it's recommended
to update your MKR1000 firmware to the latest version.
- Instructions for setting up Azure IoT Hub:
https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-create-through-portal
- Instructions for updating Firmware and adding SSL certificate to device:
https://www.arduino.cc/en/Tutorial/FirmwareUpdater
*******************************************************************/
#include <Ultrasonic.h>
#include <WiFi101.h>
#include <RTCZero.h>
#include <WiFiUdp.h>
#include "arduino_secrets.h"
// SECRETS CONFIG -- PLEASE SET THESE IN arduino_secrets.h FILE
//WiFi creds -------------------------------------------------------------------------------------------
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_WIFIPASSWD; // your network password (use for WPA, or use as key for WEP)
//Azure IoT Hub Secrets Config -------------------------------------------------------------------------
char hostname[] = SECRET_IOTHUB_HOSTNAME;
char uri[]= SECRET_DEVICE_POST_URI;
char authSAS[] = SECRET_DEVICE_SAS;
//------------------------------------------------------------------------------------------------------
#define slotNumber 1 //This will vary for multi slot devices
// Project Config variables
unsigned int distanceThreshold = 82; // Define here the distance (in cm) that marks the threshold between sitting and standing
const int GMT = 2; //change this to adapt it to your time zone
const int TrigPin = 4; //number of the Trigger pin
const int EchoPin = 5; //number of the Echo pin
RTCZero rtc;
WiFiSSLClient client;
Ultrasonic ultrasonic(TrigPin, EchoPin);
unsigned int count = 0;
unsigned long distanceSum = 0;
unsigned int timeStanding = 0;
unsigned int timeSitting = 0;
unsigned long startMillis;
unsigned long distanceAvg;
unsigned long distance;
int status = WL_IDLE_STATUS;
void setup() {
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
startMillis = millis();
rtc.begin();
// check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("WiFi shield not present");
// don't continue:
while (true);
}
// attempt to connect to Wifi network:
while ( status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
Serial.println("Connected to Wi-Fi");
// Get Real-Time from NTP using built-in RTC module
unsigned long epoch;
int numberOfTries = 0, maxTries = 6;
do {
epoch = WiFi.getTime();
numberOfTries++;
}
while ((epoch == 0) && (numberOfTries < maxTries));
if (numberOfTries == maxTries) {
Serial.print("NTP unreachable!!");
while (1);
}
else {
Serial.print("Epoch received: ");
Serial.println(epoch);
rtc.setEpoch(epoch);
Serial.println();
}
}
void loop() {
delay(5000); // wait 5 seconds
ultrasonic.measure();
distance = ultrasonic.get_cm();
Serial.print("Sensor(cm): ");
Serial.println(distance);
distanceSum = distanceSum + distance;
count = count + 1;
/* Takes the average of the last 12 measurements (the number 12 is arbitrary, but
* with a 5-second delay between measurements and 12 measurements, that means
* data is aggregated and sent to Azure every 60 seconds, which seems reasonable for
* this project.
*/
if (count == 12) {
distanceAvg = distanceSum / count;
count = 0;
distanceSum = 0;
if (distanceAvg < distanceThreshold) {
// Add elapsed time since last measurement to sitting time
timeSitting = timeSitting + ((millis()-startMillis)/1000);
} else {
// Add elapsed time since last measurement to standing time
timeStanding = timeStanding + ((millis()-startMillis)/1000);
}
startMillis = millis();
// Show current aggregate numbers
printRTCDate();
printRTCTime();
Serial.println();
Serial.print("Time sitting: ");
Serial.print(timeSitting/60);
Serial.println("min");
Serial.print("Time standing: ");
Serial.print(timeStanding/60);
Serial.println("min");
Serial.println("");
// Creates a string to send to Azure IoT HUB.
// It's simply comma-separated string of values for sitting and standing, followed by date and time (for timestamping)
String data_string = (String(timeSitting/60) + "," + String(timeStanding/60) + "," + getRTCDate() + "," + getRTCTime());
//Serial.println(data_string);
// Send to Azure
httpPost(data_string);
String response = "";
char c;
while (client.available()) {
c = client.read();
response.concat(c);
}
}
}
void httpPost(String content)
{
if (client.connectSSL(hostname, 443)) {
client.print("POST ");
client.print(uri);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(hostname);
client.print("Authorization: ");
client.println(authSAS);
client.println("Connection: close");
client.print("Content-Type: ");
client.println("text/plain");
client.print("Content-Length: ");
client.println(content.length());
client.println();
client.println(content);
delay(500);
} else {
Serial.println("HTTP POST connection failed");
Serial.println(client.read());
}
// close connection
client.stop();
}
void printRTCTime()
{
print2digits(rtc.getHours() + GMT);
Serial.print(":");
print2digits(rtc.getMinutes());
Serial.print(":");
print2digits(rtc.getSeconds());
Serial.println();
}
void printRTCDate()
{
Serial.print(rtc.getDay());
Serial.print("/");
Serial.print(rtc.getMonth());
Serial.print("/");
Serial.print(rtc.getYear());
Serial.print(" ");
}
void print2digits(int number) {
if (number < 10) {
Serial.print("0");
}
Serial.print(number);
}
String getRTCDate()
{
String date_str = String(rtc.getDay()) + "/" + String(rtc.getMonth()) + "/" + String(rtc.getYear());
return date_str;
}
String getRTCTime()
{
String time_str = get2digits(rtc.getHours() + GMT) + ":" + get2digits(rtc.getMinutes()) + ":" + get2digits(rtc.getSeconds());
return time_str;
}
String get2digits(int number) {
if (number < 10) {
return "0" + String(number);
}
return String(number);
}

Note that Azure connection details must be provided, so you need to setup your Azure IoT Hub first.

Here are instructions for setting up Azure IoT Hub:

https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-create-through-portal

The Free tier will do just fine for this one. So it won't cost you anything!

Dashboard

For the real-time Dashboard, I used Pusher (pusher.com). I followed this tutorial and modified its sample code for my application.

You can use my code (provided below) as a reference, but you need to create an account, create an application, and note down your app connection keys as shown below:

Don't worry, this should take you well under 5 minutes to set up.

Once you have that in place, download the code available in my Github repo:

https://github.com/vmehmeri/az-iot/tree/master/QuantifiedDesk

Modify the following files:

frontend/app.py
device_handler.py

with your App keys (and, in the case of the device handler, also your Azure connection info). You will notice that information about an Azure Service Bus Queue is required. In my application, I have the Azure IoT Hub route messages to a Service Bus queue, and then I consume them from there. Setting up an Azure Service Bus queue is fairly simple, you can follow this tutorial:

https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-quickstart-portal

Configure your IoT Hub message routing under Messaging > Messaging routing > Add (then select your queue)

After that you're ready to run the application. Firstly, run the frontend:

python frontend/app.py

and in another terminal, run the device handler, which is the backend application:

python device_handler.py

Now you can just open a browser window on localhost:5000 and just stare at the graph while you see the bars grow depending on how long you stand or sit at your desk :) (it might take 1-2 minutes until you see any change in the dashboard)

You can also open the Arduino serial monitor for more immediate and verbose output. The python code for device_handler should also output some text as it gets messages from the device.


Code

Complete code
Arduino and python codes for this project

Schematics

Schematics
Wiring schematics
Schematic 8vecc4fku2

Comments

Similar projects you might like

IoT Node with STM32F4 Discovery, MKR1000 and Azure IoT Hub

Project tutorial by vincent wong

  • 1,949 views
  • 0 comments
  • 6 respects

IoT Blink - Getting started with IoT

Project showcase by AppShed Support

  • 5,404 views
  • 1 comment
  • 22 respects

SmartQ Notification with Azure IOT Hub and Virtual Shields

Project showcase by vincent wong

  • 2,052 views
  • 0 comments
  • 6 respects

Smart Plant IoT

Project tutorial by 3 developers

  • 14,133 views
  • 3 comments
  • 41 respects

IOT Lighted Xmas Tree

Project tutorial by Sameer

  • 1,175 views
  • 0 comments
  • 2 respects
Add projectSign up / Login