XRAD'S AUTOMATIC MODEL BOILER PUMP CONTROLLER

EL Wire/Tape/Panels, LEDs, pixels and strips, LCDs and TFTs, etc products from Adafruit

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
XRAD
 
Posts: 761
Joined: Sat Nov 19, 2016 3:28 pm

XRAD'S AUTOMATIC MODEL BOILER PUMP CONTROLLER

Post by XRAD »

Hello All,

So I wanted longer run times with my live steam models. That requires an automatic way to refill the boiler as water is used up. The challenge with this build was that I only have ONE sensor in the boiler! So rather than just filling UP to the sensor, a timer is needed to fill beyond the sensor level. Otherwise, the pump valve would cycle too often. Yes, 2 sensors would have made this easier, and at the same time a boring build challenge!

Hardware:
ADAFRUIT SSD1306 monochrome display
Teensy 3.2
basic rotary encoder with built in resistors
15K resistor for sensor
2N3904 transistor
x2 470ohm resistors
RED and BLUE 5v LED

BUILD: wiring pretty easy: all connections are in the sketch. See pic for sensor diagram. It looks like TWO sensors in the water, but one is connected to outside of copper boiler tank.

When water level is below the sensor pin, pump turns ON. When water level covers the two leads, the transistor completes the circuit to the Teensy sensor pin and pump turn OFF. Timer is using 'while'..so nothing else can happen while pump is running.
Obviously, this sketch design can be used for many things that need a 'do something for this long...' timer setup, rather than just the 'do something every 'x' seconds... EEPROM saves the entered timer setting so you don't have to reset it again for 99 years....

Enjoy

little video:
https://www.youtube.com/watch?v=TrY132VywmE
small water pic.JPG
small water pic.JPG (95.26 KiB) Viewed 351 times
small dgm.JPG
small dgm.JPG (24.39 KiB) Viewed 351 times

Code: Select all

/*XRAD'S Model Live Steam Boiler Filler Pump Controller
So I wanted longer run times with my live steam models. That
requires an automatic way to refill the boiler as water is used up.
5/22/2022 

Hardware: 
using an ADAFRUIT SSD1306 monochrome display (I modified the 
base files so the splash screen does not show), Teensy 3.2, basic 
rotary encoder with built in resistors, 15K resistor for sensor 
circuit on base of 2N3904 transistor, and x2 470ohm resistors 
(one for each LED). wiring pretty easy: 5v to the collector.  
emitter to Teensy sensor pin.  Base via 15K resistor to water tank. 
Another 5v  lead to water tank.  When water level covers the two leads, 
the transistor completes the circuit to the Teensy sensor pin(pump OFF).  
Timer is using 'while'..so nothing else can happen while pump is running.   
Obviously, this sketch design can be used for many things that need a 
'do something for this long...' timer setup, rather than just the 
'do something every 'x' seconds... EEPROM saves the entered timer 
setting so you don't have to reset it again for 99 years....The challenge 
with this build was that I only have ONE sensor in the boiler! So 
rather than just filling UP to the sensor, a timer is needed to fill 
beyond the sensor level.... Enjoy....
*/


#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#include <Servo.h> 

int address = 0; //where to store data in EEPROM
int value = 0;//initial EEPROM value

#define SCREEN_WIDTH 128 // display pixel width
#define SCREEN_HEIGHT 64 // display pixel height


//Adafruit SSD1306 display connected using hardware SPI, adjust for your needs
#define OLED_MOSI   11
#define OLED_CLK   14
#define OLED_DC    6
#define OLED_CS    7
#define OLED_RESET 8
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
                         OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);


// Define rotary encoder pins
#define CLK 2
#define DT 3
#define SW 4

// Rotary encoder variables
int counter; //this is the stored rotary data for pump timer
int currentStateCLK;
int lastStateCLK;
String currentDir = "";
unsigned long lastButtonPress = 0;


//define water sensor pins
#define SENSOR 19
#define REDLED 20
#define BLUELED 21

char* WaterLevelLine[] = {" READING", " NORMAL", " LOW", " FILLING"};
int WaterLevelMenu = 0;//for saving the chosen element, begin at '0'

char* WaterPumpLine[] = {" OFF", " ON"};
int WaterPumpMenu = 0;//for saving the chosen element, begin at '0'


//servo/pump variables
Servo rotServo;
int posRot = 20;//on boot, should be same as last position to avoid jump start
bool servoOpen = false;
bool servoClosed = true;
int starttime;
int endtime;
bool pumpState = true;


void servoTest() {
  for (int x = 0; x < 1; x++) {
    for (posRot = 20; posRot <= 180; posRot += 1) {
      rotServo.write(posRot);
      delay(5);
    }
    for (posRot = 180; posRot >= 20; posRot -= 1) {
      rotServo.write(posRot);
      delay(5);
    }
  }
}

void printWaterLevelMenu() {
  display.setCursor(75, 10);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.print(WaterLevelLine[WaterLevelMenu]);
  display.display();//need to call this to show the display buffer!
}

void printWaterPumpMenu() {
  display.fillRect(75, 30, 50, 10, SSD1306_BLACK);
  display.setCursor(75, 30);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.print(WaterPumpLine[WaterPumpMenu]);
  display.display();
}


void EEPROMREAD() {
  value = EEPROM.read(address);// read a byte from the current address of the EEPROM
  //Serial.print(address);
  //Serial.print("\t");
  //Serial.print(value, DEC);
  //Serial.println();
  address = address + 1;//advance to next address
  if (address == EEPROM.length()) {
    address = 0;
  }
  counter = value;//get the value from EEPROM and update
  Serial.println("Reading EEPROM value...");
  Serial.print("value: ");
  Serial.println(value);
  delay(50);//not really needed...
}

void clearEEPROM() {
  for (int i = 0 ; i < EEPROM.length() ; i++) {
    if (EEPROM.read(i) != 0) { //skip already "empty" addresses
      EEPROM.write(i, 0); //write 0 to address i
    }
  }
  Serial.println("EEPROM erased");
  address = 0; //reset address counter
}


void valveOpen() {
  if (servoOpen == false) {
    //open pump valve
    for (posRot = 20; posRot <= 180; posRot += 1) {
      rotServo.write(posRot);
      delay(5);
    }
    servoOpen = true;
  }
}

void valveClose() {
  if (servoOpen == true) {
    for (posRot = 180; posRot >= 20; posRot -= 1) {
      rotServo.write(posRot);
      delay(5);
    }
    servoOpen = false;
  }
}

void setup() {
  Serial.begin(9600);

  pinMode(CLK, INPUT);
  pinMode(DT, INPUT);
  pinMode(SW, INPUT_PULLUP); //can do this on Teensy 3.2

  lastStateCLK = digitalRead(CLK);// Read the initial state of CLK for rotary encoder

  pinMode(SENSOR, INPUT_PULLDOWN);//can do this on Teensy 3.2
  pinMode(REDLED, OUTPUT);
  pinMode(BLUELED, OUTPUT);

  rotServo.attach(22);
  rotServo.write(posRot); //initial position

  display.begin(SSD1306_SWITCHCAPVCC);

  display.clearDisplay(); // Clear the buffer

  display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE); //draw double thick rectangle
  display.drawRect(1, 1, SCREEN_WIDTH - 2, SCREEN_HEIGHT - 2, SSD1306_WHITE);
  display.setCursor(10, 10);
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.print(" XRAD'S");
  display.setCursor(10, 35);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.print("MODEL STEAM BOILER");
  display.setCursor(10, 50);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.print(" PUMP CONTROLLER");
  display.display();//need to call this to show the display buffer!

  delay(4000);

  //servoTest();//see if your servo is working

  display.clearDisplay(); // Clear the display buffer

  display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE); //draw double thick rectangle
  display.drawRect(1, 1, SCREEN_WIDTH - 2, SCREEN_HEIGHT - 2, SSD1306_WHITE);

  display.setCursor(5, 10);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.print("WATER LEVEL: ");
  display.fillRect(75, 10, 50, 10, SSD1306_BLACK);//clear the text box
  printWaterLevelMenu();//write in text box

  display.setCursor(5, 30);
  display.setTextSize(1);
  display.print("WATER PUMP: ");
  //display.fillRect(75, 30, 50, 10, SSD1306_BLACK);
  printWaterPumpMenu();//write in text box

  EEPROMREAD();//let's get the old pump delay setting from EEPROM
  display.setCursor(5, 50);
  display.setTextSize(1);
  display.print("PUMP RUN TIME: ");
  display.fillRect(90, 47, 30, 13, SSD1306_BLACK);
  display.setCursor(100, 50);
  display.println(counter);

  display.display();
  delay(2000);
}

void loop() {
  
  //Rotary encoder to set pump 'run' time, and SW to save timer setting!
  currentStateCLK = digitalRead(CLK);

  if (currentStateCLK != lastStateCLK  && currentStateCLK == 1) {
    if (digitalRead(DT) != currentStateCLK) {
      counter ++;
      currentDir = "CW";
      if (counter >= 40) {
        counter = 40;//40 second MAX timer
      }
    }
    else {
      counter --;
      currentDir = "CCW";
      if (counter <= 1) {
        counter = 1;
      }
    }
    //Serial.print("Direction: ");
    //Serial.print(currentDir);
    //Serial.print("  Counter: ");
    //Serial.println(counter);
    display.fillRect(90, 47, 30, 13, SSD1306_BLACK);
    display.display();
    display.setCursor(100, 50);
    display.println(counter);
    display.display();
    delay(1);// Put in a slight delay to help debounce the rotary reading, adust if needed
  }
  lastStateCLK = currentStateCLK;// remember last CLK state

  //Rotary knob 'SW' push button is for saving the pump run timer (seconds),
  //which is then saved as 'value' to EEPROM so that you do not have to reset it
  //on each boot...
  int btnState = digitalRead(SW);//look for button press
  //If LOW signal, button is pressed
  if (btnState == LOW) {
    if (millis() - lastButtonPress > 50) {
      Serial.println("Button pressed!");

      clearEEPROM();//erase old data

      display.fillRect(90, 47, 30, 13, SSD1306_WHITE);
      display.setCursor(100, 50);
      display.setTextColor(SSD1306_BLACK);
      display.println(counter);
      display.display();

      value = counter;

      EEPROM.write(address, value);//write new data
      Serial.println("Writing to EEPROM...");
      Serial.print("value: ");
      Serial.println(value);

      //EEPROMREAD();//debug read back the new value just to be sure

      delay(1000); //show the white filled rectangle for 'x' millis
      display.fillRect(90, 47, 30, 13, SSD1306_BLACK);
      display.setCursor(100, 50);
      display.setTextColor(SSD1306_WHITE);
      display.println(counter);
      display.display();
    }
    lastButtonPress = millis(); // Remember last button press event
  }


  //read the boiler water level and do something
  int sensorState = digitalRead(SENSOR);

  if (sensorState == HIGH) {
    digitalWrite(REDLED, HIGH);
    digitalWrite(BLUELED, LOW);
    display.fillRect(75, 10, 50, 10, SSD1306_BLACK);//clear the text box
    WaterLevelMenu = 1;//{" READING", " NORMAL", " LOW", " FILLING"};
    printWaterLevelMenu();
    WaterPumpMenu = 0;
    printWaterPumpMenu();
    valveClose();
  }

  else if (sensorState == LOW) {
    digitalWrite(REDLED, LOW);
    digitalWrite(BLUELED, HIGH);
    display.fillRect(75, 10, 50, 10, SSD1306_BLACK);//clear the text box
    WaterLevelMenu = 2;
    printWaterLevelMenu();
    delay(1000);
    WaterPumpMenu = 1;
    printWaterPumpMenu();
    starttime = millis();
    endtime = starttime;
    pumpState = true;

    while ((endtime - starttime) <= (counter * 1000) && (pumpState == true)) // do this loop for up to 1000mS
    {
      valveOpen();
      display.fillRect(75, 10, 50, 10, SSD1306_BLACK);//clear the text box
      WaterLevelMenu = 3;
      printWaterLevelMenu();
      endtime = millis();
    }
    pumpState = false;
    valveClose();
  }
}

User avatar
Franklin97355
 
Posts: 24266
Joined: Mon Apr 21, 2008 2:33 pm

Re: XRAD'S AUTOMATIC MODEL BOILER PUMP CONTROLLER

Post by Franklin97355 »

Always good projects. Thanks for posting.

User avatar
XRAD
 
Posts: 761
Joined: Sat Nov 19, 2016 3:28 pm

Re: XRAD'S AUTOMATIC MODEL BOILER PUMP CONTROLLER

Post by XRAD »

Thanks Franklin! Here is a pic of the boiler, duplex steam pump , and marine twin cylinder engine. These mechanicals are going into a 52" version of a Brooklyn style train barge tug I am building. Here is a pic of a 40" live steam fully remote version of said tugboat. I built it a few years ago. When I was a child, my parents sailed the East river and Long Island sound. I miss the smell of the salt water and the beautiful visuals....More to come...
boiler sm.JPG
boiler sm.JPG (72.98 KiB) Viewed 345 times
Brookly sml.JPG
Brookly sml.JPG (74.48 KiB) Viewed 345 times
41JV863fdRL._AC_.jpg
41JV863fdRL._AC_.jpg (28.13 KiB) Viewed 345 times

User avatar
Franklin97355
 
Posts: 24266
Joined: Mon Apr 21, 2008 2:33 pm

Re: XRAD'S AUTOMATIC MODEL BOILER PUMP CONTROLLER

Post by Franklin97355 »

Just WOW!

User avatar
XRAD
 
Posts: 761
Joined: Sat Nov 19, 2016 3:28 pm

Re: XRAD'S AUTOMATIC MODEL BOILER PUMP CONTROLLER

Post by XRAD »

Thank you Franklin! So here is the 'final' build. I put everything into a plastic case and added a 1200mAh 3.7v lipo and charger. I only draw .05 amps max with servo running, so this battery size will be more than enough for an hour of run-time. Everything plugs into board so easy to repair if needed. I added a few more LED effects. Both ON at boot, After that, BLUE = OK, RED != OK. The black button bottom right is a pump test button. This gives a 2 second burst to clear out pump condensation and warm it up a bit. I have set up the boiler contacts with stainless test strip as POS and copper test strip as NEG. Although I use distilled water, some ions always make their way to one or the other electrode. I would rather sacrifice the stainless (minimally) and plate the boiler, than pit the boiler and plate the stainless with copper. I am going to run the set-up for 12 hours and see what happens. The propeller in the pic above is copper plated brass using table salt water solution. I like to make my propellers look old and used. As always , feel free to use my code and make it your own. Thx to Adafruit for SSD1306 and GFX libraries!

See a <1 minute vid: https://www.youtube.com/watch?v=5CZLYyKj5IQ
water small.JPG
water small.JPG (77.56 KiB) Viewed 301 times
WATER CASE SML.JPG
WATER CASE SML.JPG (62.98 KiB) Viewed 301 times
FINAL CODE:

Code: Select all

/*XRAD'S Model Live Steam Boiler Filler Pump Controller
  So I wanted longer run times with my live steam models. That
  requires an automatic way to refill the boiler as water is used up.
  5/22/2022

  Hardware:
  using an ADAFRUIT SSD1306 monochrome display (I modified the
  base files so the splash screen does not show), Teensy 3.2, basic
  rotary encoder with built in resistors, 15K resistor for sensor
  circuit on base of 2N3904 transistor, and x2 470ohm resistors
  (one for each LED). wiring pretty easy: 5v to the collector.
  emitter to Teensy sensor pin.  Base via 15K resistor to water tank.
  Another 5v  lead to water tank.  When water level covers the two leads,
  the transistor completes the circuit to the Teensy sensor pin(pump OFF).
  Timer is using 'while'..so nothing else can happen while pump is running.
  Obviously, this sketch design can be used for many things that need a
  'do something for this long...' timer setup, rather than just the
  'do something every 'x' seconds... EEPROM saves the entered timer
  setting so you don't have to reset it again for 99 years....The challenge
  with this build was that I only have ONE sensor in the boiler! So
  rather than just filling UP to the sensor, a timer is needed to fill
  beyond the sensor level.... Enjoy....
*/


#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#include <Servo.h>

#define SCREEN_WIDTH 128 // display pixel width
#define SCREEN_HEIGHT 64 // display pixel height

//Define rotary encoder pins
#define CLK 2
#define DT 3
#define SW 4

//Adafruit SSD1306 display connected using these pins, adjust for your needs
#define OLED_DC    6
#define OLED_CS    7
#define OLED_RESET 8
#define OLED_MOSI  11
#define OLED_CLK   14
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
                         OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

//test pump pin
#define TESTPUMP 16
#define PUMPDELAY 2//how long to test run pump in seconds

//define water sensor pins
#define SENSOR 19  //input 
#define REDLED 20  //warning LED, for LOW water and LOW battery
#define BLUELED 21 //system OK


//EEPROM variables
int address = 0; //where to store data in EEPROM
int value = 0;//initial EEPROM value for pump timer


// Rotary encoder variables
int counter; //this is the stored rotary data for pump timer
int currentStateCLK;
int lastStateCLK;
String currentDir = "";
unsigned long lastButtonPress = 0;


//display menus
char* WaterLevelLine[] = {" READING", " NORMAL", " LOW", " FILLING"};
int WaterLevelMenu = 0;//for saving the chosen element, begin at '0'

char* WaterPumpLine[] = {" OFF", " ON"};
int WaterPumpMenu = 0;//for saving the chosen element, begin at '0'

//Voltmeter variables , this is a very basic voltage divider, accuracy ~ +/- .2 V
int analogInput = 17;
float vout = 0.0;
float vin = 0.0;
float R1 = 1000000.0; // resistance of R1 (100K)
float R2 = 100000.0; // resistance of R2 (10K)
int volts = 0;


//servo-pump variables
Servo rotServo;
int posRot = 20;//on boot, should be same as last position to avoid jump start
bool servoOpen = false;
int starttime;
int endtime;
bool pumpState = true;


void servoTest() {
  WaterLevelMenu = 3;
  printWaterLevelMenu();
  WaterPumpMenu = 1;
  printWaterPumpMenu();
  display.fillRect(90, 47, 30, 13, SSD1306_WHITE);
  display.setCursor(100, 50);
  display.setTextColor(SSD1306_BLACK);
  display.println(PUMPDELAY);
  display.display();
  for (int x = 0; x < 1; x++) {
    for (posRot = 20; posRot <= 160; posRot += 1) {
      rotServo.write(posRot);
      delay(7); //controls servo speed
    }
    delay(PUMPDELAY * 1000); //just a short burst of steam here to clear out the pipes
    for (posRot = 160; posRot >= 20; posRot -= 1) {
      rotServo.write(posRot);
      delay(7);
    }
  }
  display.fillRect(90, 47, 30, 13, SSD1306_BLACK);
  display.setCursor(100, 50);
  display.setTextColor(SSD1306_WHITE);
  display.println(counter);
  display.display();
  WaterPumpMenu = 0;
  printWaterPumpMenu();
}

void printWaterLevelMenu() {
  display.fillRect(75, 10, 50, 10, SSD1306_BLACK);//clear the text 'box'
  display.setCursor(75, 10);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.print(WaterLevelLine[WaterLevelMenu]);
  display.display();
}


void printWaterPumpMenu() {
  display.fillRect(75, 30, 50, 10, SSD1306_BLACK);
  display.setCursor(75, 30);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.print(WaterPumpLine[WaterPumpMenu]);
  display.display();
}


void EEPROMREAD() {
  value = EEPROM.read(address);// read a byte from the current address of the EEPROM
  //Serial.print(address);
  //Serial.print("\t");
  //Serial.print(value, DEC);
  //Serial.println();
  address = address + 1;//advance to next address
  if (address == EEPROM.length()) {
    address = 0;
  }
  counter = value;//get the value from EEPROM and update
  Serial.println("Reading EEPROM value...");
  Serial.print("value: ");
  Serial.println(value);
  delay(50);//not really needed...
}


void clearEEPROM() {
  for (int i = 0 ; i < EEPROM.length() ; i++) {
    if (EEPROM.read(i) != 0) { //skip already "empty" addresses
      EEPROM.write(i, 0); //write 0 to address i
    }
  }
  Serial.println("EEPROM erased");
  address = 0; //reset address counter
}


void valveOpen() {
  if (servoOpen == false) {
    for (posRot = 20; posRot <= 180; posRot += 1) {
      rotServo.write(posRot);
      delay(5);// controls servo speed
    }
    servoOpen = true;
  }
}

void valveClose() {
  if (servoOpen == true) {
    for (posRot = 180; posRot >= 20; posRot -= 1) {
      rotServo.write(posRot);
      delay(5);
    }
    servoOpen = false;
  }
}

void readVolts() {//take 20 samples and find average volts
  int average = 0;
  for (int i = 0; i < 20; i++) {
    average = average + analogRead(analogInput);
    delay(100);
    //Serial.println(average); //debug average variable
  }
  average = average / 20;
  vout = (average * 3.15) / 1024.0;//have to adjust '3.15' value to get a 'kinda' correct vout
  vin = vout / (R2 / (R1 + R2));
}


void drawVolts(void) { //draw the averaged volts to screen
  display.clearDisplay(); // Clear the buffer
  display.setCursor(18, 12);
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(2);
  display.print( "VOLTAGE:");
  display.setCursor(40, 35);
  display.print(vin);
  if (vin >= 3.7) {
    digitalWrite(BLUELED, HIGH);
  }
  if (vin < 3.7) {
    digitalWrite(REDLED, HIGH);
  }
  display.display();
}


void drawIntro() {
  display.clearDisplay();
  display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE);
  display.drawRect(1, 1, SCREEN_WIDTH - 2, SCREEN_HEIGHT - 2, SSD1306_WHITE); //draw double thick rectangle
  display.setCursor(10, 10);
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.print(" XRAD'S");
  display.setCursor(10, 35);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.print("MODEL STEAM BOILER");
  display.setCursor(10, 50);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.print(" PUMP CONTROLLER");
  display.display();
}


void drawLoopScreen() {
  display.clearDisplay();
  display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE); //draw double thick rectangle
  display.drawRect(1, 1, SCREEN_WIDTH - 2, SCREEN_HEIGHT - 2, SSD1306_WHITE);
  display.setCursor(5, 10);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.print("WATER LEVEL: ");
  display.fillRect(75, 10, 50, 10, SSD1306_BLACK);//clear txt 'box'
  printWaterLevelMenu();//show text in 'box'
  display.setCursor(5, 30);
  display.setTextSize(1);
  display.print("WATER PUMP: ");
  display.fillRect(75, 30, 50, 10, SSD1306_BLACK);
  printWaterPumpMenu();
  EEPROMREAD();//let's get the stored pump delay setting from EEPROM
  display.setCursor(5, 50);
  display.setTextSize(1);
  display.print("PUMP RUN TIME: ");
  display.fillRect(90, 47, 30, 13, SSD1306_BLACK);
  display.setCursor(100, 50);
  display.println(counter);
  display.display();
}

///////////////////////////////////SETUP/////////////////////////////////
void setup() {
  //Serial.begin(9600);

  pinMode(CLK, INPUT);
  pinMode(DT, INPUT);
  pinMode(SW, INPUT_PULLUP); //can do this on Teensy 3.2
  pinMode(SENSOR, INPUT_PULLDOWN);
  pinMode(REDLED, OUTPUT);
  pinMode(BLUELED, OUTPUT);
  pinMode(TESTPUMP, INPUT_PULLDOWN);
  pinMode(analogInput, INPUT);
  
  lastStateCLK = digitalRead(CLK);// Read the initial state of CLK for rotary encoder
  rotServo.attach(22);
  rotServo.write(posRot); //initial position
  display.begin(SSD1306_SWITCHCAPVCC);
  digitalWrite(REDLED, HIGH);
  digitalWrite(BLUELED, HIGH);
  //servoTest();//debug to see if your servo is working
  
  drawIntro();
  delay(4000);
  digitalWrite(REDLED, LOW);
  digitalWrite(BLUELED, LOW);
  
  readVolts();
  drawVolts();
  delay(4000);
  digitalWrite(REDLED, LOW);
  digitalWrite(BLUELED, LOW);
  
  drawLoopScreen();
  delay(2000);
}


///////////////////////////////////LOOP/////////////////////////////////
void loop() {
  //Rotary encoder to set pump 'run' time, and rotary SW to save timer setting!
  currentStateCLK = digitalRead(CLK);
  
  if (currentStateCLK != lastStateCLK  && currentStateCLK == 1) {
    if (digitalRead(DT) != currentStateCLK) {
      delay(30);//debounce CLK,messy but works OK
      counter ++;
      currentDir = "CW";
      if (counter >= 40) {
        counter = 40;//40 second MAX timer
      }
    }
    else {
      counter --;
      currentDir = "CCW";
      if (counter <= 1) {
        counter = 1;
      }
    }
    //Serial.print("Direction: ");
    //Serial.print(currentDir);
    //Serial.print("  Counter: ");
    //Serial.println(counter);
    display.fillRect(90, 47, 30, 13, SSD1306_BLACK);
    display.display();
    display.setCursor(100, 50);
    display.println(counter);
    display.display();
    delay(1);// Put in a slight delay to help debounce the rotary reading, adust if needed
  }
  lastStateCLK = currentStateCLK;// remember last CLK state

  //Rotary knob 'SW' push button is for saving the pump run timer (seconds),
  //which is then saved as 'value' to EEPROM so that you do not have to reset it
  //on each boot...
  int btnState = digitalRead(SW);//look for button press
  //If LOW signal, button is pressed
  if (btnState == LOW) {
    if (millis() - lastButtonPress > 50) {
      //Serial.println("Button pressed!")
      clearEEPROM();//erase old data
      display.fillRect(90, 47, 30, 13, SSD1306_WHITE);
      display.setCursor(100, 50);
      display.setTextColor(SSD1306_BLACK);
      display.println(counter);
      display.display();
      value = counter;
      
      EEPROM.write(address, value);//write new data
      Serial.println("Writing to EEPROM...");
      Serial.print("value: ");
      Serial.println(value);
      //EEPROMREAD();//debug read back the new value just to be sure
      delay(1000); //show the white filled rectangle for 'x' millis
      
      display.fillRect(90, 47, 30, 13, SSD1306_BLACK);
      display.setCursor(100, 50);
      display.setTextColor(SSD1306_WHITE);
      display.println(counter);
      display.display();
    }
    lastButtonPress = millis(); // Remember last button press event
  }

  //read the boiler water level and do something
  int sensorState = digitalRead(SENSOR);

  if (sensorState == HIGH) {
    digitalWrite(REDLED, LOW);
    digitalWrite(BLUELED, HIGH);
    WaterLevelMenu = 1;//{" READING", " NORMAL", " LOW", " FILLING"};
    printWaterLevelMenu();
    WaterPumpMenu = 0;
    printWaterPumpMenu();
    valveClose();
  }

  else if (sensorState == LOW) {
    digitalWrite(REDLED, HIGH);
    digitalWrite(BLUELED, LOW);
    WaterLevelMenu = 2;
    printWaterLevelMenu();
    delay(1000);
    WaterPumpMenu = 1;
    printWaterPumpMenu();
    starttime = millis();
    endtime = starttime;
    pumpState = true;

    while ((endtime - starttime) <= (counter * 1000) && (pumpState == true)) // do this for 'x' seconds
    {
      valveOpen();
      WaterLevelMenu = 3;
      printWaterLevelMenu();
      endtime = millis();
    }
    pumpState = false;
    valveClose();
  }

  //Push button to momentarily clear out pipes of pump with steam (2 seconds)
  int testPumpState = digitalRead(TESTPUMP);

  if (testPumpState == HIGH) {
    digitalWrite(BLUELED, LOW);
    digitalWrite(REDLED, HIGH);
    servoTest();
  }
  else {
    testPumpState = LOW;
  }
}

User avatar
adafruit_support_bill
 
Posts: 89196
Joined: Sat Feb 07, 2009 10:11 am

Re: XRAD'S AUTOMATIC MODEL BOILER PUMP CONTROLLER

Post by adafruit_support_bill »

Beautiful models! Thanks for the photos.

User avatar
XRAD
 
Posts: 761
Joined: Sat Nov 19, 2016 3:28 pm

Re: XRAD'S AUTOMATIC MODEL BOILER PUMP CONTROLLER

Post by XRAD »

Thx Bill! I appreciate everyone's comments. I have built many models (see search link below for just a few...you have to join to see the pics) and I started adding effects to them a few years back when I discovered Adafruit. Here is another using and Adafruit trinket for triggering a WT588D soundboard. Electronics and models go together like chocolate and peanut butter! One of my other favorites, the Nantucket lightship ( I won't digress on this thread anymore, but anyone interested can PM me on other sites).

Nice smooth relatively clear video:
https://www.youtube.com/watch?v=rGWoK1OVomI

https://www.google.com/search?q=xrad%27 ... 0&dpr=2.64
NANTUCK.jpg
NANTUCK.jpg (136.05 KiB) Viewed 290 times
nantuck1.jpg
nantuck1.jpg (119.59 KiB) Viewed 290 times

Locked
Please be positive and constructive with your questions and comments.

Return to “Glowy things (LCD, LED, TFT, EL) purchased at Adafruit”