Jonathan Xu
Published © GPL3+

Smart Home Electrical Distribution for Floods

This hack is a proof of concept that shuts off power only to the level of the house that has been flooded, allowing for normal use elsewhere

IntermediateFull instructions provided5 hours4,425
Smart Home Electrical Distribution for Floods

Things used in this project

Hardware components

NodeMCU ESP8266 Breakout Board
NodeMCU ESP8266 Breakout Board
×1
Extension Cord
There's one per floor, representing the electrical grid of each floor of the house. In this case I'm assuming 3 floors in the house. Make sure the two cables inside are separable.
×3
Water Sensor
×3
Relay Module
The one I used is a 4 channel relay module as it's cheaper than buying 3 single channel modules.
×1
Small Plastic Box
Any box will do, as it's just to house the project.
×1
Micro-USB to USB Cable (Generic)
Micro-USB to USB Cable (Generic)
To power the ESP8266
×1
Jumper wires (generic)
Jumper wires (generic)
×1

Software apps and online services

Arduino Web Editor
Arduino Web Editor
FileZilla
000Webhost
Just used as a host and server, feel free to use your own service.
Freenom
Used to get a free.tk domain for a year, feel free to use your own service.

Story

Read more

Schematics

Wiring Schematic for Control Module

Connect the parts as shown using jumper cables. This setup is made for 3 floors but can be customized.

Code

Arduino code for ESP8266

Arduino
This is the code for the ESP module, to be pasted in the Arduino IDE and uploaded to the board. Replace every CHANGE_THIS label, in order, with your domain name, wifi name, wifi password, and domain name respectively (there are 4 labels to be changed).
#include <ESP8266WiFi.h>
//Pin declarations
int s1pin = 15;
int s2pin = 14;
int s3pin = 16;
int r1pin = 5;
int r2pin = 4;
int r3pin = 0;
//Sensor variable declarations
int sensor1, sensor2, sensor3;
int sen1prev = 0, sen2prev = 0, sen3prev = 0;
//Networking vars
const char server[] = "CHANGE_THIS";
const char* MY_SSID = "CHANGE_THIS";
const char* MY_PWD =  "CHANGE_THIS";
WiFiClient client;
void setup() {
 Serial.begin(9600);
 //Pin setup
 pinMode(s1pin, INPUT);
 pinMode(s2pin, INPUT);
 pinMode(s3pin, INPUT);
 pinMode(r1pin, OUTPUT);
 pinMode(r2pin, OUTPUT);
 pinMode(r3pin, OUTPUT);
 digitalWrite(r1pin, HIGH);
 digitalWrite(r2pin, HIGH);
 digitalWrite(r3pin, HIGH);
 //Connecting to wifi
 Serial.print("Connecting to " + *MY_SSID);
 WiFi.begin(MY_SSID, MY_PWD);
 Serial.println("going into wl connect");
 while (WiFi.status() != WL_CONNECTED) { //not connected,  ...waiting to connect
   delay(1000);
   Serial.print(".");
 }
 Serial.println("wl connected");
 Serial.println("");
 Serial.println("Credentials accepted! Connected to wifi\n ");
 Serial.println("");
}
void loop() {
 delay(500);
 //Collect data
 sensor1 = digitalRead(s1pin) == HIGH;
 sensor2 = digitalRead(s2pin) == HIGH;
 sensor3 = digitalRead(s3pin) == HIGH;
 //Serial output
 Serial.print("Sensor 1: ");
 Serial.print(sensor1);
 Serial.print("     Sensor 2: ");
 Serial.print(sensor2);
 Serial.print("     Sensor 3: ");
 Serial.println(sensor3);
 //Relay control
 if (sensor1 == 1) {
   digitalWrite(r1pin, LOW);
 } else {
   digitalWrite(r1pin, HIGH);
 }
 if (sensor2 == 1) {
   digitalWrite(r2pin, LOW);
 } else {
   digitalWrite(r2pin, HIGH);
 }
 if (sensor3 == 1) {
   digitalWrite(r3pin, LOW);
 } else {
   digitalWrite(r3pin, HIGH);
 }
 //Sensor state changed
 if ((sensor1 != sen1prev) || (sensor2 != sen2prev) || (sensor3 != sen3prev)) {
   Serial.println("Something changed!");
   sen1prev = sensor1;
   sen2prev = sensor2;
   sen3prev = sensor3;
   //Connect to server
   Serial.println("\nStarting connection to server...");
   if (client.connect(server, 80)) {
     Serial.println("Connected to server");
     //POST request
     String data = "Floor1="
                   + (String) sensor1
                   + "&Floor2="  + (String) sensor2
                   + "&Floor3=" + (String) sensor3;
     client.println("POST /dataCollector.php HTTP/1.1");
     client.println("Host: CHANGE_THIS");                 //change this if using your Domain
     client.println("User-Agent: ESP8266/1.0");
     client.println("Connection: close");
     client.println("Content-Type: application/x-www-form-urlencoded");
     client.print("Content-Length: ");
     client.print(data.length());
     client.print("\n\n");
     client.print(data);
     //Output debug to serial
     Serial.println("\n");
     Serial.println("My data string im POSTing looks like this: ");
     Serial.println(data);
     Serial.println("And it is this many bytes: ");
     Serial.println(data.length());
     //Server confirmation, uncomment if you'd like to see the collector's response
     /*
     Serial.println("Server Resopnse:");
     Serial.println("--------------------");
     while (client.connected()) {
       if (client.available()) {
         String line = client.readStringUntil('\n');
         Serial.println(line);
       }
     }
     Serial.println("--------------------");
     */
   } else {                                        //If not connected to a server
     Serial.println("Connection failure");
     client.stop();
   }
 } else {                                          //If nothing changed
   Serial.println("Nothing changed.");
 }
}

dataCollector.php

PHP
The code for the dataCollector.php file. There are 4 CHANGE_THIS variables. Replace them with the DB Host, DB User, DB password, and DB Name. For 000webhost you can find them in your Manage Databases page. You can customize the timezone and variables for the # of floors.
<?php
  //Timestamp creation
   date_default_timezone_set("America/Toronto");
   $timeStamp = date("Y-m-d H:i:s");

  //If data is sent in from ESP
  if(isset($_REQUEST["Floor1"]) && isset($_REQUEST["Floor2"]) && isset($_REQUEST["Floor3"])){
    //Variable declarations
    $floor1 = $_REQUEST["Floor1"];
    $floor2 = $_REQUEST["Floor2"];
    $floor3 = $_REQUEST["Floor3"];

    echo "Timestamp: " . $timeStamp . "%<br>";
    echo "Floor 1: " . $floor1 . "%<br>";
    echo "Floor 2: " . $floor2 . "%<br>";
    echo "Floor 3: " . $floor3 . "%<br>";

    //Connect to MySQL
    $con = mysqli_connect("CHANGE_THIS", "CHANGE_THIS", "CHANGE_THIS")
     or die('Could not connect: ' . mysqli_error());

    $db_select = mysqli_select_db($con, "CHANGE_THIS") or die
    ("Database selection failed: " . mysqli_error());

     //Tells script to stop executing if articles aren't booleans
     if ( !(is_numeric($floor1) && is_numeric($floor1) && is_numeric($floor1)) ){
         die('invalid article id');
     }

    //Write request
    $sql = "
    INSERT INTO `data` (`datetime`, `floor1`, `floor2`, `floor3`) VALUES ('$timeStamp', '$floor1', '$floor2', '$floor3');
     ";

     if ($con->query($sql) === TRUE) {
         echo "New record created successfully";
     } else {
         echo "Error: " . $sql . "<br>" . $conn->error;
     }
  } else {
    echo "Nothing sent or not all parameters met";
  }
?>

index.php

PHP
This is the code for index.php, the landing page of your domain. There are 4 CHANGE_THIS variables. Replace them with the DB Host, DB User, DB password, and DB Name. For 000webhost you can find them in your Manage Databases page. Code is customizable to accommodate # of floors.

Edit- It's messy code but it gets the job done :')
<html>
  <head>
    <title>HydroSafe Water Detection</title>
  <style type="text/css">
    body {
      background: linear-gradient(141deg, #0fb8ad 0%, #1fc8db 51%, #2cb5e8 75%);
    }

    h1 {
    font-family: Century Gothic, CenturyGothic, AppleGothic, sans-serif;
    font-size: 70px;
    font-weight: 500;
    text-align: center;
    color: #F9F9F9;
    }

  h2 {
    color: #333;
    font-size: 20px;
    font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
    }

  h3 {
    font-family: Candara,Calibri,Segoe,Segoe UI,Optima,Arial,sans-serif;
    text-align: center;
    font-size: 30px;
    color: #ffffff;
  }

  p {
    font-size: 35px;
    font-family: Georgia, "Times New Roman", Times, serif;
    color: #DEDEDE;
    padding-left: 50px;
    padding-right: 50px;
    line-height: 200%;
  }

  #translation1 {
    font-size: 35px;
    font-family: Georgia, "Times New Roman", Times, serif;
    color: #DEDEDE;
    padding-left: 50px;
    padding-right: 50px;
    line-height: 200%;
  }

  #translation2 {
    font-size: 35px;
    font-family: Georgia, "Times New Roman", Times, serif;
    color: #DEDEDE;
    padding-left: 50px;
    padding-right: 50px;
    line-height: 200%;
  }

  #translation3 {
    font-size: 35px;
    font-family: Georgia, "Times New Roman", Times, serif;
    color: #DEDEDE;
    padding-left: 50px;
    padding-right: 50px;
    line-height: 200%;
  }

  </style>

  </head>
  <body>
  <center><img src="https://i.imgur.com/HumUAOA.png" width = "30%"></center>
    <?php
      //Connect to MySQL
      $con = mysqli_connect("CHANGE_THIS", "CHANGE_THIS", "CHANGE_THIS")
       or die('Could not connect: ' . mysqli_error());

      $db_select = mysqli_select_db($con, "CHANGE_THIS") or die
      ("Database selection failed: " . mysqli_error());

      //Store table in array
      $query = "SELECT * FROM `data` ORDER BY `data`.`datetime` ASC ";
      $result = mysqli_query($con, $query);
      $data = array();
      while($row = mysqli_fetch_assoc($result) ){
        $data[]= $row;
      }
      mysqli_free_result($result);

      //Create arrays for each column
      $datetime = array();
      $floor1 = array();
      $floor2 = array();
      $floor3 = array();
      foreach ($data as $row) {
        $phpdate = strtotime( $row['datetime'] );//Make datetime legible
        $datetime[] = $phpdate;
        $floor1[] = $row['floor1'];
        $floor2[] = $row['floor2'];
        $floor3[] = $row['floor3'];
      }
    ?>
    <h1>Water Detection Status</h1>

    <p>Timestamp: <?php echo date( 'Y-m-d H:i:s', end($datetime) ); ?></p>

    <p>Floor 1:</p> 
    <div id ="translation1"><?php echo end($floor1);?></div>
    <br>

    <p>Floor 2:</p> 
    <div id ="translation2"><?php echo end($floor2);?></div>
    <br>

    <p>Floor 3:</p> 
    <div id ="translation3"><?php echo end($floor3);?></div>
    <br>


  <script type="text/javascript">

      if (document.getElementById("translation1").innerHTML == 0) {
      document.getElementById("translation1").innerHTML = "Dry";
      }
      
      else if (document.getElementById("translation1").innerHTML == 1) {
        document.getElementById("translation1").innerHTML = "Flooded";
      }

      if (document.getElementById("translation2").innerHTML == 0) {
        document.getElementById("translation2").innerHTML = "Dry";
      }
      
      else if (document.getElementById("translation2").innerHTML == 1) {
        document.getElementById("translation2").innerHTML = "Flooded";
      }

      if (document.getElementById("translation3").innerHTML == 0) {
        document.getElementById("translation3").innerHTML = "Dry";
      }
      
      if (document.getElementById("translation3").innerHTML == 1) {
        document.getElementById("translation3").innerHTML = "Flooded";
      }

  </script>

  </body>
</html>

Credits

Jonathan Xu

Jonathan Xu

7 projects • 16 followers
Hardware enthusiast who's good at shorting out Arduinos. @ University of Waterloo Software Engineering 2024
Thanks to Henry Liu.

Comments