Refactor. Receives commands from remote and just sends monitoring state.
1 parent 1965b73 commit c3eb76fc458d78f2ed6ef4b4fc8bfddf4a93ee48
@Alex Tucker Alex Tucker authored on 15 Apr
Showing 1 changed file
View
132
greenhouse.ino
uint8_t flags;
};
 
struct State {
unsigned int voltage, moisture, intervals;
unsigned int dry, wet;
byte state, delay_hours, max_time_mins, pumpSpeed;
unsigned int voltage, moisture;
byte pumpSpeed;
bool pumpRunning;
byte errors;
};
 
struct Payload {
Header header;
State state;
#define PROC_PUMP_OFF 0
#define PROC_PUMP_ON 1
#define PROC_SLEEP 2
 
struct Cmd {
byte proc, arg;
};
 
Header my_header, their_header;
 
State state;
Header my_header = {
HOME_ID, STATION_ID, 0, 0
};
Cmd cmd;
 
bool setupLoRa() {
LoRa.setPins(10, 9, 2);
LoRa.enableCrc();
void setup() {
#ifdef DEBUG
Serial.begin(9600);
#endif
state.state = WAIT_FOR_DELAY_OR_DRY;
state.intervals = 0;
state.pumpRunning = false;
state.pumpSpeed = PUMP_SPEED;
state.dry = DRY;
state.wet = WET;
state.delay_hours = DELAY;
state.max_time_mins = MAX_TIME;
state.errors = 0;
my_header = { HOME_ID, STATION_ID, 0, 0 };
their_header = { 0, 0, 0, 0 };
state = { 0, 0, PUMP_SPEED, false, 0 };
cmd = { 0, 0 };
// DPRINTLN("Setting one time state to EEPROM");
// EEPROM.put(0, state);
 
analogReference(DEFAULT);
}
}
 
void pumpOn(int speed) {
DPRINT("Switching pump on at ");
DPRINTLN(speed);
pinMode(motor_in_1, OUTPUT);
pinMode(motor_in_2, OUTPUT);
pinMode(motor_sleep_pin, OUTPUT);
digitalWrite(motor_sleep_pin, HIGH);
digitalWrite(motor_in_1, LOW);
analogWrite(motor_in_2, speed);
state.pumpSpeed = speed;
state.pumpRunning = true;
}
 
void pumpOff() {
DPRINTLN("Switching pump off");
pinMode(motor_in_1, OUTPUT);
pinMode(motor_in_2, OUTPUT);
pinMode(motor_sleep_pin, OUTPUT);
digitalWrite(motor_in_1, LOW);
voltage = voltage + voltage_reads[i];
moisture = moisture + moisture_reads[i];
}
state.voltage = voltage / SAMPLES;
state.moisture = moisture / SAMPLES;
if (state.voltage <= 135) {
LoRa.sleep();
LoRa.end();
radio_initialized = false;
}
state.moisture = moisture / SAMPLES;
pumpOff();
} else {
sendState();
delay(2000);
LoRa.sleep();
}
DPRINT("voltage = ");
DPRINTLN(state.voltage);
DPRINT("moisture = ");
DPRINTLN(state.moisture);
DPRINT("state = ");
DPRINTLN(state.state);
DPRINT("intervals = ");
DPRINTLN(state.intervals);
DPRINT("radio = ");
DPRINTLN(radio_initialized);
DFLUSH;
switch(state.state) {
case WAIT_FOR_DELAY_OR_DRY:
if ((state.moisture >= state.dry) || (state.intervals > (state.delay_hours * 60 * 60 / INTERVAL))) {
state.state = WATER_TILL_WET_MAX_TIME;
pumpOn(state.pumpSpeed);
state.intervals = 0;
}
break;
case WATER_TILL_WET_MAX_TIME:
if (state.intervals > (state.max_time_mins * 60 / INTERVAL)) {
// not yet wet enough, so leave for another MAX_TIME before watering
state.state = WAIT_FOR_MAX_TIME;
pumpOff();
state.intervals = 0;
} else if (state.moisture <= state.wet) {
state.state = WAIT_FOR_DELAY_OR_DRY;
pumpOff();
state.intervals = 0;
}
break;
case WAIT_FOR_MAX_TIME:
if (state.intervals > (state.max_time_mins * 60 / INTERVAL)) {
state.state = WATER_TILL_WET_MAX_TIME;
pumpOn(PUMP_SPEED);
state.intervals = 0;
}
break;
default:
state.state = WAIT_FOR_DELAY_OR_DRY;
pumpOff();
state.intervals = 0;
state.errors++;
}
sendState();
if (state.pumpRunning) {
delay(INTERVAL * 1000);
delay(8000);
// LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_ON, TIMER1_ON, TIMER0_ON,
// SPI_OFF, USART0_OFF, TWI_OFF);
} else {
// LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
delay(2000);
LoRa.sleep();
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
// delay(8000);
}
state.intervals++;
}
}
 
void sendState() {
if (radio_initialized) {
my_header.seq++;
LoRa.beginPacket();
LoRa.write((byte *)&(my_header), sizeof(Header));
LoRa.write((byte *)&(state), sizeof(State));
LoRa.endPacket();
 
void onReceive(int packetSize) {
DPRINT("Received packet, size=");
DPRINTLN(packetSize);
if (packetSize == (sizeof(Header) + sizeof(State))) {
if (packetSize == (sizeof(Header) + sizeof(Cmd))) {
DPRINT("Reading: ");
Header their_header;
for (int i=0; i<sizeof(Header); i++) {
byte b = LoRa.read();
DPRINTHEX(b);
((byte *)&their_header)[i] = b;
bool for_me = ((their_header.to == STATION_ID) && (their_header.from == HOME_ID));
DPRINTLN("");
DPRINT("For me: ");
DPRINTLN(for_me);
for (int i=0; i<sizeof(State); i++) {
for (int i=0; i<sizeof(Cmd); i++) {
byte b = LoRa.read();
if (for_me) {
((byte *)&state)[i] = b;
((byte *)&cmd)[i] = b;
}
DPRINTHEX(b);
}
if (for_me) {
if (cmd.proc == PROC_PUMP_OFF) {
pumpOff();
} else if (cmd.proc == PROC_PUMP_ON) {
pumpOn(cmd.arg);
}
}
}
DPRINTLN("");
DPRINTLN("Finished onReceive()");
LoRa.sleep();
}
// LoRa.sleep();
}