Latest boil kettle code.

This commit is contained in:
Chris Giacofei 2024-04-26 08:55:20 -04:00
parent 31b23910f0
commit 6730f9f390

View File

@ -1,92 +1,256 @@
//Built-in //Built-in
#include <Arduino.h> #include <Arduino.h>
#include <SPI.h> #include <SPI.h>
#include <Ethernet.h> //#include <Ethernet.h>
#include <EEPROM.h>
// Additoinal Libraries // Additoinal Libraries
#include <PubSubClient.h> #include <ArduinoJson.h>
#include <cJSON.h> //#include <MQTT.h>
#include <LiquidCrystal_I2C.h> #include <LiquidCrystal_I2C.h>
#include <LiquidMenu.h> // LiquidMenu_config.h needs to be modified to use I2C. #include <LiquidMenu.h> // LiquidMenu_config.h needs to be modified to use I2C.
#include <MD_REncoder.h> #include <MD_REncoder.h>
#include <Adafruit_MAX31865.h>
//#include <EEPROM-Storage.h>
// My Includes // My Includes
#include "config.h" #include "config.h"
#include "globals.h" #include "src/button/button.h"
#include "src/datatypes.h" #include "src/slowPWM/slowPWM.h"
#include "src/button.h" #include "src/thermoControl/thermoControl.h"
#include "src/slowPWM.h" //#include "src/Arduino-PID-Library/PID_v1.h"
#include "src/thermoControl.h"
#include "src/mqtt.h"
#include "src/functions.h"
void setup() { double KettleDuty = 0;
/** double KettleSetpoint = 70;
* Any state information that needs to be kept between reboots double CurrentTemp;
* will be stored in EEPROM. bool tuning = false;
*
* This will allow modifying these through MQTT communication
* later without needing to recompile the code.
*/
ConfigData config;
EEPROM.get(ConfAddress, config);
unsigned long lastRun = millis() - UpdateInterval; //EEPROMStorage<double> eepromKp(0, 2.0); // 9 bytes for doubles 8 + 1 for checksum
Serial.begin(9600); //EEPROMStorage<double> eepromKi(9, 5.0); // Initialize at zero.
//EEPROMStorage<double> eepromKd(18, 1.0);
Ethernet.begin(config.mac, config.ip); // User I/O objects.
Button Enter;
slowPWM boilPWM;
MD_REncoder rotary = MD_REncoder(encoderDT, encoderCLK);
LiquidCrystal_I2C lcd(0x27, 20, 4);
Adafruit_MAX31865 thermoRTD = Adafruit_MAX31865(KettleRTD);
thermoControl Controller(&CurrentTemp, &KettleSetpoint, &KettleDuty, AUTOMATIC);
/** //PID ControllerPID(&CurrentTemp, &KettleDuty, &KettleSetpoint, eepromKp, eepromKi, eepromKd, P_ON_M, DIRECT);
* Setup pins and interrupts/
*/
attachInterrupt(digitalPinToInterrupt(I_CLK), doEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(I_DT), doEncoder, CHANGE);
rotary.begin(); unsigned long lastRun = 0;
Enter.begin(I_BTN);
boilPWM.begin(O_PWM, config.period);
/** // Return a character array to represent the
* Kettle temp control // On/Off state of the kettle.
*/ char* KettleState() {
KettleController.begin(I_CS1); switch (Controller.Mode()) {
KettleController.Hysteresis(config.hysteresis); case OFF: return (char*)"OFF";
KettleController.ThreshPWR(config.threshold); case AUTOMATIC: return (char*)"AUT";
case MANUAL: return (char*)"MAN";
}
}
/** byte setpoint() {
* No sense messing with MQTT if we're not on the network. return (byte)KettleSetpoint;
*/ }
if (Ethernet.linkStatus() == LinkON) {
mqtt_client.setServer(config.mqtt.broker, 1883); byte duty() {
mqtt_client.setClient(net); return (byte)KettleDuty;
mqtt_client.setCallback(MessageReceived); }
ConnectMQTT();
byte current() {
return (byte)CurrentTemp;
}
// LCD menu setup.
LiquidLine KettleState_line(0, 0, "Boil Kettle ", KettleState);
LiquidLine kettle_temp_line(0, 1, "Setpoint (F) ", setpoint);
LiquidLine kettle_power_line(0, 2, "Power (%) ", duty);
LiquidLine kettle_currenttemp_line(0, 3, "Actual Temp (F) ", current);
LiquidScreen home_screen(KettleState_line, kettle_temp_line, kettle_power_line,kettle_currenttemp_line);
LiquidMenu menu(lcd);
// 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 = 1;
if (result) {
uint8_t speed = rotary.speed();
speed >= 10 ? inc = 5 : inc = 1;
} }
/** if (Controller.Mode() == AUTOMATIC) {
* Fire up the LCD. if (result == DIR_CW) {
*/ KettleSetpoint = (KettleSetpoint / inc) * inc + inc;
} else if (result == DIR_CCW) {
KettleSetpoint = (KettleSetpoint / inc) * inc - inc;
}
KettleSetpoint = max(KettleSetpoint,0);
KettleSetpoint = min(KettleSetpoint,212);
} else if (Controller.Mode() == MANUAL) {
if (result == DIR_CW) {
KettleDuty = (KettleDuty / inc) * inc + inc;
} else if (result == DIR_CCW) {
KettleDuty = (KettleDuty / inc) * inc - inc;
}
KettleDuty = max(KettleDuty,0);
KettleDuty = min(KettleDuty,100);
}
//menu.update();
}
void setup() {
lastRun = millis() - UpdateInterval;
Serial.begin(115200);
rotary.begin();
thermoRTD.begin(MAX31865_3WIRE);
attachInterrupt(digitalPinToInterrupt(encoderCLK), doEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(encoderDT), doEncoder, CHANGE);
pinMode(encoderCLK, INPUT_PULLUP);
pinMode(encoderDT, INPUT_PULLUP);
Enter.begin(encoderBTN);
boilPWM.begin(kettlePWM, PeriodPWM);
Controller.Mode(OFF);
lcd.init(); lcd.init();
lcd.backlight(); lcd.backlight();
menu.init(); menu.init();
menu.add_screen(home_screen); menu.add_screen(home_screen);
menu.update(); menu.update();
}; };
void loop() { void run_kettle() {
UpdateBoilKettle(); if (Enter.pressed()) {
Serial.println("Enter Pressed");
unsigned long elapsedTime = (millis() - lastRun); if (Controller.CycleMode() == OFF) {
KettleDuty = 0;
if (Ethernet.linkStatus() == LinkON && elapsedTime >= UpdateInterval) { }
mqtt_client.loop(); menu.update();
//if (!mqtt_client.connected()) ConnectMQTT();
SendSensorData();
lastRun = millis();
} }
Controller.Compute();
} }
/*
void run_tuning() {
if (Enter.pressed()) {
stopAutoTune();
}
int result = ControllerPID.ComputeTune();
if (result!=0)
{
tuning = false;
}
if(!tuning)
{ //we're done, set the tuning parameters
ControllerPID.SetTunings(ControllerPID.TunedKp(),ControllerPID.TunedKi(),ControllerPID.TunedKd());
ControllerPID.Mode(OFF);
}
}
*/
void loop() {
unsigned long now = millis();
static unsigned long lastTime=now-2000;
unsigned long timeChange = (now - lastTime);
static byte lastoutput = LOW;
static double lastKettleDuty = 0;
static double lastKettleSetpoint = 0;
static byte lastTemperature;
if(timeChange >= 2000) {
CurrentTemp = 32 + 1.8 * thermoRTD.temperature(RNOMINAL_KETTLE, RREF_KETTLE);
lastTime = now;
}
if (!tuning) {
run_kettle();
} else {
//run_tuning();
}
byte output = boilPWM.Compute(KettleDuty);
if (output != lastoutput) {
digitalWrite(kettlePWM, output);
lastoutput = output;
}
if (lastKettleDuty != KettleDuty || lastKettleSetpoint != KettleSetpoint || lastTemperature != (byte)CurrentTemp) {
menu.update();
lastKettleDuty = KettleDuty;
lastKettleSetpoint = KettleSetpoint;
lastTemperature = (byte)CurrentTemp;
}
}
/*
void startAutoTune() {
if(!tuning) {
//Set the output to the desired starting frequency.
KettleDuty=50;
ControllerPID.SetNoiseBand(1);
ControllerPID.SetOutputStep(30);
ControllerPID.SetLookbackSec(20);
ControllerPID.Mode(AUTOMATIC);
tuning=true;
}
}
void stopAutoTune() {
if(tuning) { //cancel autotune
ControllerPID.Cancel();
ControllerPID.Mode(OFF);
tuning=false;
}
}
void SaveTunings() {
eepromKp = ControllerPID.GetKp();
eepromKi = ControllerPID.GetKi();
eepromKd = ControllerPID.GetKd();
}
void SerialSend()
{
Serial.print("setpoint: ");Serial.print(KettleSetpoint); Serial.print(" ");
Serial.print("input: ");Serial.print(CurrentTemp); Serial.print(" ");
Serial.print("output: ");Serial.print(KettleDuty); Serial.print(" ");
if(tuning){
Serial.println("tuning mode");
} else {
Serial.print("kp: ");Serial.print(ControllerPID.GetKp());Serial.print(" ");
Serial.print("ki: ");Serial.print(ControllerPID.GetKi());Serial.print(" ");
Serial.print("kd: ");Serial.print(ControllerPID.GetKd());Serial.println();
}
}
void SerialReceive()
{
if(Serial.available()) {
String myinput;
myinput = Serial.readString();
myinput.trim();
if(myinput=="start"){
startAutoTune();
} else if(myinput=="stop") {
stopAutoTune();
} else if(myinput=="save") {
SaveTunings();
}
}
}
*/