Project in progress
Wise Shower Driven by Alexa Skill

Wise Shower Driven by Alexa Skill © GPL3+

This Alexa-controlled device aims to save water by planning the time and amount of water to use in each shower.

  • 2,740 views
  • 1 comment
  • 4 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)
Hy gluegun
Hot glue gun (generic)

Apps and online services

About this project

Step 1

Since a few months ago I have been developing a shower-type device that avoids the great waste of drinking water that many people do every day when take a bath, this waste is due to the incredible abuse that means bathing consuming 5, 10 or more liters of water per minute in a shower at high pressure, this waste is also given by the clean water that is left to run to the drain because it is not hot enough before take a shower. If we live in a modern city we take for granted drinking water in our house by pipe and forget that millions of people suffer to obtain a minimum quantity of clean water to survive, sometimes they have to settle for unsafe water to drink, cook or clean themselves .

Step 3

A few days ago I learned that Cape Town in South Africa suffers from a critical shortage of water due to drought and has asked residents to restrict consumption to 50 liters per person per day, it is expected that if weather conditions do not change in April 2018 the city it will run out of water and millions of people from a large urban center will face an uncertain destination without access to water. What is happening in Cape Town is the reflection of the future of cities in the world ?, I do not know, in any case this project aims to offer a new perspective to the way we bathe, rationalizing the water and time spent to this important activity.

Step 4

When I came to this challenge I did not know much about Alexa, so learning about this technology was very challenging, in addition to my English speaking level is not very good, thanks to Amazon Developer's online resources, online forums and YouTube videos get enough knowledge in a short time to make this prototype of what I call "Wise Shower" .

No doubt being able to control devices with the voice opens many opportunities to people with mobility problems, since they can take a bath independently, that in itself offers a justification to this project.

In the technical aspect build this device is not very complicated, the parts are easy to get and are very cheap, that it involves working with voltage of 110 V for what you have to be very careful and seek the help of a professional in the subject to install an electric shower safely, for me the most difficult part was to understand the Alexa technology and the whole development environment but once I reached a basic level of knowledge I was able to build the prototype.

Step 5

There is nothing I can say about Alexa and how to develop Skills, AWS IOT, Lambda, there is a multitude of references on the Internet and in Amazon Developers site. In my video I put links to other videos on YouTube that were fundamental to develop this project.

I insist that the explanation video I think I give all the necessary information on how to build this prototype but if you have any questions I will gladly answer as best I can.

Code

ESP8266 CODEArduino
MQTT, WEBSOCKET, you have to flash your esp8266 with this code
/*
Prototipo de Alexa Wise Shower
Code by Virgilio Aray Arteaga
February 2018
This skecht is an adaptation of the original code that can be found at the following address
https://github.com/odelot/aws-mqtt-websockets
*/
//-----------------------------------------------
#include <Arduino.h>
#include <Stream.h>

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>

//AWS
#include "sha256.h"
#include "Utils.h"

//WEBSockets
#include <Hash.h>
#include <WebSocketsClient.h>

//MQTT PAHO
#include <SPI.h>
#include <IPStack.h>
#include <Countdown.h>
#include <MQTTClient.h>

//AWS MQTT Websocket
#include "Client.h"
#include "AWSWebSocketClient.h"
#include "CircularByteBuffer.h"

//AWS IOT config, change these:
char wifi_ssid[]       = "your network";
char wifi_password[]   = "your wifi password";
char aws_endpoint[]    = "?????????.iot.us-east-1.amazonaws.com";
char aws_key[]         = "???????????";    // your IAM credentials
char aws_secret[]      = "??????????????????";   // your IAM credentials
char aws_region[]      = "us-east-1";
char* aws_topic        = "$aws/things/ducha/shadow/update";
int port = 443;

//MQTT config
//---------------------------------------//
const int maxMQTTpackageSize = 1024;     //  VERY IMPORTANT
//---------------------------------------//
const int maxMQTTMessageHandlers = 4;    //  VERY IMPORTANT  
//---------------------------------------//

ESP8266WiFiMulti WiFiMulti;

AWSWebSocketClient awsWSclient(1000);

IPStack ipstack(awsWSclient);
MQTT::Client<IPStack, Countdown, maxMQTTpackageSize, maxMQTTMessageHandlers> *client = NULL;

//# of connections
long connection = 0;
//generate random mqtt clientID
char* generateClientID () {
  char* cID = new char[23]();
  for (int i=0; i<22; i+=1)
    cID[i]=(char)random(1, 256);
  return cID;
}
//count messages arrived
int arrivedcount = 0;
char buf[500];
int ParImpar=1;
int OnOff=1;
String Respuesta ;
//
// Here the response of the AWS IOT
// 
//callback to handle mqtt messages
//
//
void messageArrived(MQTT::MessageData& md)
{
  MQTT::Message &message = md.message;
/*
  //Serial.print("Message ");
  //Serial.print(++arrivedcount);
  //Serial.print(" arrived: qos ");
  //Serial.print(message.qos);
  //Serial.print(", retained ");
  //Serial.print(message.retained);
  //Serial.print(", dup ");
  //Serial.print(message.dup);
  //Serial.print(", packetid ");
  //Serial.println(message.id);
  //Serial.print("Payload ");
*/  
  char* msg = new char[message.payloadlen+1]();
  memcpy (msg,message.payload,message.payloadlen);
//  //Serial.println(msg);
  Respuesta=msg;  // "REspuesta" is a global var will be contain the paiload from aws iot
  delete msg;
}
//
//
//

//connects to websocket layer and mqtt layer
bool connect () {

    if (client == NULL) {
      client = new MQTT::Client<IPStack, Countdown, maxMQTTpackageSize, maxMQTTMessageHandlers>(ipstack);
    } else {

      if (client->isConnected ()) {    
        client->disconnect ();
      }  
      delete client;
      client = new MQTT::Client<IPStack, Countdown, maxMQTTpackageSize, maxMQTTMessageHandlers>(ipstack);
    }


    //delay is not necessary... it just help us to get a "trustful" heap space value
    delay (1000);
    //Serial.print (millis ());
    //Serial.print (" - conn: ");
    //Serial.print (++connection);
    //Serial.print (" - (");
    //Serial.print (ESP.getFreeHeap ());
    //Serial.println (")");

   int rc = ipstack.connect(aws_endpoint, port);
    if (rc != 1)
    {
      //Serial.println("error connection to the websocket server");
      return false;
    } else {
      //Serial.println("websocket layer connected");
    }
    //Serial.println("MQTT connecting");
    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.MQTTVersion = 3;
    char* clientID = generateClientID ();
    data.clientID.cstring = clientID;
    rc = client->connect(data);
    delete[] clientID;
    if (rc != 0)
    {
      //Serial.print("error connection to MQTT server");
      //Serial.println(rc);
      return false;
    }
    //Serial.println("MQTT connected");
    return true;
}

//subscribe to a mqtt topic
void subscribe () {
   //subscript to a topic
    int rc = client->subscribe(aws_topic, MQTT::QOS0, messageArrived);
    if (rc != 0) {
      //Serial.print("rc from MQTT subscribe is ");
      //Serial.println(rc);
      return;
    }
    //Serial.println("MQTT subscribed");
}

//send a message to a mqtt topic
void sendmessage () {
    //send a message
    MQTT::Message message;
    //char buf[100];
    //strcpy(buf, "{\"state\":{\"reported\":{\"on\": false}, \"desired\":{\"on\": false}}}");
    //strcpy(buf, "{\"state\":{\"reported\":{\"interruptor\":\"on\"}}}");
    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf)+1;
    int rc = client->publish(aws_topic, message); 
    //Serial.println(rc);
}


void setup() {
    //
    //  Serial To comunicate with arduino mega
    //
    Serial.begin (19200,SERIAL_8N1);
    ////delay (20000);
    ////Serial.setDebugOutput(1);

    //fill with ssid and wifi password
    WiFiMulti.addAP(wifi_ssid, wifi_password);
    //Serial.println ("connecting to wifi");
    while(WiFiMulti.run() != WL_CONNECTED) {
        delay(100);
        //Serial.print (".");
    }
    //Serial.println ("\nconnected");

    //fill AWS parameters    
    awsWSclient.setAWSRegion(aws_region);
    awsWSclient.setAWSDomain(aws_endpoint);
    awsWSclient.setAWSKeyID(aws_key);
    awsWSclient.setAWSSecretKey(aws_secret);
    awsWSclient.setUseSSL(true);

    Respuesta = "nothing" ;// this global var will be contain the paiload from aws iot
    
    //Serial.println ("marca 1");

    if (connect ()){
          //Serial.println ("marca 2");

      aws_topic  = "$aws/things/ducha/shadow/get/accepted";
      subscribe ();
      aws_topic  = "$aws/things/ducha/shadow/update";
      subscribe ();
    }
    //Serial.println ("marca 3");

}

void loop() {
  //
  // the "esp8266" will be consulted by mqtt the status of the "thing", 
  // when the "delta" section appears it means that there is an instruction 
  // in the data that will be sent to the MEGA
  //
  //
  //keep the mqtt up and running
  if (awsWSclient.connected ()) {    
      client->yield();
  } else {
    //handle reconnection
    if (connect ()){
      aws_topic  = "$aws/things/ducha/shadow/get/accepted";
      subscribe ();
      aws_topic  = "$aws/things/ducha/shadow/update";
      subscribe ();
    }
  }
  //
  //  THIS IS FOR QUERY AND SET THE THINGS SHADOW  
  //
  aws_topic  = "$aws/things/ducha/shadow/get";
  strcpy(buf, "{}");  // dont need sent any parameter  or payload
  sendmessage ();
  //
  // wait for anwser, now its posible that variable "Respuesta" got the paidload
  //
  String valorcomando   = "nochange";
  String valorminutos   = "5" ; 
  String valorlitros    = "5" ; 
  String valorcalentador= "off" ; 
  String sPaidLoad      = "{}";
  String valortap       = "off";
  //
  if (Respuesta.indexOf("delta")>0) {    // got a valid message from aws iot
                                         // when "delta" is present meaning have to change "reported"
      valorcomando=RetornaValor("desired","ducha");
      //Serial.println(valorcomando);
      if (valorcomando=="\"setup\"") {
        valorminutos   =RetornaValor("desired","time"); 
        valorlitros    =RetornaValor("desired","water"); 
        valorcalentador=RetornaValor("desired","heater"); 
        // Send parameters to ARDUINO MEGA
        Serial.println(valorcomando+","+valorminutos+","+valorlitros+","+valorcalentador+",off");
        // Update reported value
        sPaidLoad="{\"state\":{\"reported\":{\"ducha\":"+valorcomando+",\"time\":"+valorminutos+",\"water\":"+valorlitros+",\"heater\":"+valorcalentador+"}}}";
      }
      if (valorcomando=="\"runing\"") {  // open o close the water
        valortap       =RetornaValor("desired","tap");
        valorcalentador=RetornaValor("desired","heater"); 
        Serial.println(valorcomando+",0,0,"+valorcalentador+","+valortap);
        sPaidLoad="{\"state\":{\"reported\":{\"ducha\":"+valorcomando+",\"heater\":"+valorcalentador+",\"tap\":"+valortap+"}}}";
      }
      if (valorcomando=="\"finished\"") {
        valorminutos   =RetornaValor("desired","time"); 
        valorlitros    =RetornaValor("desired","water"); 
        valorcalentador=RetornaValor("desired","heater"); 
        valortap       =RetornaValor("desired","tap"); 
        Serial.println(valorcomando+","+valorminutos+","+valorlitros+","+"off"+","+"off");
        // Update reported value
        sPaidLoad="{\"state\":{\"reported\":{\"ducha\":"+valorcomando+",\"time\":"+valorminutos+",\"water\":"+valorlitros+",\"heater\":\"off\",\"tap\":\"off\"}}}";
      }
      if (sPaidLoad!="{}") {
        const char *buf1 = sPaidLoad.c_str();                   
        strcpy(buf,buf1);
        //Serial.println(buf);
        aws_topic  = "$aws/things/ducha/shadow/update";
        sendmessage ();  // send message to update de "reported" value
      }
  }
  //
  delay(500);
  //
 }
//
//----------
//
 String RetornaValor(String seccion, String dato) {
  /* 
   * "Respuesta" is a global variable that has the "Payload" sent by AWS in the "topic"
   * format of the response from aws:
   * Payload {"state":{"desired":{"ducha":"setup","time":"10",},"reported":{"time":"15"},"delta":{"time":"10"}}}
   * It has three sections (seccion): "desired", "reported", "delta"
   * Solo me interesa obtener el valor de un dato de una seccion en especial
   * "section" can be "desired" or "reported" or "delta"
   * "dato" can be "ducha", "time", "water", "heater", "tap" or "switch" or anything
   * 
   */
  String StrRetorno ;
  int iIndex1=0;
  int iIndex2=0;
  int iIndex3=0;
  iIndex1=Respuesta.indexOf(seccion);           // posicion  de "desired" en payload
  iIndex2=Respuesta.indexOf("}",iIndex1);       // posicion del primer "}" despues de la seccion
  StrRetorno=Respuesta.substring(iIndex1,iIndex2);  // la seccion que me intersa ej -> {"desired":{"light":"on","interruptor":"on"}
  iIndex1=StrRetorno.indexOf(dato);             // posicion del dato que me intersa
  iIndex2=StrRetorno.indexOf(",",iIndex1);
  iIndex3=StrRetorno.indexOf("}",iIndex1);
  if (iIndex2==-1 && iIndex2>iIndex3){
     StrRetorno=StrRetorno.substring(iIndex1,iIndex3);     //  el dato que me intersa ej -> "interruptor":"on"
  }
  else
  {
     StrRetorno=StrRetorno.substring(iIndex1,iIndex2);     //  el dato que me intersa ej -> "interruptor":"on"
  }
  StrRetorno.replace(dato+"\":"," ");  // elimino [interruptor":] me quedo solo con el valor ->  "on"
  StrRetorno.trim();             // elimino espacios en blanco, me quedo solo con el valor -> "on" 
  return StrRetorno;  // retorna algo como "on" o "off" o "12" o "30"
 }
ARDUINO MEGA CODEArduino
You have to load this code in your Arduino Mega
/*
Prototipo de Alexa Wise Shower
Code by Virgilio Aray Arteaga
February 2018

This sketch reads the instructions it receives through serial communication from the ESP8266
but also receives instructions from the touch screen.

Manage the devices that make up the WiseShower:

- electric water heater by relay
- Water valve by relay
- water flow meter
- temperature sensor
*/
//-----------------------------------------------
//Required libraries
#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Time.h>
//-----------------------------------------------
//Assignment of digital pins
#define FLUJO_AGUA      20 // Water flow Sensor YF-S201 
#define VALVULA1        37 // Relay SOLENOID WATER VALVE (12 V) (Relay)
#define CALENTADOR      47 // Relay Water Heater Rele           
#define SEN_TEMPERATURA 31 // TEMPERATURE SENSOR DS18B20
//------------------------------------------------  
// Touch Screen stuff
#include <Elegoo_GFX.h>    // Core graphics library
#include <Elegoo_TFTLCD.h> // Hardware-specific library
#include <TouchScreen.h>
//
#define LCD_CS A3 
#define LCD_CD A2 
#define LCD_WR A1 
#define LCD_RD A0 
#define LCD_RESET A4 
//
#define TS_MINX 115 // 204
#define TS_MINY 115 // 195
#define TS_MAXX 950 // 948
#define TS_MAXY 920 // 910
//
#define YP A2  // must be an analog pin, use "An" notation!
#define XM A3  // must be an analog pin, use "An" notation!
#define YM 8   // can be a digital pin
#define XP 9   // can be a digital pin
//
#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF
//
Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 700);
//  End of touch screen stuff
//---------------------------------------------------
//To measure water flow with sensor YF-S201
volatile long NumPulsos;
void ContarPulsos()
{
  NumPulsos++;
}
//
// Instancia a las clases OneWire y DallasTemperature
OneWire oneWireObjeto(SEN_TEMPERATURA);
DallasTemperature sensorDS18B20(&oneWireObjeto);
//----------------------------------------------------
// Global variables
int SegAnt  = 0;
int NumMenu = 1;  // Menu Level
//
int Minutos = 10; // Default time
int Litros  = 20; // Default liters of water
int Grados  = 40; // Default tempo 
int Calentador = 2; // 0 water heater off, 1 water heater on, 2 water header automatic
String HeaterMode = "OFF";
String FechaAct = "";
String HoraAct  = "";
String sMensaje = "          " ;
//  
//
int RespuestaDucha = 0;
float SegundoInicio= 0.00;
float LitrosUsados = 0.00;
float MinutosUsados = 0.00;
char ComandoDucha = '*';
char ComandoDuchaAnt = '*';
float TempActual=0.00;
const float TempHeaterOff=40.00;
const float TempHeaterOn=35.00;
//----------------------------------------------------
void setup() {
  //
  // -Setup pins
  //
  pinMode(SEN_TEMPERATURA,INPUT); // Temperature sensor
  pinMode(FLUJO_AGUA,INPUT);      // flujo de agua
  pinMode(VALVULA1,OUTPUT);       // relay valvula 1
  pinMode(CALENTADOR,OUTPUT);     // realy heater
  //
  //
  digitalWrite(VALVULA1,HIGH); 
  digitalWrite(CALENTADOR,HIGH);    
  //
  // Initialize Serial Port "1" to communicate with ESP8266
  //
  Serial.begin(19200);   // Comm with IDE
  Serial1.begin(19200);  // Comm with ESP8266
  //
  // InicializE TFT Screen
  //
  tft.reset();
  tft.begin(0x9341);  // direccion
  tft.setRotation(3);   // valores 0 1 2 3
  // Welcome Message on tft
  // ---
  PantallaInicio();  // Welcome Screen
  //
  //  Se requiere la fecha y hora Consulta cada segundo
  //
  // Temporal
  int anio = 1970;
  int mes = 01;
  int dia = 01;
  int hora = 00;
  int minuto = 00;
  int segundo = 00;
  setTime(hora,minuto,segundo,dia,mes,anio);
  //
  //--------------------------------
  // bus 1-Wire  temperature sensor
  sensorDS18B20.begin(); // Temperature  
  //--------------------------------
  // water flow control
  attachInterrupt(digitalPinToInterrupt(FLUJO_AGUA),ContarPulsos,RISING);  // flow meter
  interrupts();
  //-----------------------------------
  //
  //
}

void loop(){


  if (Serial1.available()) {
     //
     // Read info from ESP8266 device
     //
     pinMode(XM, OUTPUT);  // Very Important because
     pinMode(YP, OUTPUT);  // Touch screen change this pins
     //     
     sMensaje = "";
     while (Serial1.available()) {
        sMensaje += (char)Serial1.read();
        //Serial.print((char)Serial1.read());
     }
     Serial.println(sMensaje);
     DivideComando(sMensaje);
     /*FechaAct = sMensaje.substring(0,8);
     HoraAct  = sMensaje.substring(8,14);
     Minutos = sMensaje.substring(14,16).toInt();
     Litros  = sMensaje.substring(16,18).toInt();
     Grados  = sMensaje.substring(18,20).toInt();
     //buttonEnabled = false;
     */
     pinMode(XM, OUTPUT);
     pinMode(YP, OUTPUT);
     //EmpezarDucha();
     //NumMenu=3;
     //
     //
     //
  }  
  //
  // Check if the screen was touched
  //
  TSPoint p = ts.getPoint();  //Get touch point
  //
  //
  if (p.z > ts.pressureThreshhold) {   // User touch the screen
   //
   p.x = map(p.x, TS_MAXX, TS_MINX, 0, 320);  // x coordinate 
   p.y = map(p.y, TS_MAXY, TS_MINY, 0, 240);  // y coordinate
   //This is important, because the libraries are sharing pins
   pinMode(XM, OUTPUT);
   pinMode(YP, OUTPUT);
   //
   //  based on the menu each area of the screen has a function
   //
   switch (NumMenu) {
   case 1:  // firt level menu --> Welcome Screen
     //
     // 
     //
     if(p.x>60 && p.x<260 && p.y>180 && p.y<220)// The user has pressed inside the red rectangle
     {
       PantallaParametros(0); // show parameters
       NumMenu=2;             // go to next level menu
     }
     break;
   case 2: // Second level menu --> change parameters 
     //
     //  Parameters screen
     //  user can change parameter or confirm then
     //
     if (p.x>60 && p.x<260 && p.y>190 && p.y<230)  // user has pressed inside the WHITE rectangle
     {
       EmpezarDucha();    // Open Tap
       NumMenu=3;         // Menu Level 3
     }
     //
     //  Use can touch te up / down arrows to change parameters
     //
     else {
        if (p.x>14 && p.x<3140 && p.y>13 && p.y<190){
           ActualizaParametros(p.x,p.y);
           PantallaParametros(1);
        }
     }     
     break;
   case 3:  // Water is runing  (tap open)
      // 
      //
      // When water is runing
      //
      // Touch Red zone to stop shower and return to level 1 menu
      //
      if (p.x>210 && p.x<210+95 && p.y>95 && p.y<110+110){
         CloseWaterTap();
         PantallaInicio();
         NumMenu=1;         // Menu Level 1         
         break;
      }
      //
      //  touch Yellow zone to hold (close tap)
      //
      if (p.x>110 && p.x<110+95 && p.y>95 && p.y<110+110){
         CloseWaterTap();
         break;
      }
      //
      // Touch Green zone to reopen water tap
      //
      if (p.x>10 && p.x<10+95 && p.y>95 && p.y<110+110){
         OpenWaterTap();
         break;
      }        
      //
      //
      //
      break;
   }
  }
  //
  if (NumMenu==3) {
     ShowStatus() ; // shows the time and liters used at the moment
  }
  //
  delay(100); 
   
}
//
// ----------------------------------------------------------
//
void PantallaInicio()  // Welcome Screen
{
  tft.reset();          // reset screen 
  tft.begin(0x9341);    // direccion of device
  tft.setRotation(3);   // valores 0 1 2 3  
  tft.fillScreen(BLACK);
  //
  tft.drawRect(0,0,319,239,WHITE);  //Draw white frame
  tft.drawRect(2,2,315,235,BLUE);  
  tft.drawRect(4,4,310,230,RED);  
  //
  tft.setCursor(30,30);
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.print("Aray Innovations LLC");
  tft.setCursor(30,50);
  tft.setTextSize(1);
  tft.print("Virgilio Enrique Aray Arteaga");
  tft.setCursor(30,70);
  tft.setTextSize(0);
  tft.print("February 2018");  
  //
  tft.setCursor(20,100);
  tft.setTextColor(RED);
  tft.setTextSize(4);
  tft.print("Wise Shower");
  tft.setCursor(20,140);
  tft.print("Alexa driven");
  //
  //  Zone to touch to start
  //
  tft.fillRect(60,180, 200, 40, RED);
  tft.drawRect(60,180,200,40,WHITE);
  tft.setCursor(88,190);
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.print("<<<<START>>>>");
  //
  NumMenu=1;
  //
}
//
// ----------------------------------------------------------
//
void EmpezarDucha() {   // Screen to show minutes and liters used
     NumMenu==3;
     pinMode(XM, OUTPUT);
     pinMode(YP, OUTPUT);
     tft.fillScreen(BLUE);  

     tft.drawRect(1,10,318,32,WHITE);
     tft.drawRect(1,41,318,33,WHITE);
     tft.drawRect(1,73,318,33,WHITE);
     
     tft.drawRect(1,10,106,96,WHITE);
     tft.drawRect(1,10,212,96,WHITE);

      
     tft.setTextColor(WHITE);
     tft.setTextSize(2);
    
     tft.setCursor(4,14);
     tft.print("Minutes");
     tft.setCursor(110,14);
     tft.print("Liters");
     tft.setCursor(216,14);
     tft.print("Heater");
     tft.setCursor(34,50);
     tft.print(Minutos);
     tft.setCursor(140,50);
     tft.print(Litros);
     tft.setCursor(230,50);
     HeaterMode = "OFF";
     if (Calentador==1) HeaterMode = "ON";
     if (Calentador==2) HeaterMode = "AUTO";
     tft.print(HeaterMode);
     tft.fillRect(10,110,95,110,GREEN);
     tft.fillRect(110,110,95,110,YELLOW);
     tft.fillRect(210,110,95,110,RED);
     //
     //  Reset values
     //
     NumPulsos     = 0.0; 
     LitrosUsados  = 0.00;
     MinutosUsados = 0.00;
     TempActual    = 0.00;  
     SegundoInicio = millis() ;  // Point of start to count time
     //
     //
     //
     OpenWaterTap();  // Open the water tap and heater if is necesary
     //
     //
     //
}
//
//
//To show the number of liters and time used
void ShowStatus()
{
   int Min = 0;
   int Seg = 0;
   float SegundoActual = millis();
   float Calculo = 0.00;
   MinutosUsados = ((millis()-SegundoInicio)/1000)/60;
   Min=MinutosUsados;
   Calculo=(MinutosUsados-Min)*100;
   Seg=Calculo*60/100;
   LitrosUsados = (float)NumPulsos/450;
   sensorDS18B20.requestTemperatures();
   //TempActual = sensorDS18B20.getTempFByIndex(0);     //FAHRENHEIT
   TempActual = sensorDS18B20.getTempCByIndex(0);       //CELSIUS
   if (Seg!=SegAnt) {
     pinMode(XM, OUTPUT);
     pinMode(YP, OUTPUT);
     tft.fillRect(34,85,60,20,BLUE);
     tft.fillRect(140,85,60,20,BLUE);
     tft.fillRect(246,85,60,20,BLUE);
     tft.setTextColor(WHITE);
     tft.setTextSize(2);
     tft.setCursor(34,85);
     tft.print(Min);
     tft.print(":");
     tft.print(Seg);
     tft.setCursor(140,85);
     tft.print(LitrosUsados);
     tft.setCursor(246,85);
     tft.print(TempActual);
     SegAnt = Seg;
   }
   
   if (Calentador==2) CheckTemp(); // Heater mode Automatic
   if (MinutosUsados >= Minutos) {
      CloseWaterTap();
      PantallaInicio();
   }
   if (LitrosUsados >= Litros) {
      CloseWaterTap();
      PantallaInicio();
   }
}
//
//
//
void MensajeFB(String sMensaje) {   // To show message in the bottom of touch screen
     tft.fillRect(1,221,318,19,BLUE); 
     tft.drawRect(1,221,318,19,WHITE);
     tft.setTextColor(WHITE);
     tft.setTextSize(2);
     tft.setCursor(4,223);
     tft.print(sMensaje);
}
//
//
//
void ActualizaParametros(int x, int y){
    if (x>14  && x<104 && y>13  && y<61)  Minutos++;
    if (x>114 && x<214 && y>13  && y<61)  Litros++;
    if (x>214 && x<314 && y>13  && y<61)  Calentador++;
    if (x>14  && x<104 && y>113 && y<190) Minutos--;
    if (x>114 && x<214 && y>113 && y<190) Litros--;
    if (x>214 && x<314 && y>113 && y<190) Calentador--;
    if (Minutos<1) Minutos=1;
    if (Litros<1) Litros=1;
    if (Calentador<0) Calentador = 2;
    if (Minutos>30) Minutos=30;
    if (Litros>30) Litros=30;
    if (Calentador>2) Calentador = 0;
}

void PantallaParametros(int Flag) {

    if (Flag==0) { 
      //Erase the screen
      tft.fillScreen(BLUE);
      
      //Draw frame
      //tft.fillRect(0,0,320,240,BLUE);
      tft.setCursor(50,50);
      tft.setTextColor(WHITE);
      tft.setTextSize(2);
  
      tft.drawRect(0,0,160,120,YELLOW);    
      tft.drawRect(160,120,160,120,YELLOW);    
      //
      // Parametros
      //
      BotonUpoDn((14+45),(61-48),"+");
      BotonUpoDn((14+45),(61+47+75),"-");
      BotonUpoDn((114+45),(61-48),"+");
      BotonUpoDn((114+45),(61+47+75),"-");
      BotonUpoDn((214+45),(61-48),"+");
      BotonUpoDn((214+45),(61+47+75),"-");
      BotonStart(60,190,"Open the Tap");
    }
    
    CajaIndicador(13,61,"Minutes",Minutos,Flag);
    CajaIndicador(114,61,"Liters",Litros,Flag);
    CajaIndicador(214,61,"Heater",Grados,Flag);
      
}

void BotonStart(int x, int y, String mensaje){
  tft.fillRect(x, y,200,40, WHITE);
  tft.drawRect(x, y,200,40,RED);
  tft.setCursor(x+22,y+10);
  tft.setTextColor(RED);
  tft.setTextSize(2);
  tft.print(mensaje);  
}  

void CajaIndicador (int x, int y, String mensaje, int valor, int Flag){
    if (Flag==0){
    tft.fillRect(x,y,90,75,RED);
    tft.drawRect(x,y,90,75,WHITE);
    tft.setCursor(x+5,y+5);
    tft.setTextColor(WHITE);
    tft.setTextSize(2);
    tft.print(mensaje);    

    }
    else
    {
    tft.fillRect(x+2,y+30,85,35,RED);
    }
    tft.setTextSize(5);
    tft.setCursor(x+30,y+30);
    tft.setTextColor(WHITE);
    if (mensaje!="Heater") {
       tft.print(valor);     
    } else {
       HeaterMode = "OFF";
       if (Calentador==1) HeaterMode = "ON";
       if (Calentador==2) HeaterMode = "AUT";
       tft.setCursor(x+2,y+30);
       tft.print(HeaterMode); 
    }
}


void BotonUpoDn(int x, int y, String uod) {
    int numero = 45;
    if (uod=="+") 
    {
      numero = 45;
    }
    else
    { 
      numero= -45;
    }
    tft.fillTriangle(x,y,(x-numero),(y+numero),(x+numero),(y+numero),WHITE);
    tft.drawTriangle(x,y,(x-numero),(y+numero),(x+numero),(y+numero),RED);
    if (uod=="+")
    {
       tft.setCursor(x-7,y+15);
    }
    else
    {
       tft.setCursor(x-7,y-30);
    }
    tft.setTextColor(RED);
    tft.setTextSize(3);
    tft.print(uod);    
}
//
//
//
void CloseWaterTap(){
     MensajeFB("Green to open, Red finished");         
     TurnOffValve();
     TurnOffHeater();
}
//
//
//
void OpenWaterTap(){
     MensajeFB("Yellow to hold, Red finished");         
     TurnOnValve();
     if (Calentador==1) TurnOnHeater();  // user request heater on
     if (Calentador==2) CheckTemp();    // Heater mode Automatic
}
//
//
//
void TurnOnValve()
{
  digitalWrite(VALVULA1,LOW); 
}
//
//
//
void TurnOffValve()
{
  digitalWrite(VALVULA1,HIGH); 
  digitalWrite(CALENTADOR,HIGH); 
}
//
//
//
void TurnOnHeater()
{
  digitalWrite(CALENTADOR,LOW); 
}
//
//
//
void TurnOffHeater()
{
  digitalWrite(CALENTADOR,HIGH); 
}
//
//
//
void CheckTemp() {
   //Heater mode Automatic
   if (TempActual>=TempHeaterOff) TurnOffHeater(); // 
   if (TempActual<=TempHeaterOn)  TurnOnHeater(); // 
   //
}
//
//----------
//
void DivideComando(String StrDato) {
  /* 
   */
  int iIndex1 = 0;
  StrDato.replace("\"","");                   // the quotes are taken out
  
  iIndex1=StrDato.indexOf(",");    
  String StrCmd=StrDato.substring(0,iIndex1); // Command 
  StrDato=StrDato.substring(iIndex1+1);         // 
  
  iIndex1=StrDato.indexOf(",");   
  String StrMin=StrDato.substring(0,iIndex1); // Minutes
  StrDato=StrDato.substring(iIndex1+1);         // 
  
  iIndex1=StrDato.indexOf(",");   
  String StrLit=StrDato.substring(0,iIndex1); // Liters 
  StrDato=StrDato.substring(iIndex1+1);         // 
  
  iIndex1=StrDato.indexOf(",");   
  String StrHea=StrDato.substring(0,iIndex1); // Heater
  StrDato=StrDato.substring(iIndex1+1);         // 
  
  iIndex1=StrDato.indexOf(",");   
  String StrTap=StrDato.substring(0,iIndex1); // Tap
  //
  StrCmd.trim();
  StrMin.trim();
  StrLit.trim();
  StrHea.trim();
  StrTap.trim();
  //
  /*Serial.print(StrCmd);
  Serial.print(StrMin);
  Serial.print(StrLit);
  Serial.print(StrHea);
  Serial.print(StrTap);*/
  if (StrCmd=="setup") {
    Minutos    = StrMin.toInt();
    Litros     = StrLit.toInt();
    if (StrHea =="off")  Calentador = 0;
    if (StrHea =="on")   Calentador = 1;
    if (StrHea =="auto") Calentador = 2;
    int DrawFlag = (NumMenu - 1);
    PantallaParametros(DrawFlag);                // show parameters   
    NumMenu=2;
  }
  //
  if (StrCmd=="runing") {
    Serial.println("Tap "+StrTap);
    Serial.print("NumMenu ");
    Serial.println(NumMenu);
    if (StrHea =="on")   Calentador = 1;
    if (StrHea =="off")  Calentador = 0;
    if (StrTap =="on")   
    {
       Serial.print("NumMenu ");
       Serial.println(NumMenu);      
       if (NumMenu<3) {
          EmpezarDucha();
       } 
       else
       {
          OpenWaterTap();
       }
       NumMenu=3;
    }
    if (StrTap =="off") 
    {
       if (NumMenu<3) EmpezarDucha();
       CloseWaterTap();
       NumMenu=3;
    }
  }
  if (StrCmd=="finished") 
  {
    CloseWaterTap();
    PantallaInicio();    
    NumMenu=1;    
  }
  
}
Alexa Skill Kit codeJSON
{
  "languageModel": {
    "types": [
      {
        "name": "heater",
        "values": [
          {
            "id": null,
            "name": {
              "value": "off",
              "synonyms": []
            }
          },
          {
            "id": null,
            "name": {
              "value": "auto",
              "synonyms": []
            }
          },
          {
            "id": null,
            "name": {
              "value": "on",
              "synonyms": []
            }
          }
        ]
      }
    ],
    "intents": [
      {
        "name": "AMAZON.CancelIntent",
        "samples": []
      },
      {
        "name": "AMAZON.HelpIntent",
        "samples": []
      },
      {
        "name": "AMAZON.StopIntent",
        "samples": []
      },
      {
        "name": "closethetap",
        "samples": [
          "close the tap"
        ],
        "slots": []
      },
      {
        "name": "finishshower",
        "samples": [
          "I have finished",
          "I have finished tanks",
          "i finished showering"
        ],
        "slots": []
      },
      {
        "name": "openthetap",
        "samples": [
          "Open the tap"
        ],
        "slots": []
      },
      {
        "name": "setupshower",
        "samples": [
          "I'm going to take a shower of {timeinminutes} minutes {waterinliters} liters with the heater {HeaterMode}",
          "i need a shower",
          "I want a shower",
          "shower",
          "{timeinminutes} minutes shower",
          "i want take a shower",
          "I want a shower of {timeinminutes} minutes {waterinliters} liters with the heater {HeaterMode}"
        ],
        "slots": [
          {
            "name": "timeinminutes",
            "type": "AMAZON.NUMBER",
            "samples": [
              "{timeinminutes} minutes",
              "{timeinminutes}",
              "about {timeinminutes}"
            ]
          },
          {
            "name": "waterinliters",
            "type": "AMAZON.NUMBER",
            "samples": [
              "{timeinminutes} minutes {waterinliters} liters heater {HeaterMode}",
              "{waterinliters} liters"
            ]
          },
          {
            "name": "HeaterMode",
            "type": "heater",
            "samples": [
              "{HeaterMode}"
            ]
          }
        ]
      },
      {
        "name": "turnoffheater",
        "samples": [
          "Turn off the heater",
          "heater off"
        ],
        "slots": []
      },
      {
        "name": "turnonheater",
        "samples": [
          "Turn on the water heater",
          "Heater on"
        ],
        "slots": []
      }
    ],
    "invocationName": "wiseshower"
  },
  "prompts": [
    {
      "id": "Confirm.Intent-setupshower",
      "variations": [
        {
          "type": "PlainText",
          "value": "Well so you want a shower of {timeinminutes} minutes with a maximun use de {waterinliters} liters of water and heater in {HeaterMode}, right?"
        }
      ]
    },
    {
      "id": "Elicit.Intent-setupshower.IntentSlot-timeinminutes",
      "variations": [
        {
          "type": "PlainText",
          "value": "How long?"
        },
        {
          "type": "PlainText",
          "value": "How many minutes?"
        }
      ]
    },
    {
      "id": "Confirm.Intent-setupshower.IntentSlot-timeinminutes",
      "variations": [
        {
          "type": "PlainText",
          "value": "{timeinminutes} minutes, ok?"
        }
      ]
    },
    {
      "id": "Elicit.Intent-setupshower.IntentSlot-waterinliters",
      "variations": [
        {
          "type": "PlainText",
          "value": "How many liters?"
        }
      ]
    },
    {
      "id": "Confirm.Intent-setupshower.IntentSlot-waterinliters",
      "variations": [
        {
          "type": "PlainText",
          "value": "{waterinliters} liters of water, ok?"
        }
      ]
    },
    {
      "id": "Elicit.Intent-setupshower.IntentSlot-HeaterMode",
      "variations": [
        {
          "type": "PlainText",
          "value": "How about the water heater?"
        },
        {
          "type": "PlainText",
          "value": "Heater on, off or auto?"
        }
      ]
    },
    {
      "id": "Confirm.Intent-setupshower.IntentSlot-HeaterMode",
      "variations": [
        {
          "type": "PlainText",
          "value": "Water heater {HeaterMode}, right?"
        }
      ]
    }
  ],
  "dialog": {
    "intents": [
      {
        "name": "setupshower",
        "confirmationRequired": true,
        "prompts": {
          "confirmation": "Confirm.Intent-setupshower"
        },
        "slots": [
          {
            "name": "timeinminutes",
            "type": "AMAZON.NUMBER",
            "elicitationRequired": true,
            "confirmationRequired": true,
            "prompts": {
              "elicitation": "Elicit.Intent-setupshower.IntentSlot-timeinminutes",
              "confirmation": "Confirm.Intent-setupshower.IntentSlot-timeinminutes"
            }
          },
          {
            "name": "waterinliters",
            "type": "AMAZON.NUMBER",
            "elicitationRequired": true,
            "confirmationRequired": true,
            "prompts": {
              "elicitation": "Elicit.Intent-setupshower.IntentSlot-waterinliters",
              "confirmation": "Confirm.Intent-setupshower.IntentSlot-waterinliters"
            }
          },
          {
            "name": "HeaterMode",
            "type": "heater",
            "elicitationRequired": true,
            "confirmationRequired": true,
            "prompts": {
              "elicitation": "Elicit.Intent-setupshower.IntentSlot-HeaterMode",
              "confirmation": "Confirm.Intent-setupshower.IntentSlot-HeaterMode"
            }
          }
        ]
      }
    ]
  }
}
LambdaJSON
Funtion to access to the AWS IOT
No preview (download only).

Schematics

ALEXA WISE SHOWER
Schematic
Alexawiseshower bb mmjxoxtrx1
Schematic Fritzing.org
Schematic Fritzing.org
alexawiseshower_YUaSta10HB.fzz

Comments

Similar projects you might like

Smart Pool: Alexa Controlled Pool Manager

Project tutorial by Benjamin Winiarski

  • 1,360 views
  • 2 comments
  • 7 respects

Alexa BBQ/Kitchen Thermometer with IoT Arduino and e-Paper

Project tutorial by Roger Theriault

  • 2,387 views
  • 0 comments
  • 9 respects

Alexa Based Smart Home Monitoring

Project tutorial by Adithya TG

  • 16,681 views
  • 19 comments
  • 47 respects

Secure Package Delivery Trunk for Your Front Porch

Project tutorial by Team Castle Locker

  • 2,515 views
  • 1 comment
  • 15 respects

Intelligent Door Lock

Project in progress by Md. Khairul Alam

  • 15,983 views
  • 19 comments
  • 95 respects

Alexa Doorman: Who Is at My Door?

Project tutorial by MD R. Islam

  • 9,151 views
  • 0 comments
  • 25 respects
Add projectSign up / Login