Mpho Mphego
Published © GPL3+

Automated StandUp Desk

Standing/Seating detection - For easy multiple monitors management when using Stand Desks.

BeginnerFull instructions provided1 hour2,725
Automated StandUp Desk

Things used in this project

Hardware components

NodeMCU ESP8266 Breakout Board
NodeMCU ESP8266 Breakout Board
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Node MCU and HC-SR04

Connection Diagram

Code

StandUpDesk_NodeMCU_HCSR04.ino

Arduino
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h> 
//https://github.com/tzapu/WiFiManager
#include <WiFiManager.h>        

//https://github.com/dancol90/ESP8266Ping
#include <ESP8266Ping.h>
#include <PubSubClient.h>

// https://github.com/MajenkoLibraries/Average
#include <Average.h>    
#include<stdlib.h>

#define   Hostname        "stand-up-desk-proximity-sensor"
#define   MasterPass      "ESP8266"
#define   OTAPort         8266
 
//"alexapi"
//#define   mqtt_server_1   "192.168.1.232"
#define   mqtt_server_1   "192.168.1.232"
#define   mqtt_topic    "work/proximity"
#define   mqtt_port     1883

// Define NodeMCU D5 pin to as temperature data pin of  DHT11
#define   ECHO          D1
#define   TRIGGER       D2
#define   Statusled     D3
#define   WiFiLed       D5
// #define   Reset_Button D6

// Define macros
#define Between(x, a, b)  (((a) <= (x)) && ((x) <= (b)))
#define Outside(x, a, b)  (((x) < (a)) || ((b) < (x)))
#define LessOrEqual(x, y) ((x) <= (y))
#define MoreOrEqual(x, y) ((x) >= (y))

// Variables

// Reserve space for 10 entries in the average bucket.
Average<float> ave_distance(10);
int count = 0;
int wifiCount = 0;
int sleep = 50;
int wifi_reset = 0;

int Samples = 50;
int maximumRange = 200; // Maximum range
int minimumRange = 2; // Minimum range
float prohibitedDistance = 60.0; // Distance Alarm will be sounded

// long lastMsg = 0;
char msg[50];
char message[65];

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  Serial.begin(115200);
  setup_GPIO();
  setup_OTA();
  setup_WiFi(); 
  setup_MQTT();
}

void setup_GPIO(){
  pinMode(TRIGGER, OUTPUT);
  pinMode(ECHO, INPUT);
  pinMode(WiFiLed, OUTPUT);
  pinMode(Statusled, OUTPUT);
}

void setup_OTA() {
  // Port defaults to 8266
  ArduinoOTA.setPort(OTAPort);
  // Hostname to Temp_Hum_Sensor-01
  ArduinoOTA.setHostname(Hostname);
  // Enable authentication
  ArduinoOTA.setPassword(MasterPass);
  ArduinoOTA.onStart([]() {
    Serial.println("Start OTA");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("End OTA");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\n", (progress / (total / 100)));
  });

  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
}

void setup_WiFi() {
  // Connect to WiFi access point.
  WiFiManager wifiManager;
  Serial.print("WiFi Reset status: ");
  Serial.println(wifi_reset);
  if (wifi_reset == 1) {
    //reset settings - assign a button for this.
    wifiManager.resetSettings();
    wifi_reset = 0;
  }
  //sets timeout until configuration portal gets turned off
  //useful to make it all retry or go to sleep
  //in seconds
  wifiManager.setTimeout(180);
  // Connect to WiFi access point.
  if (!wifiManager.autoConnect(Hostname, MasterPass)) {
    Serial.println("failed to connect, we should reset as see if it connects");
    delay(3000);
    ESP.restart();
    delay(5000);
  }
  delay(50);
  Serial.println();
  Serial.print("Connecting to WiFi access point: ");
  //Serial.println(ssid_1);
  Serial.print("Connecting.");
  while (WiFi.status() != WL_CONNECTED) {
    digitalWrite(WiFiLed, HIGH);
    delay(50);
    digitalWrite(WiFiLed, LOW);
    delay(50);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  digitalWrite(WiFiLed, HIGH);
  Serial.print("MAC Address: ");
  Serial.println(WiFi.macAddress());
  Serial.println();
}

void setup_MQTT(){
  delay(10);
  Serial.print("Connecting to MQTT Server: ");
  Serial.println(mqtt_server_1);
  client.setServer(mqtt_server_1, mqtt_port);
}

void reconnect() {
  Serial.println();
  Serial.print("Pinging MQTT BrokerIP: ");
  Serial.print(mqtt_server_1);

  if(Ping.ping(mqtt_server_1)){
    Serial.println(" Ok!!!");
    // Loop until we"re reconnected
    while (!client.connected()) {
      Serial.print("Attempting MQTT connection...");
      // Create a random client ID
      String clientId = "ESP8266Client-";
      clientId += String(random(0xffff), HEX);

      // Attempt to connect
      //if you MQTT broker has clientID,username and password_1
      //please change following line to    if (client.connect(clientId, userName, password_1))
      if (client.connect(clientId.c_str())){
        Serial.println("connected...");
        Serial.print("and subscribe to topic: ");
        Serial.println(mqtt_topic);
       //once connected to MQTT broker, subscribe command if any
        client.subscribe(mqtt_topic);
      }else {
        Serial.print("failed, rc=");
        Serial.print(client.state());
        Serial.println(" try again in 5 seconds");
        // Wait 5 seconds before retrying
        delay(5000);
      }
    }
  }
  else if (WiFi.status() != 3) {
    Serial.println("");
    Serial.println("WiFi disconnects, reconnecting.");
    wifi_reset = 1;
    delay(1000);
    ESP.restart();
    delay(3000);
    Serial.print("WiFi Reset status: ");
    Serial.print(wifi_reset);
    setup_WiFi();
  }
  else {
    Serial.println();
    Serial.print(":Failed to establish a connection on MQTT Broker.");
    delay(1000);
    ESP.restart();
    delay(1000);
  }//end reconnect()
}


float Proximity(){
  //delay(10);
  float duration, distance;
  digitalWrite(TRIGGER, LOW);
  delayMicroseconds(2);

  digitalWrite(TRIGGER, HIGH);
  delayMicroseconds(10);

  digitalWrite(TRIGGER, LOW);
  duration = pulseIn(ECHO, HIGH);
  //Serial.print(duration);
  distance = duration / 58.0;
  //Serial.print(distance);
  return distance;
}

// For Debug
// void loop(){
//   float raw_distance;
//   raw_distance = Proximity();
//   Serial.print("Raw distance: ");
//   Serial.println(raw_distance);
//   delay(1000);
// }

void loop() {
  ArduinoOTA.handle();
  if (!client.connected()){
    reconnect();
  }
  client.loop();
  delay(10);
  float raw_distance, distance;
  raw_distance = Proximity();
  //Serial.print("Raw distance: ");
  //Serial.println(raw_distance);
  ave_distance.push(raw_distance);
  // calculate the average of samples
  for(int i = 0; i < Samples; i++){
    ave_distance.get(i);
  }
  count += 1;
  if(count > Samples){
    count = 0;
    distance = ave_distance.mean();
    //Serial.print("Current Distance (CM)");
    //Serial.println(distance);
    if (Between(distance, minimumRange, maximumRange) && LessOrEqual(distance, prohibitedDistance)){
      Serial.println("You are standing up, moving to Monitor#2!!!!");
      String msg = "Distance (Cm): ";
      msg = msg + distance;
      msg.toCharArray(message, 65);
      Serial.println(message);
      client.publish(mqtt_topic, "1");
      delay(500);
     }
    else{
      Serial.println("You possibly seating!!!!");
      Serial.print("Distance (Cm): ");
      Serial.println(distance);
      client.publish(mqtt_topic, "0");
      }
    if Outside(distance, minimumRange, maximumRange){
      Serial.println("Invalid range. Range set to 2-200cm");
     }
    /*
    if LessOrEqual(distance, prohibitedDistance){
      Serial.println("You are standing up, moving to Monitor#2!!!!");
      digitalWrite(Statusled, HIGH);
      delay(1000);
    } 
    else{
      Serial.println("You possibly not standing up, staying on Monitor#1!!!!");
      digitalWrite(Statusled, LOW);
    }*/
  }
}

Proximity.py

Python
#!/usr/bin/python

import paho.mqtt.subscribe as subscribe
import subprocess
import time
import pynotify

mqtt_topic = 'work/proximity'
notified = False

def sendmessage(title, message):
    pynotify.init("Basic")
    notice = pynotify.Notification(title, message)
    notice.show()

while True:
    msg = subscribe.simple(mqtt_topic)
    value = float(msg.payload)
    if value == 0:
        if not notified:
            title = '...Seating...'
            message = 'Moving your desktop and windows over.'
            sendmessage(title, message)
            time.sleep(0.5)
            subprocess.call(["$HOME/bin/seating"])
            notified = True
    else:
        if notified:
            title = '...Standing...'
            message = 'Moving your desktop and windows over.'
            sendmessage(title, message)
            time.sleep(0.5)
            subprocess.call(["$HOME/bin/standing"])
            notified = False
    time.sleep(1)

seating

BatchFile
Bash Script for Monitor 1
#!/bin/bash
xrandr --auto --output HDMI2 --off --output HDMI1 --off --output DP1 --above eDP1 --mode 1920x1200 --pos 1920x0 --rotate normal --output eDP1 --mode 1920x1080 --pos 0x88 --rotate normal --output VIRTUAL1 --off 

standing

BatchFile
Bash script for Monitor 2
#!/bin/bash
xrandr --output HDMI2 --off --output HDMI1 --off --output DP1 --left-of eDP1 --mode 1920x1200 --pos 1920x0 --rotate normal --output eDP1 --mode 1920x1080 --pos 0x88 --rotate normal --output VIRTUAL1 --off

Credits

Mpho Mphego

Mpho Mphego

3 projects • 6 followers
github.com/mmphego https://blog.mphomphego.co.za/

Comments