StrudelMitch
Published © GPL3+

MEGR 3171 - Saltwater Pump Monitor

Monitor and control the constant supply of nutrient rich salt water to ensure the health of expensive live bait fish.

IntermediateFull instructions provided3 hours771
MEGR 3171 - Saltwater Pump Monitor

Things used in this project

Hardware components

Photon
Particle Photon
×2
Seeed Studio Water Pressure Sensor
×1
General Purpose Dual Op-Amp
Texas Instruments General Purpose Dual Op-Amp
×1
Resistor 100 ohm
Resistor 100 ohm
×1
LED (generic)
LED (generic)
×8
Capacitor 100 µF
Capacitor 100 µF
×1
RGB Diffused Common Cathode
RGB Diffused Common Cathode
×1
Slide Switch
Slide Switch
×1

Software apps and online services

ThingSpeak API
ThingSpeak API
Mobicle
ControlEverything.com Mobicle
Maker service
IFTTT Maker service

Story

Read more

Schematics

Pump_pressure_module

Schematic for the Pressure monitoring module

Code

Pump_pressure

C/C++
Monitor pump pressure
//Including Libraries for OLED 
#include <SparkFunMicroOLED.h>
#include <math.h>

#define publish_delay 600000//Delay between Thingspeak publish events (ms)
unsigned int lastPublish = 599750;//Initial publish time, set so user reset pushes most recent pressure reading
/*  Include the SparkFunMicroOLED library 

Hardware Connections:
  This sketch was written specifically for the Photon Micro OLED Shield, which does all the wiring for you. If you have a Micro OLED breakout, use the following hardware setup:

    MicroOLED ------------- Photon
      GND ------------------- GND
      VDD ------------------- 3.3V (VCC)
    D1/MOSI ----------------- A5 (don't change)
    D0/SCK ------------------ A3 (don't change)
      D2
      D/C ------------------- D6 (can be any digital pin)
      RST ------------------- D7 (can be any digital pin)
      CS  ------------------- A2 (can be any digital pin)
*/
int tinkerDigitalRead(String pin);
int tinkerDigitalWrite(String command);
int tinkerAnalogRead(String pin);
int tinkerAnalogWrite(String command);

// -------------------------------------------
// Publish and Subscribe with Pressure Sensors
/* -------------------------------------------
Built from "Publish and Subscribe with Photoresistors" project example downloaded from Particle

Go find a buddy who also has a Particle device.
Each of you will pick a unique event name
   (make it weird so that no one else will have it)
   (no more that 63 ASCII characters, and no spaces)

In the following code, replace "pump_pressure" with your chosen name.
Replace "pump_control" with your buddy's chosen name.

Have your buddy do the same on his or her IDE.

Then, each of you should flash the code to your device.

Breaking the threshold pressure on one device will turn on the RGB LED on the second device.

But how does this magic work? Through the miracle of publish and subscribe.

We are going to Particle.publish a public event to the cloud.
That means that everyone can see you event and anyone can subscribe to it.
You and your buddy will both publish an event, and listen for each others events.

------------------------------------------*/


int led_red = D0; // RED LED Pin D0
int led_green = D1;//Green LED Pin D1
int led_blue = D2;//Blue LED Pin D2
int led_pump = D5;//Pump status indicator White LED Pin D5
//int boardLed = D7;//Board LED Pin D7
int pressure = A0;// Pressure sensor input
int power = A1;//Pressure Sensor Voltage(+) Pin

int normalValue;//Set a variable to call later
int highValue;//Set a variable to call later
int lowValue;//Set a variable to call later
int highThreshold;//Set a variable to call later
int lowThreshold;//Set a variable to call later

bool presHigh = true;//Set initial condition for pump pressure (normal)

MicroOLED oled;// Establish the OLED Display


void setup() {

  pinMode(led_green,OUTPUT);// Our LED pins are output (lighting up the LEDs)
  pinMode(led_blue,OUTPUT);//Our LED pins are output (lighting up the LEDs)
  pinMode(led_red,OUTPUT);
  pinMode(led_pump,OUTPUT);//Our LED pins are output (lighting up the LEDs)
 // pinMode(boardLed,OUTPUT); // Our on-board LED is output as well
  pinMode(pressure,INPUT);  // Our pressure sensor pin is input (reading the pressure sensor)
  //pinMode(power,INPUT); // The pin powering the pressure sensor is output (sending out consistent power)(notused)
  digitalWrite(led_green,HIGH);// Turn on status light (Green)
  digitalWrite(led_red,HIGH);// Ensure other LED is off
  digitalWrite(led_blue,HIGH);// Ensure other LED is off
  // Here we are going to subscribe to the pump control station event using Particle.subscribe
  // Subscribe will listen for the event Turn_pump_off and, when it finds it, will run the function myHandler()
      Particle.subscribe("Pump_control", myHandler);
  // myHandler() is declared later in this app.
  // Next, write the power of the photoresistor to be the maximum possible, which is 4095 in analog.(notused)
  oled.begin();    // Initialize the OLED display
  oled.clear(ALL); // Clear the display's internal memory
  oled.display();  // Display what's in the buffer (splashscreen)
  delay(250);     // Delay 250 ms
  oled.clear(PAGE); // Clear the buffer.
  randomSeed(analogRead(A0)); 
  
  	Particle.function("digitalread", tinkerDigitalRead);
	Particle.function("digitalwrite", tinkerDigitalWrite);
	Particle.function("analogread", tinkerAnalogRead);
	Particle.function("analogwrite", tinkerAnalogWrite);

// Pressure Sensor calibration. 
  normalValue = 385;//Measure pump pressure under normal operating conditions set the normal value 
  highValue = 450;//Measure pump pressure under abnormal operating conditions set the high value 
  lowValue = 300;//Measure pump pressure under abnormal operating conditions set the low value 
  highThreshold = (normalValue+highValue)/2;// Calculate a threshold for alert trigger
  lowThreshold = (normalValue+lowValue)/2;// Calculate a threshold for alert trigger
}
void loop() {
      if (Particle.connected() == false) {
  Particle.connect();
}
     gaugeDisplay();
     delay(30000); //Delay alerts until pressure is normalized.
  // This loop sends a publish when the pressure is high.
  if (analogRead(pressure)<highThreshold&&analogRead(pressure)>lowThreshold) {// System must meet both requirements for normal publish
    if (presHigh==true) {
        Particle.publish("Pump_pressure","normal");
         // digitalWrite(led_green, LOW);
        // publish this public event

        // Set the flag to reflect the current status of the beam.
        presHigh=false;
    }
  }
  else {
      if (presHigh==false) {
        // Same deal as before...
        Particle.publish("Pump_pressure","abnormal");
        presHigh=true;
        }
    }

  // To blink the LED, when pressure is high
  if (presHigh==true) {
      
  digitalWrite(led_green, HIGH);
  digitalWrite(led_red, HIGH);
  digitalWrite(led_blue, LOW);
  
  delay(500);

  // Then we'll turn it off...
  digitalWrite(led_green, LOW);
  digitalWrite(led_red, HIGH);
  digitalWrite(led_blue, HIGH);
  
  delay(500);
  
  digitalWrite(led_green, HIGH);
  digitalWrite(led_red, LOW);// Running the RED LED last to leave the light red until user input
  digitalWrite(led_blue, HIGH);

  delay(500);
  }
 
          unsigned long now = millis();  // Publish the pressure data collected to thingspeak for plotting 
    if ((now - lastPublish) < publish_delay) {
        return;
    }

    int value = (((analogRead(A0))*.26)+.5);
    Particle.publish("thingSpeakWrite_A0", "{ \"1\": \"" + String(value) + "\", \"k\": \"ZB9COBBPARXH3UAJ\" }", 60, PRIVATE);//ZB9COBBPARXH3UAJ
    lastPublish = now;
    Particle.variable("Control", value);//ZB9COBBPARXH3UAJ
    
}

// Now for the myHandler function, which is called when the cloud tells us that our buddy's event is published.
  void myHandler(const char *event, const char *data){
  /* Particle.subscribe handlers are void functions, which means they don't return anything.
  They take two variables-- the name of your event, and any data that goes along with your event.
  In this case, the event will be "Pump_control" and the data will be "normal" or "high"

  Since the input here is a char, we can't do
     data=="normal"
    or
     data=="high"

  chars just don't play that way. Instead we're going to strcmp(), which compares two chars.
  If they are the same, strcmp will return 0.
  */

  if (strcmp(data,"on")==0) {
    // if pressure is normal, then turn your board LED off
//    digitalWrite(boardLed,LOW); //Status light remains off
    digitalWrite(led_green,LOW);
    digitalWrite(led_red,HIGH);
    digitalWrite(led_blue,HIGH);
//    digitalWrite(led_pump,LOW);
    delay(1000);
  }
  else if (strcmp(data,"off")==0) {
    // if Pump pressure is high, turn your board LED on
 //   digitalWrite(boardLed,HIGH); // Status Light turns on
    digitalWrite(led_red,LOW);
    digitalWrite(led_green,HIGH);
    digitalWrite(led_blue,HIGH);//Pump turns off
//    digitalWrite(led_pump,HIGH);
   delay(1000);
  }
   else{} // Really the data shouldn't be anything but those two listed above.
  }
  // Below is to display on OLED display
   void gaugeDisplay()
{ 
    
      for (int i=0; i<25; i++)
  {
    oled.clear(PAGE);            // Clear the display
    oled.setCursor(0, 0);        // Set cursor to top-left
    //oled.setFontType(0);         // Smallest font
    //oled.print("Pressure :");          // Print "A0"
    //const char kPa=101.5;
    oled.setFontType(3);  // 7-segment font
    oled.print(((analogRead(pressure)*.26)+.5));  // Print a0 reading P_out=0.26*V + 0.05
    //oled.setCursor(0, 16);       // Set cursor to top-middle-left
    //oled.setFontType(0);         // Repeat
    //oled.print("A1:");
    //oled.setFontType(2);
    //oled.print(analogRead(A1));
    //oled.setCursor(0, 32);
    //oled.setFontType(0);
    //oled.print("A7:");
    //oled.setFontType(2);
    //oled.print(analogRead(A7));
    oled.display();
    delay(100);
  }
}
/*******************************************************************************
 * Function Name  : tinkerDigitalRead
 * Description    : Reads the digital value of a given pin
 * Input          : Pin
 * Output         : None.
 * Return         : Value of the pin (0 or 1) in INT type
                    Returns a negative number on failure
 *******************************************************************************/
int tinkerDigitalRead(String pin)
{
	//convert ascii to integer
	int pinNumber = pin.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(pin.startsWith("D"))
	{
		pinMode(pinNumber, INPUT_PULLDOWN);
		return digitalRead(pinNumber);
	}
	else if (pin.startsWith("A"))
	{
		pinMode(pinNumber+10, INPUT_PULLDOWN);
		return digitalRead(pinNumber+10);
	}
	return -2;
}

/*******************************************************************************
 * Function Name  : tinkerDigitalWrite
 * Description    : Sets the specified pin HIGH or LOW
 * Input          : Pin and value
 * Output         : None.
 * Return         : 1 on success and a negative number on failure
 *******************************************************************************/
int tinkerDigitalWrite(String command)
{
	bool value = 0;
	//convert ascii to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(command.substring(3,7) == "HIGH") value = 1;
	else if(command.substring(3,6) == "LOW") value = 0;
	else return -2;

	if(command.startsWith("D"))
	{
		pinMode(pinNumber, OUTPUT);
		digitalWrite(pinNumber, value);
		return 1;
	}
	else if(command.startsWith("A"))
	{
		pinMode(pinNumber+10, OUTPUT);
		digitalWrite(pinNumber+10, value);
		return 1;
	}
	else return -3;
}

/*******************************************************************************
 * Function Name  : tinkerAnalogRead
 * Description    : Reads the analog value of a pin
 * Input          : Pin
 * Output         : None.
 * Return         : Returns the analog value in INT type (0 to 4095)
                    Returns a negative number on failure
 *******************************************************************************/
int tinkerAnalogRead(String pin)
{
	//convert ascii to integer
	int pinNumber = pin.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(pin.startsWith("D"))
	{
		return -3;
	}
	else if (pin.startsWith("A0"))// Setting Calibrated output for Tinker App display
	{
	    return (analogRead(pinNumber+10));
	}
	else if (pin.startsWith("A"))
	{
		return (analogRead(pinNumber+10));
	}
	return -2;
}

/*******************************************************************************
 * Function Name  : tinkerAnalogWrite
 * Description    : Writes an analog value (PWM) to the specified pin
 * Input          : Pin and Value (0 to 255)
 * Output         : None.
 * Return         : 1 on success and a negative number on failure
 *******************************************************************************/
int tinkerAnalogWrite(String command)
{
	//convert ascii to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	String value = command.substring(3);

	if(command.startsWith("D"))
	{
		pinMode(pinNumber, OUTPUT);
		analogWrite(pinNumber, value.toInt());
		return 1;
	}
	else if(command.startsWith("A"))
	{
		pinMode(pinNumber+10, OUTPUT);
		analogWrite(pinNumber+10, value.toInt());
		return 1;
	}
	else return -2;
Particle.publish("Pump_Pressure", "150", 21600);
}

Pump_control

C/C++
Monitors for pump events
// This #include statement was automatically added by the Particle IDE.
#include <SparkFunMicroOLED.h>
#include <math.h>
//#define max_pres 160
//#define min_pres 70
#define publish_delay 600000//Delay between Thingspeak publish events (ms)
unsigned int lastPublish = 599750;//Initial publish time, set so user reset pushes most recent pressure reading
/*  Include the SparkFunMicroOLED library 

Hardware Connections:
  This sketch was written specifically for the Photon Micro OLED Shield, which does all the wiring for you. If you have a Micro OLED breakout, use the following hardware setup:

    MicroOLED ------------- Photon
      GND ------------------- GND
      VDD ------------------- 3.3V (VCC)
    D1/MOSI ----------------- A5 (don't change)
    D0/SCK ------------------ A3 (don't change)
      D2
      D/C ------------------- D6 (can be any digital pin)
      RST ------------------- D7 (can be any digital pin)
      CS  ------------------- A2 (can be any digital pin)
*/
  int Pump_off_led = D3; //Any Digital Pin connected to switch
  int Pump_off = A0; 
  int Pump_on_led = D4;
  int boardLed = D7; // lights led on doard
  int led_green = D1; //4 pin LED - Pin 2 to pull up resistor
  int led_red = D0;
  int led_blue = D2;
  int Threshold;
  int presNormal;

  double    presRead;
  
  int tinkerDigitalRead(String pin);
  int tinkerDigitalWrite(String command);
  int tinkerAnalogRead(String pin);
  int tinkerAnalogWrite(String command);
  int pressure(String command);
  
  MicroOLED oled;// Establish the OLED Display

void setup() {
      // Subscribe to the integration response event

  Particle.subscribe("Pump_pressure", myHandler);
  
  Particle.variable("Control", presRead);
  //Particle.variable("presRead", &presRead, DOUBLE);

  pinMode(led_green,OUTPUT);// Our LED pins are output (lighting up the LEDs)
  pinMode(Pump_on_led,OUTPUT);
  pinMode(Pump_off_led,OUTPUT);// 3 POSITION SWITCH FROM SPARK FUN KIT
  pinMode(Pump_off,INPUT);
  //pinMode(Pump_on,INPUT_PULLDOWN);//OTHER TERMINAL OF 3 POSITION SWITCH
  pinMode(led_blue,OUTPUT);
  pinMode(led_red,OUTPUT);
  pinMode(boardLed,OUTPUT); // Our on-board LED is output as well
  //pinMode(pressure,INPUT);  // Our pressure sensor pin is input (reading the pressure sensor)
  //pinMode(power,INPUT); // The pin powering the photoresistor is output (sending out consistent power)
  digitalWrite(led_red,HIGH);
  digitalWrite(led_green,HIGH);
  digitalWrite(led_blue,HIGH);
  digitalWrite(Pump_on_led,HIGH);
  digitalWrite(Pump_off_led,HIGH);
  oled.begin();    // Initialize the OLED display
  oled.clear(ALL); // Clear the display's internal memory
  oled.display();  // Display what's in the buffer (splashscreen)
  delay(250);     // Delay 250 ms
  oled.clear(PAGE); // Clear the buffer.
  randomSeed(analogRead(A0)); 
  
  	Particle.function("digitalread", tinkerDigitalRead);
	Particle.function("digitalwrite", tinkerDigitalWrite);
	Particle.function("analogread", tinkerAnalogRead);
	Particle.function("analogwrite", tinkerAnalogWrite);
  
  Threshold = 700;
  
  bool presNormal = true;
  
}

void loop() {
     gaugeDisplay();

    if (analogRead(Pump_off)>Threshold) {
    if (presNormal==true) {
        Particle.publish("Pump_control","off");
          digitalWrite(Pump_on_led, LOW);
          digitalWrite(Pump_off_led, HIGH);
          digitalWrite(led_red, HIGH);
          delay(1000);
        // publish this public event
        // Set the flag to reflect the current status of the beam.
        presNormal=false;
    }
  }

  else {
      if (presNormal==false) {
        // Same deal as before...
        //j=j+1;
        //if (j==100) {
        Particle.publish("Pump_control","on");
        digitalWrite(Pump_on_led, HIGH);
        digitalWrite(Pump_off_led, LOW);
        digitalWrite(led_green, HIGH);
        presNormal=true;
        delay(1000);
        //j=1; }
        //else {
       // }
        }
        }  
}

void myHandler(const char *event, const char *data)
{
  /* Particle.subscribe handlers are void functions, which means they don't return anything.
  They take two variables-- the name of your event, and any data that goes along with your event.
  In this case, the event will be "Pump_control" and the data will be "normal" or "high"

  Since the input here is a char, we can't do
     data=="normal"
    or
     data=="high"

  chars just don't play that way. Instead we're going to strcmp(), which compares two chars.
  If they are the same, strcmp will return 0.
  */

  if (strcmp(data,"normal")==0) {
    // if pressure is normal, then turn your board LED off
    digitalWrite(boardLed,HIGH); //Status light remains green
    digitalWrite(led_green,LOW);
    digitalWrite(led_red,HIGH);
    digitalWrite(led_blue,HIGH);
  }
  else if (strcmp(data,"abnormal")==0) {
    // if Pump pressure is high, turn your board LED on
   digitalWrite(boardLed,LOW); // Status Light turns RED
   digitalWrite(led_red,LOW);
   digitalWrite(led_green,HIGH);
   digitalWrite(led_blue,HIGH);
  } 
}
//int presRead = Particle.variable();{}
/*int pressure(String controlstring)
{

    if(controlstring.startsWith("data"))
	    {
		 controlstring =  controlstring.substring(4, controlstring.length());
		 presRead = controlstring.toFloat();
		 //presRead = 100;
		 //settemp = min(settemp, maxsettemp);
		 //settemp = max(settemp, minsettemp);
		 //heaterenable = TRUE;
		 //circenable = TRUE;
		 //timeheatercheck = 0;
		 //return controlstring.toInt();
		 //settemp = 98.0;
        }
        else{}
}
 */
   void gaugeDisplay()
{ 
    
      for (int i=0; i<25; i++)
  {
    oled.clear(PAGE);            // Clear the display
    oled.setCursor(0, 0);  
    oled.setFontType(3);  // 7-segment font
    oled.print("100");// Set cursor to top-left
    oled.display();
    delay(250);
  }
}
/*******************************************************************************
 * Function Name  : tinkerDigitalRead
 * Description    : Reads the digital value of a given pin
 * Input          : Pin
 * Output         : None.
 * Return         : Value of the pin (0 or 1) in INT type
                    Returns a negative number on failure
 *******************************************************************************/
int tinkerDigitalRead(String pin)
{
	//convert ascii to integer
	int pinNumber = pin.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(pin.startsWith("D"))
	{
		pinMode(pinNumber, INPUT_PULLDOWN);
		return digitalRead(pinNumber);
	}
	else if (pin.startsWith("A"))
	{
		pinMode(pinNumber+10, INPUT_PULLDOWN);
		return digitalRead(pinNumber+10);
	}
	return -2;
}

/*******************************************************************************
 * Function Name  : tinkerDigitalWrite
 * Description    : Sets the specified pin HIGH or LOW
 * Input          : Pin and value
 * Output         : None.
 * Return         : 1 on success and a negative number on failure
 *******************************************************************************/
int tinkerDigitalWrite(String command)
{
	bool value = 0;
	//convert ascii to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(command.substring(3,7) == "HIGH") value = 1;
	else if(command.substring(3,6) == "LOW") value = 0;
	else return -2;

	if(command.startsWith("D"))
	{
		pinMode(pinNumber, OUTPUT);
		digitalWrite(pinNumber, value);
		return 1;
	}
	else if(command.startsWith("A"))
	{
		pinMode(pinNumber+10, OUTPUT);
		digitalWrite(pinNumber+10, value);
		return 1;
	}
	else return -3;
}

/*******************************************************************************
 * Function Name  : tinkerAnalogRead
 * Description    : Reads the analog value of a pin
 * Input          : Pin
 * Output         : None.
 * Return         : Returns the analog value in INT type (0 to 4095)
                    Returns a negative number on failure
 *******************************************************************************/
int tinkerAnalogRead(String pin)
{
	//convert ascii to integer
	int pinNumber = pin.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(pin.startsWith("D"))
	{
		return -3;
	}
	else if (pin.startsWith("A"))
	{
		return analogRead(pinNumber+10);
	}
	return -2;
}

/*******************************************************************************
 * Function Name  : tinkerAnalogWrite
 * Description    : Writes an analog value (PWM) to the specified pin
 * Input          : Pin and Value (0 to 255)
 * Output         : None.
 * Return         : 1 on success and a negative number on failure
 *******************************************************************************/
int tinkerAnalogWrite(String command)
{
	//convert ascii to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	String value = command.substring(3);

	if(command.startsWith("D"))
	{
		pinMode(pinNumber, OUTPUT);
		analogWrite(pinNumber, value.toInt());
		return 1;
	}
	else if(command.startsWith("A"))
	{
		pinMode(pinNumber+10, OUTPUT);
		analogWrite(pinNumber+10, value.toInt());
		return 1;
	}
	else return -2;
}

Credits

Strudel

Strudel

1 project • 0 followers
Mitch

Mitch

1 project • 0 followers

Comments