diff --git a/boil_kettle/boil_kettle.ino b/boil_kettle/boil_kettle.ino index 2034e4a..cb71a42 100644 --- a/boil_kettle/boil_kettle.ino +++ b/boil_kettle/boil_kettle.ino @@ -11,90 +11,61 @@ #include #include -// Secret stuff #include "config.h" +#include "menu.h" -// Global variables. +enum kettle_mode : uint8_t {OFF = 0, PWM = 1, OVERFLOW}; + +enum encoder_state : uint8_t { + ENC_ST_LINE = 0, // in this state it cycles the focus through the lines + ENC_ST_SETTING = 1, // in this state it "increases or decreases" the value of a setting + ENC_ST_OUT_OF_BOUNDS +}; + +enum function_types : uint8_t {increase = 1, decrease = 2}; + +/* ---------- Global variables ---------- */ byte KettleDuty = 0; -bool KettleOn = false; +kettle_mode KettleMode = OFF; +encoder_state EncoderState = ENC_ST_LINE; -// User I/O objects. -Button Enter(encoderBTN); -MD_REncoder rotary = MD_REncoder(encoderDT, encoderCLK); +/* ---------- User I/O objects ---------- */ +Button EncoderButton(encoderBTN); +MD_REncoder RotaryEncoder(encoderDT, encoderCLK); LiquidCrystal_I2C lcd(0x27,20,4); +/* ---------- Network bits ---------- */ EthernetClient net; MQTTClient mqtt_client; -// Return a character array to represent the -// On/Off state of the kettle. -char* KettleState() { - if (KettleOn) { - return (char*)"On"; - } else { - return (char*)"Off"; - } -} - -// Interrupt function to run when encoder is turned. -// -// Increases/decreases the kettle output to a max -// of 100% and minimum of 0%. -void doEncoder() -{ - uint8_t result = rotary.read(); - - if (result == DIR_CW && KettleDuty < 100) { - KettleDuty++; - } else if (result == DIR_CCW && KettleDuty > 0) { - KettleDuty--; - } - -} - -// LCD menu setup. - -LiquidLine KettleState_line(0, 0, "Boil Kettle ", KettleState); -LiquidLine kettle_power_line(0, 1, "Kettle Power % ", KettleDuty); - -LiquidScreen home_screen(KettleState_line, kettle_power_line); - +/* ---------- LCD menu setup ---------- */ +LiquidLine kettle_mode_line(0, 0, "Output Mode ", KettleState); +LiquidLine kettle_setpoint_line(0, 1, "Kettle Power ", KettleSetpoint, SetpointUnit); +LiquidLine kettle_actual_line(0, 2, "Kettle Temp ", KettleActual, "F"); +LiquidScreen home_screen(kettle_mode_line, kettle_setpoint_line, kettle_actual_line); LiquidMenu menu(lcd); -void UpdateBoilKettle(){ - static byte last_kettle_duty = 0; - - if (Enter.pressed()) { - KettleOn = !KettleOn; - menu.update(); - } - - if (last_kettle_duty != KettleDuty) { - last_kettle_duty = KettleDuty; - menu.update(); - } - - if (KettleOn) { - slowPWM(kettlePWM, KettleDuty, PeriodPWM); - } else { - slowPWM(kettlePWM, 0, PeriodPWM); - } -} - void setup() { Serial.begin(9600); - rotary.begin(); + RotaryEncoder.begin(); + EncoderButton.begin(); Ethernet.begin(mac, ip); Serial.println("Setting up..."); + // Attach functions menu lines + kettle_mode_line.attach_function(increase, kettle_mode_up); + kettle_mode_line.attach_function(decrease, kettle_mode_down); + kettle_setpoint_line.attach_function(increase, increase_setpoint); + kettle_setpoint_line.attach_function(decrease, decrease_setpoint); + + // Attach interrupts to the rotary encoder attachInterrupt(digitalPinToInterrupt(encoderCLK), doEncoder, CHANGE); attachInterrupt(digitalPinToInterrupt(encoderDT), doEncoder, CHANGE); pinMode(encoderCLK, INPUT_PULLUP); pinMode(encoderDT, INPUT_PULLUP); pinMode(kettlePWM, OUTPUT); - Enter.begin(); // if you get a connection, report back via serial: if (net.connect("www.google.com", 80)) { @@ -121,7 +92,14 @@ void setup() { }; void loop() { - UpdateBoilKettle(); + ButtonCheck(); + + if (KettleMode == PWM) { + slowPWM(kettlePWM, KettleDuty, PeriodPWM); + } else { + slowPWM(kettlePWM, 0, PeriodPWM); + } + static unsigned long lastRun = millis() - UpdateInterval; unsigned long elapsedTime = (millis() - lastRun); @@ -134,3 +112,147 @@ void loop() { } } + +/* Interrupt function to run when encoder is turned. +Either switches focus of the menu lines or +changes setpoint of focused line. */ +void doEncoder() { + uint8_t result = RotaryEncoder.read(); + + // check in which state the encoder is currently in + switch (EncoderState) { + case ENC_ST_LINE: // cycling focus through the lines + if (result == DIR_CW) { + menu.switch_focus(true); + } else { + menu.switch_focus(false); + } + break; + case ENC_ST_SETTING: // changing a setting + if (result == DIR_CW) { + menu.call_function(increase); + } else { + menu.call_function(decrease); + } + break; + default: // invalid state + EncoderState = 0; // return to a valid state + break; + } + menu.update(); +} + +// Cycle the rotary encoder state when button is pressed. +// Switches between menu navigation and adjusting setpoints. +void ButtonCheck(){ + + if (!EncoderButton.pressed()) { return; } + + if (EncoderState + 1 < ENC_ST_OUT_OF_BOUNDS) { // check if the next state is valid + EncoderState = (encoder_state)(EncoderState + 1); // increment to the next state (ENC_ST_LINE -> ENC_ST_SETTING) + } else { + EncoderState = 0; // in case of press while changing a setting - wrap around to state ENC_ST_LINE + } + +} + +/** + * Return a character array to represent the + * On/Off state of the kettle. + */ +char* KettleState() { + if (KettleMode == OFF) { + return (char*)"Off"; + } else if (KettleMode == PWM) { + return (char*)"PWM"; + } else { + return (char*)"PID"; + } +} + +/** + * Return the setpoint of the kettle + */ +char* KettleSetpoint() { + if (KettleMode == OFF) { + return (char*)"---"; + } else if (KettleMode == PWM) { + return (char*)KettleDuty; + } + /* Eventually + else if (KettleMode == PID) { + return (char*)KettleTEMP; + } + */ +} + +/** + * Return the setpoint as char. + * Dummy function for now. + */ +char* KettleActual() { + return (char*)"NA"; +} + +char* SetpointUnit(){ + if (KettleMode == OFF) { + return (char*)" "; + } else if (KettleMode == PWM) { + return (char*)"%"; + } else { + return (char*)"F"; + } +} + +/** + * Cycle kettle mode forward. + */ +void kettle_mode_up() { + if (KettleMode + 1 < OVERFLOW) { + KettleMode = (kettle_mode)(KettleMode + 1); + } else { + KettleMode = 0; + } +} + +/** + * Cycle kettle mode backward. + */ +void kettle_mode_down() { + if (KettleMode - 1 >= 0) { + KettleMode = (kettle_mode)(KettleMode - 1); + } else { + KettleMode = OVERFLOW - 1; + } +} + +/** + * Increase setpoint for line. + */ +void increase_setpoint() { + if (KettleMode == PWM && KettleDuty < 100) { + KettleDuty++; + } + + /* Eventually + else if (KettleMode == PID && KettleTEMP < 220) { + KettleTEMP++; + } + */ +} + +/** + * Decrease setpoint for line. + */ +void decrease_setpoint() { + if (KettleMode == PWM && KettleDuty > 0) { + KettleDuty--; + } + + /* Eventually + else if (KettleMode == PID && KettleTEMP > 0) { + KettleTEMP--; + } + */ +} + diff --git a/boil_kettle/menu.h b/boil_kettle/menu.h new file mode 100644 index 0000000..f57c79e --- /dev/null +++ b/boil_kettle/menu.h @@ -0,0 +1,10 @@ +/* ---------- Menu Function Prototypes ---------- */ + +char* KettleState(); +char* KettleSetpoint(); +char* KettleActual(); +char* SetpointUnit(); +void kettle_mode_up(); +void kettle_mode_down(); +void increase_setpoint(); +void decrease_setpoint(); diff --git a/boil_kettle/mqtt.ino b/boil_kettle/mqtt.ino index c24a5ca..497913f 100644 --- a/boil_kettle/mqtt.ino +++ b/boil_kettle/mqtt.ino @@ -14,7 +14,7 @@ void ConnectMQTT() { Serial.println("\nconnected!"); - mqtt_client.subscribe(Concatenate(TOPIC_PREFIX, BKTOPIC)); + mqtt_client.subscribe(Concatenate(TOPIC_PREFIX, BK_SETPOINT_TOPIC)); } void MessageReceived(String &topic, String &payload) { @@ -33,7 +33,7 @@ void MessageReceived(String &topic, String &payload) { return; } - if (topic == Concatenate(TOPIC_PREFIX, BKTOPIC)) { + if (topic == Concatenate(TOPIC_PREFIX, BK_SETPOINT_TOPIC)) { // Update PWM setpoint. String name = doc["entity"]; String setting = doc["setpoint"]; @@ -68,6 +68,6 @@ static void SendSensorData() { String jstr; serializeJson(doc, jstr); - mqtt_client.publish(Concatenate(TOPIC_PREFIX, "sensor/boil_kettle"), jstr); + mqtt_client.publish(Concatenate(TOPIC_PREFIX, BK_ACTUAL_TOPIC), jstr); } diff --git a/boil_kettle/slowPWM.ino b/boil_kettle/slowPWM.ino index 7e10035..4ff9bc4 100644 --- a/boil_kettle/slowPWM.ino +++ b/boil_kettle/slowPWM.ino @@ -1,9 +1,10 @@ -// Bit bang low frequency PWM. -// -// Parameters: -// outputPin (byte) - Pin number to output PWM. -// dutyCycle (byte) - PWM from 0 - 100. -// period (unsigned long) - Period in milliseconds. +/** Bit bang low frequency PWM. + * + * Parameters: + * outputPin (byte) - Pin number to output PWM. + * dutyCycle (byte) - PWM from 0 - 100. + * period (unsigned long) - Period in milliseconds. + */ void slowPWM(byte outputPin, byte dutyCycle, unsigned long period) { pinMode(outputPin, OUTPUT);