/*
Pumps
Test 4 hydraulic pumps. Turns an pump on for 2 minutes,
then off for 2 seconds, and so on.
For the Arduino UNO, check the Technical Specs of board at:
https://www.arduino.cc/en/Main/Products
For the PCF8574 Remote 8-Bit I/O Expander for I2C Bus,
check the Technical Specs of device at:
https://www.ti.com/lit/ds/symlink/pcf8574.pdf
For HLW8032 User manual Rev 1.5, check the pdf document at:
https://w2.electrodragon.com/Chip-cn-dat/HLW-dat/HLW8032-dat/HLW8032.pdf
For the ScheduleTable - A Schedule Table Library for Arduino,
check the repository at:
https://github.com/Locoduino/ScheduleTable
For the EasyButton - Arduino library for debouncing
momentary contact switches, detect press, release,
long press and sequences with event definitions and callbacks,
check the repository at:
https://github.com/evert-arias/EasyButton/
For HLW8032 Arduino Library, check the repository at:
https://github.com/ahmedarif193/Hlw8032
For AltSoftSerial Library - Improved software emulated serial,
using hardware timers for precise signal timing and availability of
CPU time for other libraries to respond to interrupts during data
AltSoftSerial data transmission and reception, check the repository at:
https://github.com/PaulStoffregen/AltSoftSerial
https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
Motors:
Nominal Power: 375W
Nominal Voltage: 220V
Nominal current: 1.7A (375W / 220V)
Start current: ~10A (1.7A x 6)
Start time: 10s
Overload time: 20s
Overcurrent: 2.1A (+30%)
Undervoltage: 180V (-18%)
Overvoltage: 260V (+18%)
Steps for pump checkup
* Verify pumps until all pumps free
* All pumps halt
* For each pump:
* Pump LED yellow
* Delay 2s
* Start pump current monitoring
* Pump power on for 10s
* Start current limit monitoring for 1m50s
* If I > Imax then next pump
* Pump power off
* Delay 2s
* All pumps liberate
Modified 04 Apr 2025
by Gopala Dasa (HDG)
*/
//----------------------------------------------------------------------
// Includes
#include <avr/wdt.h> // to soft reset
#include <ScheduleTable.h> // to schedule events
#include <EasyButton.h> // to command buttons
#include <PCF8574.h> // to imput/output expander module
#include <Hlw8032.h> // to HLW8032 energy metering module
#include <AltSoftSerial.h> // to HLW8032 communication
// AltSoftSerial always uses these pins:
// Board Transmit Receive PWM Unusable
// Arduino Uno 9 8 10
// Arduino Leonardo 5 13 (none)
// Arduino Mega 46 48 44, 45
//----------------------------------------------------------------------
// Defines
// Arduino pin where the buttons, keys and buzzer are connected to
#define BUTTON_GREEN_PIN 5
#define BUTTON_RED_PIN 4
#define KEY_NORMAL_SIMULATION_PIN 3
#define BUZZER_PIN P7
#define OVERCURRENT_PIN 2 // For development only
// Required Baud rate for HLW8032 is 4800bps
#define BAUDRATE 4800 // 115200 // required Baud rate for HLW8032 is 4800bps
//----------------------------------------------------------------------
// Structs
struct pump {
byte redPin;
byte greenPin;
byte haltPin;
byte powerPin;
byte sensorPin;
};
struct bcLed {
byte redPin;
byte greenPin;
};
struct rgbLed {
byte redPin;
byte greenPin;
byte bluePin;
};
struct timeMarks {
int timeOfPowerOn;
int timeOfNormalOp;
int timeOfPowerOff;
int timeOfDisable;
int simulation;
};
//----------------------------------------------------------------------
// Constants
const struct pump pump1 = { A1, A3, P2, P1, P3 };
const struct pump pump2 = { A2, A0, P5, P4, P6 };
const struct pump pump3 = { 12, 13, P2, P1, P3 };
const struct pump pump4 = { 7, 11, P5, P4, P6 };
const struct bcLed powerLed = { 6, 10 };
const struct rgbLed dispatcherLed = { P0, P7, P0 };
const int gTimeBeforeTest = 2; // in seconds
const int gTimeOfTest = 120; // in seconds
const int gTimeAfterTest = 2; // in seconds
const int gTimeOfStartUp = 10; // in seconds (at sumulation, is half simulation time)
const unsigned long gTimeOfOverCurrent = 10; // in seconds (at sumulation, is 2 seconds)
const int gTimeOfSimulation = 10; // in seconds (10 seconds or more)
//----------------------------------------------------------------------
// Variables
int gPump = 0;
bool gPowerOn = false;
bool gPumpNormalOperation = false;
bool gPumpOverCurrent = false;
bool gPump1Status = false;
bool gPump2Status = false;
bool gPump3Status = false;
bool gPump4Status = false;
//----------------------------------------------------------------------
// Objects
/*
* ledsBlink object uses a unique ScheduleTable with 6 actions which switch
* the all LEDs on and off, and start next scheduletable
* The period of the schedule table is 6 with a timebase of 1000ms (6s).
* The actions are put at each second.
* i.e.:
ledsBlink.at(1, allRedLedsOn);
ledsBlink.at(2, allLedsOff);
ledsBlink.at(3, allGreenLedsOn);
ledsBlink.at(4, allLedsOff);
ledsBlink.at(5, testStart);
ledsBlink.at(6, pump1StartTimes);
*/
SchedTable<6> ledsBlink(6, 1000);
/*
* Each pumpTimes object uses a unique ScheduleTable with 5 actions which switch
* the pump enabled, on, off, and disabled
* i.e.:
pump1Times.at( 0, pumpEnable);
pump1Times.at(timeOfPowerOn, pumpPowerOn);
pump1Times.at(timeOfNormalOp, pumpNormalOperation);
pump1Times.at(timeOfPowerOff, pumpPowerOff);
pump1Times.at(timeOfDisable, pumpDisable);
* For a unique pump test, the period of the schedule table is 124 with a
* timebase of 1000ms (2m and 4s). The actions are put
* at 0, 2, 122 and 124 (0s, 2s, 122s e 124s - or 2m and 2s).
*/
SchedTable<5> pump1Times(gTimeBeforeTest + gTimeOfTest + gTimeAfterTest, 1000);
SchedTable<5> pump2Times(gTimeBeforeTest + gTimeOfTest + gTimeAfterTest, 1000);
SchedTable<5> pump3Times(gTimeBeforeTest + gTimeOfTest + gTimeAfterTest, 1000);
SchedTable<5> pump4Times(gTimeBeforeTest + gTimeOfTest + gTimeAfterTest, 1000);
/*
* This object uses a unique ScheduleTable with 2 actions which switch
* the power LED on and off
* The period of the schedule table is 10 with a timebase of 100ms.
* The actions are put at 1 (100ms) and 2 (200ms).
* i.e.:
blinkPowerLed.at(1, PowerLedOn);
blinkPowerLed.at(2, PowerLedOff);
*/
SchedTable<2> blinkPowerLed(10, 100);
// Button Green
EasyButton buttonGreen(BUTTON_GREEN_PIN);
// Button Red
EasyButton buttonRed(BUTTON_RED_PIN);
// PCF8574
// Set i2c address of io expanders
// PCF8574P address map 0x20-0x27
// Dispacher Module
// U1
// A7 A6 A5 A4 A3 A2 A1 A0
// 0 0 1 0 0 x y 0
// 0 0 1 0 0 0 0 0 = 0x20
// U2
// A7 A6 A5 A4 A3 A2 A1 A0
// 0 0 1 0 0 x y 1
// 0 0 1 0 0 0 0 1 = 0x21
// PCF8574AP address map 0x38-0x3f
// U1 ->
// A7 A6 A5 A4 A3 A2 A1 A0
// 0 0 1 1 1 x y 0
// 0 0 1 1 1 0 0 0 = 0x38
// U2
// A7 A6 A5 A4 A3 A2 A1 A0
// 0 0 1 1 1 x y 1
// 0 0 1 1 1 0 0 1 = 0x39
PCF8574 pcf8574_1(0x20);
PCF8574 pcf8574_2(0x21);
// HLW8032 energy metering
Hlw8032 energyMeter;
// Emulates an additional serial port using timer hardware, allowing
// to communicate with another serial device, the HLW8032 energyMeter
AltSoftSerial altSerial;
//----------------------------------------------------------------------
// Functions
/*
* Set pins as input or output
*/
void pinsMode() {
pinMode(OVERCURRENT_PIN, INPUT); // For development only
pinMode(KEY_NORMAL_SIMULATION_PIN, INPUT);
pinMode(pump1.redPin, OUTPUT);
pinMode(pump2.redPin, OUTPUT);
pinMode(pump3.redPin, OUTPUT);
pinMode(pump4.redPin, OUTPUT);
pinMode(pump1.greenPin, OUTPUT);
pinMode(pump2.greenPin, OUTPUT);
pinMode(pump3.greenPin, OUTPUT);
pinMode(pump4.greenPin, OUTPUT);
pinMode(powerLed.redPin, OUTPUT);
pinMode(powerLed.greenPin, OUTPUT);
// U1 Set pinMode
pcf8574_1.pinMode(dispatcherLed.bluePin, OUTPUT, HIGH); // P0 RGB LED Blue pin
pcf8574_1.pinMode(pump1.powerPin, OUTPUT, HIGH); // P1 RL.A.2-PumpTest-Yellow
pcf8574_1.pinMode(pump1.haltPin, OUTPUT, HIGH); // P2 RL.A.1-PumpHalt-White
pcf8574_1.pinMode(pump1.sensorPin, INPUT); // P3 RL.A.3-PumpOn-Green
pcf8574_1.pinMode(pump2.powerPin, OUTPUT, HIGH); // P4 RL.B.2-PumpTest-Yellow
pcf8574_1.pinMode(pump2.haltPin, OUTPUT, HIGH); // P5 RL.B.1-PumpHalt-White
pcf8574_1.pinMode(pump2.sensorPin, INPUT); // P6 RL.B.3-PumpOn-Green
pcf8574_1.pinMode(dispatcherLed.greenPin, OUTPUT, HIGH); // P7 RGB LED Green pin
// U2 Set pinMode
pcf8574_2.pinMode(dispatcherLed.redPin, OUTPUT, HIGH); // P0 RGB LED Red pin
pcf8574_2.pinMode(pump3.powerPin, OUTPUT, HIGH); // P1 RL.C.2-PumpTest-Yellow
pcf8574_2.pinMode(pump3.haltPin, OUTPUT, HIGH); // P2 RL.C.1-PumpHalt-White
pcf8574_2.pinMode(pump3.sensorPin, INPUT); // P3 RL.C.3-PumpOn-Green
pcf8574_2.pinMode(pump4.powerPin, OUTPUT, HIGH); // P4 RL.D.2-PumpTest-Yellow
pcf8574_2.pinMode(pump4.haltPin, OUTPUT, HIGH); // P5 RL.D.1-PumpHalt-White
pcf8574_2.pinMode(pump4.sensorPin, INPUT); // P6 RL.D.3-PumpOn-Green
pcf8574_2.pinMode(BUZZER_PIN, OUTPUT, HIGH); // P7 BUZ1 Buzzer pin
}
// RGB LED
void setRGBLedRed() {
pcf8574_2.digitalWrite(dispatcherLed.redPin, LOW);
pcf8574_1.digitalWrite(dispatcherLed.greenPin, HIGH);
pcf8574_2.digitalWrite(dispatcherLed.bluePin, HIGH);
}
void setRGBLedGreen() {
pcf8574_2.digitalWrite(dispatcherLed.redPin, HIGH);
pcf8574_1.digitalWrite(dispatcherLed.greenPin, LOW);
pcf8574_2.digitalWrite(dispatcherLed.bluePin, HIGH);
}
void setRGBLedBlue() {
pcf8574_2.digitalWrite(dispatcherLed.redPin, HIGH);
pcf8574_1.digitalWrite(dispatcherLed.greenPin, HIGH);
pcf8574_2.digitalWrite(dispatcherLed.bluePin, LOW);
}
void setRGBLedBlank() {
pcf8574_2.digitalWrite(dispatcherLed.redPin, HIGH);
pcf8574_1.digitalWrite(dispatcherLed.greenPin, HIGH);
pcf8574_2.digitalWrite(dispatcherLed.bluePin, HIGH);
}
// Pump Power LED
void setPowerLedYellow() {
digitalWrite(powerLed.redPin, HIGH);
digitalWrite(powerLed.greenPin, HIGH);
}
void setPowerLedGreen() {
digitalWrite(powerLed.redPin, LOW);
digitalWrite(powerLed.greenPin, HIGH);
}
void setPowerLedRed() {
digitalWrite(powerLed.redPin, HIGH);
digitalWrite(powerLed.greenPin, LOW);
}
void setPowerLedBlank() {
digitalWrite(powerLed.redPin, LOW);
digitalWrite(powerLed.greenPin, LOW);
}
// Pumps lights
void setPump1Yellow() {
digitalWrite(pump1.redPin, HIGH);
digitalWrite(pump1.greenPin, HIGH);
}
void setPump2Yellow() {
digitalWrite(pump2.redPin, HIGH);
digitalWrite(pump2.greenPin, HIGH);
}
void setPump3Yellow() {
digitalWrite(pump3.redPin, HIGH);
digitalWrite(pump3.greenPin, HIGH);
}
void setPump4Yellow() {
digitalWrite(pump4.redPin, HIGH);
digitalWrite(pump4.greenPin, HIGH);
}
void setPump1Green() {
digitalWrite(pump1.redPin, LOW);
digitalWrite(pump1.greenPin, HIGH);
}
void setPump2Green() {
digitalWrite(pump2.redPin, LOW);
digitalWrite(pump2.greenPin, HIGH);
}
void setPump3Green() {
digitalWrite(pump3.redPin, LOW);
digitalWrite(pump3.greenPin, HIGH);
}
void setPump4Green() {
digitalWrite(pump4.redPin, LOW);
digitalWrite(pump4.greenPin, HIGH);
}
void setPump1Red() {
digitalWrite(pump1.redPin, HIGH);
digitalWrite(pump1.greenPin, LOW);
}
void setPump2Red() {
digitalWrite(pump2.redPin, HIGH);
digitalWrite(pump2.greenPin, LOW);
}
void setPump3Red() {
digitalWrite(pump3.redPin, HIGH);
digitalWrite(pump3.greenPin, LOW);
}
void setPump4Red() {
digitalWrite(pump4.redPin, HIGH);
digitalWrite(pump4.greenPin, LOW);
}
void setPump1Blank() {
digitalWrite(pump1.redPin, LOW);
digitalWrite(pump1.greenPin, LOW);
}
void setPump2Blank() {
digitalWrite(pump2.redPin, LOW);
digitalWrite(pump2.greenPin, LOW);
}
void setPump3Blank() {
digitalWrite(pump3.redPin, LOW);
digitalWrite(pump3.greenPin, LOW);
}
void setPump4Blank() {
digitalWrite(pump4.redPin, LOW);
digitalWrite(pump4.greenPin, LOW);
}
//----------------------------------------------------------------------
// SchedTable ledsBlink specific callback functions
// It is a lamp test
/*
* Turn all red LEDs on
*/
void allRedLedsOn() {
setPump1Red();
setPump2Red();
setPump3Red();
setPump4Red();
setPowerLedRed();
setRGBLedRed();
}
/*
* Turn all green LEDs on
*/
void allGreenLedsOn() {
setPump1Green();
setPump2Green();
setPump3Green();
setPump4Green();
setPowerLedGreen();
setRGBLedGreen();
}
/*
* Turn all LEDs off
*/
void allLedsOff() {
setPump1Blank();
setPump2Blank();
setPump3Blank();
setPump4Blank();
setPowerLedBlank();
setRGBLedBlank();
}
//----------------------------------------------------------------------
// Pumps callbacks functions
bool getPump1On() {
if ( pcf8574_1.digitalRead(pump1.sensorPin) == HIGH ) {
return true;
} else {
return false;
}
}
bool getPump2On() {
if ( pcf8574_1.digitalRead(pump2.sensorPin) == HIGH ) {
return true;
} else {
return false;
}
}
bool getPump3On() {
if ( pcf8574_2.digitalRead(pump3.sensorPin) == HIGH ) {
return true;
} else {
return false;
}
}
bool getPump4On() {
if ( pcf8574_2.digitalRead(pump4.sensorPin) == HIGH ) {
return true;
} else {
return false;
}
}
void setPump1Halt() {
pcf8574_1.digitalWrite(pump1.haltPin, LOW);
}
void setPump2Halt() {
pcf8574_1.digitalWrite(pump2.haltPin, LOW);
}
void setPump3Halt() {
pcf8574_2.digitalWrite(pump3.haltPin, LOW);
}
void setPump4Halt() {
pcf8574_2.digitalWrite(pump4.haltPin, LOW);
}
void setPump1Liberate() {
pcf8574_1.digitalWrite(pump1.haltPin, HIGH);
}
void setPump2Liberate() {
pcf8574_1.digitalWrite(pump2.haltPin, HIGH);
}
void setPump3Liberate() {
pcf8574_2.digitalWrite(pump3.haltPin, HIGH);
}
void setPump4Liberate() {
pcf8574_2.digitalWrite(pump4.haltPin, HIGH);
}
void setPump1PowerOn() {
blinkPowerLed.start();
pcf8574_1.digitalWrite(pump1.powerPin, LOW);
gPowerOn = true;
Serial.print(F("Pump 1 Power On - Start time: "));
Serial.print(gTimeOfStartUp, DEC);
Serial.println(F("s"));
}
void setPump2PowerOn() {
blinkPowerLed.start();
pcf8574_1.digitalWrite(pump2.powerPin, LOW);
gPowerOn = true;
Serial.print(F("Pump 2 Power On - Start time: "));
Serial.print(gTimeOfStartUp, DEC);
Serial.println(F("s"));
}
void setPump3PowerOn() {
blinkPowerLed.start();
pcf8574_2.digitalWrite(pump3.powerPin, LOW);
gPowerOn = true;
Serial.print(F("Pump 3 Power On - Start time: "));
Serial.print(gTimeOfStartUp, DEC);
Serial.println(F("s"));
}
void setPump4PowerOn() {
blinkPowerLed.start();
pcf8574_2.digitalWrite(pump4.powerPin, LOW);
gPowerOn = true;
Serial.print(F("Pump 4 Power On - Start time: "));
Serial.print(gTimeOfStartUp, DEC);
Serial.println(F("s"));
}
void setPump1PowerOff() {
Serial.print(F("Pump 1 Status: "));
if (gPump1Status == true) {
Serial.println(F("OK"));
} else {
Serial.println(F("Over Current"));
}
pcf8574_1.digitalWrite(pump1.powerPin, HIGH);
gPowerOn = false;
blinkPowerLed.stop();
setPowerLedBlank();
Serial.println(F("Pump 1 Power Off"));
}
void setPump2PowerOff() {
Serial.print(F("Pump 2 Status: "));
if (gPump2Status == true) {
Serial.println(F("OK"));
} else {
Serial.println(F("Over Current"));
}
pcf8574_1.digitalWrite(pump2.powerPin, HIGH);
gPowerOn = false;
blinkPowerLed.stop();
setPowerLedBlank();
Serial.println(F("Pump 2 Power Off"));
}
void setPump3PowerOff() {
Serial.print(F("Pump 3 Status: "));
if (gPump3Status == true) {
Serial.println(F("OK"));
} else {
Serial.println(F("Over Current"));
}
pcf8574_2.digitalWrite(pump3.powerPin, HIGH);
gPowerOn = false;
blinkPowerLed.stop();
setPowerLedBlank();
Serial.println(F("Pump 3 Power Off"));
}
void setPump4PowerOff() {
Serial.print(F("Pump 4 Status: "));
if (gPump4Status == true) {
Serial.println(F("OK"));
} else {
Serial.println(F("Over Current"));
}
pcf8574_2.digitalWrite(pump4.powerPin, HIGH);
gPowerOn = false;
blinkPowerLed.stop();
setPowerLedBlank();
Serial.println(F("Pump 4 Power Off"));
}
void setPump1Enable() {
gPump = 1;
//setAllPumpsPowerOff();
setPump1Yellow();
Serial.println(F("Pump 1 Enabled"));
}
void setPump2Enable() {
gPump = 2;
//setAllPumpsPowerOff();
setPump2Yellow();
Serial.println(F("Pump 2 Enabled"));
}
void setPump3Enable() {
gPump = 3;
//setAllPumpsPowerOff();
setPump3Yellow();
Serial.println(F("Pump 3 Enabled"));
}
void setPump4Enable() {
gPump = 4;
//setAllPumpsPowerOff();
setPump4Yellow();
Serial.println(F("Pump 4 Enabled"));
}
void setPump1Disable() {
//gPump = 0;
Serial.println(F("Pump 1 Disabled"));
Serial.println(F("-------------------------------------------------"));
pump2StartTimes();
}
void setPump2Disable() {
//gPump = 0;
Serial.println(F("Pump 2 Disabled"));
Serial.println(F("-------------------------------------------------"));
pump3StartTimes();
}
void setPump3Disable() {
//gPump = 0;
Serial.println(F("Pump 3 Disabled"));
Serial.println(F("-------------------------------------------------"));
pump4StartTimes();
}
void setPump4Disable() {
//gPump = 0;
Serial.println(F("Pump 4 Disabled"));
Serial.println(F("-------------------------------------------------"));
checkupEnd();
}
/*
* Pump times
*/
timeMarks pumpTimes() {
/* struct timeMarks {
int timeOfPowerOn;
int timeOfNormalOp;
int timeOfPowerOff;
int timeOfDisable;
int simulation;
} */
timeMarks tm;
tm.timeOfPowerOn = gTimeBeforeTest;
if (digitalRead(KEY_NORMAL_SIMULATION_PIN) == HIGH) {
tm.simulation = 1;
tm.timeOfNormalOp = tm.timeOfPowerOn + (gTimeOfSimulation/2);
tm.timeOfPowerOff = tm.timeOfPowerOn + gTimeOfSimulation;
tm.timeOfDisable = tm.timeOfPowerOff + gTimeAfterTest;
}
else {
tm.simulation = 0;
tm.timeOfNormalOp = tm.timeOfPowerOn + gTimeOfStartUp;
tm.timeOfPowerOff = tm.timeOfPowerOn + gTimeOfTest;
tm.timeOfDisable = tm.timeOfPowerOff + gTimeAfterTest;
}
return tm;
}
void pump1StartTimes() {
timeMarks tm = pumpTimes();
if (tm.simulation == 1) {
// Simulation of the pumps
Serial.println(F("Pump 1 Simulation"));
} else {
// Test of pumps
Serial.println(F("Pump 1 Test"));
}
pump1Times.empty();
pump1Times.at( 0, setPump1Enable);
pump1Times.at(tm.timeOfPowerOn, setPump1PowerOn);
pump1Times.at(tm.timeOfNormalOp, setPumpNormalOperation);
pump1Times.at(tm.timeOfPowerOff, setPump1PowerOff);
pump1Times.at(tm.timeOfDisable, setPump1Disable);
pump1Times.start(1);
}
void pump2StartTimes() {
timeMarks tm = pumpTimes();
if (tm.simulation == 1) {
// Simulation of the pumps
Serial.println(F("Pump 2 Simulation"));
} else {
// Test of pumps
Serial.println(F("Pump 2 Test"));
}
pump2Times.empty();
pump2Times.at( 0, setPump2Enable);
pump2Times.at(tm.timeOfPowerOn, setPump2PowerOn);
pump2Times.at(tm.timeOfNormalOp, setPumpNormalOperation);
pump2Times.at(tm.timeOfPowerOff, setPump2PowerOff);
pump2Times.at(tm.timeOfDisable, setPump2Disable);
pump2Times.start(1);
}
void pump3StartTimes() {
timeMarks tm = pumpTimes();
if (tm.simulation == 1) {
// Simulation of the pumps
Serial.println(F("Pump 3 Simulation"));
} else {
// Test of pumps
Serial.println(F("Pump 3 Test"));
}
pump3Times.empty();
pump3Times.at( 0, setPump3Enable);
pump3Times.at(tm.timeOfPowerOn, setPump3PowerOn);
pump3Times.at(tm.timeOfNormalOp, setPumpNormalOperation);
pump3Times.at(tm.timeOfPowerOff, setPump3PowerOff);
pump3Times.at(tm.timeOfDisable, setPump3Disable);
pump3Times.start(1);
}
void pump4StartTimes() {
timeMarks tm = pumpTimes();
if (tm.simulation == 1) {
// Simulation of the pumps
Serial.println(F("Pump 4 Simulation"));
} else {
// Test of pumps
Serial.println(F("Pump 4 Test"));
}
pump4Times.empty();
pump4Times.at( 0, setPump4Enable);
pump4Times.at(tm.timeOfPowerOn, setPump4PowerOn);
pump4Times.at(tm.timeOfNormalOp, setPumpNormalOperation);
pump4Times.at(tm.timeOfPowerOff, setPump4PowerOff);
pump4Times.at(tm.timeOfDisable, setPump4Disable);
pump4Times.start(1);
}
void checkupEnd() {
if (digitalRead(KEY_NORMAL_SIMULATION_PIN) == HIGH) {
Serial.println(F("End of Pumps Checkup Simulation"));
} else {
Serial.println(F("End of Pumps Checkup"));
}
Serial.println(F("Checkup Summary"));
if (gPump >= 1) {
Serial.print(F("Pump 1 Status: "));
if (gPump1Status == true) {
Serial.println(F("OK"));
} else {
Serial.println(F("Over Current"));
}
}
if (gPump >= 2) {
Serial.print(F("Pump 2 Status: "));
if (gPump2Status == true) {
Serial.println(F("OK"));
} else {
Serial.println(F("Over Current"));
}
}
if (gPump >= 3) {
Serial.print(F("Pump 3 Status: "));
if (gPump3Status == true) {
Serial.println(F("OK"));
} else {
Serial.println(F("Over Current"));
}
}
if (gPump >= 4) {
Serial.print(F("Pump 4 Status: "));
if (gPump4Status == true) {
Serial.println(F("OK"));
} else {
Serial.println(F("Over Current"));
}
}
blinkPowerLed.setPeriod(5);
blinkPowerLed.start();
Serial.println(F("-------------------------------------------------"));
}
/*
* Pump status and show
*/
void pumpStatusAndShow() {
switch (gPump) {
case 1:
if (gPumpOverCurrent) {
gPump1Status = false;
setPump1Red();
} else {
gPump1Status = true;
setPump1Green();
}
break;
case 2:
if (gPumpOverCurrent) {
gPump2Status = false;
setPump2Red();
} else {
gPump2Status = true;
setPump2Green();
}
break;
case 3:
if (gPumpOverCurrent) {
gPump3Status = false;
setPump3Red();
} else {
gPump3Status = true;
setPump3Green();
}
break;
case 4:
if (gPumpOverCurrent) {
gPump4Status = false;
setPump4Red();
} else {
gPump4Status = true;
setPump4Green();
}
break;
default:
// Do nothing
break;
}
}
/*
* Pump Normal Operation
*/
void setPumpNormalOperation() {
Serial.print(F("Pump "));
Serial.print(gPump, DEC);
Serial.println(F(" Start of Normal Operation and Current Monitoring"));
gPumpNormalOperation = true;
}
void checkupStart() {
setRGBLedBlue();
}
//----------------------------------------------------------------------
//
/*
* Pump Test Start
*/
void pumpTestStart() {
pump1Times.empty();
pump2Times.empty();
pump3Times.empty();
pump4Times.empty();
switch (gPump) {
case 1:
gPump1Status = false;
setPump1Blank();
pump1StartTimes();
break;
case 2:
gPump2Status = false;
setPump2Blank();
pump2StartTimes();
break;
case 3:
gPump3Status = false;
setPump3Blank();
pump3StartTimes();
break;
case 4:
gPump4Status = false;
setPump4Blank();
pump4StartTimes();
break;
default:
// Do nothing
break;
}
}
/*
* Pump Test Stop
*/
void pumpTestStop() {
pump1Times.empty();
pump2Times.empty();
pump3Times.empty();
pump4Times.empty();
switch (gPump) {
case 1:
setPump1PowerOff();
break;
case 2:
setPump2PowerOff();
break;
case 3:
setPump3PowerOff();
break;
case 4:
setPump4PowerOff();
break;
default:
// Do nothing
break;
}
}
//----------------------------------------------------------------------
// EasyButton Callback functions
// Callback function to be called when buttonRed is pressed
void onButtonRedPressed()
{
Serial.println(F("Red Button pressed: Stop"));
pumpTestStop();
}
// Callback function to be called when the buttonRed sequence is matched.
void onButtonRedSequenceMatched()
{
Serial.println(F("Red Button sequence matched: Stop & Start Next"));
pumpTestStop();
gPump = gPump + 1;
//pumpTestStop();
Serial.println(F("-------------------------------------------------"));
pumpTestStart();
}
// Callback function to be called when the buttonRed is pressed for duration.
void onButtonRedPressedForDuration()
{
Serial.println(F("Red Button pressed for duration: Stop & End"));
pumpTestStop();
Serial.println(F("-------------------------------------------------"));
//gPump = 5;
checkupEnd();
}
// Callback function to be called when buttonGreen is pressed
void onButtonGreenPressed()
{
Serial.println(F("Green Button pressed: Restart"));
pumpTestStart();
}
// Callback function to be called when the buttonGreen sequence is matched.
void onButtonGreenSequenceMatched()
{
Serial.println(F("Green Button sequence matched: Stop & Start Previous"));
pumpTestStop();
gPump = gPump - 1;
//pumpTestStop();
Serial.println(F("-------------------------------------------------"));
pumpTestStart();
}
// Callback function to be called when the buttonGreen is pressed for duration.
void onButtonGreenPressedForDuration()
{
Serial.println(F("Green Button pressed for duration: Stop & Reset"));
pumpTestStop();
Serial.println(F("Reseting now"));
Serial.println(F("-------------------------------------------------"));
delay(1000);
allGreenLedsOn();
allRedLedsOn();
delay(1000);
reboot();
}
void reboot() {
wdt_disable();
wdt_enable(WDTO_15MS);
while (1) {}
}
//----------------------------------------------------------------------
// HLW8032 energy metering callback function
void powerDataCallBack(int magic, float Vrms, float Irms, float P, float CF) {
(void)magic;
Serial.print("Vrms: ");
Serial.print(Vrms);
Serial.print(" V, Irms: ");
Serial.print(Irms);
Serial.print(" A, Power: ");
Serial.print(P);
Serial.print(" W, PF: ");
Serial.print(CF);
Serial.println(".");
}
//======================================================================
//----------------------------------------------------------------------
//**********************************************************************
// Setup function - runs once when you press reset or power the board
//**********************************************************************
void setup() {
//Serial print - initialize Serial for debuging purposes
Serial.begin(BAUDRATE);
/*
HLW8032 has a simple UART interface and adopts asynchronous serial communication
mode, which allows data communication via two one-way pins. The UART interface operates
at fixed frequency of 4800 bps and its interval for transmitting data is 50mS, which
is suitable for design of low velocity.
*/
altSerial.begin(4800);
delay(1000);
Serial.println();
Serial.println(F("================================================="));
Serial.println(F(">>> Hydraulic Pumps Checkup <<<"));
Serial.println(F("================================================="));
//=================================================
// Pins mode
pinsMode();
//=================================================
// pcf8574 IO Extends begining
Serial.print(F("Init pcf8574_1... "));
if (pcf8574_1.begin()){
Serial.println(F("U1 pcf8574_1 OK"));
} else {
Serial.println(F("U1 pcf8574_1 KO"));
}
Serial.print(F("Init pcf8574_2... "));
if (pcf8574_2.begin()){
Serial.println(F("U2 pcf8574_2 OK"));
} else {
Serial.println(F("U2 pcf8574_2 KO"));
}
if (altSerial.available() > 0) {
Serial.println(F("Alternative Serial Port OK"));
} else {
Serial.println(F("Alternative Serial Port KO"));
}
Serial.println(F("================================================="));
//=================================================
// EasyButtons begining and callback functions
// Initialize the buttonGreen
buttonGreen.begin();
// Initialize the buttonRed
buttonRed.begin();
// Add the callback function to be called when the buttonGreen is pressed.
buttonGreen.onPressed(onButtonGreenPressed);
// Add the callback function to be called when the buttonGreen is pressed for at least the given time.
buttonGreen.onPressedFor(2000, onButtonGreenPressedForDuration);
// Add the callback function to be called when buttonGreen the given sequence of presses is matched.
buttonGreen.onSequence(2 /* number of presses */, 2000 /* timeout */, onButtonGreenSequenceMatched /* callback */);
// Add the callback function to be called when the buttonRed is pressed.
buttonRed.onPressed(onButtonRedPressed);
// Add the callback function to be called when the buttonRed is pressed for at least the given time.
buttonRed.onPressedFor(2000, onButtonRedPressedForDuration);
// Add the callback function to be called when buttonRed the given sequence of presses is matched.
buttonRed.onSequence(2 /* number of presses */, 2000 /* timeout */, onButtonRedSequenceMatched /* callback */);
//=================================================
// ScheduleTable actions and times
// Schedule test of all LEDs
ledsBlink.at(1, allRedLedsOn);
ledsBlink.at(2, allLedsOff);
ledsBlink.at(3, allGreenLedsOn);
ledsBlink.at(4, allLedsOff);
ledsBlink.at(4, checkupStart);
ledsBlink.at(5, pump1StartTimes);
// Schedule Power LED blink
blinkPowerLed.at(1, setPowerLedYellow);
blinkPowerLed.at(2, setPowerLedBlank);
//=================================================
// HLW8032 Energy Meter
energyMeter.setVF(1.94);
energyMeter.onReceiveCallBack(powerDataCallBack);
//=================================================
Serial.println(F("Blink LEDS for lamp test"));
// Start LEDS blink
ledsBlink.start(1);
Serial.println(F("================================================="));
}
//**********************************************************************
// Loop function - runs over and over again forever
//**********************************************************************
void loop() {
static unsigned long previousTime;
static unsigned long intervalTime;
static unsigned long nowtime;
static bool overCurrent;
static bool previousOverCurrent;
//if (altSerial.available() > 0) {
// energyMeter.rxProcess(altSerial.read());
//}
energyMeter.rxProcess(altSerial.read());
// intervalTime of Overcurrent
if (digitalRead(KEY_NORMAL_SIMULATION_PIN) == HIGH) {
// Simulation of the pumps
intervalTime = 1000; // 1s
} else {
// Test of pumps
intervalTime = gTimeOfOverCurrent * 1000; // in seconds
}
if (gPowerOn) {
overCurrent = (digitalRead(OVERCURRENT_PIN) == HIGH);
gPumpOverCurrent = overCurrent;
pumpStatusAndShow();
if (overCurrent) {
//gPumpOverCurrent = true;
if (gPumpNormalOperation) {
if (previousOverCurrent != overCurrent) {
previousOverCurrent = overCurrent;
previousTime = millis();
Serial.print(F("Pump "));
Serial.print(gPump, DEC);
Serial.print(F(" Over Current! - Time limit: "));
Serial.print(intervalTime/1000, DEC);
Serial.println("s");
} else {
nowtime = millis();
if (nowtime - previousTime >= intervalTime) {
Serial.println(F("==> Over Current time limit <=="));
gPumpNormalOperation = false;
previousOverCurrent = false;
gPumpOverCurrent = false;
previousTime = 0;
// Move on to testing the next hydraulic pump
pumpTestStop();
Serial.println(F("-------------------------------------------------"));
gPump = gPump + 1;
if (gPump > 4) {
checkupEnd();
} else {
pumpTestStart();
}
}
}
}
} else {
//gPumpOverCurrent = false;
if (gPumpNormalOperation) {
if (previousOverCurrent != overCurrent) {
previousOverCurrent = overCurrent;
previousTime = 0;
Serial.print(F("Pump "));
Serial.print(gPump, DEC);
Serial.println(F(" Normal Current restored."));
}
}
}
} else {
gPumpOverCurrent = false;
previousTime = 0;
}
// Continuously read the status of the buttons
buttonGreen.read();
buttonRed.read();
ScheduleTable::update();
}