| |
---|
| | 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(); |
---|
| | } |
---|
| | |
---|
| | |