//Built-in #include #include #include #include // Additoinal Libraries #include #include #include #include // LiquidMenu_config.h needs to be modified to use I2C. #include #include // My Includes #include "config.h" #include "button.h" #include "slowPWM.h" #include "thermoControl.h" // Global variables. uint8_t KettleDuty = 0; uint8_t KettleTemp; uint8_t KettleSetpoint; modes KettleMode = OFF; const int UpdateInterval = 5000; /* Defined in config.h for now */ // uint8_t ThreshPWR = 5; // double Hysteresis = 1; // User I/O objects. Button Enter; MD_REncoder rotary = MD_REncoder(encoderDT, encoderCLK); LiquidCrystal_I2C lcd(0x27,20,4); // Internal I/O Adafruit_MAX31865 KettleThermo = Adafruit_MAX31865(kettleRTDCS); slowPWM boilPWM; thermoControl KettleController; void MessageReceived(char*, byte*, unsigned int); EthernetClient net; PubSubClient mqtt_client; unsigned long lastRun = 0; // Return a character array to represent the // On/Off state of the kettle. char* ShowKettleState() { if (KettleMode == MANUAL) { return (char*)F("Kettle: Manual"); } else if (KettleMode == AUTOMATIC) { return (char*)F("Kettle: Auto"); } else { return (char*)F("Kettle: Off"); } } char* ShowKettleSetting() { static char LCD_Line[21]; char setting[4]; if (KettleMode == MANUAL) { strcpy(LCD_Line, (char*)F("Kettle Power: ")); itoa(KettleDuty / 10, setting, 10); strcat(LCD_Line, setting); strcat(LCD_Line, "%"); return LCD_Line; } else if (KettleMode == AUTOMATIC) { strcpy(LCD_Line, (char*)F("Kettle Temp: ")); itoa(KettleSetpoint / 10, setting, 10); strcat(LCD_Line, setting); strcat(LCD_Line, "F"); return LCD_Line; } else { return (char*)""; } } // 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(); uint8_t inc; if (result) { uint8_t speed = rotary.speed(); speed >= 10 ? inc = 50 : inc = 10; } if (result == DIR_CW && KettleDuty < 1000) { KettleDuty = (KettleDuty / inc) * inc + inc; } else if (result == DIR_CCW && KettleDuty > 0) { KettleDuty = (KettleDuty / inc) * inc - inc; } } // LCD menu setup. LiquidLine kettle_state_line(0, 0, ShowKettleState); LiquidLine kettle_power_line(0, 1, ShowKettleSetting); LiquidScreen home_screen(kettle_state_line, kettle_power_line); LiquidMenu menu(lcd); void setup() { ConfigData config; EEPROM.get(ConfAddress, config); unsigned long lastRun = millis() - UpdateInterval; Serial.begin(9600); rotary.begin(); Ethernet.begin(config.mac, config.ip); attachInterrupt(digitalPinToInterrupt(encoderCLK), doEncoder, CHANGE); attachInterrupt(digitalPinToInterrupt(encoderDT), doEncoder, CHANGE); pinMode(encoderCLK, INPUT_PULLUP); pinMode(encoderDT, INPUT_PULLUP); Enter.begin(encoderBTN); boilPWM.begin(kettlePWM, config.period); KettleThermo.begin(MAX31865_3WIRE); mqtt_client.setServer(config.mqtt.broker, 1883); mqtt_client.setClient(net); mqtt_client.setCallback(MessageReceived); KettleController.begin(&KettleTemp, &KettleSetpoint, &KettleDuty, config.threshold, config.hysteresis); // if you get a connection, report back via serial: if (Ethernet.linkStatus() == LinkON) { ConnectMQTT(); } lcd.init(); lcd.backlight(); menu.init(); menu.add_screen(home_screen); menu.update(); }; void UpdateBoilKettle(){ static uint8_t last_KettleDuty = 0; static uint8_t last_KettleTemp = 0; if (Enter.pressed()) { KettleMode = (modes)(KettleMode + 1); menu.update(); } if (last_KettleDuty != KettleDuty) { last_KettleDuty = KettleDuty; menu.update(); } if (last_KettleTemp != KettleTemp) { last_KettleTemp = KettleTemp; menu.update(); } if (KettleMode != OFF) { KettleController.Compute(); digitalWrite(kettlePWM, boilPWM.compute(KettleDuty)); } else { digitalWrite(kettlePWM, boilPWM.compute(0)); } } void loop() { KettleTemp = (uint8_t)(KettleThermo.readRTD() * 10); UpdateBoilKettle(); unsigned long elapsedTime = (millis() - lastRun); if (Ethernet.linkStatus() == LinkON && elapsedTime >= UpdateInterval) { mqtt_client.loop(); //if (!mqtt_client.connected()) ConnectMQTT(); SendSensorData(); lastRun = millis(); } }