273 lines
6.4 KiB
C++
273 lines
6.4 KiB
C++
//Built-in
|
|
#include <Arduino.h>
|
|
#include <SPI.h>
|
|
#include <Ethernet.h>
|
|
|
|
// Additoinal Libraries
|
|
#include <ArduinoJson.h>
|
|
#include <MQTT.h>
|
|
#include <LiquidCrystal_I2C.h>
|
|
#include <LiquidMenu.h> // LiquidMenu_config.h needs to be modified to use I2C.
|
|
#include <Button.h>
|
|
#include <MD_REncoder.h>
|
|
#include <Adafruit_MAX31865.h>
|
|
|
|
// My Includes
|
|
#include "config.h"
|
|
#include "menu.h"
|
|
|
|
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;
|
|
kettle_mode KettleMode = OFF;
|
|
encoder_state EncoderState = ENC_ST_LINE;
|
|
|
|
/* ---------- User I/O objects ---------- */
|
|
Button EncoderButton(encoderBTN);
|
|
MD_REncoder RotaryEncoder(encoderDT, encoderCLK);
|
|
LiquidCrystal_I2C lcd(0x27,20,4);
|
|
Adafruit_MAX31865 kettleRTD(kettleRTDCS);
|
|
Adafruit_MAX31865 mashRTD(mashRTDCS);
|
|
|
|
/* ---------- 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);
|
|
LiquidMenu menu(lcd);
|
|
|
|
void setup() {
|
|
|
|
Serial.begin(9600);
|
|
RotaryEncoder.begin();
|
|
EncoderButton.begin();
|
|
Ethernet.begin(mac, ip);
|
|
kettleRTD.begin(MAX31865_3WIRE);
|
|
mashRTD.begin(MAX31865_3WIRE);
|
|
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);
|
|
|
|
// if you get a connection, report back via serial:
|
|
if (net.connect("www.google.com", 80)) {
|
|
Serial.print("you connected to ");
|
|
Serial.println(net.remoteIP());
|
|
// Make a HTTP request:
|
|
net.println("GET /search?q=arduino HTTP/1.1");
|
|
net.println("Host: www.google.com");
|
|
net.println("Connection: close");
|
|
net.println();
|
|
SetupMQTT("192.168.1.198");
|
|
} else {
|
|
// if you didn't get a connection to the server:
|
|
Serial.println("connection failed");
|
|
}
|
|
|
|
lcd.init();
|
|
lcd.backlight();
|
|
|
|
menu.init();
|
|
menu.add_screen(home_screen);
|
|
menu.update();
|
|
|
|
};
|
|
|
|
void loop() {
|
|
ButtonCheck();
|
|
|
|
if (KettleMode == PWM) {
|
|
slowPWM(kettlePWM, KettleDuty, PeriodPWM);
|
|
} else {
|
|
slowPWM(kettlePWM, 0, PeriodPWM);
|
|
}
|
|
|
|
static unsigned long lastRun = millis() - UpdateInterval;
|
|
unsigned long elapsedTime = (millis() - lastRun);
|
|
|
|
if (elapsedTime >= UpdateInterval) {
|
|
mqtt_client.loop();
|
|
//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_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 actual temp as char.
|
|
*/
|
|
char* KettleActual() {
|
|
int temp = (int)(kettleRTD.temperature(RNOMINAL_KETTLE, RREF_KETTLE)*10);
|
|
return (char*)(temp/10);
|
|
}
|
|
|
|
/**
|
|
* Return the actual temp as char.
|
|
*/
|
|
char* MashActual() {
|
|
int temp = (int)(mashRTD.temperature(RNOMINAL_MASH, RREF_MASH)*10);
|
|
return (char*)(temp/10);
|
|
}
|
|
|
|
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--;
|
|
}
|
|
*/
|
|
}
|
|
|