Merge branch 'better_menu' into 'master'
Better menu system. See merge request cgiacofei-brewing/brewery_controller!1
This commit is contained in:
commit
3f554449a7
@ -11,90 +11,61 @@
|
||||
#include <Button.h>
|
||||
#include <MD_REncoder.h>
|
||||
|
||||
// Secret stuff
|
||||
#include "config.h"
|
||||
#include "menu.h"
|
||||
|
||||
// Global variables.
|
||||
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;
|
||||
bool KettleOn = false;
|
||||
kettle_mode KettleMode = OFF;
|
||||
encoder_state EncoderState = ENC_ST_LINE;
|
||||
|
||||
// User I/O objects.
|
||||
Button Enter(encoderBTN);
|
||||
MD_REncoder rotary = MD_REncoder(encoderDT, encoderCLK);
|
||||
/* ---------- User I/O objects ---------- */
|
||||
Button EncoderButton(encoderBTN);
|
||||
MD_REncoder RotaryEncoder(encoderDT, encoderCLK);
|
||||
LiquidCrystal_I2C lcd(0x27,20,4);
|
||||
|
||||
/* ---------- Network bits ---------- */
|
||||
EthernetClient net;
|
||||
MQTTClient mqtt_client;
|
||||
|
||||
// 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);
|
||||
|
||||
/* ---------- 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 UpdateBoilKettle(){
|
||||
static byte last_kettle_duty = 0;
|
||||
|
||||
if (Enter.pressed()) {
|
||||
KettleOn = !KettleOn;
|
||||
menu.update();
|
||||
}
|
||||
|
||||
if (last_kettle_duty != KettleDuty) {
|
||||
last_kettle_duty = KettleDuty;
|
||||
menu.update();
|
||||
}
|
||||
|
||||
if (KettleOn) {
|
||||
slowPWM(kettlePWM, KettleDuty, PeriodPWM);
|
||||
} else {
|
||||
slowPWM(kettlePWM, 0, PeriodPWM);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(9600);
|
||||
rotary.begin();
|
||||
RotaryEncoder.begin();
|
||||
EncoderButton.begin();
|
||||
Ethernet.begin(mac, ip);
|
||||
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);
|
||||
Enter.begin();
|
||||
|
||||
// if you get a connection, report back via serial:
|
||||
if (net.connect("www.google.com", 80)) {
|
||||
@ -121,7 +92,14 @@ void setup() {
|
||||
};
|
||||
|
||||
void loop() {
|
||||
UpdateBoilKettle();
|
||||
ButtonCheck();
|
||||
|
||||
if (KettleMode == PWM) {
|
||||
slowPWM(kettlePWM, KettleDuty, PeriodPWM);
|
||||
} else {
|
||||
slowPWM(kettlePWM, 0, PeriodPWM);
|
||||
}
|
||||
|
||||
static unsigned long lastRun = millis() - UpdateInterval;
|
||||
unsigned long elapsedTime = (millis() - lastRun);
|
||||
|
||||
@ -134,3 +112,147 @@ void loop() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* 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 setpoint as char.
|
||||
* Dummy function for now.
|
||||
*/
|
||||
char* KettleActual() {
|
||||
return (char*)"NA";
|
||||
}
|
||||
|
||||
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--;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
10
boil_kettle/menu.h
Normal file
10
boil_kettle/menu.h
Normal file
@ -0,0 +1,10 @@
|
||||
/* ---------- 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();
|
@ -14,7 +14,7 @@ void ConnectMQTT() {
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
mqtt_client.subscribe(Concatenate(TOPIC_PREFIX, BKTOPIC));
|
||||
mqtt_client.subscribe(Concatenate(TOPIC_PREFIX, BK_SETPOINT_TOPIC));
|
||||
}
|
||||
|
||||
void MessageReceived(String &topic, String &payload) {
|
||||
@ -33,7 +33,7 @@ void MessageReceived(String &topic, String &payload) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (topic == Concatenate(TOPIC_PREFIX, BKTOPIC)) {
|
||||
if (topic == Concatenate(TOPIC_PREFIX, BK_SETPOINT_TOPIC)) {
|
||||
// Update PWM setpoint.
|
||||
String name = doc["entity"];
|
||||
String setting = doc["setpoint"];
|
||||
@ -68,6 +68,6 @@ static void SendSensorData() {
|
||||
String jstr;
|
||||
serializeJson(doc, jstr);
|
||||
|
||||
mqtt_client.publish(Concatenate(TOPIC_PREFIX, "sensor/boil_kettle"), jstr);
|
||||
mqtt_client.publish(Concatenate(TOPIC_PREFIX, BK_ACTUAL_TOPIC), jstr);
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
// 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 from 0 - 100.
|
||||
* period (unsigned long) - Period in milliseconds.
|
||||
*/
|
||||
void slowPWM(byte outputPin, byte dutyCycle, unsigned long period)
|
||||
{
|
||||
pinMode(outputPin, OUTPUT);
|
||||
|
Loading…
Reference in New Issue
Block a user