Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
| ||||||
| ||||||
| ||||||
| ||||||
Hand tools and fabrication machines | ||||||
| ||||||
|
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 .
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 4When 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 5There 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.
/*
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"
}
/*
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;
}
}
{
"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"
}
}
]
}
]
}
}
Lambda
JSONNo preview (download only).
Comments