diff --git a/boil_kettle/boil_kettle.ino b/boil_kettle/boil_kettle.ino index e5a6048..2597925 100644 --- a/boil_kettle/boil_kettle.ino +++ b/boil_kettle/boil_kettle.ino @@ -11,265 +11,133 @@ #include #include + // My Includes -#include "button.h" #include "config.h" -#include "menu.h" +#include "button.h" -enum kettle_mode {OFF=0, PWM=1, OVERFLOW}; -enum encoder_state {ENC_ST_LINE=0, ENC_ST_SETTING=1, ENC_ST_OOB}; -enum function_types {increase=1, decrease}; +// Pin definitions +#define encoderCLK 2 +#define encoderDT 3 +#define encoderBTN 4 +#define kettlePWM 5 -/* ---------- Global variables ---------- */ +// Global variables. byte KettleDuty = 0; -bool NetworkOn = false; -kettle_mode KettleMode = OFF; -encoder_state EncoderState = ENC_ST_LINE; +bool KettleOn = false; -/* ---------- User I/O objects ---------- */ -Button EncoderButton; -MD_REncoder RotaryEncoder = MD_REncoder(encoderDT, encoderCLK); -LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27,20,4); +// User I/O objects. +Button Enter; +MD_REncoder rotary = MD_REncoder(encoderDT, encoderCLK); +LiquidCrystal_I2C lcd(0x27,20,4); -/* ---------- Controller I/O objects ---------- */ -Adafruit_MAX31865 kettleRTD = Adafruit_MAX31865(kettleRTDCS); -Adafruit_MAX31865 mashRTD = Adafruit_MAX31865(mashRTDCS); +float output = 0; +int updateInterval = 1000; -/* ---------- Network bits ---------- */ EthernetClient net; MQTTClient mqtt_client; -/* ---------- 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); +unsigned long lastRun = 0; + +// 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); + LiquidMenu menu(lcd); void setup() { + unsigned long lastRun = millis() - updateInterval; Serial.begin(9600); - Serial.println("Setting up..."); + rotary.begin(); Ethernet.begin(mac, ip); + Serial.println("Setting up..."); - // Set all the I/O pin states - RotaryEncoder.begin(); - EncoderButton.begin(encoderBTN); - kettleRTD.begin(MAX31865_3WIRE); - mashRTD.begin(MAX31865_3WIRE); - pinMode(encoderCLK, INPUT_PULLUP); - pinMode(encoderDT, INPUT_PULLUP); - pinMode(kettlePWM, OUTPUT); - - // Attach interrupts to the rotary encoder attachInterrupt(digitalPinToInterrupt(encoderCLK), doEncoder, CHANGE); attachInterrupt(digitalPinToInterrupt(encoderDT), doEncoder, CHANGE); - // Attach functions to menu lines - kettle_mode_line.attach_function(increase, kettle_mode_next); - kettle_mode_line.attach_function(decrease, kettle_mode_previous); - kettle_setpoint_line.attach_function(increase, increase_setpoint); - kettle_setpoint_line.attach_function(decrease, decrease_setpoint); + pinMode(encoderCLK, INPUT_PULLUP); + pinMode(encoderDT, INPUT_PULLUP); + Enter.begin(encoderBTN); + pinMode(encoderBTN, INPUT_PULLUP); + + // if you get a connection, report back via serial: + if (Ethernet.linkStatus() == LinkON) { + SetupMQTT(MQTT_BROKER); + } else { + // if you didn't get a connection to the server: + Serial.println("connection failed"); + } lcd.init(); lcd.backlight(); - // Check for network connection before attemping MQTT setup. - if (Ethernet.linkStatus() == LinkON) { - NetworkOn = true; - - lcd.setCursor(0, 1); - lcd.print("Ethernet connected."); - lcd.setCursor(1, 1); - lcd.print(net.remoteIP()); - - SetupMQTT(MQTT_BROKER); - } else { - lcd.setCursor(0, 1); - lcd.print("No network connection."); - } - - delay(5000); - lcd.clear(); - menu.init(); menu.add_screen(home_screen); menu.update(); }; -void loop() { - ButtonCheck(); +void UpdateBoilKettle(){ + static byte last_KettleDuty = 0; - if (KettleMode == PWM) { + if (Enter.pressed()) { + KettleOn = !KettleOn; + menu.update(); + } + + if (last_KettleDuty != KettleDuty) { + last_KettleDuty = KettleDuty; + menu.update(); + } + + if (KettleOn) { slowPWM(kettlePWM, KettleDuty, PeriodPWM); } else { slowPWM(kettlePWM, 0, PeriodPWM); } +} + +void loop() { + UpdateBoilKettle(); - static unsigned long lastRun = millis() - UpdateInterval; unsigned long elapsedTime = (millis() - lastRun); - // - if (NetworkOn && elapsedTime >= UpdateInterval) { + if (elapsedTime >= updateInterval) { mqtt_client.loop(); - if (!mqtt_client.connected()) ConnectMQTT(); + //if (!mqtt_client.connected()) ConnectMQTT(); SendSensorData(); lastRun = millis(); } } - -/* 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_OOB) { // 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 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 actual temp as char. - */ -char* KettleActual() { - char buffer[6]; - dtostrf(kettleRTD.temperature(RNOMINAL_KETTLE, RREF_KETTLE), 5, 1, buffer); - return buffer; -} - -/** - * Return the actual temp as char. - */ -char* MashActual() { - char buffer[6]; - dtostrf(mashRTD.temperature(RNOMINAL_MASH, RREF_MASH), 5, 1, buffer); - return buffer; -} - -char* SetpointUnit(){ - if (KettleMode == OFF) { - return (char*)" "; - } else if (KettleMode == PWM) { - return (char*)"%"; - } else { - return (char*)"F"; - } -} - -/** - * Cycle kettle mode forward. - */ -void kettle_mode_next() { - if (KettleMode + 1 < OVERFLOW) { - KettleMode = (kettle_mode)(KettleMode + 1); - } else { - KettleMode = 0; - } -} - -/** - * Cycle kettle mode backward. - */ -void kettle_mode_previous() { - 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 deleted file mode 100644 index f57c79e..0000000 --- a/boil_kettle/menu.h +++ /dev/null @@ -1,10 +0,0 @@ -/* ---------- 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 d72d471..bd63847 100644 --- a/boil_kettle/mqtt.ino +++ b/boil_kettle/mqtt.ino @@ -1,16 +1,14 @@ -char * Concatenate(char *first, char *second) { - static char buf[30]; - strcpy(buf,first); - strcat(buf,second); - return buf; -} - void ConnectMQTT() { - while (!mqtt_client.connect("brewhouse", MQTT_USER, MQTT_PASSWORD)) { + static char *password = MQTT_PASSWORD; + static char *user = MQTT_USER; + Serial.println("connecting MQTT..."); + while (!mqtt_client.connect("brewhouse", user, password)) { + Serial.print("."); delay(1000); } - mqtt_client.subscribe(Concatenate(TOPIC_PREFIX, BK_SETPOINT_TOPIC)); + Serial.println("\nconnected!"); + mqtt_client.subscribe("brewery/setpoint/bk"); } void MessageReceived(String &topic, String &payload) { @@ -28,8 +26,10 @@ void MessageReceived(String &topic, String &payload) { Serial.println(error.f_str()); return; } - - if (topic == Concatenate(TOPIC_PREFIX, BK_SETPOINT_TOPIC)) { + char buf[30]; + strcpy(buf,TOPIC_PREFIX); + strcat(buf,BOIL_SETPOINT_TOPIC); + if (topic == buf) { // Update PWM setpoint. String name = doc["entity"]; String setting = doc["setpoint"]; @@ -41,7 +41,7 @@ void MessageReceived(String &topic, String &payload) { } } -void SetupMQTT(char *broker) { +void SetupMQTT(const char *broker) { // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported // by Arduino. You need to set the IP address directly. Serial.println("Setup MQTT client."); @@ -64,6 +64,9 @@ static void SendSensorData() { String jstr; serializeJson(doc, jstr); - mqtt_client.publish(Concatenate(TOPIC_PREFIX, BK_ACTUAL_TOPIC), jstr); + String topic = TOPIC_PREFIX; + topic += "sensor/boil_kettle"; + + mqtt_client.publish(topic, jstr); } diff --git a/boil_kettle/slowPWM.ino b/boil_kettle/slowPWM.ino index 9bca78a..5ec4777 100644 --- a/boil_kettle/slowPWM.ino +++ b/boil_kettle/slowPWM.ino @@ -1,12 +1,11 @@ -/** 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 period from 0 - 100. void slowPWM(byte outputPin, byte dutyCycle, unsigned long period) { + pinMode(outputPin, OUTPUT); static byte outputState = LOW; static unsigned long lastSwitchTime = 0;