175 lines
4.1 KiB
C++
175 lines
4.1 KiB
C++
//Built-in
|
|
#include <Arduino.h>
|
|
#include <SPI.h>
|
|
#include <Ethernet.h>
|
|
#include <EEPROM.h>
|
|
#include <PubSubClient.h>
|
|
#include <cJSON.h>
|
|
|
|
// Additoinal Libraries
|
|
#include <LiquidCrystal_I2C.h>
|
|
#include <LiquidMenu.h> // LiquidMenu_config.h needs to be modified to use I2C.
|
|
#include <MD_REncoder.h>
|
|
|
|
// My Includes
|
|
#include "config.h"
|
|
#include "globals.h"
|
|
#include "button.h"
|
|
#include "slowPWM.h"
|
|
#include "thermoControl.h"
|
|
|
|
/* Defined in config.h for now */
|
|
// uint8_t ThreshPWR = 5;
|
|
// double Hysteresis = 1;
|
|
|
|
// User I/O objects.
|
|
Button Enter;
|
|
MD_REncoder rotary = MD_REncoder(I_DT, I_CLK);
|
|
LiquidCrystal_I2C lcd(0x27,20,4);
|
|
|
|
// Internal I/O objects.
|
|
slowPWM boilPWM;
|
|
thermoControl KettleController;
|
|
|
|
// Network objects.
|
|
EthernetClient net;
|
|
PubSubClient mqtt_client;
|
|
|
|
// Return a character array to represent the
|
|
// state of the kettle.
|
|
char* ShowKettleState() {
|
|
if (KettleController.Mode() == MANUAL) {
|
|
return (char*)F("Kettle: Manual");
|
|
} else if (KettleController.Mode() == AUTOMATIC) {
|
|
return (char*)F("Kettle: Auto");
|
|
} else {
|
|
return (char*)F("Kettle: Off");
|
|
}
|
|
}
|
|
|
|
char* ShowKettleSetting() {
|
|
static char LCD_Line[21];
|
|
char setting[4];
|
|
if (KettleController.Mode() == MANUAL) {
|
|
strcpy(LCD_Line, (char*)F("Kettle Power: "));
|
|
itoa(KettleController.Power(), setting, 10);
|
|
strcat(LCD_Line, setting);
|
|
strcat(LCD_Line, (char*)F("%"));
|
|
|
|
return LCD_Line;
|
|
} else if (KettleController.Mode() == AUTOMATIC) {
|
|
strcpy(LCD_Line, (char*)F("Kettle Temp: "));
|
|
itoa(KettleController.Setpoint(), setting, 10);
|
|
strcat(LCD_Line, setting);
|
|
strcat(LCD_Line, (char*)F("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;
|
|
uint8_t KettleDuty = (uint8_t)KettleController.Power();
|
|
|
|
if (result) {
|
|
uint8_t speed = rotary.speed();
|
|
speed >= 10 ? inc = 5 : inc = 1;
|
|
}
|
|
|
|
if (result == DIR_CW && KettleDuty < 100) {
|
|
KettleDuty = (KettleDuty / inc) * inc + inc;
|
|
} else if (result == DIR_CCW && KettleDuty > 0) {
|
|
KettleDuty = (KettleDuty / inc) * inc - inc;
|
|
}
|
|
KettleController.Power((double)KettleDuty);
|
|
SettingChanged = true;
|
|
}
|
|
|
|
// 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(I_CLK), doEncoder, CHANGE);
|
|
attachInterrupt(digitalPinToInterrupt(I_DT), doEncoder, CHANGE);
|
|
|
|
pinMode(I_CLK, INPUT_PULLUP);
|
|
pinMode(I_DT, INPUT_PULLUP);
|
|
Enter.begin(I_BTN);
|
|
boilPWM.begin(O_PWM, config.period);
|
|
|
|
mqtt_client.setServer(config.mqtt.broker, 1883);
|
|
mqtt_client.setClient(net);
|
|
mqtt_client.setCallback(MessageReceived);
|
|
|
|
KettleController.begin(I_CS1);
|
|
KettleController.SetHysteresis(config.hysteresis);
|
|
KettleController.SetThreshPWR(config.threshold);
|
|
|
|
// 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(){
|
|
|
|
|
|
if (Enter.pressed()) {
|
|
KettleController.CycleMode();
|
|
SettingChanged = true;
|
|
}
|
|
|
|
if (SettingChanged) {
|
|
menu.update();
|
|
SettingChanged = false;
|
|
}
|
|
|
|
if (KettleController.Mode() != OFF) {
|
|
if (KettleController.Compute()) KettleDuty = KettleController.Power();
|
|
digitalWrite(O_PWM, boilPWM.compute(KettleDuty));
|
|
} else {
|
|
digitalWrite(O_PWM, boilPWM.compute(0));
|
|
}
|
|
}
|
|
|
|
void loop() {
|
|
UpdateBoilKettle();
|
|
|
|
unsigned long elapsedTime = (millis() - lastRun);
|
|
|
|
if (Ethernet.linkStatus() == LinkON && elapsedTime >= UpdateInterval) {
|
|
mqtt_client.loop();
|
|
//if (!mqtt_client.connected()) ConnectMQTT();
|
|
|
|
SendSensorData();
|
|
lastRun = millis();
|
|
}
|
|
|
|
}
|