Turn off the TV!

If you’ve got kids, you’re probably used to the TV playing to an empty room.
They’ll turn it on, watch their show, and then just go and play with something else.

This device turns the TV off after no motion has been detected for 5 minutes.

The PIR sensor detects movement in the room. If nothing is detected for 4 minutes, the Warning LED flashes for 1 minute… and if there’s still no movement, the Infrared Transmitter sends a TV OFF signal, as if someone had pressed the OFF button on the remote.

To stop it turning the TV back on again and going into an ON/OFF loop, the device is powered from the USB port on the back of the TV – which means when the TV is off, so is the device.

I based this around an Arduino Nano, but I’d like to get it working on an ATtiny85 at some point.
Then I’ll box it all up and make it look nice.

This project was inspired by the one Neil Lovegrove made here.

Here’s my code:

#include <IRremote.h>

int pirPin = 7;
IRsend irsend; // 3
int ledPin = 6;

const int timeLimit = 300; // How many seconds before the OFF signal is sent
int currentCount = timeLimit; // The current counter, start it at max and count down
int warningThreshold = 60; // How many seconds before the warning LED flashes

int brightness = 0; // How bright the Warning LED is
int fadeAmount = 5; // How many points to fade the Warning LED by each step
int fadeSpeed = 10; // How much delay in the fade

// 0x20DF10EF is ON/OFF for LG TVs
#define IR_CODE 0x20DF10EF

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  pinMode(pirPin, INPUT);
  digitalWrite(ledPin, LOW); // Turn the Warning LED off to start with
}

void loop() {
  Serial.println(currentCount);
  currentCount = currentCount - 1;

  // If the warning threshold has been reached, flash the warning LED!
  if (currentCount < warningThreshold) {
    for (brightness = 0; brightness < 255; brightness = brightness + fadeAmount ) {
      analogWrite(ledPin, brightness);
      delay(fadeSpeed);
    }
    for (brightness = 255; brightness > 0;  brightness = brightness - fadeAmount ) {
      analogWrite(ledPin, brightness);
      delay(fadeSpeed);
    }
  } else {
    digitalWrite(ledPin, LOW);
    delay(1000);
  }

  // If we detect movement, reset the count and start again
  if (digitalRead(pirPin) == true) {
    currentCount = timeLimit;
    Serial.println("Movement Detected");
  }

  // If the counter hits zero, turn off the TV!
  if (currentCount == 0) {
    digitalWrite(ledPin, LOW);
    Serial.print("Sending OFF now... ");
    delay(200);
    irsend.sendNEC(IR_CODE, 32); // SEND "TV OFF"
    // From here on probably won't happen, but it's there for testing...
    Serial.println("Done.");
    currentCount = timeLimit;
  }
}
Advertisements

Keypad

I bought a handful of 3×4 Keypads from eBay for about $1 each.

Here’s a simple example of entering a password to turn on a relay.

Here’s the code:

#include <Keypad.h>

#define passwordLength 5

char userInput[passwordLength];
char password[passwordLength] = "1234";
byte userInputCount = 0;

const byte ROWS = 4;
const byte COLS = 3;

char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3};

Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

int relay = 12;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  pinMode(relay, OUTPUT);
  digitalWrite(relay, HIGH);

  Serial.begin(9600);

  Serial.print("Enter your ");
  Serial.print(passwordLength - 1);
  Serial.println(" digit password.");
  Serial.println("Use # to reset your attempt.");
}

void loop() {
  char keyPressed = customKeypad.getKey();

  if (keyPressed) {
    Serial.print(keyPressed);
    userInput[userInputCount] = keyPressed;
    userInputCount++;
  }

  if (keyPressed == '#') {
    userInputCount = 0; // Reset the count so thet next input goes to position 0 of the array
    Serial.println(" RESET");
  }

  if (userInputCount == passwordLength - 1) {
    if (!strcmp(userInput, password)) {
      Serial.println(" CORRECT");
      digitalWrite(LED_BUILTIN, HIGH);
      digitalWrite(relay, LOW);
      delay(3000);
      digitalWrite(LED_BUILTIN, LOW);
      digitalWrite(relay, HIGH);
    } else {
      Serial.println(" INCORRECT");
      digitalWrite(LED_BUILTIN, LOW);
      digitalWrite(relay, HIGH);
    }
    userInputCount = 0; // Reset the count so thet next input goes to position 0 of the array
  }

}

Parking Sensor

Parking the car without smashing into the wall can be a tough task… well, not anymore with this “Parking Sensor”!

I thought I’d have a go at using the ATtiny85’s I bought a while ago. They have just enough GPIO for two LEDs, a button, and a HC-SR04 ultrasonic distance sensor.

The idea is that a LED blinks increasingly faster as you get closer until it goes solid, indicating you should stop the car. The button can be used to set a new “Stop Distance”, and the other LED is there to indicate that the new “Stop Distance” has been set successfully. It runs on 5v from a USB cable.

 

 

I built it on a breadboard and tested it out for a few weeks. Once I was happy, I put in on a bit of Pref Board, and 3D Printed a case for the HC-SR04 (using this design)

In the future I’d like to run it from batteries, but the problem is that it needs to be constantly checking for a car. It would be good if I could put it to sleep when the car is stationary, or the garage is empty – but there’s no trigger to wake it up again!

I’d like to design and 3D print a proper case for it, either as an all-in-one box, or two separate enclosures connected by a cable.

I’m sure I’ll tweak it more.

Here’s the code:

int buttonPin = 0; //Physical 5
int led2Pin = 1; //Physical 6
int ledPin = 2; //Physical 7
int trigPin = 3; //Physical 2
int echoPin = 4; //Physical 3

long duration;
unsigned long distance;
int stillCounter = 0;
int buttonState = 0;

volatile int stopDistance = 10; // the default ideal partking distance in cm
int blinkRate = 4; // the speed of the blink
int stillTurnOffAfter = 2000; // time in (approx) ms before turning LED off after car is parked
int distanceMultiplier = 4; // the stopDistance * this value sets the range of the sensor before it blinks

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  pinMode(buttonPin, INPUT);

  // Turn the LEDs off to start with
  digitalWrite(ledPin, LOW);
  digitalWrite(led2Pin, LOW);
}

void loop() {
  // GET DISTANCE
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  distance = pulseIn(echoPin, HIGH) * 0.034 / 2; // Calculating the distance in cm

  // IF WE ARE IN THE STOP ZONE
  if (distance <= stopDistance) { 
      stillCounter++;
      if (stillCounter > stillTurnOffAfter) {
        stillCounter = stillTurnOffAfter + 1; // keeps the counter high, avoids overflow
        digitalWrite(ledPin, LOW);
      } else {
      digitalWrite(ledPin, HIGH);
    }
    
  // ELSE, BLINK IF WE ARE IN RANGE
  } else if (distance > stopDistance && distance <= stopDistance * distanceMultiplier) {
    stillCounter = 0;
    digitalWrite(ledPin, HIGH);
    delay(distance * blinkRate);
    digitalWrite(ledPin, LOW);
    delay(distance * blinkRate); // ELSE, WE ARE TOO FAR AWAY
   } else if (distance > stopDistance * distanceMultiplier) {
    digitalWrite(ledPin, LOW);
  }

  // SET DESIRED DISTANCE IF BUTTON IS PRESSED
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
    //digitalWrite(ledPin, HIGH);
    digitalWrite(led2Pin, HIGH);
    delay(1500);
    stopDistance = distance;
    delay(1500);
    //digitalWrite(ledPin, LOW);
    digitalWrite(led2Pin, LOW);
  }
}

Doorbell Email

Using a $9 doorbell from Bunnings, a $6 WiFi module, a soldering iron, and C++, my doorbell now sends an email to my phone when pressed.

I connected it to the LED on the doorbell so that when the doorbell goes off, the Wemos D1 Mini sends a GET request off to “doorbell.php” that logs it, and sends an email. It also hits a “heartbeat.php” every 5 minutes, just so I can see if it’s alive when I’m not home.

Here is the code:

// When the doorbell LED lights up, hit a website.

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

String lastUpdate = "8 July, 2018";

// WiFi Details
const char* ssid = "XXXX";
const char* password = "XXXX";

// The URL to hit when the doorbell is pressed
String urlDoorbell = "http://example.com/doorbell.php?id=FRONT-DOOR";

// This is the pin the doorbell LED is connected to
int pinDoorbellLed = D3;

// A reset function, to reboot the device
void(* resetFunc) (void) = 0; //declare reset function at address 0

// This doorbell also hits the 'heartbeat.php' file every now and then
String urlHeartbeat = "http://example.com/heartbeat.php?from=doorbell";
unsigned long previousMillis  = 0;
unsigned long currentMillis   = 0;
int interval = 300000; // in ms. eg: 300000 = 300secs = 5mins

void setup () {
  // Set up IO
  pinMode(pinDoorbellLed, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW); // Turn the LED on

  // Connect to WiFi
  Serial.begin(115200);

  Serial.println("DOORBELL");
  Serial.println("LAST UPDATED: " + lastUpdate + "\n");

  Serial.print("Connecting");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected! IP: ");
  Serial.println(WiFi.localIP());
  WiFi.printDiag(Serial);
  digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off
  Serial.println("");
  Serial.println("Waiting for doorbell...");
}

void loop() {

  // If for some reason we're not on the WiFi, reboot!
  if (WiFi.status() != WL_CONNECTED) {
    resetFunc(); //call reset
  }

  // If the doorbell is pressed, its LED turns on, and triggers this:
  if (digitalRead(pinDoorbellLed) == 1) {
    digitalWrite(LED_BUILTIN, LOW); // Turn the LED on
    Serial.println("DING DONG!");

    HTTPClient http;
    http.begin(urlDoorbell);
    http.GET();
    Serial.println("Notification sent to: " + urlDoorbell);
    http.end();

    digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off
    Serial.println("Waiting for 15 seconds...");
    delay(15000); // This is to allow the doorbell chime to sound, and to also debounce the button!
    Serial.println("");
    Serial.println("Waiting for doorbell...");
  }

  // This is the heartbeat stuff:
  currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    digitalWrite(LED_BUILTIN, LOW); // Turn the LED on
    HTTPClient http;
    http.begin(urlHeartbeat);
    http.GET();
    Serial.println("Heartbeat sent to: " + urlHeartbeat);
    http.end();
    previousMillis = currentMillis;
    digitalWrite(LED_BUILTIN, HIGH); // Turn the LED on
  }
}


 

 

 

 

 

ESP8266 as an Access Point

I wanted to create a simple switch that can be turned on and off via my phone.

Normally, you’d do this by connecting the device and the phone to the same WiFi network, but because I didn’t have access to a WiFi network, I had to work out a way to connect directly to the device from my phone.

It turns out you can connect directly to the Wemos D1 Mini by making it into an Soft Access Point. This means that up to 5 devices can connect to it, as if it’s a WiFi Access Point. You can then run a webserver on it, and us that to turn on and off any GPIO as needed.

Here is the code I used, it could be improved upon, but it works:

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

#define redLedPin D4 // This LED goes from D4 to GND - good for controlling a relay, etc...
#define greenLedPin D8 // This LED goes from 3.3v to D8 (so D8 acts as GND)

const char *ssid = "MarcusESP8266-1";
//const char *password = "password";

String webPage = "";
String colourOn = "#08dd5a";
String colourOff = "#c41e0b";
String bgColour = colourOff;

ESP8266WebServer server(80);

/*Go to http://192.168.4.1 in a web browser to connect */

void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println("Configuring access point...");
  /* You can remove the password parameter if you want the AP to be open */
  //WiFi.softAP(ssid, password);
  WiFi.softAP(ssid);

  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);

  pinMode(greenLedPin, OUTPUT);
  digitalWrite(greenLedPin, 1);

  pinMode(redLedPin, OUTPUT);
  digitalWrite(redLedPin, 0);

  server.on("/", []() {
    webPage = "";
    webPage += "<!DOCTYPE HTML>";
    webPage += "<html>";
    webPage += "<head>";
    webPage += "<title>Wifi Switch</title><style>body{font-family:Verdana, sans-serif;font-size:22px;text-align:center;background:" + bgColour + ";} button{font-size: 22px; margin: 20px; padding: 20px;}</style><meta name='viewport' content='width=device-width, initial-scale=1'>";
    webPage += "</head>";
    webPage += "<body>";
    webPage += "<h1>Wifi Switch</h1>";
    webPage += "<p><a href=\"on\"><button>ON</button></a></p>";
    webPage += "<p><a href=\"off\"><button>OFF</button></p>";
    webPage += "<p><a href=\"toggle\"><button>TOGGLE</button></p>";
    webPage += "</body>";
    webPage += "</html>";
    server.send(200, "text/html", webPage);
  });
  server.on("/on", []() {
    digitalWrite(redLedPin, 1);
    digitalWrite(greenLedPin, 0);
    bgColour = colourOn;
    Serial.println("ON");
    server.sendHeader("Location", "/");
    server.send(303);
  });
  server.on("/off", []() {
    digitalWrite(redLedPin, 0);
    digitalWrite(greenLedPin, 1);
    bgColour = colourOff;
    Serial.println("OFF");
    server.sendHeader("Location", "/");
    server.send(303);
  });
  server.on("/toggle", []() {
    digitalWrite(redLedPin, !digitalRead(redLedPin));
    digitalWrite(greenLedPin, !digitalRead(greenLedPin));
    if (digitalRead(redLedPin)) {
      bgColour = colourOn;
    } else {
      bgColour = colourOff;
    }
    server.sendHeader("Location", "/");
    server.send(303);
  });
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  server.handleClient();
}

 

RFID with MFRC522 and Arduino

I bought an RFID reader/writer and a couple of tags from eBay for $1.98.

To test it all out, I created a simple project that reads a tag’s ID, compares it to a known ID, and grants or denies access.

  • If the card is recognised, the green LED lights up
  • If the card is not recognised, the red LED lights up

These behaviours could easily be changed to turn a motor to unlock a door, or whatever.

 

Here’s the code:

/*
 MFRC522 - Uno
     RST - Pin 9
      SS - Pin 10
    MOSI - Pin 11
    MISO - Pin 12
     SCK - Pin 13
     GND - GND
    3.3v - 3.3v

 Buzzer: Pin 5, then Resistor to GND
 Red LED: Pin 6, then Resistor to GND
 Greed LED: Pin 7, then Resistor to GND
*/

#include <SPI.h>
#include <MFRC522.h>

#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN);
#define buzzer 5
#define ledRed 6
#define ledGreen 7

void setup() {
 Serial.begin(9600);
 SPI.begin();
 mfrc522.PCD_Init();

 pinMode(ledRed, OUTPUT);
 pinMode(ledGreen, OUTPUT);

 Serial.println("Waiting for card...");
 Serial.println();
}

void loop() {
 // Turn LEDs off
 digitalWrite(ledGreen, LOW);
 digitalWrite(ledRed, LOW);

 // Look for new cards, if no cards found then restart the loop
 if ( ! mfrc522.PICC_IsNewCardPresent()) {
  return;
 }

 // Select one of the found cards, if no cards found then restart the loop
 if ( ! mfrc522.PICC_ReadCardSerial()) {
  return;
 }

 //Show UID of the card on serial monitor
 Serial.print("UID tag :");
 String content = "";
 byte letter;
 for (byte i = 0; i < mfrc522.uid.size; i++) {
  Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
  Serial.print(mfrc522.uid.uidByte[i], HEX);
  content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
  content.concat(String(mfrc522.uid.uidByte[i], HEX));
 }
 Serial.println();
 content.toUpperCase();

 if (content.substring(1) == "F3 CB 81 2A") { //change here the UID of the card/cards that you want to give access
  accessGranted();
 } else {
  accessDenied();
 }
}

void accessGranted() {
 Serial.println("Access Granted");
 Serial.println();
 digitalWrite(ledGreen, HIGH);
 tone(buzzer, 1000);
 delay(200);
 tone(buzzer, 1600);
 delay(300);
 noTone(buzzer);
 delay(500);
}

void accessDenied() {
 Serial.println("Access Denied");
 Serial.println();
 digitalWrite(ledRed, HIGH);
 tone(buzzer, 1600);
 delay(200);
 tone(buzzer, 1000);
 delay(300);
 noTone(buzzer);
 delay(500);
}