JSMSolns
Published © GPL3+

Garden Watering System with Alexa Control

Watering control system with Alexa integration for lazy gardeners (like me!) using Arduino WEMOS and 12volt solenoid valve

IntermediateFull instructions provided4 hours1,354
Garden Watering System with Alexa Control

Things used in this project

Hardware components

Wemos D1 Mini
Espressif Wemos D1 Mini
Wemos D1 Mini
×1
LM2596 DC-DC Module (Adjustable)
×1
SparkFun Motor Driver - Dual TB6612FNG (with Headers)
SparkFun Motor Driver - Dual TB6612FNG (with Headers)
×1
Valve 12v Solenoid 1/2"BSP
×1
12v PSU (sufficient current to drive solenoid)
×1

Story

Read more

Schematics

Irrigation Valve Schematic

Code

IrrigationSolenoid_NoMQTT

Arduino
Main program
#include "MotorDrive.h"
#include "credentials.h"

#include <Arduino.h>
#include <ESP8266WiFi.h>
//#include <PubSubClient.h>

#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

#include <WiFiClient.h>
//

//
//
////#define DEBUG_FAUXMO Serial
//


#include <fauxmoESP.h>

extern void reconnect();
extern bool ShutValveOff(bool TimedOut);
extern bool OpenValveUp();

const char* ssid = WIFI_SSID;
const char* password = WIFI_PASS;

struct AlexaAction {
  bool Active;
  int  AlexaIndex;
  bool AlexaState;
}AlexaStatus;

const int device_count = 1;

const char* wemo_devicenames[] = {
  ALEXA_TAG,  //remote 1
};



//WiFiClient espClient;
//PubSubClient client(espClient);

// Pins for all inputs, keep in mind the PWM defines must be on PWM pins
// the default pins listed are the ones used on the Redbot (ROB-12097) with
// the exception of STBY which the Redbot controls with a physical switch
#define STBY D4
#define AIN1 D3
#define AIN2 D2
#define PWMA D1
#define SWIP D7

#define IS_CLOSED false
#define IS_OPEN true
#define CLOSEVALVE false
#define OPENVALVE true


Motor Valve = Motor(AIN1,AIN2,PWMA,STBY,SWIP);
char receivedChar;
fauxmoESP fauxmo;
time_t LastRestartDateTime = 0;
//time_t LastCommandDateTime = 0;

int LastCommand = 0;
bool LastState;
unsigned long ValveOpenedAt = 0;

const char* mqttTopicIrrigationValveControl = "home/automation/Irrigation/ValveSetting";   // MQTT topic  for turning on/off
const char* mqttTopicIrrigationValveStatus = "home/automation/Irrigation/ValveStatus";   // MQTT topic for inidcating open/close
const char* mqttTopicIrrigationValveErrorStatus = "home/automation/Irrigation/ValveErrorStatus";   // MQTT topic for inidcating  fault status

//WiFiServer TelnetServer(8266);




//******************************************** MQTT handling ******************************************


/*
void UpdateMQTTStatus(const char* InMess){

   char Mess[50];

   strncpy(Mess,InMess,49);
   Mess[49] = '\0';
   
   Serial.print("Updating MQTT status");  
   if (!client.connected()) {
       reconnect();
   }
   client.publish(mqttTopicIrrigationValveStatus, Mess,true);
   Serial.print("Sent MQTT setting = : ");  
   Serial.println(Mess); 

}
*/

/*
void UpdateMQTTErrorStatus(const char* InMess){

   char Mess[50];

   strncpy(Mess,InMess,49);
   Mess[49] = '\0';
   
   Serial.print("Updating MQTT error status");  
   if (!client.connected()) {
       reconnect();
   }

   client.publish(mqttTopicIrrigationValveErrorStatus, Mess,true);
   Serial.print("Sent MQTT setting = : ");  
   Serial.println(Mess); 

}
*/

/*
void mqttcallback(char* topic, byte* payload, unsigned int length) 
{
   
   char l_payload[100];
   char* ptr;
   const char* SettingTopic = "ValveSetting";
   bool ret;
   
   Serial.print("Message arrived in topic: ");
   Serial.println(topic);
   
   int angle = 0;
   
   Serial.print("Payload:");
   for (int i = 0; i < length; i++) {
     l_payload[i]= (char)payload[i];
     Serial.print((char)payload[i]);
   }
   l_payload[length] = '\0';
   
   ptr = strstr((char *)topic,SettingTopic);

   if (ptr)
   {
     
     if (l_payload[0] == '0')
     {
        ShutValveOff(false);
          
     }
     if (l_payload[0] == '1')
     {
         OpenValveUp();
    
     }
   }
}
*/

/*
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    // If you do not want to use a username and password, change next line to
    // if (client.connect("ESP8266Client")) {

    if (client.connect(mqtt_Name, mqtt_user, mqtt_password)) {
      client.setCallback(mqttcallback); 
      //client.subscribe(mqttCommandBlindSeting);   
      client.subscribe(mqttTopicIrrigationValveControl);
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 3 seconds");
      // Wait 5 seconds before retrying
      delay(3000);
    }
  }
}
*/


void ActionAlexa(int index, bool state) {

  bool confirm;
  
  //LastCommandDateTime = now();
  LastCommand = index;
  LastState = state;
  
  
  //Serial.printf("Button: %d, State: %s\n", index, state ? "ON" : "OFF");

  switch (index) {


    case 1:  //open/close valve
      if (state == OPENVALVE) {
        OpenValveUp();
      }
      else {
        ShutValveOff(false);
      }

  }
}

bool ShutValveOff(bool TimedOut)
{
     bool ret;
     
     ret = Valve.CloseValve();
     if (ret == true)
     {
        /*
        UpdateMQTTStatus("0");
        if (TimedOut)
        {
            UpdateMQTTErrorStatus("CLOSED - Timeout shut off");
        }
        else
        {
            UpdateMQTTErrorStatus("CLOSED");
        }
        */
        fauxmo.setState( (unsigned char) 0, IS_CLOSED,  (unsigned char) 255);
     }
     return(ret); 
}

bool OpenValveUp()
{
       bool ret;
       
       ret = Valve.OpenValve();
       if (ret == true)
       {
          //UpdateMQTTStatus("1");
          //UpdateMQTTErrorStatus("OPEN");
          fauxmo.setState((unsigned char) 0,IS_OPEN , (unsigned char) 255);
       }
       return(ret); 
}  

void setup()
{
   bool ret;

   Serial.begin(115200);
   delay(1000);
   Serial.println("Booting...");
  
   Valve.CloseValve();
   
  //TelnetServer.begin();
   

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");
    delay(10000);
    ESP.restart();
  } 

  Serial.println("WiFi connected");

  ArduinoOTA.setHostname("IrrigationValve");

    ArduinoOTA.onStart([]() {
    Serial.println("OTA Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("OTA End");
    Serial.println("Rebooting...");
    Serial.flush();
    ESP.restart();
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r\n", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

   AlexaStatus.Active = false;
   

   if (ret == true){   
      Serial.println("Valve closed");
   }
   else
   {
      Serial.println("Fault: Valve stuck open!!!");
   }

   fauxmo.createServer(true);
   fauxmo.setPort(80);
   fauxmo.enable(true);
   for (int i = 0; i < device_count; i++) {
    Serial.printf("Adding device: %s\n", wemo_devicenames[i]);
    fauxmo.addDevice(wemo_devicenames[i]);
  }

  fauxmo.onSetState([](unsigned char device_id, const char * device_name, bool state, unsigned char value) {
     Serial.printf("[MAIN] Device #%d (%s) state: %s value: %d\n", device_id, device_name, state ? "OPEN" : "CLOSED", value);
        //Serial.printf("[MAIN] Device #%d (%s) state: %s\n", device_id, device_name, state ? "OPEN" : "CLOSED");
        //digitalWrite(LED, !state);
         int j;
         j= device_id;
         if (j < device_count)
         {
            //ActionEnergenie(j+1, state);
            if (AlexaStatus.Active == false){
               AlexaStatus.AlexaIndex = j+1;
               AlexaStatus.AlexaState = state;
               AlexaStatus.Active = true;
            }
         }
    });

//    // Callback to retrieve current state (for GetBinaryState queries)
//    fauxmo.onGetState([](unsigned char device_id, const char * device_name) {
//       return(CurrentValveState);  //may need to change this to 0 and 1???
//    });

  /*
   client.setServer(mqtt_server, mqtt_port);
   client.setCallback(mqttcallback);
   
   if (!client.connected()){
     reconnect();
   }
   */

   ShutValveOff(false);
   ValveOpenedAt = 0;

   //UpdateMQTTErrorStatus("RESET");


   delay(500);
      
   //client.subscribe(mqttTopicIrrigationValveControl);

 
   
  
}


void loop()
{
   bool ret;
   
   ArduinoOTA.handle();

   fauxmo.handle();

  if (AlexaStatus.Active == true) {
     Serial.print("Alexa:");
     Serial.println(AlexaStatus.AlexaState);
     ActionAlexa(AlexaStatus.AlexaIndex, AlexaStatus.AlexaState);
     AlexaStatus.Active = false;
    
  }

  //Serial.println("Pre-client.loop");
 // client.loop();
  //Serial.println("Post-client.loop");
  /*
  if (!client.connected())
  {
     reconnect();
  }
  */
  if (Valve.IsOpen() && ValveOpenedAt != 0)
  {
        if ((((millis() - ValveOpenedAt) /1000.0)/60.0) >= MAXONTIME_MINS)
        {
           ShutValveOff(true);
           ValveOpenedAt = 0;
        }
  }
  if (Valve.IsOpen() && ValveOpenedAt == 0)
  {

     ValveOpenedAt = millis();  //precautionary!
  }


   
}

MotorDrive

C Header File
Not really motor drive - more solenoid drive.
In-program library for controlling the solenoid valve via the TB6612FNG motor driver module
#include <Arduino.h>

#define VALVECLOSED HIGH  //switch shorted when open (LOW) and o/c when valve closed (pulled HIGH)
#define VALVEOPENED LOW
#define OPENCLOSEWAITTIME_ms 15000

extern bool CurrentValveState;
extern unsigned long ValveOpenedAt;

class Motor
{
  
  
  public:
    // Constructor. Mainly sets up pins.
    Motor(int In1pin, int In2pin,  int PWMpin, int STBYpin, int Sensorpin);      


  bool OpenValve();
	bool CloseValve();
	
	bool IsOpen();
	bool IsClosed();
	
  private:
    //variables for the 1 inputs, PWM input
	int In1,In2,  PWM, Standby, Sensor;
  bool ValveIsOpen = false;

	
	//private functions that spin the motor CC and CCW
	void CCW();
  void CW();
  void HiImp();
  void stop();          



};


Motor::Motor(int In1pin, int In2pin,  int PWMpin, int STBYpin, int Sensorpin)
{
  In1 = In1pin;
  In2 = In2pin;
  PWM = PWMpin;
  Standby = STBYpin;
  //Offset = offset;
  
  Sensor = Sensorpin;
  
  pinMode(In1, OUTPUT);
  pinMode(In2, OUTPUT);
  pinMode(PWM, OUTPUT);
  pinMode(Standby, OUTPUT);
  
  stop();
  HiImp();
  
}


void Motor::HiImp()
{
  digitalWrite(Standby, LOW);
}

void Motor::stop()
{
	digitalWrite(Standby, HIGH);
  digitalWrite(In1, LOW);
  digitalWrite(In1, LOW);
	digitalWrite(PWM, HIGH);
}


bool Motor::IsOpen()
{
   return(ValveIsOpen);
}

bool Motor::IsClosed()
{
   return(!ValveIsOpen);
}

void Motor::CCW()
{
   digitalWrite(Standby, HIGH);
   digitalWrite(In1, LOW);
   digitalWrite(In2, HIGH);
   digitalWrite(PWM, HIGH);

}

void Motor::CW()
{
   digitalWrite(Standby, HIGH);
   digitalWrite(In1, HIGH);
   digitalWrite(In2, LOW);
   digitalWrite(PWM, HIGH);

}

bool Motor::CloseValve()
{
	 stop();
   HiImp();
   ValveIsOpen = false;
   return(true);
}

bool Motor::OpenValve()
{



  ValveOpenedAt = millis();
  CCW();
  ValveIsOpen = true;
  return(true);
	
}

credentials

C Header File
Wifi settings + other key defines
#define WIFI_SSID "YourWiFiSSID"
#define WIFI_PASS "**********"  //Your Wifi password

#define MAXONTIME_MINS 8
#define ALEXA_TAG "watering system"

#define mqtt_server "192.168.0.31"
#define mqtt_port 1883
#define mqtt_user "YourMQTTusername"
#define mqtt_password "**********"  //Your MQTT password
#define mqtt_Name "ESPIrrigationValve"

fauxmoESP

Library for Alexa integration by Xose Perez. Please read the notes and dependencies carefully to avoid compatibility issues.

Credits

JSMSolns
12 projects • 36 followers
Contact

Comments

Please log in or sign up to comment.